node-server-engine 2.0.1 → 2.1.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.
Files changed (47) hide show
  1. package/.commitlintrc.js +10 -10
  2. package/.nycrc +1 -3
  3. package/.releaserc.js +2 -1
  4. package/README.md +206 -146
  5. package/dist/const/metrics.js.map +1 -1
  6. package/dist/db/models/index.js.map +1 -1
  7. package/dist/entities/AWSS3/AWSS3.js +12 -12
  8. package/dist/entities/AWSS3/AWSS3.js.map +1 -1
  9. package/dist/entities/ElasticSearch/ElasticSearch.js.map +1 -1
  10. package/dist/entities/Endpoint/Endpoint.types.js.map +1 -1
  11. package/dist/entities/GoogleCloudStorage/GoogleCloudStorage.js +11 -11
  12. package/dist/entities/GoogleCloudStorage/GoogleCloudStorage.js.map +1 -1
  13. package/dist/entities/KeySet/KeySet.js.map +1 -1
  14. package/dist/entities/PubSub/PubSub.js.map +1 -1
  15. package/dist/entities/PushNotification/PushNotification.js.map +1 -1
  16. package/dist/entities/Redis/Redis.js +3 -3
  17. package/dist/entities/Redis/Redis.js.map +1 -1
  18. package/dist/entities/SecretManager/SecretManager.js +3 -3
  19. package/dist/entities/SecretManager/SecretManager.js.map +1 -1
  20. package/dist/entities/Sequelize/Sequelize.config.js +11 -7
  21. package/dist/entities/Sequelize/Sequelize.config.js.map +1 -1
  22. package/dist/entities/Sequelize/Sequelize.js.map +1 -1
  23. package/dist/entities/Server/Server.js.map +1 -1
  24. package/dist/entities/Server/Server.types.js.map +1 -1
  25. package/dist/entities/SocketClient/SocketClient.d.ts +12 -0
  26. package/dist/entities/SocketClient/SocketClient.js +34 -3
  27. package/dist/entities/SocketClient/SocketClient.js.map +1 -1
  28. package/dist/entities/SocketClient/SocketClient.types.d.ts +6 -0
  29. package/dist/entities/SocketClient/SocketClient.types.js.map +1 -1
  30. package/dist/entities/index.js.map +1 -1
  31. package/dist/middleware/checkPermission/checkPermission.js.map +1 -1
  32. package/dist/middleware/checkPermission/index.js.map +1 -1
  33. package/dist/middleware/index.js.map +1 -1
  34. package/dist/middleware/multiPartFileUploader/multiPartFileUploader.js.map +1 -1
  35. package/dist/middleware/requestMetrics/requestMetrics.js.map +1 -1
  36. package/dist/middleware/swaggerDocs/swaggerDocs.js.map +1 -1
  37. package/dist/middleware/verificationToken/verificationToken.js.map +1 -1
  38. package/dist/utils/createSortedObject/createSortedObject.js.map +1 -1
  39. package/dist/utils/dbMigration/dbMigration.js.map +1 -1
  40. package/dist/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.js.map +1 -1
  41. package/dist/utils/jwt/jwt.js.map +1 -1
  42. package/dist/utils/jwt/jwt.types.js.map +1 -1
  43. package/dist/utils/report/output.js.map +1 -1
  44. package/dist/utils/report/report.js.map +1 -1
  45. package/dist/utils/semverCompare/semverCompare.js.map +1 -1
  46. package/dist/utils/verificationToken/verificationToken.js.map +1 -1
  47. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"multiPartFileUploader.js","names":["_multer","_interopRequireDefault","require","_fsExtra","_path","_utils","_WebError","_validate","_bytes","namespace","TEMP_DIR","path","join","process","env","FILE_STORAGE_FOLDER","FILE_DIR","fs","ensureDirSync","storage","multer","memoryStorage","DEFAULT_MAX_CHUNK_SIZE","MAX_CHUNKS","Number","UPLOAD_MAX_CHUNKS","SAFE_ID_PATTERN","isSafeFilename","filename","length","test","basename","multiPartFileUploader","filesOption","validator","req","res","next","reportDebug","message","chunkSizeLimit","maxSize","bytes","UPLOAD_MAX_SIZE","uploadSingle","limits","fileSize","files","single","err","code","WebError","statusCode","errorCode","data","reportError","error","validate","totalChunks","chunkIndex","uniqueID","body","undefined","file","receivedChunk","chunkIndexNum","totalChunksNum","isInteger","size","receivedSize","sessionFolder","chunkPath","writeFile","buffer","writeErr","uploadedChunks","readdir","finalFilePath","mergeChunks","multipartFile","isPending","originalname","filePath","mergeErr","writeStream","createWriteStream","parseInt","chunks","i","partPath","chunkData","readFile","push","remove","catch","cleanupErr","write","end","Promise","resolve","reject","on","then"],"sources":["../../../src/middleware/multiPartFileUploader/multiPartFileUploader.ts"],"sourcesContent":["import { Request, Response, NextFunction } from 'express';\nimport multer from 'multer';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { Schema } from 'express-validator';\nimport { reportDebug, reportError } from 'utils';\nimport { WebError } from 'entities/WebError';\nimport { validate } from './validate';\nimport { MultiPartFileUploaderConfig } from './multiPartFileUploader.types';\nimport bytes from 'bytes';\n\nconst namespace = 'engine:middleware:multiPartFileUploader';\n\nconst TEMP_DIR: string = path.join(\n process.env.FILE_STORAGE_FOLDER || './uploads',\n 'temp_chunks'\n);\nconst FILE_DIR: string = path.join(\n process.env.FILE_STORAGE_FOLDER || './uploads',\n 'completed_files'\n);\n\nfs.ensureDirSync(FILE_DIR);\nfs.ensureDirSync(TEMP_DIR);\n\nconst storage = multer.memoryStorage();\n\n/** Default maximum size of a single chunk when no limit is configured */\nconst DEFAULT_MAX_CHUNK_SIZE = 32 * 1024 * 1024;\n/** Maximum number of chunks a single upload can be split into */\nconst MAX_CHUNKS = Number(process.env.UPLOAD_MAX_CHUNKS) || 10000;\n/** Upload session IDs are restricted to a safe charset so they can be used as a folder name */\nconst SAFE_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;\n\n/** Check that a client supplied file name cannot escape its destination folder */\nfunction isSafeFilename(filename: string): boolean {\n return (\n filename.length > 0 &&\n filename.length <= 255 &&\n filename !== '.' &&\n filename !== '..' &&\n !/[/\\\\\\0]/.test(filename) &&\n path.basename(filename) === filename\n );\n}\n\nexport function multiPartFileUploader(\n filesOption: MultiPartFileUploaderConfig,\n validator: Schema\n) {\n return async (\n req: Request,\n res: Response,\n next: NextFunction\n ): Promise<void> => {\n try {\n reportDebug({ namespace, message: 'Starting file upload middleware' });\n\n // Bound the size of a single chunk held in memory\n const chunkSizeLimit =\n (filesOption?.maxSize && bytes(filesOption.maxSize)) ||\n (process.env.UPLOAD_MAX_SIZE && bytes(process.env.UPLOAD_MAX_SIZE)) ||\n DEFAULT_MAX_CHUNK_SIZE;\n const uploadSingle = multer({\n storage,\n limits: { fileSize: chunkSizeLimit, files: 1 }\n }).single('file');\n uploadSingle(req, res, async (err) => {\n if ((err as { code?: string } | undefined)?.code === 'LIMIT_FILE_SIZE') {\n return next(\n new WebError({\n statusCode: 413,\n errorCode: 'chunk-too-large',\n message: 'Uploaded chunk exceeds the maximum allowed size',\n data: { maxSize: chunkSizeLimit }\n })\n );\n }\n if (err) {\n reportError('Error uploading chunk');\n return next(\n new WebError({\n statusCode: 500,\n errorCode: 'upload-failed',\n message: 'Error uploading file chunk',\n data: { error: err.message }\n })\n );\n }\n\n try {\n reportDebug({ namespace, message: 'Validating request' });\n await validate(req, validator);\n } catch (error) {\n reportDebug({\n namespace,\n message: 'Validation failed',\n data: { error }\n });\n return next(\n new WebError({\n statusCode: 400,\n errorCode: 'validation-failed',\n message: 'Validation failed for file upload',\n data: { error: (error as Error).message }\n })\n );\n }\n\n const { filename, totalChunks, chunkIndex, uniqueID } = req.body;\n reportDebug({\n namespace,\n message: 'Received chunk data',\n data: { filename, totalChunks, chunkIndex, uniqueID }\n });\n\n if (\n !filename ||\n !totalChunks ||\n chunkIndex === undefined ||\n !uniqueID ||\n !req.file\n ) {\n return next(\n new WebError({\n statusCode: 400,\n errorCode: 'missing-field',\n message: 'Missing required fields',\n data: {\n filename,\n totalChunks,\n chunkIndex,\n uniqueID,\n receivedChunk: !!req.file\n }\n })\n );\n }\n\n // Client supplied values are used to build file system paths, they must be strictly validated\n // to prevent path traversal (e.g. uniqueID=\"../../etc\") and resource exhaustion\n const chunkIndexNum = Number(chunkIndex);\n const totalChunksNum = Number(totalChunks);\n if (\n typeof uniqueID !== 'string' ||\n !SAFE_ID_PATTERN.test(uniqueID) ||\n typeof filename !== 'string' ||\n !isSafeFilename(filename) ||\n !Number.isInteger(totalChunksNum) ||\n totalChunksNum < 1 ||\n totalChunksNum > MAX_CHUNKS ||\n !Number.isInteger(chunkIndexNum) ||\n chunkIndexNum < 0 ||\n chunkIndexNum >= totalChunksNum\n ) {\n return next(\n new WebError({\n statusCode: 400,\n errorCode: 'invalid-field',\n message: 'Invalid chunk upload parameters',\n data: { filename, totalChunks, chunkIndex, uniqueID }\n })\n );\n }\n\n if (\n filesOption?.maxSize &&\n req.file.size > (bytes(filesOption.maxSize) || 0)\n ) {\n return next(\n new WebError({\n statusCode: 400,\n errorCode: 'chunk-too-large',\n message: 'Uploaded chunk exceeds the maximum allowed size',\n data: {\n maxSize: filesOption.maxSize,\n receivedSize: req.file.size\n }\n })\n );\n }\n\n const sessionFolder = path.join(TEMP_DIR, uniqueID);\n fs.ensureDirSync(sessionFolder);\n const chunkPath = path.join(\n sessionFolder,\n `${filename}.part${chunkIndexNum}`\n );\n\n try {\n reportDebug({\n namespace,\n message: 'Writing chunk to disk',\n data: { chunkPath }\n });\n await fs.writeFile(chunkPath, req.file.buffer);\n } catch (writeErr) {\n return next(\n new WebError({\n statusCode: 500,\n errorCode: 'chunk-write-failed',\n message: 'Failed to write chunk',\n data: { chunkIndex, error: (writeErr as Error).message }\n })\n );\n }\n\n const uploadedChunks = await fs.readdir(sessionFolder);\n reportDebug({\n namespace,\n message: 'Uploaded chunk count',\n data: { uploadedChunks: uploadedChunks.length, totalChunks }\n });\n\n if (uploadedChunks.length === totalChunksNum) {\n try {\n const finalFilePath = path.join(\n FILE_DIR,\n `${uniqueID}_${filename}`\n );\n await mergeChunks(\n filename,\n totalChunks,\n sessionFolder,\n finalFilePath\n );\n req.multipartFile = {\n isPending: false,\n originalname: filename,\n uniqueID,\n filePath: finalFilePath\n };\n } catch (mergeErr) {\n return next(\n new WebError({\n statusCode: 500,\n errorCode: 'file-merge-failed',\n message: 'Error merging file chunks',\n data: { error: (mergeErr as Error).message }\n })\n );\n }\n return next();\n }\n\n req.multipartFile = {\n isPending: true,\n originalname: filename,\n uniqueID,\n chunkIndex,\n totalChunks\n };\n next();\n });\n } catch (error) {\n next(\n new WebError({\n statusCode: 500,\n errorCode: 'unexpected-error',\n message: 'Unexpected error in file upload',\n data: { error: (error as Error).message }\n })\n );\n }\n };\n}\n\nasync function mergeChunks(\n filename: string,\n totalChunks: string | number,\n sessionFolder: string,\n finalFilePath: string\n): Promise<void> {\n const writeStream = fs.createWriteStream(finalFilePath);\n reportDebug({\n namespace,\n message: 'Merging file chunks',\n data: { finalFilePath }\n });\n\n const totalChunksNum = parseInt(totalChunks as string, 10);\n const chunks: Buffer[] = [];\n\n // Read all chunks into memory first\n for (let i = 0; i < totalChunksNum; i++) {\n const partPath = path.join(sessionFolder, `${filename}.part${i}`);\n try {\n const chunkData = await fs.readFile(partPath);\n chunks.push(chunkData);\n } catch (error) {\n // Cleanup on error\n await fs.remove(sessionFolder).catch((cleanupErr: Error) =>\n reportError(`Error cleaning up folder ${sessionFolder}: ${cleanupErr.message}`)\n );\n throw new WebError({\n statusCode: 500,\n errorCode: 'chunk-read-failed',\n message: `Error reading chunk ${i}`,\n data: { error: (error as Error).message }\n });\n }\n }\n\n // Write all chunks sequentially\n for (const chunkData of chunks) {\n writeStream.write(chunkData);\n }\n\n // Remove temp files\n for (let i = 0; i < totalChunksNum; i++) {\n const partPath = path.join(sessionFolder, `${filename}.part${i}`);\n fs.remove(partPath).catch((err: Error) =>\n reportError(`Error removing part ${partPath}: ${err.message}`)\n );\n }\n\n writeStream.end();\n return new Promise<void>((resolve, reject) => {\n writeStream.on('finish', () => {\n // Clean up temp folder after successful merge\n fs.remove(sessionFolder)\n .then(() => resolve(undefined))\n .catch((cleanupErr: Error) => {\n reportError(\n `Error cleaning up temp folder ${sessionFolder}: ${cleanupErr.message}`\n );\n resolve(undefined); // Don't fail the merge if cleanup fails\n });\n });\n writeStream.on('error', (error) => {\n // Cleanup on write error\n fs.remove(sessionFolder).catch((cleanupErr: Error) =>\n reportError(`Error cleaning up folder after write error: ${cleanupErr.message}`)\n );\n reject(\n new WebError({\n statusCode: 500,\n errorCode: 'file-merge-error',\n message: 'Error merging file chunks',\n data: { error: (error as Error).message }\n })\n );\n });\n });\n}\n"],"mappings":";;;;;;;AACA,IAAAA,OAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,QAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,KAAA,GAAAH,sBAAA,CAAAC,OAAA;AAEA,IAAAG,MAAA,GAAAH,OAAA;AACA,IAAAI,SAAA,GAAAJ,OAAA;AACA,IAAAK,SAAA,GAAAL,OAAA;AAEA,IAAAM,MAAA,GAAAP,sBAAA,CAAAC,OAAA;AAEA,MAAMO,SAAS,GAAG,yCAAyC;AAE3D,MAAMC,QAAgB,GAAGC,aAAI,CAACC,IAAI,CAChCC,OAAO,CAACC,GAAG,CAACC,mBAAmB,IAAI,WAAW,EAC9C,aACF,CAAC;AACD,MAAMC,QAAgB,GAAGL,aAAI,CAACC,IAAI,CAChCC,OAAO,CAACC,GAAG,CAACC,mBAAmB,IAAI,WAAW,EAC9C,iBACF,CAAC;AAEDE,gBAAE,CAACC,aAAa,CAACF,QAAQ,CAAC;AAC1BC,gBAAE,CAACC,aAAa,CAACR,QAAQ,CAAC;AAE1B,MAAMS,OAAO,GAAGC,eAAM,CAACC,aAAa,CAAC,CAAC;;AAEtC;AACA,MAAMC,sBAAsB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI;AAC/C;AACA,MAAMC,UAAU,GAAGC,MAAM,CAACX,OAAO,CAACC,GAAG,CAACW,iBAAiB,CAAC,IAAI,KAAK;AACjE;AACA,MAAMC,eAAe,GAAG,wBAAwB;;AAEhD;AACA,SAASC,cAAcA,CAACC,QAAgB,EAAW;EACjD,OACEA,QAAQ,CAACC,MAAM,GAAG,CAAC,IACnBD,QAAQ,CAACC,MAAM,IAAI,GAAG,IACtBD,QAAQ,KAAK,GAAG,IAChBA,QAAQ,KAAK,IAAI,IACjB,CAAC,SAAS,CAACE,IAAI,CAACF,QAAQ,CAAC,IACzBjB,aAAI,CAACoB,QAAQ,CAACH,QAAQ,CAAC,KAAKA,QAAQ;AAExC;AAEO,SAASI,qBAAqBA,CACnCC,WAAwC,EACxCC,SAAiB,EACjB;EACA,OAAO,OACLC,GAAY,EACZC,GAAa,EACbC,IAAkB,KACA;IAClB,IAAI;MACF,IAAAC,kBAAW,EAAC;QAAE7B,SAAS;QAAE8B,OAAO,EAAE;MAAkC,CAAC,CAAC;;MAEtE;MACA,MAAMC,cAAc,GACjBP,WAAW,EAAEQ,OAAO,IAAI,IAAAC,cAAK,EAACT,WAAW,CAACQ,OAAO,CAAC,IAClD5B,OAAO,CAACC,GAAG,CAAC6B,eAAe,IAAI,IAAAD,cAAK,EAAC7B,OAAO,CAACC,GAAG,CAAC6B,eAAe,CAAE,IACnErB,sBAAsB;MACxB,MAAMsB,YAAY,GAAG,IAAAxB,eAAM,EAAC;QAC1BD,OAAO;QACP0B,MAAM,EAAE;UAAEC,QAAQ,EAAEN,cAAc;UAAEO,KAAK,EAAE;QAAE;MAC/C,CAAC,CAAC,CAACC,MAAM,CAAC,MAAM,CAAC;MACjBJ,YAAY,CAACT,GAAG,EAAEC,GAAG,EAAE,MAAOa,GAAG,IAAK;QACpC,IAAKA,GAAG,EAAoCC,IAAI,KAAK,iBAAiB,EAAE;UACtE,OAAOb,IAAI,CACT,IAAIc,kBAAQ,CAAC;YACXC,UAAU,EAAE,GAAG;YACfC,SAAS,EAAE,iBAAiB;YAC5Bd,OAAO,EAAE,iDAAiD;YAC1De,IAAI,EAAE;cAAEb,OAAO,EAAED;YAAe;UAClC,CAAC,CACH,CAAC;QACH;QACA,IAAIS,GAAG,EAAE;UACP,IAAAM,kBAAW,EAAC,uBAAuB,CAAC;UACpC,OAAOlB,IAAI,CACT,IAAIc,kBAAQ,CAAC;YACXC,UAAU,EAAE,GAAG;YACfC,SAAS,EAAE,eAAe;YAC1Bd,OAAO,EAAE,4BAA4B;YACrCe,IAAI,EAAE;cAAEE,KAAK,EAAEP,GAAG,CAACV;YAAQ;UAC7B,CAAC,CACH,CAAC;QACH;QAEA,IAAI;UACF,IAAAD,kBAAW,EAAC;YAAE7B,SAAS;YAAE8B,OAAO,EAAE;UAAqB,CAAC,CAAC;UACzD,MAAM,IAAAkB,kBAAQ,EAACtB,GAAG,EAAED,SAAS,CAAC;QAChC,CAAC,CAAC,OAAOsB,KAAK,EAAE;UACd,IAAAlB,kBAAW,EAAC;YACV7B,SAAS;YACT8B,OAAO,EAAE,mBAAmB;YAC5Be,IAAI,EAAE;cAAEE;YAAM;UAChB,CAAC,CAAC;UACF,OAAOnB,IAAI,CACT,IAAIc,kBAAQ,CAAC;YACXC,UAAU,EAAE,GAAG;YACfC,SAAS,EAAE,mBAAmB;YAC9Bd,OAAO,EAAE,mCAAmC;YAC5Ce,IAAI,EAAE;cAAEE,KAAK,EAAGA,KAAK,CAAWjB;YAAQ;UAC1C,CAAC,CACH,CAAC;QACH;QAEA,MAAM;UAAEX,QAAQ;UAAE8B,WAAW;UAAEC,UAAU;UAAEC;QAAS,CAAC,GAAGzB,GAAG,CAAC0B,IAAI;QAChE,IAAAvB,kBAAW,EAAC;UACV7B,SAAS;UACT8B,OAAO,EAAE,qBAAqB;UAC9Be,IAAI,EAAE;YAAE1B,QAAQ;YAAE8B,WAAW;YAAEC,UAAU;YAAEC;UAAS;QACtD,CAAC,CAAC;QAEF,IACE,CAAChC,QAAQ,IACT,CAAC8B,WAAW,IACZC,UAAU,KAAKG,SAAS,IACxB,CAACF,QAAQ,IACT,CAACzB,GAAG,CAAC4B,IAAI,EACT;UACA,OAAO1B,IAAI,CACT,IAAIc,kBAAQ,CAAC;YACXC,UAAU,EAAE,GAAG;YACfC,SAAS,EAAE,eAAe;YAC1Bd,OAAO,EAAE,yBAAyB;YAClCe,IAAI,EAAE;cACJ1B,QAAQ;cACR8B,WAAW;cACXC,UAAU;cACVC,QAAQ;cACRI,aAAa,EAAE,CAAC,CAAC7B,GAAG,CAAC4B;YACvB;UACF,CAAC,CACH,CAAC;QACH;;QAEA;QACA;QACA,MAAME,aAAa,GAAGzC,MAAM,CAACmC,UAAU,CAAC;QACxC,MAAMO,cAAc,GAAG1C,MAAM,CAACkC,WAAW,CAAC;QAC1C,IACE,OAAOE,QAAQ,KAAK,QAAQ,IAC5B,CAAClC,eAAe,CAACI,IAAI,CAAC8B,QAAQ,CAAC,IAC/B,OAAOhC,QAAQ,KAAK,QAAQ,IAC5B,CAACD,cAAc,CAACC,QAAQ,CAAC,IACzB,CAACJ,MAAM,CAAC2C,SAAS,CAACD,cAAc,CAAC,IACjCA,cAAc,GAAG,CAAC,IAClBA,cAAc,GAAG3C,UAAU,IAC3B,CAACC,MAAM,CAAC2C,SAAS,CAACF,aAAa,CAAC,IAChCA,aAAa,GAAG,CAAC,IACjBA,aAAa,IAAIC,cAAc,EAC/B;UACA,OAAO7B,IAAI,CACT,IAAIc,kBAAQ,CAAC;YACXC,UAAU,EAAE,GAAG;YACfC,SAAS,EAAE,eAAe;YAC1Bd,OAAO,EAAE,iCAAiC;YAC1Ce,IAAI,EAAE;cAAE1B,QAAQ;cAAE8B,WAAW;cAAEC,UAAU;cAAEC;YAAS;UACtD,CAAC,CACH,CAAC;QACH;QAEA,IACE3B,WAAW,EAAEQ,OAAO,IACpBN,GAAG,CAAC4B,IAAI,CAACK,IAAI,IAAI,IAAA1B,cAAK,EAACT,WAAW,CAACQ,OAAO,CAAC,IAAI,CAAC,CAAC,EACjD;UACA,OAAOJ,IAAI,CACT,IAAIc,kBAAQ,CAAC;YACXC,UAAU,EAAE,GAAG;YACfC,SAAS,EAAE,iBAAiB;YAC5Bd,OAAO,EAAE,iDAAiD;YAC1De,IAAI,EAAE;cACJb,OAAO,EAAER,WAAW,CAACQ,OAAO;cAC5B4B,YAAY,EAAElC,GAAG,CAAC4B,IAAI,CAACK;YACzB;UACF,CAAC,CACH,CAAC;QACH;QAEA,MAAME,aAAa,GAAG3D,aAAI,CAACC,IAAI,CAACF,QAAQ,EAAEkD,QAAQ,CAAC;QACnD3C,gBAAE,CAACC,aAAa,CAACoD,aAAa,CAAC;QAC/B,MAAMC,SAAS,GAAG5D,aAAI,CAACC,IAAI,CACzB0D,aAAa,EACb,GAAG1C,QAAQ,QAAQqC,aAAa,EAClC,CAAC;QAED,IAAI;UACF,IAAA3B,kBAAW,EAAC;YACV7B,SAAS;YACT8B,OAAO,EAAE,uBAAuB;YAChCe,IAAI,EAAE;cAAEiB;YAAU;UACpB,CAAC,CAAC;UACF,MAAMtD,gBAAE,CAACuD,SAAS,CAACD,SAAS,EAAEpC,GAAG,CAAC4B,IAAI,CAACU,MAAM,CAAC;QAChD,CAAC,CAAC,OAAOC,QAAQ,EAAE;UACjB,OAAOrC,IAAI,CACT,IAAIc,kBAAQ,CAAC;YACXC,UAAU,EAAE,GAAG;YACfC,SAAS,EAAE,oBAAoB;YAC/Bd,OAAO,EAAE,uBAAuB;YAChCe,IAAI,EAAE;cAAEK,UAAU;cAAEH,KAAK,EAAGkB,QAAQ,CAAWnC;YAAQ;UACzD,CAAC,CACH,CAAC;QACH;QAEA,MAAMoC,cAAc,GAAG,MAAM1D,gBAAE,CAAC2D,OAAO,CAACN,aAAa,CAAC;QACtD,IAAAhC,kBAAW,EAAC;UACV7B,SAAS;UACT8B,OAAO,EAAE,sBAAsB;UAC/Be,IAAI,EAAE;YAAEqB,cAAc,EAAEA,cAAc,CAAC9C,MAAM;YAAE6B;UAAY;QAC7D,CAAC,CAAC;QAEF,IAAIiB,cAAc,CAAC9C,MAAM,KAAKqC,cAAc,EAAE;UAC5C,IAAI;YACF,MAAMW,aAAa,GAAGlE,aAAI,CAACC,IAAI,CAC7BI,QAAQ,EACR,GAAG4C,QAAQ,IAAIhC,QAAQ,EACzB,CAAC;YACD,MAAMkD,WAAW,CACflD,QAAQ,EACR8B,WAAW,EACXY,aAAa,EACbO,aACF,CAAC;YACD1C,GAAG,CAAC4C,aAAa,GAAG;cAClBC,SAAS,EAAE,KAAK;cAChBC,YAAY,EAAErD,QAAQ;cACtBgC,QAAQ;cACRsB,QAAQ,EAAEL;YACZ,CAAC;UACH,CAAC,CAAC,OAAOM,QAAQ,EAAE;YACjB,OAAO9C,IAAI,CACT,IAAIc,kBAAQ,CAAC;cACXC,UAAU,EAAE,GAAG;cACfC,SAAS,EAAE,mBAAmB;cAC9Bd,OAAO,EAAE,2BAA2B;cACpCe,IAAI,EAAE;gBAAEE,KAAK,EAAG2B,QAAQ,CAAW5C;cAAQ;YAC7C,CAAC,CACH,CAAC;UACH;UACA,OAAOF,IAAI,CAAC,CAAC;QACf;QAEAF,GAAG,CAAC4C,aAAa,GAAG;UAClBC,SAAS,EAAE,IAAI;UACfC,YAAY,EAAErD,QAAQ;UACtBgC,QAAQ;UACRD,UAAU;UACVD;QACF,CAAC;QACDrB,IAAI,CAAC,CAAC;MACR,CAAC,CAAC;IACJ,CAAC,CAAC,OAAOmB,KAAK,EAAE;MACdnB,IAAI,CACF,IAAIc,kBAAQ,CAAC;QACXC,UAAU,EAAE,GAAG;QACfC,SAAS,EAAE,kBAAkB;QAC7Bd,OAAO,EAAE,iCAAiC;QAC1Ce,IAAI,EAAE;UAAEE,KAAK,EAAGA,KAAK,CAAWjB;QAAQ;MAC1C,CAAC,CACH,CAAC;IACH;EACF,CAAC;AACH;AAEA,eAAeuC,WAAWA,CACxBlD,QAAgB,EAChB8B,WAA4B,EAC5BY,aAAqB,EACrBO,aAAqB,EACN;EACf,MAAMO,WAAW,GAAGnE,gBAAE,CAACoE,iBAAiB,CAACR,aAAa,CAAC;EACvD,IAAAvC,kBAAW,EAAC;IACV7B,SAAS;IACT8B,OAAO,EAAE,qBAAqB;IAC9Be,IAAI,EAAE;MAAEuB;IAAc;EACxB,CAAC,CAAC;EAEF,MAAMX,cAAc,GAAGoB,QAAQ,CAAC5B,WAAW,EAAY,EAAE,CAAC;EAC1D,MAAM6B,MAAgB,GAAG,EAAE;;EAE3B;EACA,KAAK,IAAIC,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGtB,cAAc,EAAEsB,CAAC,EAAE,EAAE;IACvC,MAAMC,QAAQ,GAAG9E,aAAI,CAACC,IAAI,CAAC0D,aAAa,EAAE,GAAG1C,QAAQ,QAAQ4D,CAAC,EAAE,CAAC;IACjE,IAAI;MACF,MAAME,SAAS,GAAG,MAAMzE,gBAAE,CAAC0E,QAAQ,CAACF,QAAQ,CAAC;MAC7CF,MAAM,CAACK,IAAI,CAACF,SAAS,CAAC;IACxB,CAAC,CAAC,OAAOlC,KAAK,EAAE;MACd;MACA,MAAMvC,gBAAE,CAAC4E,MAAM,CAACvB,aAAa,CAAC,CAACwB,KAAK,CAAEC,UAAiB,IACrD,IAAAxC,kBAAW,EAAC,4BAA4Be,aAAa,KAAKyB,UAAU,CAACxD,OAAO,EAAE,CAChF,CAAC;MACD,MAAM,IAAIY,kBAAQ,CAAC;QACjBC,UAAU,EAAE,GAAG;QACfC,SAAS,EAAE,mBAAmB;QAC9Bd,OAAO,EAAE,uBAAuBiD,CAAC,EAAE;QACnClC,IAAI,EAAE;UAAEE,KAAK,EAAGA,KAAK,CAAWjB;QAAQ;MAC1C,CAAC,CAAC;IACJ;EACF;;EAEA;EACA,KAAK,MAAMmD,SAAS,IAAIH,MAAM,EAAE;IAC9BH,WAAW,CAACY,KAAK,CAACN,SAAS,CAAC;EAC9B;;EAEA;EACA,KAAK,IAAIF,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGtB,cAAc,EAAEsB,CAAC,EAAE,EAAE;IACvC,MAAMC,QAAQ,GAAG9E,aAAI,CAACC,IAAI,CAAC0D,aAAa,EAAE,GAAG1C,QAAQ,QAAQ4D,CAAC,EAAE,CAAC;IACjEvE,gBAAE,CAAC4E,MAAM,CAACJ,QAAQ,CAAC,CAACK,KAAK,CAAE7C,GAAU,IACnC,IAAAM,kBAAW,EAAC,uBAAuBkC,QAAQ,KAAKxC,GAAG,CAACV,OAAO,EAAE,CAC/D,CAAC;EACH;EAEA6C,WAAW,CAACa,GAAG,CAAC,CAAC;EACjB,OAAO,IAAIC,OAAO,CAAO,CAACC,OAAO,EAAEC,MAAM,KAAK;IAC5ChB,WAAW,CAACiB,EAAE,CAAC,QAAQ,EAAE,MAAM;MAC7B;MACApF,gBAAE,CAAC4E,MAAM,CAACvB,aAAa,CAAC,CACrBgC,IAAI,CAAC,MAAMH,OAAO,CAACrC,SAAS,CAAC,CAAC,CAC9BgC,KAAK,CAAEC,UAAiB,IAAK;QAC5B,IAAAxC,kBAAW,EACT,iCAAiCe,aAAa,KAAKyB,UAAU,CAACxD,OAAO,EACvE,CAAC;QACD4D,OAAO,CAACrC,SAAS,CAAC,CAAC,CAAC;MACtB,CAAC,CAAC;IACN,CAAC,CAAC;IACFsB,WAAW,CAACiB,EAAE,CAAC,OAAO,EAAG7C,KAAK,IAAK;MACjC;MACAvC,gBAAE,CAAC4E,MAAM,CAACvB,aAAa,CAAC,CAACwB,KAAK,CAAEC,UAAiB,IAC/C,IAAAxC,kBAAW,EAAC,+CAA+CwC,UAAU,CAACxD,OAAO,EAAE,CACjF,CAAC;MACD6D,MAAM,CACJ,IAAIjD,kBAAQ,CAAC;QACXC,UAAU,EAAE,GAAG;QACfC,SAAS,EAAE,kBAAkB;QAC7Bd,OAAO,EAAE,2BAA2B;QACpCe,IAAI,EAAE;UAAEE,KAAK,EAAGA,KAAK,CAAWjB;QAAQ;MAC1C,CAAC,CACH,CAAC;IACH,CAAC,CAAC;EACJ,CAAC,CAAC;AACJ","ignoreList":[]}
1
+ {"version":3,"file":"multiPartFileUploader.js","names":["_multer","_interopRequireDefault","require","_fsExtra","_path","_utils","_WebError","_validate","_bytes","namespace","TEMP_DIR","path","join","process","env","FILE_STORAGE_FOLDER","FILE_DIR","fs","ensureDirSync","storage","multer","memoryStorage","DEFAULT_MAX_CHUNK_SIZE","MAX_CHUNKS","Number","UPLOAD_MAX_CHUNKS","SAFE_ID_PATTERN","isSafeFilename","filename","length","test","basename","multiPartFileUploader","filesOption","validator","req","res","next","reportDebug","message","chunkSizeLimit","maxSize","bytes","UPLOAD_MAX_SIZE","uploadSingle","limits","fileSize","files","single","err","code","WebError","statusCode","errorCode","data","reportError","error","validate","totalChunks","chunkIndex","uniqueID","body","undefined","file","receivedChunk","chunkIndexNum","totalChunksNum","isInteger","size","receivedSize","sessionFolder","chunkPath","writeFile","buffer","writeErr","uploadedChunks","readdir","finalFilePath","mergeChunks","multipartFile","isPending","originalname","filePath","mergeErr","writeStream","createWriteStream","parseInt","chunks","i","partPath","chunkData","readFile","push","remove","catch","cleanupErr","write","end","Promise","resolve","reject","on","then"],"sources":["../../../src/middleware/multiPartFileUploader/multiPartFileUploader.ts"],"sourcesContent":["import { Request, Response, NextFunction } from 'express';\nimport multer from 'multer';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { Schema } from 'express-validator';\nimport { reportDebug, reportError } from 'utils';\nimport { WebError } from 'entities/WebError';\nimport { validate } from './validate';\nimport { MultiPartFileUploaderConfig } from './multiPartFileUploader.types';\nimport bytes from 'bytes';\n\nconst namespace = 'engine:middleware:multiPartFileUploader';\n\nconst TEMP_DIR: string = path.join(\n process.env.FILE_STORAGE_FOLDER || './uploads',\n 'temp_chunks'\n);\nconst FILE_DIR: string = path.join(\n process.env.FILE_STORAGE_FOLDER || './uploads',\n 'completed_files'\n);\n\nfs.ensureDirSync(FILE_DIR);\nfs.ensureDirSync(TEMP_DIR);\n\nconst storage = multer.memoryStorage();\n\n/** Default maximum size of a single chunk when no limit is configured */\nconst DEFAULT_MAX_CHUNK_SIZE = 32 * 1024 * 1024;\n/** Maximum number of chunks a single upload can be split into */\nconst MAX_CHUNKS = Number(process.env.UPLOAD_MAX_CHUNKS) || 10000;\n/** Upload session IDs are restricted to a safe charset so they can be used as a folder name */\nconst SAFE_ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;\n\n/** Check that a client supplied file name cannot escape its destination folder */\nfunction isSafeFilename(filename: string): boolean {\n return (\n filename.length > 0 &&\n filename.length <= 255 &&\n filename !== '.' &&\n filename !== '..' &&\n !/[/\\\\\\0]/.test(filename) &&\n path.basename(filename) === filename\n );\n}\n\nexport function multiPartFileUploader(\n filesOption: MultiPartFileUploaderConfig,\n validator: Schema\n) {\n return async (\n req: Request,\n res: Response,\n next: NextFunction\n ): Promise<void> => {\n try {\n reportDebug({ namespace, message: 'Starting file upload middleware' });\n\n // Bound the size of a single chunk held in memory\n const chunkSizeLimit =\n (filesOption?.maxSize && bytes(filesOption.maxSize)) ||\n (process.env.UPLOAD_MAX_SIZE && bytes(process.env.UPLOAD_MAX_SIZE)) ||\n DEFAULT_MAX_CHUNK_SIZE;\n const uploadSingle = multer({\n storage,\n limits: { fileSize: chunkSizeLimit, files: 1 }\n }).single('file');\n uploadSingle(req, res, async (err) => {\n if (\n (err as { code?: string } | undefined)?.code === 'LIMIT_FILE_SIZE'\n ) {\n return next(\n new WebError({\n statusCode: 413,\n errorCode: 'chunk-too-large',\n message: 'Uploaded chunk exceeds the maximum allowed size',\n data: { maxSize: chunkSizeLimit }\n })\n );\n }\n if (err) {\n reportError('Error uploading chunk');\n return next(\n new WebError({\n statusCode: 500,\n errorCode: 'upload-failed',\n message: 'Error uploading file chunk',\n data: { error: err.message }\n })\n );\n }\n\n try {\n reportDebug({ namespace, message: 'Validating request' });\n await validate(req, validator);\n } catch (error) {\n reportDebug({\n namespace,\n message: 'Validation failed',\n data: { error }\n });\n return next(\n new WebError({\n statusCode: 400,\n errorCode: 'validation-failed',\n message: 'Validation failed for file upload',\n data: { error: (error as Error).message }\n })\n );\n }\n\n const { filename, totalChunks, chunkIndex, uniqueID } = req.body;\n reportDebug({\n namespace,\n message: 'Received chunk data',\n data: { filename, totalChunks, chunkIndex, uniqueID }\n });\n\n if (\n !filename ||\n !totalChunks ||\n chunkIndex === undefined ||\n !uniqueID ||\n !req.file\n ) {\n return next(\n new WebError({\n statusCode: 400,\n errorCode: 'missing-field',\n message: 'Missing required fields',\n data: {\n filename,\n totalChunks,\n chunkIndex,\n uniqueID,\n receivedChunk: !!req.file\n }\n })\n );\n }\n\n // Client supplied values are used to build file system paths, they must be strictly validated\n // to prevent path traversal (e.g. uniqueID=\"../../etc\") and resource exhaustion\n const chunkIndexNum = Number(chunkIndex);\n const totalChunksNum = Number(totalChunks);\n if (\n typeof uniqueID !== 'string' ||\n !SAFE_ID_PATTERN.test(uniqueID) ||\n typeof filename !== 'string' ||\n !isSafeFilename(filename) ||\n !Number.isInteger(totalChunksNum) ||\n totalChunksNum < 1 ||\n totalChunksNum > MAX_CHUNKS ||\n !Number.isInteger(chunkIndexNum) ||\n chunkIndexNum < 0 ||\n chunkIndexNum >= totalChunksNum\n ) {\n return next(\n new WebError({\n statusCode: 400,\n errorCode: 'invalid-field',\n message: 'Invalid chunk upload parameters',\n data: { filename, totalChunks, chunkIndex, uniqueID }\n })\n );\n }\n\n if (\n filesOption?.maxSize &&\n req.file.size > (bytes(filesOption.maxSize) || 0)\n ) {\n return next(\n new WebError({\n statusCode: 400,\n errorCode: 'chunk-too-large',\n message: 'Uploaded chunk exceeds the maximum allowed size',\n data: {\n maxSize: filesOption.maxSize,\n receivedSize: req.file.size\n }\n })\n );\n }\n\n const sessionFolder = path.join(TEMP_DIR, uniqueID);\n fs.ensureDirSync(sessionFolder);\n const chunkPath = path.join(\n sessionFolder,\n `${filename}.part${chunkIndexNum}`\n );\n\n try {\n reportDebug({\n namespace,\n message: 'Writing chunk to disk',\n data: { chunkPath }\n });\n await fs.writeFile(chunkPath, req.file.buffer);\n } catch (writeErr) {\n return next(\n new WebError({\n statusCode: 500,\n errorCode: 'chunk-write-failed',\n message: 'Failed to write chunk',\n data: { chunkIndex, error: (writeErr as Error).message }\n })\n );\n }\n\n const uploadedChunks = await fs.readdir(sessionFolder);\n reportDebug({\n namespace,\n message: 'Uploaded chunk count',\n data: { uploadedChunks: uploadedChunks.length, totalChunks }\n });\n\n if (uploadedChunks.length === totalChunksNum) {\n try {\n const finalFilePath = path.join(\n FILE_DIR,\n `${uniqueID}_${filename}`\n );\n await mergeChunks(\n filename,\n totalChunks,\n sessionFolder,\n finalFilePath\n );\n req.multipartFile = {\n isPending: false,\n originalname: filename,\n uniqueID,\n filePath: finalFilePath\n };\n } catch (mergeErr) {\n return next(\n new WebError({\n statusCode: 500,\n errorCode: 'file-merge-failed',\n message: 'Error merging file chunks',\n data: { error: (mergeErr as Error).message }\n })\n );\n }\n return next();\n }\n\n req.multipartFile = {\n isPending: true,\n originalname: filename,\n uniqueID,\n chunkIndex,\n totalChunks\n };\n next();\n });\n } catch (error) {\n next(\n new WebError({\n statusCode: 500,\n errorCode: 'unexpected-error',\n message: 'Unexpected error in file upload',\n data: { error: (error as Error).message }\n })\n );\n }\n };\n}\n\nasync function mergeChunks(\n filename: string,\n totalChunks: string | number,\n sessionFolder: string,\n finalFilePath: string\n): Promise<void> {\n const writeStream = fs.createWriteStream(finalFilePath);\n reportDebug({\n namespace,\n message: 'Merging file chunks',\n data: { finalFilePath }\n });\n\n const totalChunksNum = parseInt(totalChunks as string, 10);\n const chunks: Buffer[] = [];\n\n // Read all chunks into memory first\n for (let i = 0; i < totalChunksNum; i++) {\n const partPath = path.join(sessionFolder, `${filename}.part${i}`);\n try {\n const chunkData = await fs.readFile(partPath);\n chunks.push(chunkData);\n } catch (error) {\n // Cleanup on error\n await fs\n .remove(sessionFolder)\n .catch((cleanupErr: Error) =>\n reportError(\n `Error cleaning up folder ${sessionFolder}: ${cleanupErr.message}`\n )\n );\n throw new WebError({\n statusCode: 500,\n errorCode: 'chunk-read-failed',\n message: `Error reading chunk ${i}`,\n data: { error: (error as Error).message }\n });\n }\n }\n\n // Write all chunks sequentially\n for (const chunkData of chunks) {\n writeStream.write(chunkData);\n }\n\n // Remove temp files\n for (let i = 0; i < totalChunksNum; i++) {\n const partPath = path.join(sessionFolder, `${filename}.part${i}`);\n fs.remove(partPath).catch((err: Error) =>\n reportError(`Error removing part ${partPath}: ${err.message}`)\n );\n }\n\n writeStream.end();\n return new Promise<void>((resolve, reject) => {\n writeStream.on('finish', () => {\n // Clean up temp folder after successful merge\n fs.remove(sessionFolder)\n .then(() => resolve(undefined))\n .catch((cleanupErr: Error) => {\n reportError(\n `Error cleaning up temp folder ${sessionFolder}: ${cleanupErr.message}`\n );\n resolve(undefined); // Don't fail the merge if cleanup fails\n });\n });\n writeStream.on('error', (error) => {\n // Cleanup on write error\n fs.remove(sessionFolder).catch((cleanupErr: Error) =>\n reportError(\n `Error cleaning up folder after write error: ${cleanupErr.message}`\n )\n );\n reject(\n new WebError({\n statusCode: 500,\n errorCode: 'file-merge-error',\n message: 'Error merging file chunks',\n data: { error: (error as Error).message }\n })\n );\n });\n });\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"requestMetrics.js","names":["_responseTime","_interopRequireDefault","require","_metrics","excludedPrefixes","requestMetrics","request","response","next","path","route","prefix","startsWith","httpInFlight","inc","inflightDecremented","cleanup","dec","once","statusCode","statusClass","toString","substring","httpErrorCount","service","process","env","CHART","status","method","lenHeader","getHeader","len","parseInt","String","NaN","Number","isNaN","httpResponseSize","observe","rt","responseTime","req","res","time","labels","httpRequestCount","httpRequestDuration","exports"],"sources":["../../../src/middleware/requestMetrics/requestMetrics.ts"],"sourcesContent":["import { Request, Response, NextFunction } from 'express';\nimport responseTime from 'response-time';\nimport {\n httpRequestCount,\n httpRequestDuration,\n httpInFlight,\n httpErrorCount,\n httpResponseSize\n} from 'metrics';\n\nconst excludedPrefixes = ['/swagger', '/docs', '/api-docs', '/metrics', '/favicon.ico', '/.well-known'];\n\n/** Composite middleware that tracks in-flight requests, errors, response size and timings */\nexport const requestMetrics = (request: Request, response: Response, next: NextFunction) => {\n const path = (request.route?.path ?? request.path) as string;\n\n // Skip operational/static routes\n for (const prefix of excludedPrefixes) {\n if (path.startsWith(prefix)) return next();\n }\n\n // Increment in-flight\n try {\n httpInFlight.inc();\n } catch {\n // Ignore metric collection errors\n }\n\n // Ensure we decrement on finish/close (only once)\n let inflightDecremented = false;\n const cleanup = () => {\n if (inflightDecremented) return;\n inflightDecremented = true;\n try {\n httpInFlight.dec();\n } catch {\n // Ignore metric collection errors\n }\n };\n\n response.once('finish', () => {\n // record errors\n const statusCode = response.statusCode ?? 0;\n const statusClass = statusCode ? `${statusCode.toString().substring(0, 1)}XX` : '';\n if (statusCode >= 400) {\n try {\n httpErrorCount.inc({ service: process.env.CHART, status: statusClass, method: request.method });\n } catch {\n // Ignore metric collection errors\n }\n }\n\n // observe response size if content-length header available\n const lenHeader = response.getHeader('content-length');\n const len = lenHeader ? parseInt(String(lenHeader), 10) : NaN;\n if (!Number.isNaN(len)) {\n try {\n httpResponseSize.observe({ service: process.env.CHART, path, method: request.method, status: statusClass }, len);\n } catch {\n // Ignore metric collection errors\n }\n }\n\n cleanup();\n });\n\n response.once('close', cleanup);\n\n // Use response-time to record duration and request counts\n const rt = responseTime((req: Request, res: Response, time: number) => {\n const labels = {\n path,\n method: request.method,\n status: res.statusCode ? `${res.statusCode.toString().substring(0, 1)}XX` : '',\n service: process.env.CHART || 'unknown'\n };\n\n try {\n httpRequestCount.inc(labels);\n httpRequestDuration.observe(labels, time / 1000);\n } catch {\n // Ignore metric collection errors\n }\n });\n\n // Call the response-time middleware which will call next when done\n rt(request as Request, response as Response, next as NextFunction);\n};\n"],"mappings":";;;;;;;AACA,IAAAA,aAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,QAAA,GAAAD,OAAA;AAQA,MAAME,gBAAgB,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,CAAC;;AAEvG;AACO,MAAMC,cAAc,GAAGA,CAACC,OAAgB,EAAEC,QAAkB,EAAEC,IAAkB,KAAK;EAC1F,MAAMC,IAAI,GAAIH,OAAO,CAACI,KAAK,EAAED,IAAI,IAAIH,OAAO,CAACG,IAAe;;EAE5D;EACA,KAAK,MAAME,MAAM,IAAIP,gBAAgB,EAAE;IACrC,IAAIK,IAAI,CAACG,UAAU,CAACD,MAAM,CAAC,EAAE,OAAOH,IAAI,CAAC,CAAC;EAC5C;;EAEA;EACA,IAAI;IACFK,qBAAY,CAACC,GAAG,CAAC,CAAC;EACpB,CAAC,CAAC,MAAM;IACN;EAAA;;EAGF;EACA,IAAIC,mBAAmB,GAAG,KAAK;EAC/B,MAAMC,OAAO,GAAGA,CAAA,KAAM;IACpB,IAAID,mBAAmB,EAAE;IACzBA,mBAAmB,GAAG,IAAI;IAC1B,IAAI;MACFF,qBAAY,CAACI,GAAG,CAAC,CAAC;IACpB,CAAC,CAAC,MAAM;MACN;IAAA;EAEJ,CAAC;EAEDV,QAAQ,CAACW,IAAI,CAAC,QAAQ,EAAE,MAAM;IAC5B;IACA,MAAMC,UAAU,GAAGZ,QAAQ,CAACY,UAAU,IAAI,CAAC;IAC3C,MAAMC,WAAW,GAAGD,UAAU,GAAG,GAAGA,UAAU,CAACE,QAAQ,CAAC,CAAC,CAACC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,EAAE;IAClF,IAAIH,UAAU,IAAI,GAAG,EAAE;MACrB,IAAI;QACFI,uBAAc,CAACT,GAAG,CAAC;UAAEU,OAAO,EAAEC,OAAO,CAACC,GAAG,CAACC,KAAK;UAAEC,MAAM,EAAER,WAAW;UAAES,MAAM,EAAEvB,OAAO,CAACuB;QAAO,CAAC,CAAC;MACjG,CAAC,CAAC,MAAM;QACN;MAAA;IAEJ;;IAEA;IACA,MAAMC,SAAS,GAAGvB,QAAQ,CAACwB,SAAS,CAAC,gBAAgB,CAAC;IACtD,MAAMC,GAAG,GAAGF,SAAS,GAAGG,QAAQ,CAACC,MAAM,CAACJ,SAAS,CAAC,EAAE,EAAE,CAAC,GAAGK,GAAG;IAC7D,IAAI,CAACC,MAAM,CAACC,KAAK,CAACL,GAAG,CAAC,EAAE;MACtB,IAAI;QACFM,yBAAgB,CAACC,OAAO,CAAC;UAAEf,OAAO,EAAEC,OAAO,CAACC,GAAG,CAACC,KAAK;UAAElB,IAAI;UAAEoB,MAAM,EAAEvB,OAAO,CAACuB,MAAM;UAAED,MAAM,EAAER;QAAY,CAAC,EAAEY,GAAG,CAAC;MAClH,CAAC,CAAC,MAAM;QACN;MAAA;IAEJ;IAEAhB,OAAO,CAAC,CAAC;EACX,CAAC,CAAC;EAEFT,QAAQ,CAACW,IAAI,CAAC,OAAO,EAAEF,OAAO,CAAC;;EAE/B;EACA,MAAMwB,EAAE,GAAG,IAAAC,qBAAY,EAAC,CAACC,GAAY,EAAEC,GAAa,EAAEC,IAAY,KAAK;IACrE,MAAMC,MAAM,GAAG;MACbpC,IAAI;MACJoB,MAAM,EAAEvB,OAAO,CAACuB,MAAM;MACtBD,MAAM,EAAEe,GAAG,CAACxB,UAAU,GAAG,GAAGwB,GAAG,CAACxB,UAAU,CAACE,QAAQ,CAAC,CAAC,CAACC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,EAAE;MAC9EE,OAAO,EAAEC,OAAO,CAACC,GAAG,CAACC,KAAK,IAAI;IAChC,CAAC;IAED,IAAI;MACFmB,yBAAgB,CAAChC,GAAG,CAAC+B,MAAM,CAAC;MAC5BE,4BAAmB,CAACR,OAAO,CAACM,MAAM,EAAED,IAAI,GAAG,IAAI,CAAC;IAClD,CAAC,CAAC,MAAM;MACN;IAAA;EAEJ,CAAC,CAAC;;EAEF;EACAJ,EAAE,CAAClC,OAAO,EAAaC,QAAQ,EAAcC,IAAoB,CAAC;AACpE,CAAC;AAACwC,OAAA,CAAA3C,cAAA,GAAAA,cAAA","ignoreList":[]}
1
+ {"version":3,"file":"requestMetrics.js","names":["_responseTime","_interopRequireDefault","require","_metrics","excludedPrefixes","requestMetrics","request","response","next","path","route","prefix","startsWith","httpInFlight","inc","inflightDecremented","cleanup","dec","once","statusCode","statusClass","toString","substring","httpErrorCount","service","process","env","CHART","status","method","lenHeader","getHeader","len","parseInt","String","NaN","Number","isNaN","httpResponseSize","observe","rt","responseTime","req","res","time","labels","httpRequestCount","httpRequestDuration","exports"],"sources":["../../../src/middleware/requestMetrics/requestMetrics.ts"],"sourcesContent":["import { Request, Response, NextFunction } from 'express';\nimport responseTime from 'response-time';\nimport {\n httpRequestCount,\n httpRequestDuration,\n httpInFlight,\n httpErrorCount,\n httpResponseSize\n} from 'metrics';\n\nconst excludedPrefixes = [\n '/swagger',\n '/docs',\n '/api-docs',\n '/metrics',\n '/favicon.ico',\n '/.well-known'\n];\n\n/** Composite middleware that tracks in-flight requests, errors, response size and timings */\nexport const requestMetrics = (\n request: Request,\n response: Response,\n next: NextFunction\n) => {\n const path = (request.route?.path ?? request.path) as string;\n\n // Skip operational/static routes\n for (const prefix of excludedPrefixes) {\n if (path.startsWith(prefix)) return next();\n }\n\n // Increment in-flight\n try {\n httpInFlight.inc();\n } catch {\n // Ignore metric collection errors\n }\n\n // Ensure we decrement on finish/close (only once)\n let inflightDecremented = false;\n const cleanup = () => {\n if (inflightDecremented) return;\n inflightDecremented = true;\n try {\n httpInFlight.dec();\n } catch {\n // Ignore metric collection errors\n }\n };\n\n response.once('finish', () => {\n // record errors\n const statusCode = response.statusCode ?? 0;\n const statusClass = statusCode\n ? `${statusCode.toString().substring(0, 1)}XX`\n : '';\n if (statusCode >= 400) {\n try {\n httpErrorCount.inc({\n service: process.env.CHART,\n status: statusClass,\n method: request.method\n });\n } catch {\n // Ignore metric collection errors\n }\n }\n\n // observe response size if content-length header available\n const lenHeader = response.getHeader('content-length');\n const len = lenHeader ? parseInt(String(lenHeader), 10) : NaN;\n if (!Number.isNaN(len)) {\n try {\n httpResponseSize.observe(\n {\n service: process.env.CHART,\n path,\n method: request.method,\n status: statusClass\n },\n len\n );\n } catch {\n // Ignore metric collection errors\n }\n }\n\n cleanup();\n });\n\n response.once('close', cleanup);\n\n // Use response-time to record duration and request counts\n const rt = responseTime((req: Request, res: Response, time: number) => {\n const labels = {\n path,\n method: request.method,\n status: res.statusCode\n ? `${res.statusCode.toString().substring(0, 1)}XX`\n : '',\n service: process.env.CHART || 'unknown'\n };\n\n try {\n httpRequestCount.inc(labels);\n httpRequestDuration.observe(labels, time / 1000);\n } catch {\n // Ignore metric collection errors\n }\n });\n\n // Call the response-time middleware which will call next when done\n rt(request as Request, response as Response, next as NextFunction);\n};\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"swaggerDocs.js","names":["_fs","_interopRequireDefault","require","_express","_glob","_yamljs","_swaggerUiExpress","getEndpointDocPaths","glob","sync","process","cwd","getSchemaPaths","getResponsePaths","loadAndMergeData","files","map","file","YAML","load","reduce","result","endpoint","path","Object","keys","loadEndpoints","paths","endpoints","loadSchemas","schemas","loadResponses","responses","loadConfig","indexPath","config","fs","existsSync","schemaConfig","responseConfig","endpointConfig","components","swaggerDocs","stringifiedDocumentation","JSON","stringify","placeholderRegex","overwrittenDocumentation","replace","match","p1","env","parse","Router","use","swaggerUi","serve","setup"],"sources":["../../../src/middleware/swaggerDocs/swaggerDocs.ts"],"sourcesContent":["import fs from 'fs';\nimport { Router } from 'express';\nimport { glob } from 'glob';\nimport YAML from 'yamljs';\nimport swaggerUi from 'swagger-ui-express';\nimport {\n EndpointDocumentation,\n IndexDocumentation,\n ResponsesConfig,\n EndpointConfig,\n SchemasConfig,\n SwaggerConfig\n} from './swaggerDocs.types';\n\n/** Get the paths of all the endpoint documentation files */\nfunction getEndpointDocPaths(): Array<string> {\n return [\n ...glob.sync(`${process.cwd()}/src/**/*.docs.yaml`),\n ...glob.sync(`${process.cwd()}/dist/**/*.docs.yaml`)\n ];\n}\n\n/** Get the paths of all the schema files */\nfunction getSchemaPaths(): Array<string> {\n return [\n ...glob.sync(`${process.cwd()}/src/docs/schemas/*.yaml`),\n ...glob.sync(`${process.cwd()}/dist/docs/schemas/*.yaml`)\n ];\n}\n\n/** Get the paths of all the response files */\nfunction getResponsePaths(): Array<string> {\n return [\n ...glob.sync(`${process.cwd()}/src/docs/responses/*.yaml`),\n ...glob.sync(`${process.cwd()}/dist/docs/responses/*.yaml`)\n ];\n}\n\n/**\n * Load all data files and merge them in a single object\n * @param files\n * @return {Object}\n */\nfunction loadAndMergeData(files: Array<string>): EndpointDocumentation {\n return files\n .map((file) => YAML.load(file) as EndpointDocumentation)\n .reduce((result, endpoint) => {\n for (const path of Object.keys(endpoint)) {\n if (!(path in result)) result[path] = {};\n result[path] = { ...result[path], ...endpoint[path] };\n }\n return result;\n }, {});\n}\n\n/** Load documentation files of all the endpoints */\nfunction loadEndpoints(): EndpointConfig {\n const paths = getEndpointDocPaths();\n const endpoints = loadAndMergeData(paths);\n return {\n paths: endpoints\n };\n}\n\n/** Load documentation files of all the schemas */\nfunction loadSchemas(): SchemasConfig {\n const paths = getSchemaPaths();\n const schemas = loadAndMergeData(paths);\n return { schemas };\n}\n\n/** Load documentation files of all the responses */\nfunction loadResponses(): ResponsesConfig {\n const paths = getResponsePaths();\n const responses = loadAndMergeData(paths);\n return { responses };\n}\n\n/** Load the whole Swagger config */\nfunction loadConfig(): SwaggerConfig {\n const indexPath = `${process.cwd()}/src/docs/index.yaml`;\n const config = (\n fs.existsSync(indexPath) ? YAML.load(indexPath) : {}\n ) as IndexDocumentation;\n const schemaConfig = loadSchemas();\n const responseConfig = loadResponses();\n const endpointConfig = loadEndpoints();\n return {\n ...config,\n ...endpointConfig,\n components: {\n ...config.components,\n ...schemaConfig,\n ...responseConfig\n }\n };\n}\n\n/**\n * Get a middleware that serves the documentation\n * @return {Router}\n */\nexport function swaggerDocs(): Router {\n // Stringify the result and replace any environment variable, then turn it again to an object\n const stringifiedDocumentation = JSON.stringify(loadConfig());\n const placeholderRegex = /##(.+?)##/g;\n const overwrittenDocumentation = stringifiedDocumentation.replace(\n placeholderRegex,\n (match: string, p1: string): string => process.env[p1] ?? ''\n );\n const config = JSON.parse(overwrittenDocumentation) as EndpointDocumentation;\n \n return Router().use('/docs', swaggerUi.serve, swaggerUi.setup(config));\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"swaggerDocs.js","names":["_fs","_interopRequireDefault","require","_express","_glob","_yamljs","_swaggerUiExpress","getEndpointDocPaths","glob","sync","process","cwd","getSchemaPaths","getResponsePaths","loadAndMergeData","files","map","file","YAML","load","reduce","result","endpoint","path","Object","keys","loadEndpoints","paths","endpoints","loadSchemas","schemas","loadResponses","responses","loadConfig","indexPath","config","fs","existsSync","schemaConfig","responseConfig","endpointConfig","components","swaggerDocs","stringifiedDocumentation","JSON","stringify","placeholderRegex","overwrittenDocumentation","replace","match","p1","env","parse","Router","use","swaggerUi","serve","setup"],"sources":["../../../src/middleware/swaggerDocs/swaggerDocs.ts"],"sourcesContent":["import fs from 'fs';\nimport { Router } from 'express';\nimport { glob } from 'glob';\nimport YAML from 'yamljs';\nimport swaggerUi from 'swagger-ui-express';\nimport {\n EndpointDocumentation,\n IndexDocumentation,\n ResponsesConfig,\n EndpointConfig,\n SchemasConfig,\n SwaggerConfig\n} from './swaggerDocs.types';\n\n/** Get the paths of all the endpoint documentation files */\nfunction getEndpointDocPaths(): Array<string> {\n return [\n ...glob.sync(`${process.cwd()}/src/**/*.docs.yaml`),\n ...glob.sync(`${process.cwd()}/dist/**/*.docs.yaml`)\n ];\n}\n\n/** Get the paths of all the schema files */\nfunction getSchemaPaths(): Array<string> {\n return [\n ...glob.sync(`${process.cwd()}/src/docs/schemas/*.yaml`),\n ...glob.sync(`${process.cwd()}/dist/docs/schemas/*.yaml`)\n ];\n}\n\n/** Get the paths of all the response files */\nfunction getResponsePaths(): Array<string> {\n return [\n ...glob.sync(`${process.cwd()}/src/docs/responses/*.yaml`),\n ...glob.sync(`${process.cwd()}/dist/docs/responses/*.yaml`)\n ];\n}\n\n/**\n * Load all data files and merge them in a single object\n * @param files\n * @return {Object}\n */\nfunction loadAndMergeData(files: Array<string>): EndpointDocumentation {\n return files\n .map((file) => YAML.load(file) as EndpointDocumentation)\n .reduce((result, endpoint) => {\n for (const path of Object.keys(endpoint)) {\n if (!(path in result)) result[path] = {};\n result[path] = { ...result[path], ...endpoint[path] };\n }\n return result;\n }, {});\n}\n\n/** Load documentation files of all the endpoints */\nfunction loadEndpoints(): EndpointConfig {\n const paths = getEndpointDocPaths();\n const endpoints = loadAndMergeData(paths);\n return {\n paths: endpoints\n };\n}\n\n/** Load documentation files of all the schemas */\nfunction loadSchemas(): SchemasConfig {\n const paths = getSchemaPaths();\n const schemas = loadAndMergeData(paths);\n return { schemas };\n}\n\n/** Load documentation files of all the responses */\nfunction loadResponses(): ResponsesConfig {\n const paths = getResponsePaths();\n const responses = loadAndMergeData(paths);\n return { responses };\n}\n\n/** Load the whole Swagger config */\nfunction loadConfig(): SwaggerConfig {\n const indexPath = `${process.cwd()}/src/docs/index.yaml`;\n const config = (\n fs.existsSync(indexPath) ? YAML.load(indexPath) : {}\n ) as IndexDocumentation;\n const schemaConfig = loadSchemas();\n const responseConfig = loadResponses();\n const endpointConfig = loadEndpoints();\n return {\n ...config,\n ...endpointConfig,\n components: {\n ...config.components,\n ...schemaConfig,\n ...responseConfig\n }\n };\n}\n\n/**\n * Get a middleware that serves the documentation\n * @return {Router}\n */\nexport function swaggerDocs(): Router {\n // Stringify the result and replace any environment variable, then turn it again to an object\n const stringifiedDocumentation = JSON.stringify(loadConfig());\n const placeholderRegex = /##(.+?)##/g;\n const overwrittenDocumentation = stringifiedDocumentation.replace(\n placeholderRegex,\n (match: string, p1: string): string => process.env[p1] ?? ''\n );\n const config = JSON.parse(overwrittenDocumentation) as EndpointDocumentation;\n\n return Router().use('/docs', swaggerUi.serve, swaggerUi.setup(config));\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"verificationToken.js","names":["_WebError","require","_report","_verificationToken","namespace","DEFAULT_TOKEN_HEADER","DEFAULT_OTP_HEADER","DEFAULT_TOKEN_FIELD","DEFAULT_OTP_FIELD","readString","request","headerName","fieldName","headerValue","headers","toLowerCase","Array","isArray","bodyValue","body","undefined","queryValue","query","verificationToken","action","options","_response","next","tokenHeader","otpHeader","tokenField","otpField","requireOtp","token","WebError","errorCode","statusCode","message","data","otp","resolvedSubject","subjectResolver","user","id","sub","payload","verifyVerificationToken","issuer","audience","requireSubject","expected","actual","verification","reportDebug","act","subject"],"sources":["../../../src/middleware/verificationToken/verificationToken.ts"],"sourcesContent":["import { Request, Response, NextFunction } from 'express';\nimport { WebError } from 'entities/WebError';\nimport { reportDebug } from 'utils/report';\nimport { verifyVerificationToken } from 'utils/verificationToken';\nimport { VerificationTokenMiddlewareOptions } from './verificationToken.types';\n\nconst namespace = 'engine:middleware:verificationToken';\n\nconst DEFAULT_TOKEN_HEADER = 'x-verification-token';\nconst DEFAULT_OTP_HEADER = 'x-verification-otp';\nconst DEFAULT_TOKEN_FIELD = 'verificationToken';\nconst DEFAULT_OTP_FIELD = 'verificationOtp';\n\nfunction readString(\n request: Request,\n headerName: string,\n fieldName: string\n): string | undefined {\n const headerValue = request.headers[headerName.toLowerCase()];\n if (typeof headerValue === 'string') return headerValue;\n if (Array.isArray(headerValue)) return headerValue[0];\n\n const bodyValue =\n request.body && typeof request.body === 'object'\n ? (request.body as Record<string, unknown>)[fieldName]\n : undefined;\n if (typeof bodyValue === 'string') return bodyValue;\n\n const queryValue =\n request.query && typeof request.query === 'object'\n ? (request.query as Record<string, unknown>)[fieldName]\n : undefined;\n if (typeof queryValue === 'string') return queryValue;\n if (Array.isArray(queryValue)) return queryValue[0];\n\n return undefined;\n}\n\nexport function verificationToken(\n action: string,\n options: VerificationTokenMiddlewareOptions = {}\n): (request: Request, response: Response, next: NextFunction) => void {\n return (request: Request, _response: Response, next: NextFunction): void => {\n const tokenHeader = options.tokenHeader ?? DEFAULT_TOKEN_HEADER;\n const otpHeader = options.otpHeader ?? DEFAULT_OTP_HEADER;\n const tokenField = options.tokenField ?? DEFAULT_TOKEN_FIELD;\n const otpField = options.otpField ?? DEFAULT_OTP_FIELD;\n const requireOtp = options.requireOtp !== false;\n\n const token = readString(request, tokenHeader, tokenField);\n if (!token) {\n throw new WebError({\n errorCode: 'verification_token_missing',\n statusCode: 400,\n message: 'Verification token is required',\n data: { tokenHeader, tokenField }\n });\n }\n\n const otp = readString(request, otpHeader, otpField);\n if (requireOtp && !otp) {\n throw new WebError({\n errorCode: 'verification_otp_missing',\n statusCode: 400,\n message: 'Verification OTP is required',\n data: { otpHeader, otpField }\n });\n }\n\n const resolvedSubject = options.subjectResolver\n ? options.subjectResolver(request)\n : (request.user?.id as string | undefined) ??\n (request.user?.sub as string | undefined);\n\n const payload = verifyVerificationToken(token, {\n action,\n otp: requireOtp ? otp : undefined,\n issuer: options.issuer,\n audience: options.audience\n });\n\n if (resolvedSubject) {\n if (!payload.sub && options.requireSubject) {\n throw new WebError({\n errorCode: 'verification_failed',\n statusCode: 403,\n message: 'Verification token missing subject'\n });\n }\n if (payload.sub && payload.sub !== resolvedSubject) {\n throw new WebError({\n errorCode: 'verification_failed',\n statusCode: 403,\n message: 'Verification subject mismatch',\n data: { expected: resolvedSubject, actual: payload.sub }\n });\n }\n }\n\n request.verification = payload;\n reportDebug({\n namespace,\n message: 'Verification token validated',\n data: { action: payload.act, subject: payload.sub }\n });\n\n next();\n };\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"verificationToken.js","names":["_WebError","require","_report","_verificationToken","namespace","DEFAULT_TOKEN_HEADER","DEFAULT_OTP_HEADER","DEFAULT_TOKEN_FIELD","DEFAULT_OTP_FIELD","readString","request","headerName","fieldName","headerValue","headers","toLowerCase","Array","isArray","bodyValue","body","undefined","queryValue","query","verificationToken","action","options","_response","next","tokenHeader","otpHeader","tokenField","otpField","requireOtp","token","WebError","errorCode","statusCode","message","data","otp","resolvedSubject","subjectResolver","user","id","sub","payload","verifyVerificationToken","issuer","audience","requireSubject","expected","actual","verification","reportDebug","act","subject"],"sources":["../../../src/middleware/verificationToken/verificationToken.ts"],"sourcesContent":["import { Request, Response, NextFunction } from 'express';\nimport { WebError } from 'entities/WebError';\nimport { reportDebug } from 'utils/report';\nimport { verifyVerificationToken } from 'utils/verificationToken';\nimport { VerificationTokenMiddlewareOptions } from './verificationToken.types';\n\nconst namespace = 'engine:middleware:verificationToken';\n\nconst DEFAULT_TOKEN_HEADER = 'x-verification-token';\nconst DEFAULT_OTP_HEADER = 'x-verification-otp';\nconst DEFAULT_TOKEN_FIELD = 'verificationToken';\nconst DEFAULT_OTP_FIELD = 'verificationOtp';\n\nfunction readString(\n request: Request,\n headerName: string,\n fieldName: string\n): string | undefined {\n const headerValue = request.headers[headerName.toLowerCase()];\n if (typeof headerValue === 'string') return headerValue;\n if (Array.isArray(headerValue)) return headerValue[0];\n\n const bodyValue =\n request.body && typeof request.body === 'object'\n ? (request.body as Record<string, unknown>)[fieldName]\n : undefined;\n if (typeof bodyValue === 'string') return bodyValue;\n\n const queryValue =\n request.query && typeof request.query === 'object'\n ? (request.query as Record<string, unknown>)[fieldName]\n : undefined;\n if (typeof queryValue === 'string') return queryValue;\n if (Array.isArray(queryValue)) return queryValue[0];\n\n return undefined;\n}\n\nexport function verificationToken(\n action: string,\n options: VerificationTokenMiddlewareOptions = {}\n): (request: Request, response: Response, next: NextFunction) => void {\n return (request: Request, _response: Response, next: NextFunction): void => {\n const tokenHeader = options.tokenHeader ?? DEFAULT_TOKEN_HEADER;\n const otpHeader = options.otpHeader ?? DEFAULT_OTP_HEADER;\n const tokenField = options.tokenField ?? DEFAULT_TOKEN_FIELD;\n const otpField = options.otpField ?? DEFAULT_OTP_FIELD;\n const requireOtp = options.requireOtp !== false;\n\n const token = readString(request, tokenHeader, tokenField);\n if (!token) {\n throw new WebError({\n errorCode: 'verification_token_missing',\n statusCode: 400,\n message: 'Verification token is required',\n data: { tokenHeader, tokenField }\n });\n }\n\n const otp = readString(request, otpHeader, otpField);\n if (requireOtp && !otp) {\n throw new WebError({\n errorCode: 'verification_otp_missing',\n statusCode: 400,\n message: 'Verification OTP is required',\n data: { otpHeader, otpField }\n });\n }\n\n const resolvedSubject = options.subjectResolver\n ? options.subjectResolver(request)\n : ((request.user?.id as string | undefined) ??\n (request.user?.sub as string | undefined));\n\n const payload = verifyVerificationToken(token, {\n action,\n otp: requireOtp ? otp : undefined,\n issuer: options.issuer,\n audience: options.audience\n });\n\n if (resolvedSubject) {\n if (!payload.sub && options.requireSubject) {\n throw new WebError({\n errorCode: 'verification_failed',\n statusCode: 403,\n message: 'Verification token missing subject'\n });\n }\n if (payload.sub && payload.sub !== resolvedSubject) {\n throw new WebError({\n errorCode: 'verification_failed',\n statusCode: 403,\n message: 'Verification subject mismatch',\n data: { expected: resolvedSubject, actual: payload.sub }\n });\n }\n }\n\n request.verification = payload;\n reportDebug({\n namespace,\n message: 'Verification token validated',\n data: { action: payload.act, subject: payload.sub }\n });\n\n next();\n };\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
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":[]}
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\n ? createSortedObject(item)\n : 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,GACrCN,kBAAkB,CAACM,IAAI,CAAC,GACxBA,IACN,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":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"dbMigration.js","names":["_fs","require","_path","_umzug","_migrateMetadataTable","_models","_EngineError","_Sequelize","_report","_semverCompare","cache","_interopRequireWildcard","e","t","__esModule","r","c","a","Object","defineProperty","n","__proto__","default","WeakMap","has","get","set","hasOwnProperty","call","getOwnPropertyDescriptor","namespace","getMigrationPaths","prodDefaultPath","join","process","cwd","devDefaultPath","isProduction","includes","env","NODE_ENV","path","DB_MIGRATIONS_DIR","filter","existsSync","lstatSync","isDirectory","reportDebug","message","data","prodPath","devPath","customPath","map","p","getMigrationExtension","directory","hasTypeScript","readdirSync","some","file","endsWith","runPendingMigrations","sequelize","EngineError","sqlHost","SQL_HOST","sqlDb","SQL_DB","sqlUser","SQL_USER","nodeEnv","migrateMetadataTable","migrationPaths","length","migrator","Umzug","migrations","glob","resolve","name","context","nameWithoutExtension","replace","migrationPromise","specifier","Promise","then","s","up","migration","down","getQueryInterface","storage","SequelizeStorage","logger","console","reportInfo","error","Error","String","stack","undefined","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, readdirSync } 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\nexport function 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 isProduction = ['prod', 'production'].includes(\n process.env.NODE_ENV ?? ''\n );\n const path = [\n process.env.DB_MIGRATIONS_DIR,\n isProduction ? prodDefaultPath : devDefaultPath\n ].filter(\n (path): path is string =>\n !!path && existsSync(path) && lstatSync(path).isDirectory()\n );\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) => `${p}/*.${getMigrationExtension(p)}`);\n}\n\n/**\n * Detect whether a migration folder holds TypeScript sources or compiled JavaScript,\n * so migrations are found regardless of the NODE_ENV value\n */\nfunction getMigrationExtension(directory: string): 'ts' | 'js' {\n const hasTypeScript = readdirSync(directory).some(\n (file) => file.endsWith('.ts') && !file.endsWith('.d.ts')\n );\n return hasTypeScript ? 'ts' : 'js';\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 \n try {\n reportDebug({\n namespace,\n message: 'Starting migration process',\n data: {\n sqlHost: process.env.SQL_HOST,\n sqlDb: process.env.SQL_DB,\n sqlUser: process.env.SQL_USER,\n nodeEnv: process.env.NODE_ENV\n }\n });\n\n // First make sure that the metadata table is up to date\n reportDebug({\n namespace,\n message: 'Migrating metadata table'\n });\n await migrateMetadataTable(sequelize);\n \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 reportDebug({\n namespace,\n message: 'Processing migration path',\n data: { path }\n });\n\n const migrator = new Umzug({\n migrations: {\n glob: path,\n resolve: ({ name, path, context }) => {\n const nameWithoutExtension = name.replace(/\\.(ts|js)$/, '');\n \n // Use dynamic import for better TypeScript/ES module support\n const migrationPromise = import(path || '');\n return {\n name: nameWithoutExtension,\n up: async () => {\n reportDebug({\n namespace,\n message: `Running migration: ${nameWithoutExtension}`\n });\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 \n await migrator.up();\n \n reportInfo({\n message: 'Database migration completed successfully',\n data: { path }\n });\n }\n } catch (error) {\n reportDebug({\n namespace,\n message: 'Migration failed with error',\n data: {\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n sqlHost: process.env.SQL_HOST,\n sqlDb: process.env.SQL_DB\n }\n });\n throw error;\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 // Strip file extension to ensure consistent naming across .ts and .js files\n const nameWithoutExtension = name.replace(/\\.(ts|js)$/, '');\n \n const migrationPromise = import(path || '');\n return {\n name: nameWithoutExtension,\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":"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","ignoreList":[]}
1
+ {"version":3,"file":"dbMigration.js","names":["_fs","require","_path","_umzug","_migrateMetadataTable","_models","_EngineError","_Sequelize","_report","_semverCompare","cache","_interopRequireWildcard","e","t","__esModule","r","c","a","Object","defineProperty","n","__proto__","default","WeakMap","has","get","set","hasOwnProperty","call","getOwnPropertyDescriptor","namespace","getMigrationPaths","prodDefaultPath","join","process","cwd","devDefaultPath","isProduction","includes","env","NODE_ENV","path","DB_MIGRATIONS_DIR","filter","existsSync","lstatSync","isDirectory","reportDebug","message","data","prodPath","devPath","customPath","map","p","getMigrationExtension","directory","hasTypeScript","readdirSync","some","file","endsWith","runPendingMigrations","sequelize","EngineError","sqlHost","SQL_HOST","sqlDb","SQL_DB","sqlUser","SQL_USER","nodeEnv","migrateMetadataTable","migrationPaths","length","migrator","Umzug","migrations","glob","resolve","name","context","nameWithoutExtension","replace","migrationPromise","specifier","Promise","then","s","up","migration","down","getQueryInterface","storage","SequelizeStorage","logger","console","reportInfo","error","Error","String","stack","undefined","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, readdirSync } 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\nexport function 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 isProduction = ['prod', 'production'].includes(\n process.env.NODE_ENV ?? ''\n );\n const path = [\n process.env.DB_MIGRATIONS_DIR,\n isProduction ? prodDefaultPath : devDefaultPath\n ].filter(\n (path): path is string =>\n !!path && existsSync(path) && lstatSync(path).isDirectory()\n );\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) => `${p}/*.${getMigrationExtension(p)}`);\n}\n\n/**\n * Detect whether a migration folder holds TypeScript sources or compiled JavaScript,\n * so migrations are found regardless of the NODE_ENV value\n */\nfunction getMigrationExtension(directory: string): 'ts' | 'js' {\n const hasTypeScript = readdirSync(directory).some(\n (file) => file.endsWith('.ts') && !file.endsWith('.d.ts')\n );\n return hasTypeScript ? 'ts' : 'js';\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\n try {\n reportDebug({\n namespace,\n message: 'Starting migration process',\n data: {\n sqlHost: process.env.SQL_HOST,\n sqlDb: process.env.SQL_DB,\n sqlUser: process.env.SQL_USER,\n nodeEnv: process.env.NODE_ENV\n }\n });\n\n // First make sure that the metadata table is up to date\n reportDebug({\n namespace,\n message: 'Migrating metadata table'\n });\n await migrateMetadataTable(sequelize);\n\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 reportDebug({\n namespace,\n message: 'Processing migration path',\n data: { path }\n });\n\n const migrator = new Umzug({\n migrations: {\n glob: path,\n resolve: ({ name, path, context }) => {\n const nameWithoutExtension = name.replace(/\\.(ts|js)$/, '');\n\n // Use dynamic import for better TypeScript/ES module support\n const migrationPromise = import(path || '');\n return {\n name: nameWithoutExtension,\n up: async () => {\n reportDebug({\n namespace,\n message: `Running migration: ${nameWithoutExtension}`\n });\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\n await migrator.up();\n\n reportInfo({\n message: 'Database migration completed successfully',\n data: { path }\n });\n }\n } catch (error) {\n reportDebug({\n namespace,\n message: 'Migration failed with error',\n data: {\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n sqlHost: process.env.SQL_HOST,\n sqlDb: process.env.SQL_DB\n }\n });\n throw error;\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 // Strip file extension to ensure consistent naming across .ts and .js files\n const nameWithoutExtension = name.replace(/\\.(ts|js)$/, '');\n\n const migrationPromise = import(path || '');\n return {\n name: nameWithoutExtension,\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":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"migrateMetadataTable.js","names":["_sequelize","require","_report","namespace","listTablesQuery","sqlType","getTableName","row","Array","isArray","Object","values","undefined","migrateMetadataTable","sequelize","reportDebug","message","query","process","env","SQL_TYPE","data","tables","type","QueryTypes","SELECT","tableNames","map","hasCustomSequelizeMeta","includes","hasLegacySequelizeMeta","createTableQuery","Error","RAW","migrations","insertQuery","migration","name","join","INSERT","error","reportError","String","stack","sqlHost","SQL_HOST"],"sources":["../../../../src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.ts"],"sourcesContent":["import { Sequelize, QueryTypes } from 'sequelize';\nimport { SequelizeMeta } from 'db/models';\nimport { reportDebug, reportError } from 'utils/report';\n\nconst namespace = 'engine:utils:dbMigration';\n\n/** List the tables of the current database (not of every database on the server) */\nfunction listTablesQuery(sqlType?: string): string {\n switch (sqlType) {\n case 'sqlite':\n return `SELECT name AS table_name FROM sqlite_master WHERE type = 'table'`;\n case 'mysql':\n return `SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE()`;\n case 'postgres':\n return `SELECT table_name FROM information_schema.tables WHERE table_schema = current_schema()`;\n default:\n return `SELECT table_name FROM information_schema.tables`;\n }\n}\n\n/** Extract the table name from a result row, whatever shape the driver returns */\nfunction getTableName(row: unknown): string | undefined {\n if (typeof row === 'string') return row;\n if (Array.isArray(row)) return getTableName(row[0]);\n if (row && typeof row === 'object') return getTableName(Object.values(row)[0]);\n return undefined;\n}\n\n/**\n * Run migrations on the metadata table\n * The table containing the migrations metadata cannot be handled through migrations\n * Therefore, we use a more classic approach with this function and pure SQL queries\n */\nexport async function migrateMetadataTable(\n sequelize: Sequelize\n): Promise<void> {\n try {\n reportDebug({ namespace, message: 'Executing metadata migration routine' });\n\n const query = listTablesQuery(process.env.SQL_TYPE);\n\n reportDebug({ \n namespace, \n message: 'Checking for existing metadata tables',\n data: { sqlType: process.env.SQL_TYPE }\n });\n\n // We check if we have a custom sequelize_meta table yet\n const tables = await sequelize.query<Record<string, unknown>>(query, {\n type: QueryTypes.SELECT\n });\n const tableNames = tables.map(getTableName);\n\n const hasCustomSequelizeMeta = tableNames.includes('sequelize_meta');\n const hasLegacySequelizeMeta = tableNames.includes('SequelizeMeta');\n if (!hasCustomSequelizeMeta) {\n reportDebug({\n namespace,\n message: 'No metadata table found, creating new one'\n });\n\n // Define SQL for creating the table based on the database type\n let createTableQuery = '';\n\n switch (process.env.SQL_TYPE) {\n case 'mysql':\n case 'postgres':\n case 'sqlite':\n createTableQuery = `\n CREATE TABLE sequelize_meta (\n name VARCHAR(100) PRIMARY KEY,\n version VARCHAR(25),\n createdAt TIMESTAMP NOT NULL,\n updatedAt TIMESTAMP NOT NULL\n )`;\n break;\n case 'mssql':\n createTableQuery = `\n CREATE TABLE sequelize_meta (\n name VARCHAR(100) PRIMARY KEY,\n version VARCHAR(25),\n createdAt DATETIME NOT NULL,\n updatedAt DATETIME NOT NULL\n )`;\n break;\n default:\n throw new Error('Unsupported SQL type');\n }\n\n // Create the new sequelize_meta table if it does not exist\n reportDebug({ \n namespace, \n message: 'Creating sequelize_meta table',\n data: { sqlType: process.env.SQL_TYPE }\n });\n await sequelize.query(createTableQuery, { type: QueryTypes.RAW });\n reportDebug({ namespace, message: 'sequelize_meta table created successfully' });\n\n // Migrate the data from the old table to the new one if needed\n if (hasLegacySequelizeMeta) {\n reportDebug({\n namespace,\n message: 'Legacy metadata table found, migrating data'\n });\n\n const migrations = await sequelize.query<SequelizeMeta>(\n 'SELECT name FROM SequelizeMeta ORDER BY name',\n {\n type: QueryTypes.SELECT\n }\n );\n\n const insertQuery = `\n INSERT INTO sequelize_meta (name, version, createdAt, updatedAt) VALUES\n ${migrations\n .map((migration) => {\n switch (process.env.SQL_TYPE) {\n case 'mysql':\n case 'postgres':\n return `('${migration.name}', NULL, NOW(), NOW())`;\n case 'sqlite':\n return `('${migration.name}', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`;\n case 'mssql':\n return `('${migration.name}', NULL, GETDATE(), GETDATE())`;\n default:\n throw new Error('Unsupported SQL type');\n }\n })\n .join(',')}\n `;\n\n await sequelize.query(insertQuery, { type: QueryTypes.INSERT });\n }\n }\n } catch (error) {\n reportError({\n namespace,\n message: 'Error in metadata migration',\n data: {\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n sqlType: process.env.SQL_TYPE,\n sqlHost: process.env.SQL_HOST\n }\n });\n throw error;\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"migrateMetadataTable.js","names":["_sequelize","require","_report","namespace","listTablesQuery","sqlType","getTableName","row","Array","isArray","Object","values","undefined","migrateMetadataTable","sequelize","reportDebug","message","query","process","env","SQL_TYPE","data","tables","type","QueryTypes","SELECT","tableNames","map","hasCustomSequelizeMeta","includes","hasLegacySequelizeMeta","createTableQuery","Error","RAW","migrations","insertQuery","migration","name","join","INSERT","error","reportError","String","stack","sqlHost","SQL_HOST"],"sources":["../../../../src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.ts"],"sourcesContent":["import { Sequelize, QueryTypes } from 'sequelize';\nimport { SequelizeMeta } from 'db/models';\nimport { reportDebug, reportError } from 'utils/report';\n\nconst namespace = 'engine:utils:dbMigration';\n\n/** List the tables of the current database (not of every database on the server) */\nfunction listTablesQuery(sqlType?: string): string {\n switch (sqlType) {\n case 'sqlite':\n return `SELECT name AS table_name FROM sqlite_master WHERE type = 'table'`;\n case 'mysql':\n return `SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE()`;\n case 'postgres':\n return `SELECT table_name FROM information_schema.tables WHERE table_schema = current_schema()`;\n default:\n return `SELECT table_name FROM information_schema.tables`;\n }\n}\n\n/** Extract the table name from a result row, whatever shape the driver returns */\nfunction getTableName(row: unknown): string | undefined {\n if (typeof row === 'string') return row;\n if (Array.isArray(row)) return getTableName(row[0]);\n if (row && typeof row === 'object')\n return getTableName(Object.values(row)[0]);\n return undefined;\n}\n\n/**\n * Run migrations on the metadata table\n * The table containing the migrations metadata cannot be handled through migrations\n * Therefore, we use a more classic approach with this function and pure SQL queries\n */\nexport async function migrateMetadataTable(\n sequelize: Sequelize\n): Promise<void> {\n try {\n reportDebug({ namespace, message: 'Executing metadata migration routine' });\n\n const query = listTablesQuery(process.env.SQL_TYPE);\n\n reportDebug({\n namespace,\n message: 'Checking for existing metadata tables',\n data: { sqlType: process.env.SQL_TYPE }\n });\n\n // We check if we have a custom sequelize_meta table yet\n const tables = await sequelize.query<Record<string, unknown>>(query, {\n type: QueryTypes.SELECT\n });\n const tableNames = tables.map(getTableName);\n\n const hasCustomSequelizeMeta = tableNames.includes('sequelize_meta');\n const hasLegacySequelizeMeta = tableNames.includes('SequelizeMeta');\n if (!hasCustomSequelizeMeta) {\n reportDebug({\n namespace,\n message: 'No metadata table found, creating new one'\n });\n\n // Define SQL for creating the table based on the database type\n let createTableQuery = '';\n\n switch (process.env.SQL_TYPE) {\n case 'mysql':\n case 'postgres':\n case 'sqlite':\n createTableQuery = `\n CREATE TABLE sequelize_meta (\n name VARCHAR(100) PRIMARY KEY,\n version VARCHAR(25),\n createdAt TIMESTAMP NOT NULL,\n updatedAt TIMESTAMP NOT NULL\n )`;\n break;\n case 'mssql':\n createTableQuery = `\n CREATE TABLE sequelize_meta (\n name VARCHAR(100) PRIMARY KEY,\n version VARCHAR(25),\n createdAt DATETIME NOT NULL,\n updatedAt DATETIME NOT NULL\n )`;\n break;\n default:\n throw new Error('Unsupported SQL type');\n }\n\n // Create the new sequelize_meta table if it does not exist\n reportDebug({\n namespace,\n message: 'Creating sequelize_meta table',\n data: { sqlType: process.env.SQL_TYPE }\n });\n await sequelize.query(createTableQuery, { type: QueryTypes.RAW });\n reportDebug({\n namespace,\n message: 'sequelize_meta table created successfully'\n });\n\n // Migrate the data from the old table to the new one if needed\n if (hasLegacySequelizeMeta) {\n reportDebug({\n namespace,\n message: 'Legacy metadata table found, migrating data'\n });\n\n const migrations = await sequelize.query<SequelizeMeta>(\n 'SELECT name FROM SequelizeMeta ORDER BY name',\n {\n type: QueryTypes.SELECT\n }\n );\n\n const insertQuery = `\n INSERT INTO sequelize_meta (name, version, createdAt, updatedAt) VALUES\n ${migrations\n .map((migration) => {\n switch (process.env.SQL_TYPE) {\n case 'mysql':\n case 'postgres':\n return `('${migration.name}', NULL, NOW(), NOW())`;\n case 'sqlite':\n return `('${migration.name}', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`;\n case 'mssql':\n return `('${migration.name}', NULL, GETDATE(), GETDATE())`;\n default:\n throw new Error('Unsupported SQL type');\n }\n })\n .join(',')}\n `;\n\n await sequelize.query(insertQuery, { type: QueryTypes.INSERT });\n }\n }\n } catch (error) {\n reportError({\n namespace,\n message: 'Error in metadata migration',\n data: {\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n sqlType: process.env.SQL_TYPE,\n sqlHost: process.env.SQL_HOST\n }\n });\n throw error;\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"jwt.js","names":["_jsonwebtoken","require","_fs","_interopRequireDefault","_const","_EngineError","_KeySet","_WebError","_checkEnvironment","_envAssert","_report","keySet","exports","namespace","initKeySets","process","env","CHART","ECDSA_PUBLIC_KEY","EngineError","message","KeySet","file","AUTH_SERVICE_URL","internal","jwksPath","JWKS_PATH","promise","init","bind","Promise","all","shutdownKeySets","shutdown","jwtGetKey","header","callback","NODE_ENV","JWT_SECRET","kid","data","reportDebug","key","getKey","error","Error","WebError","statusCode","errorCode","jwtVerify","token","issuer","TokenIssuer","AUTH_SERVICE","algorithms","assertEnvironment","envAssert","isString","ACCESS_TOKEN_AUDIENCE","ACCESS_TOKEN_ISSUER","ACCESS_TOKEN_EXPIRATION_TIME","options","audience","resolve","reject","verify","result","undefined","generateJwtToken","user","signOptions","algorithm","expiresIn","parseInt","keyid","Object","keys","getKeys","privateKey","PRIVATE_KEY","PRIVATE_KEY_PATH","fs","readFileSync","String","sign"],"sources":["../../../src/utils/jwt/jwt.ts"],"sourcesContent":["import {\n verify,\n JwtHeader,\n SigningKeyCallback,\n Algorithm,\n VerifyOptions,\n sign\n} from 'jsonwebtoken';\nimport fs from 'fs';\nimport { UserTokenPayload } from './jwt.types';\nimport { TokenIssuer } from 'const';\nimport { EngineError } from 'entities/EngineError';\nimport { KeySet } from 'entities/KeySet';\nimport { WebError } from 'entities/WebError';\nimport { assertEnvironment } from 'utils/checkEnvironment';\nimport { envAssert } from 'utils/envAssert';\nimport { reportDebug } from 'utils/report';\n\nexport let keySet: KeySet | undefined;\n\nconst namespace = 'engine:utils:jwt';\n\n/** Initiate key fetching mechanism */\nexport async function initKeySets(): Promise<void> {\n // Create the KeySet instance\n // The auth-service fetches its key from its disk and not from a network request\n // This prevents fetch failures the first time the auth-service is started\n if (process.env.CHART === 'auth-service') {\n if (!process.env.ECDSA_PUBLIC_KEY)\n throw new EngineError({\n message: 'Environment variable \"ECDSA_PUBLIC_KEY\" is not defined'\n });\n keySet = new KeySet(process.env.ECDSA_PUBLIC_KEY, { file: true });\n } else {\n if (process.env.AUTH_SERVICE_URL)\n keySet = new KeySet(\n `${process.env.AUTH_SERVICE_URL}/.well-known/jwks.json`,\n { internal: true }\n );\n else {\n // Use JWKS_PATH if set (e.g., by Secret Manager), otherwise fall back to local path\n const jwksPath = process.env.JWKS_PATH || './keys/jwks.json';\n keySet = new KeySet(jwksPath, { internal: true, file: true });\n }\n\n if (!keySet)\n throw new EngineError({\n message:\n 'Environment variable \"AUTH_SERVICE_URL\" is not defined or JWKS not found'\n });\n }\n const promise = [keySet.init.bind(keySet)()];\n\n await Promise.all(promise);\n}\n\n/** Stop fetching keys regularly */\nexport function shutdownKeySets(): void {\n if (keySet) keySet.shutdown.bind(keySet)();\n}\n\n/** Get the JWT public key */\nfunction jwtGetKey(header: JwtHeader, callback: SigningKeyCallback): void {\n // In test environment we return the symmetric signature secret\n if (process.env.NODE_ENV === 'test') {\n callback(null, process.env.JWT_SECRET);\n return;\n }\n // Check that KeySet has been initialized\n if (!keySet) {\n callback(new EngineError({ message: 'KeySet has not been initialized' }));\n return;\n }\n // Check that the token has a key ID\n if (!header.kid) {\n callback(\n new EngineError({\n message:\n 'Token has not key ID in header, impossible to match with known key',\n data: header\n })\n );\n return;\n }\n\n // In test environment we use a symmetrical secret bases signature\n if (process.env.NODE_ENV === 'test') {\n callback(null, process.env.JWT_SECRET);\n return;\n }\n reportDebug({\n namespace,\n message: `Looking for key with ID \"${header.kid}\"`\n });\n // Go through each key set to check if the token's key is in one of them\n let key;\n try {\n key = keySet.getKey(header.kid);\n } catch (error: Error | null | unknown) {\n callback(error instanceof Error ? error : null);\n return;\n }\n\n if (key) {\n reportDebug({ namespace, message: `Found key with ID \"${header.kid}\"` });\n callback(null, key);\n return;\n }\n callback(\n new WebError({\n statusCode: 401,\n errorCode: 'unauthorized',\n message: 'Could not find the tokens key in any key set',\n data: { kid: header.kid }\n })\n );\n}\n\n/** Verify an user Json Web Token */\nexport async function jwtVerify(\n token: string,\n issuer: TokenIssuer = TokenIssuer.AUTH_SERVICE\n): Promise<UserTokenPayload> {\n let algorithms = ['ES256' as Algorithm];\n if (process.env.NODE_ENV === 'test') {\n assertEnvironment({ JWT_SECRET: envAssert.isString() });\n algorithms = ['HS256' as Algorithm];\n }\n assertEnvironment({\n ACCESS_TOKEN_AUDIENCE: envAssert.isString(),\n ACCESS_TOKEN_ISSUER: envAssert.isString(),\n ACCESS_TOKEN_EXPIRATION_TIME: envAssert.isString()\n });\n let options: VerifyOptions | undefined;\n\n switch (issuer) {\n case TokenIssuer.AUTH_SERVICE:\n options = {\n audience: [process.env.ACCESS_TOKEN_AUDIENCE as string],\n issuer: [process.env.ACCESS_TOKEN_ISSUER as string],\n algorithms\n };\n break;\n default:\n throw new EngineError({\n message: `Invalid token issuer specified \"${issuer as string}\"`\n });\n }\n\n return new Promise<UserTokenPayload>((resolve, reject) => {\n verify(token, jwtGetKey, options, (error, result) => {\n if (error) {\n reject(\n new WebError({\n errorCode: 'unauthorized',\n statusCode: 401,\n message: 'Invalid token supplied',\n error: error instanceof Error ? error : undefined\n })\n );\n return;\n }\n resolve(result as UserTokenPayload);\n });\n });\n}\n\nexport function generateJwtToken(user: unknown) {\n const signOptions = {\n algorithm: 'ES256' as const, // or 'ES256' as Algorithm\n expiresIn: process.env.ACCESS_TOKEN_EXPIRATION_TIME\n ? parseInt(process.env.ACCESS_TOKEN_EXPIRATION_TIME, 10)\n : 3600,\n issuer: process.env.ACCESS_TOKEN_ISSUER,\n audience: process.env.ACCESS_TOKEN_AUDIENCE,\n keyid: Object.keys(keySet?.getKeys() ?? {})[0]\n };\n\n // Get private key - can be either the key content directly or a file path\n let privateKey: string;\n \n if (process.env.PRIVATE_KEY) {\n // Direct key content in environment variable\n privateKey = process.env.PRIVATE_KEY;\n } else if (process.env.PRIVATE_KEY_PATH) {\n // File path in environment variable - read the file\n try {\n privateKey = fs.readFileSync(process.env.PRIVATE_KEY_PATH, 'utf8');\n } catch (error) {\n throw new EngineError({\n message: `Failed to read private key from path: ${process.env.PRIVATE_KEY_PATH}`,\n data: { error: error instanceof Error ? error.message : String(error) }\n });\n }\n } else {\n throw new EngineError({ \n message: 'Neither PRIVATE_KEY nor PRIVATE_KEY_PATH environment variable is set' \n });\n }\n\n const token = sign({ user }, privateKey, signOptions);\n\n return token;\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"jwt.js","names":["_jsonwebtoken","require","_fs","_interopRequireDefault","_const","_EngineError","_KeySet","_WebError","_checkEnvironment","_envAssert","_report","keySet","exports","namespace","initKeySets","process","env","CHART","ECDSA_PUBLIC_KEY","EngineError","message","KeySet","file","AUTH_SERVICE_URL","internal","jwksPath","JWKS_PATH","promise","init","bind","Promise","all","shutdownKeySets","shutdown","jwtGetKey","header","callback","NODE_ENV","JWT_SECRET","kid","data","reportDebug","key","getKey","error","Error","WebError","statusCode","errorCode","jwtVerify","token","issuer","TokenIssuer","AUTH_SERVICE","algorithms","assertEnvironment","envAssert","isString","ACCESS_TOKEN_AUDIENCE","ACCESS_TOKEN_ISSUER","ACCESS_TOKEN_EXPIRATION_TIME","options","audience","resolve","reject","verify","result","undefined","generateJwtToken","user","signOptions","algorithm","expiresIn","parseInt","keyid","Object","keys","getKeys","privateKey","PRIVATE_KEY","PRIVATE_KEY_PATH","fs","readFileSync","String","sign"],"sources":["../../../src/utils/jwt/jwt.ts"],"sourcesContent":["import {\n verify,\n JwtHeader,\n SigningKeyCallback,\n Algorithm,\n VerifyOptions,\n sign\n} from 'jsonwebtoken';\nimport fs from 'fs';\nimport { UserTokenPayload } from './jwt.types';\nimport { TokenIssuer } from 'const';\nimport { EngineError } from 'entities/EngineError';\nimport { KeySet } from 'entities/KeySet';\nimport { WebError } from 'entities/WebError';\nimport { assertEnvironment } from 'utils/checkEnvironment';\nimport { envAssert } from 'utils/envAssert';\nimport { reportDebug } from 'utils/report';\n\nexport let keySet: KeySet | undefined;\n\nconst namespace = 'engine:utils:jwt';\n\n/** Initiate key fetching mechanism */\nexport async function initKeySets(): Promise<void> {\n // Create the KeySet instance\n // The auth-service fetches its key from its disk and not from a network request\n // This prevents fetch failures the first time the auth-service is started\n if (process.env.CHART === 'auth-service') {\n if (!process.env.ECDSA_PUBLIC_KEY)\n throw new EngineError({\n message: 'Environment variable \"ECDSA_PUBLIC_KEY\" is not defined'\n });\n keySet = new KeySet(process.env.ECDSA_PUBLIC_KEY, { file: true });\n } else {\n if (process.env.AUTH_SERVICE_URL)\n keySet = new KeySet(\n `${process.env.AUTH_SERVICE_URL}/.well-known/jwks.json`,\n { internal: true }\n );\n else {\n // Use JWKS_PATH if set (e.g., by Secret Manager), otherwise fall back to local path\n const jwksPath = process.env.JWKS_PATH || './keys/jwks.json';\n keySet = new KeySet(jwksPath, { internal: true, file: true });\n }\n\n if (!keySet)\n throw new EngineError({\n message:\n 'Environment variable \"AUTH_SERVICE_URL\" is not defined or JWKS not found'\n });\n }\n const promise = [keySet.init.bind(keySet)()];\n\n await Promise.all(promise);\n}\n\n/** Stop fetching keys regularly */\nexport function shutdownKeySets(): void {\n if (keySet) keySet.shutdown.bind(keySet)();\n}\n\n/** Get the JWT public key */\nfunction jwtGetKey(header: JwtHeader, callback: SigningKeyCallback): void {\n // In test environment we return the symmetric signature secret\n if (process.env.NODE_ENV === 'test') {\n callback(null, process.env.JWT_SECRET);\n return;\n }\n // Check that KeySet has been initialized\n if (!keySet) {\n callback(new EngineError({ message: 'KeySet has not been initialized' }));\n return;\n }\n // Check that the token has a key ID\n if (!header.kid) {\n callback(\n new EngineError({\n message:\n 'Token has not key ID in header, impossible to match with known key',\n data: header\n })\n );\n return;\n }\n\n // In test environment we use a symmetrical secret bases signature\n if (process.env.NODE_ENV === 'test') {\n callback(null, process.env.JWT_SECRET);\n return;\n }\n reportDebug({\n namespace,\n message: `Looking for key with ID \"${header.kid}\"`\n });\n // Go through each key set to check if the token's key is in one of them\n let key;\n try {\n key = keySet.getKey(header.kid);\n } catch (error: Error | null | unknown) {\n callback(error instanceof Error ? error : null);\n return;\n }\n\n if (key) {\n reportDebug({ namespace, message: `Found key with ID \"${header.kid}\"` });\n callback(null, key);\n return;\n }\n callback(\n new WebError({\n statusCode: 401,\n errorCode: 'unauthorized',\n message: 'Could not find the tokens key in any key set',\n data: { kid: header.kid }\n })\n );\n}\n\n/** Verify an user Json Web Token */\nexport async function jwtVerify(\n token: string,\n issuer: TokenIssuer = TokenIssuer.AUTH_SERVICE\n): Promise<UserTokenPayload> {\n let algorithms = ['ES256' as Algorithm];\n if (process.env.NODE_ENV === 'test') {\n assertEnvironment({ JWT_SECRET: envAssert.isString() });\n algorithms = ['HS256' as Algorithm];\n }\n assertEnvironment({\n ACCESS_TOKEN_AUDIENCE: envAssert.isString(),\n ACCESS_TOKEN_ISSUER: envAssert.isString(),\n ACCESS_TOKEN_EXPIRATION_TIME: envAssert.isString()\n });\n let options: VerifyOptions | undefined;\n\n switch (issuer) {\n case TokenIssuer.AUTH_SERVICE:\n options = {\n audience: [process.env.ACCESS_TOKEN_AUDIENCE as string],\n issuer: [process.env.ACCESS_TOKEN_ISSUER as string],\n algorithms\n };\n break;\n default:\n throw new EngineError({\n message: `Invalid token issuer specified \"${issuer as string}\"`\n });\n }\n\n return new Promise<UserTokenPayload>((resolve, reject) => {\n verify(token, jwtGetKey, options, (error, result) => {\n if (error) {\n reject(\n new WebError({\n errorCode: 'unauthorized',\n statusCode: 401,\n message: 'Invalid token supplied',\n error: error instanceof Error ? error : undefined\n })\n );\n return;\n }\n resolve(result as UserTokenPayload);\n });\n });\n}\n\nexport function generateJwtToken(user: unknown) {\n const signOptions = {\n algorithm: 'ES256' as const, // or 'ES256' as Algorithm\n expiresIn: process.env.ACCESS_TOKEN_EXPIRATION_TIME\n ? parseInt(process.env.ACCESS_TOKEN_EXPIRATION_TIME, 10)\n : 3600,\n issuer: process.env.ACCESS_TOKEN_ISSUER,\n audience: process.env.ACCESS_TOKEN_AUDIENCE,\n keyid: Object.keys(keySet?.getKeys() ?? {})[0]\n };\n\n // Get private key - can be either the key content directly or a file path\n let privateKey: string;\n\n if (process.env.PRIVATE_KEY) {\n // Direct key content in environment variable\n privateKey = process.env.PRIVATE_KEY;\n } else if (process.env.PRIVATE_KEY_PATH) {\n // File path in environment variable - read the file\n try {\n privateKey = fs.readFileSync(process.env.PRIVATE_KEY_PATH, 'utf8');\n } catch (error) {\n throw new EngineError({\n message: `Failed to read private key from path: ${process.env.PRIVATE_KEY_PATH}`,\n data: { error: error instanceof Error ? error.message : String(error) }\n });\n }\n } else {\n throw new EngineError({\n message:\n 'Neither PRIVATE_KEY nor PRIVATE_KEY_PATH environment variable is set'\n });\n }\n\n const token = sign({ user }, privateKey, signOptions);\n\n return token;\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"jwt.types.js","names":[],"sources":["../../../src/utils/jwt/jwt.types.ts"],"sourcesContent":["\n/** Content of the payload of user authentication tokens */\nexport interface UserTokenPayload {\n /** ID of the user */\n sub: string;\n /** URL of the service that issued the token */\n iss: string;\n /** URL of the services that can consume the token */\n aud: Array<string> | string;\n /** Unique ID of the token */\n jti: string;\n /** ID of the device the token was issued to */\n dev: string;\n /** Timestamp at which the token will expire */\n exp: number;\n /** List of permissions that the user has (only on the admin API) */\n per?: Array<string> | string;\n /** User */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n user: Record<string, any> | undefined;\n}\n"],"mappings":"","ignoreList":[]}
1
+ {"version":3,"file":"jwt.types.js","names":[],"sources":["../../../src/utils/jwt/jwt.types.ts"],"sourcesContent":["/** Content of the payload of user authentication tokens */\nexport interface UserTokenPayload {\n /** ID of the user */\n sub: string;\n /** URL of the service that issued the token */\n iss: string;\n /** URL of the services that can consume the token */\n aud: Array<string> | string;\n /** Unique ID of the token */\n jti: string;\n /** ID of the device the token was issued to */\n dev: string;\n /** Timestamp at which the token will expire */\n exp: number;\n /** List of permissions that the user has (only on the admin API) */\n per?: Array<string> | string;\n /** User */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n user: Record<string, any> | undefined;\n}\n"],"mappings":"","ignoreList":[]}
@@ -1 +1 @@
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","formatTime","date","now","Date","toTimeString","split","formatLocalLog","severityOrEntry","message","undefined","time","severityColor","useColors","process","env","NODE_ENV","output","padEnd","console","log","entry","showDetailedLogs","DETAILED_LOGS","parts","push","join","errorType","errorCode","statusCode","errorParts","statusColor","length","context","httpRequest","req","method","url","stack_trace","data","Object","keys","JSON","stringify","fileName","lineNumber","isLocalDevelopment","LOG_FORMAT","KUBERNETES_POD_NAME","CLOUD_RUN_JOB","SENSITIVE_KEY_PATTERN","REDACTED","MAX_REDACT_DEPTH","redactSensitive","value","depth","seen","WeakSet","has","add","Array","isArray","map","item","prototype","getPrototypeOf","result","key","entries","test","call","callsite","fullEntry","getLineNumber","getFileName","replace","serviceContext","service","CHART","HOSTNAME","version","BUILD_ID","environment","instance","SILENCE_REPORT","dir","formattedLog","error"],"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 timestamp as HH:MM:SS\n */\nexport function formatTime(date?: Date): string {\n const now = date || new Date();\n return now.toTimeString().split(' ')[0];\n}\n\n/**\n * Format log entry for human-readable local development output\n */\nexport function formatLocalLog(severity: LogSeverity | string, message: string): void;\nexport function formatLocalLog(entry: FullLogEntry): string;\nexport function formatLocalLog(severityOrEntry: LogSeverity | string | FullLogEntry, message?: string): string | void {\n // Handle overloaded signature for testing\n if (typeof severityOrEntry === 'string' && message !== undefined) {\n const time = formatTime();\n const severityColor = getSeverityColor(severityOrEntry);\n const useColors = process.env.NODE_ENV !== 'production';\n \n const output = useColors \n ? `${colors.gray}[${time}]${colors.reset} ${severityColor}${severityOrEntry.padEnd(8)}${colors.reset} ${message}`\n : `[${time}] ${severityOrEntry.padEnd(8)} ${message}`;\n \n console.log(output);\n return;\n }\n \n // Original function implementation\n const entry = severityOrEntry as FullLogEntry;\n const time = formatTime();\n const severity = entry.severity || 'INFO';\n const severityColor = getSeverityColor(severity);\n const showDetailedLogs = process.env.DETAILED_LOGS === 'true';\n \n const parts: string[] = [];\n \n // Timestamp and severity\n parts.push(\n `${colors.gray}[${time}]${colors.reset} ${severityColor}${severity.padEnd(8)}${colors.reset}`\n );\n \n // Message\n if (entry.message) {\n parts.push(`${entry.message}`);\n }\n \n let output = parts.join(' ');\n \n // Error details (compact format)\n if (entry.errorType || entry.errorCode || entry.statusCode) {\n const errorParts: string[] = [];\n if (entry.errorCode) errorParts.push(`${colors.red}${entry.errorCode}${colors.reset}`);\n if (entry.statusCode) {\n const statusColor = entry.statusCode >= 500 ? colors.red : entry.statusCode >= 400 ? colors.yellow : colors.green;\n errorParts.push(`${statusColor}${entry.statusCode}${colors.reset}`);\n }\n if (errorParts.length > 0) {\n output += ` ${colors.dim}[${errorParts.join(' ')}]${colors.reset}`;\n }\n }\n \n // HTTP request context (compact)\n if (entry.context?.httpRequest) {\n const req = entry.context.httpRequest;\n output += ` ${colors.dim}${req.method} ${req.url}${colors.reset}`;\n }\n \n // Stack trace (only in detailed mode)\n if (showDetailedLogs && 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 (only in detailed mode or if no message)\n if (showDetailedLogs && 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 // File location (only in detailed mode)\n if (showDetailedLogs && entry.fileName) {\n output += `\\n ${colors.dim}${entry.fileName}:${entry.lineNumber || '?'}${colors.reset}`;\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/** Keys whose values must never be written to the logs */\nconst SENSITIVE_KEY_PATTERN =\n /^(authorization|proxy[-_]?authorization|cookie|set[-_]?cookie|password|passwd|pass|secret|client[-_]?secret|token|access[-_]?token|refresh[-_]?token|id[-_]?token|api[-_]?key|private[-_]?key|credentials?|otp)$/i;\nconst REDACTED = '[REDACTED]';\nconst MAX_REDACT_DEPTH = 10;\n\n/** Returns a copy of the value with sensitive fields masked */\nexport function redactSensitive(\n value: unknown,\n depth = 0,\n seen: WeakSet<object> = new WeakSet()\n): unknown {\n if (!value || typeof value !== 'object' || depth > MAX_REDACT_DEPTH)\n return value;\n if (seen.has(value)) return value;\n seen.add(value);\n if (Array.isArray(value))\n return value.map((item) => redactSensitive(item, depth + 1, seen));\n // Only walk plain objects, leave class instances (Errors, Buffers, Dates...) untouched\n const prototype = Object.getPrototypeOf(value);\n if (prototype !== Object.prototype && prototype !== null) return value;\n const result: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) {\n result[key] = SENSITIVE_KEY_PATTERN.test(key)\n ? REDACTED\n : redactSensitive(entry, depth + 1, seen);\n }\n return result;\n}\n\n/** Add metadata to the log entry and print it */\nexport function output(data: LogEntry): FullLogEntry {\n if (data.data !== undefined)\n data = { ...data, data: redactSensitive(data.data) };\n\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":"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","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","formatTime","date","now","Date","toTimeString","split","formatLocalLog","severityOrEntry","message","undefined","time","severityColor","useColors","process","env","NODE_ENV","output","padEnd","console","log","entry","showDetailedLogs","DETAILED_LOGS","parts","push","join","errorType","errorCode","statusCode","errorParts","statusColor","length","context","httpRequest","req","method","url","stack_trace","data","Object","keys","JSON","stringify","fileName","lineNumber","isLocalDevelopment","LOG_FORMAT","KUBERNETES_POD_NAME","CLOUD_RUN_JOB","SENSITIVE_KEY_PATTERN","REDACTED","MAX_REDACT_DEPTH","redactSensitive","value","depth","seen","WeakSet","has","add","Array","isArray","map","item","prototype","getPrototypeOf","result","key","entries","test","call","callsite","fullEntry","getLineNumber","getFileName","replace","serviceContext","service","CHART","HOSTNAME","version","BUILD_ID","environment","instance","SILENCE_REPORT","dir","formattedLog","error"],"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 timestamp as HH:MM:SS\n */\nexport function formatTime(date?: Date): string {\n const now = date || new Date();\n return now.toTimeString().split(' ')[0];\n}\n\n/**\n * Format log entry for human-readable local development output\n */\nexport function formatLocalLog(\n severity: LogSeverity | string,\n message: string\n): void;\nexport function formatLocalLog(entry: FullLogEntry): string;\nexport function formatLocalLog(\n severityOrEntry: LogSeverity | string | FullLogEntry,\n message?: string\n): string | void {\n // Handle overloaded signature for testing\n if (typeof severityOrEntry === 'string' && message !== undefined) {\n const time = formatTime();\n const severityColor = getSeverityColor(severityOrEntry);\n const useColors = process.env.NODE_ENV !== 'production';\n\n const output = useColors\n ? `${colors.gray}[${time}]${colors.reset} ${severityColor}${severityOrEntry.padEnd(8)}${colors.reset} ${message}`\n : `[${time}] ${severityOrEntry.padEnd(8)} ${message}`;\n\n console.log(output);\n return;\n }\n\n // Original function implementation\n const entry = severityOrEntry as FullLogEntry;\n const time = formatTime();\n const severity = entry.severity || 'INFO';\n const severityColor = getSeverityColor(severity);\n const showDetailedLogs = process.env.DETAILED_LOGS === 'true';\n\n const parts: string[] = [];\n\n // Timestamp and severity\n parts.push(\n `${colors.gray}[${time}]${colors.reset} ${severityColor}${severity.padEnd(8)}${colors.reset}`\n );\n\n // Message\n if (entry.message) {\n parts.push(`${entry.message}`);\n }\n\n let output = parts.join(' ');\n\n // Error details (compact format)\n if (entry.errorType || entry.errorCode || entry.statusCode) {\n const errorParts: string[] = [];\n if (entry.errorCode)\n errorParts.push(`${colors.red}${entry.errorCode}${colors.reset}`);\n if (entry.statusCode) {\n const statusColor =\n entry.statusCode >= 500\n ? colors.red\n : entry.statusCode >= 400\n ? colors.yellow\n : colors.green;\n errorParts.push(`${statusColor}${entry.statusCode}${colors.reset}`);\n }\n if (errorParts.length > 0) {\n output += ` ${colors.dim}[${errorParts.join(' ')}]${colors.reset}`;\n }\n }\n\n // HTTP request context (compact)\n if (entry.context?.httpRequest) {\n const req = entry.context.httpRequest;\n output += ` ${colors.dim}${req.method} ${req.url}${colors.reset}`;\n }\n\n // Stack trace (only in detailed mode)\n if (showDetailedLogs && 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 (only in detailed mode or if no message)\n if (showDetailedLogs && 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 // File location (only in detailed mode)\n if (showDetailedLogs && entry.fileName) {\n output += `\\n ${colors.dim}${entry.fileName}:${entry.lineNumber || '?'}${colors.reset}`;\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 &&\n !process.env.KUBERNETES_POD_NAME &&\n !process.env.CLOUD_RUN_JOB)\n );\n}\n\n/** Keys whose values must never be written to the logs */\nconst SENSITIVE_KEY_PATTERN =\n /^(authorization|proxy[-_]?authorization|cookie|set[-_]?cookie|password|passwd|pass|secret|client[-_]?secret|token|access[-_]?token|refresh[-_]?token|id[-_]?token|api[-_]?key|private[-_]?key|credentials?|otp)$/i;\nconst REDACTED = '[REDACTED]';\nconst MAX_REDACT_DEPTH = 10;\n\n/** Returns a copy of the value with sensitive fields masked */\nexport function redactSensitive(\n value: unknown,\n depth = 0,\n seen: WeakSet<object> = new WeakSet()\n): unknown {\n if (!value || typeof value !== 'object' || depth > MAX_REDACT_DEPTH)\n return value;\n if (seen.has(value)) return value;\n seen.add(value);\n if (Array.isArray(value))\n return value.map((item) => redactSensitive(item, depth + 1, seen));\n // Only walk plain objects, leave class instances (Errors, Buffers, Dates...) untouched\n const prototype = Object.getPrototypeOf(value);\n if (prototype !== Object.prototype && prototype !== null) return value;\n const result: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) {\n result[key] = SENSITIVE_KEY_PATTERN.test(key)\n ? REDACTED\n : redactSensitive(entry, depth + 1, seen);\n }\n return result;\n}\n\n/** Add metadata to the log entry and print it */\nexport function output(data: LogEntry): FullLogEntry {\n if (data.data !== undefined)\n data = { ...data, data: redactSensitive(data.data) };\n\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 (\n data.severity === LogSeverity.ERROR ||\n data.severity === LogSeverity.CRITICAL ||\n (data.statusCode && data.statusCode >= 500)\n ) {\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":"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","ignoreList":[]}