@fdm-monster/server 2.1.0 → 2.1.1

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 (223) hide show
  1. package/.yarn/install-state.gz +0 -0
  2. package/.yarn/releases/{yarn-4.13.0.cjs → yarn-4.14.1.cjs} +288 -288
  3. package/.yarnrc.yml +5 -1
  4. package/RELEASE_NOTES.MD +14 -0
  5. package/dist/_virtual/{_@oxc-project_runtime@0.127.0 → _@oxc-project_runtime@0.129.0}/helpers/decorate.js +1 -1
  6. package/dist/_virtual/{_@oxc-project_runtime@0.127.0 → _@oxc-project_runtime@0.129.0}/helpers/decorateMetadata.js +1 -1
  7. package/dist/consoles/typeorm-create.js.map +1 -1
  8. package/dist/consoles/typeorm-generate.js.map +1 -1
  9. package/dist/consoles/typeorm-migrate.js.map +1 -1
  10. package/dist/constants/authorization.constants.js.map +1 -1
  11. package/dist/container.js.map +1 -1
  12. package/dist/controllers/api-key.controller.js +2 -2
  13. package/dist/controllers/api-key.controller.js.map +1 -1
  14. package/dist/controllers/auth.controller.js +5 -3
  15. package/dist/controllers/auth.controller.js.map +1 -1
  16. package/dist/controllers/batch-call.controller.js +2 -2
  17. package/dist/controllers/batch-call.controller.js.map +1 -1
  18. package/dist/controllers/camera-stream.controller.js +2 -2
  19. package/dist/controllers/camera-stream.controller.js.map +1 -1
  20. package/dist/controllers/file-storage.controller.js +2 -2
  21. package/dist/controllers/file-storage.controller.js.map +1 -1
  22. package/dist/controllers/first-time-setup.controller.js +2 -2
  23. package/dist/controllers/first-time-setup.controller.js.map +1 -1
  24. package/dist/controllers/floor.controller.js +2 -2
  25. package/dist/controllers/floor.controller.js.map +1 -1
  26. package/dist/controllers/metrics.controller.js +2 -2
  27. package/dist/controllers/metrics.controller.js.map +1 -1
  28. package/dist/controllers/print-job.controller.js +2 -2
  29. package/dist/controllers/print-job.controller.js.map +1 -1
  30. package/dist/controllers/print-queue.controller.js +2 -2
  31. package/dist/controllers/print-queue.controller.js.map +1 -1
  32. package/dist/controllers/printer-files.controller.js +2 -2
  33. package/dist/controllers/printer-files.controller.js.map +1 -1
  34. package/dist/controllers/printer-maintenance-log.controller.js +2 -2
  35. package/dist/controllers/printer-maintenance-log.controller.js.map +1 -1
  36. package/dist/controllers/printer-settings.controller.js +2 -2
  37. package/dist/controllers/printer-settings.controller.js.map +1 -1
  38. package/dist/controllers/printer-tag.controller.js +2 -2
  39. package/dist/controllers/printer-tag.controller.js.map +1 -1
  40. package/dist/controllers/printer.controller.js +2 -2
  41. package/dist/controllers/printer.controller.js.map +1 -1
  42. package/dist/controllers/server-private.controller.js +2 -2
  43. package/dist/controllers/server-private.controller.js.map +1 -1
  44. package/dist/controllers/server-public.controller.js +2 -2
  45. package/dist/controllers/server-public.controller.js.map +1 -1
  46. package/dist/controllers/settings.controller.js +2 -2
  47. package/dist/controllers/settings.controller.js.map +1 -1
  48. package/dist/controllers/slicer-compat.controller.js +2 -2
  49. package/dist/controllers/slicer-compat.controller.js.map +1 -1
  50. package/dist/controllers/user.controller.js +2 -2
  51. package/dist/controllers/user.controller.js.map +1 -1
  52. package/dist/entities/api-key.entity.js +2 -2
  53. package/dist/entities/camera-stream.entity.js +2 -2
  54. package/dist/entities/floor-position.entity.js +2 -2
  55. package/dist/entities/floor.entity.js +2 -2
  56. package/dist/entities/print-job.entity.js +2 -2
  57. package/dist/entities/printer-maintenance-log.entity.js +2 -2
  58. package/dist/entities/printer-tag.entity.js +2 -2
  59. package/dist/entities/printer.entity.js +2 -2
  60. package/dist/entities/refresh-token.entity.js +2 -2
  61. package/dist/entities/role.entity.js +2 -2
  62. package/dist/entities/settings.entity.js +2 -2
  63. package/dist/entities/tag.entity.js +2 -2
  64. package/dist/entities/user-role.entity.js +2 -2
  65. package/dist/entities/user.entity.js +2 -2
  66. package/dist/exceptions/failed-dependency.exception.js.map +1 -1
  67. package/dist/exceptions/job.exceptions.js.map +1 -1
  68. package/dist/exceptions/runtime.exceptions.js.map +1 -1
  69. package/dist/handlers/event-emitter.js.map +1 -1
  70. package/dist/handlers/logger-factory.js.map +1 -1
  71. package/dist/handlers/logger.js.map +1 -1
  72. package/dist/handlers/logging/file-logging.transport.js +1 -2
  73. package/dist/handlers/logging/file-logging.transport.js.map +1 -1
  74. package/dist/handlers/logging/loki-logging.transport.js.map +1 -1
  75. package/dist/handlers/logging/static.logger.js.map +1 -1
  76. package/dist/handlers/validators.js.map +1 -1
  77. package/dist/index.js.map +1 -1
  78. package/dist/middleware/api-key.strategy.js.map +1 -1
  79. package/dist/middleware/authenticate.js.map +1 -1
  80. package/dist/middleware/database.js.map +1 -1
  81. package/dist/middleware/demo.middleware.js.map +1 -1
  82. package/dist/middleware/exception.filter.js.map +1 -1
  83. package/dist/middleware/global.middleware.js.map +1 -1
  84. package/dist/middleware/param-converter.middleware.js.map +1 -1
  85. package/dist/middleware/passport.js.map +1 -1
  86. package/dist/middleware/printer-resolver.js.map +1 -1
  87. package/dist/middleware/printer.js.map +1 -1
  88. package/dist/middleware/slicer-api-key.middleware.js.map +1 -1
  89. package/dist/middleware/socketio.middleware.js.map +1 -1
  90. package/dist/migrations/1706829146617-InitSqlite.js.map +1 -1
  91. package/dist/migrations/1707494762198-PrinterGroup.js.map +1 -1
  92. package/dist/migrations/1708465930665-ChangePrintCompletionDeletePrinterCascade.js.map +1 -1
  93. package/dist/migrations/1713300747465-ChangeRoleNameUnique.js.map +1 -1
  94. package/dist/migrations/1713897879622-AddPrinterType.js.map +1 -1
  95. package/dist/migrations/1720338804844-RemovePrinterFile.js.map +1 -1
  96. package/dist/migrations/1745141688926-AddPrinterUsernamePassword.js.map +1 -1
  97. package/dist/migrations/1766576698569-DropPermissions.js.map +1 -1
  98. package/dist/migrations/1767278216516-ChangeCameraPrinterOnDeleteSetNull.js.map +1 -1
  99. package/dist/migrations/1767279607392-DropCustomGcode.js.map +1 -1
  100. package/dist/migrations/1767291804417-DropPrintCompletions.js.map +1 -1
  101. package/dist/migrations/1767352862576-DropSettingsFileClean.js.map +1 -1
  102. package/dist/migrations/1767355639023-ChangeFloorLevelToOrder.js.map +1 -1
  103. package/dist/migrations/1767370191762-ChangeFloorNonUniqueOrder.js.map +1 -1
  104. package/dist/migrations/1767432108916-RenameGroupToTag.js.map +1 -1
  105. package/dist/migrations/1767451444137-AddPrintJob.js.map +1 -1
  106. package/dist/migrations/1767909428129-AddPrinterMaintenanceLog.js.map +1 -1
  107. package/dist/migrations/1778446203015-AddApiKey.js.map +1 -1
  108. package/dist/plugins/controllers-plugin.js.map +1 -1
  109. package/dist/server.constants.js +2 -1
  110. package/dist/server.constants.js.map +1 -1
  111. package/dist/server.core.js.map +1 -1
  112. package/dist/server.env.js.map +1 -1
  113. package/dist/server.host.js.map +1 -1
  114. package/dist/services/authentication/auth.service.js.map +1 -1
  115. package/dist/services/authentication/jwt.service.js.map +1 -1
  116. package/dist/services/bambu/bambu-ftp.adapter.js.map +1 -1
  117. package/dist/services/bambu/bambu-mqtt.adapter.js.map +1 -1
  118. package/dist/services/bambu/bambu.client.js.map +1 -1
  119. package/dist/services/bambu.api.js.map +1 -1
  120. package/dist/services/core/batch-call.service.js.map +1 -1
  121. package/dist/services/core/client-bundle.service.js.map +1 -1
  122. package/dist/services/core/config.service.js +4 -0
  123. package/dist/services/core/config.service.js.map +1 -1
  124. package/dist/services/core/cradle.service.js.map +1 -1
  125. package/dist/services/core/github.service.js.map +1 -1
  126. package/dist/services/core/http-client.factory.js.map +1 -1
  127. package/dist/services/core/logs-manager.service.js.map +1 -1
  128. package/dist/services/core/monsterpi.service.js.map +1 -1
  129. package/dist/services/core/multer.service.js.map +1 -1
  130. package/dist/services/core/server-release.service.js.map +1 -1
  131. package/dist/services/core/yaml.service.js.map +1 -1
  132. package/dist/services/file-analysis.service.js.map +1 -1
  133. package/dist/services/file-storage.service.js.map +1 -1
  134. package/dist/services/moonraker/moonraker-websocket.adapter.js.map +1 -1
  135. package/dist/services/moonraker/moonraker.client.js.map +1 -1
  136. package/dist/services/moonraker.api.js.map +1 -1
  137. package/dist/services/octoprint/octoprint-api.routes.js.map +1 -1
  138. package/dist/services/octoprint/octoprint-websocket.adapter.js.map +1 -1
  139. package/dist/services/octoprint/octoprint.client.js.map +1 -1
  140. package/dist/services/octoprint/utils/api.utils.js.map +1 -1
  141. package/dist/services/octoprint/utils/file.utils.js.map +1 -1
  142. package/dist/services/octoprint/utils/octoprint-http-client.builder.js.map +1 -1
  143. package/dist/services/octoprint.api.js.map +1 -1
  144. package/dist/services/orm/api-key.service.js.map +1 -1
  145. package/dist/services/orm/base.service.js.map +1 -1
  146. package/dist/services/orm/camera-stream.service.js.map +1 -1
  147. package/dist/services/orm/floor-position.service.js.map +1 -1
  148. package/dist/services/orm/floor.service.js.map +1 -1
  149. package/dist/services/orm/permission.service.js.map +1 -1
  150. package/dist/services/orm/print-job.service.js.map +1 -1
  151. package/dist/services/orm/printer-maintenance-log.service.js.map +1 -1
  152. package/dist/services/orm/printer-tag.service.js.map +1 -1
  153. package/dist/services/orm/printer.service.js.map +1 -1
  154. package/dist/services/orm/refresh-token.service.js.map +1 -1
  155. package/dist/services/orm/role.service.js.map +1 -1
  156. package/dist/services/orm/settings.service.js.map +1 -1
  157. package/dist/services/orm/user-role.service.js.map +1 -1
  158. package/dist/services/orm/user.service.js.map +1 -1
  159. package/dist/services/print-file-downloader.service.js.map +1 -1
  160. package/dist/services/print-queue.service.js.map +1 -1
  161. package/dist/services/printer-api.factory.js.map +1 -1
  162. package/dist/services/printer-api.interface.js.map +1 -1
  163. package/dist/services/prusa-link/prusa-link-http-polling.adapter.js.map +1 -1
  164. package/dist/services/prusa-link/prusa-link.api.js.map +1 -1
  165. package/dist/services/prusa-link/utils/digest-auth.util.js +19 -12
  166. package/dist/services/prusa-link/utils/digest-auth.util.js.map +1 -1
  167. package/dist/services/prusa-link/utils/prusa-link-http-client.builder.js +45 -11
  168. package/dist/services/prusa-link/utils/prusa-link-http-client.builder.js.map +1 -1
  169. package/dist/services/socket.factory.js.map +1 -1
  170. package/dist/services/task-manager.service.js.map +1 -1
  171. package/dist/services/typeorm/typeorm.service.js.map +1 -1
  172. package/dist/services/validators/printer-service.validation.js.map +1 -1
  173. package/dist/shared/default-http-client.builder.js.map +1 -1
  174. package/dist/shared/load-controllers.js.map +1 -1
  175. package/dist/shared/runtime-settings.migration.js.map +1 -1
  176. package/dist/shared/websocket-rpc-extended.adapter.js.map +1 -1
  177. package/dist/shared/websocket.adapter.js.map +1 -1
  178. package/dist/state/file-upload-tracker.cache.js.map +1 -1
  179. package/dist/state/floor.store.js.map +1 -1
  180. package/dist/state/printer-events.cache.js.map +1 -1
  181. package/dist/state/printer-socket.store.js.map +1 -1
  182. package/dist/state/printer-thumbnail.cache.js.map +1 -1
  183. package/dist/state/printer.cache.js.map +1 -1
  184. package/dist/state/settings.store.js.map +1 -1
  185. package/dist/state/socket-io.gateway.js.map +1 -1
  186. package/dist/state/test-printer-socket.store.js.map +1 -1
  187. package/dist/tasks/boot.task.js.map +1 -1
  188. package/dist/tasks/client-bundle.task.js.map +1 -1
  189. package/dist/tasks/print-job-analysis.task.js.map +1 -1
  190. package/dist/tasks/printer-websocket-restore.task.js.map +1 -1
  191. package/dist/tasks/printer-websocket.task.js.map +1 -1
  192. package/dist/tasks/socketio.task.js.map +1 -1
  193. package/dist/tasks/software-update.task.js.map +1 -1
  194. package/dist/tasks.js.map +1 -1
  195. package/dist/utils/array.util.js.map +1 -1
  196. package/dist/utils/bgcode/bgcode-thumbnail.parser.js.map +1 -1
  197. package/dist/utils/bgcode/bgcode.utils.js.map +1 -1
  198. package/dist/utils/bgcode/heatshrink-decoder.js.map +1 -1
  199. package/dist/utils/bgcode/png-encoder.js.map +1 -1
  200. package/dist/utils/bgcode/qoi-decoder.js.map +1 -1
  201. package/dist/utils/cache/key-diff.cache.js.map +1 -1
  202. package/dist/utils/correlation-token.util.js.map +1 -1
  203. package/dist/utils/crypto.utils.js.map +1 -1
  204. package/dist/utils/env.utils.js.map +1 -1
  205. package/dist/utils/error.utils.js.map +1 -1
  206. package/dist/utils/fs.utils.js.map +1 -1
  207. package/dist/utils/gcode.utils.js.map +1 -1
  208. package/dist/utils/image-dimensions.js.map +1 -1
  209. package/dist/utils/job-stats.util.js.map +1 -1
  210. package/dist/utils/normalize-url.js.map +1 -1
  211. package/dist/utils/parsers/3mf.parser.js.map +1 -1
  212. package/dist/utils/parsers/bgcode.parser.js.map +1 -1
  213. package/dist/utils/parsers/gcode.parser.js.map +1 -1
  214. package/dist/utils/pretty-print.utils.js.map +1 -1
  215. package/dist/utils/semver.utils.js.map +1 -1
  216. package/dist/utils/swagger/decorators.js.map +1 -1
  217. package/dist/utils/swagger/generator.js.map +1 -1
  218. package/dist/utils/swagger/swagger.js.map +1 -1
  219. package/dist/utils/thumbnail.util.js.map +1 -1
  220. package/dist/utils/time.utils.js.map +1 -1
  221. package/dist/utils/url.utils.js.map +1 -1
  222. package/package.json +10 -7
  223. package/packages/consoles/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
3
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
2
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
3
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
4
4
  import { AppConstants } from "../server.constants.js";
5
5
  import { isNode } from "../utils/env.utils.js";
6
6
  import { SettingsStore } from "../state/settings.store.js";
@@ -1 +1 @@
1
- {"version":3,"file":"server-public.controller.js","names":[],"sources":["../../src/controllers/server-public.controller.ts"],"sourcesContent":["import { before, GET, route } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport { isNode } from \"@/utils/env.utils\";\nimport { authenticate, permission } from \"@/middleware/authenticate\";\nimport { PERMS } from \"@/constants/authorization.constants\";\nimport { SettingsStore } from \"@/state/settings.store\";\nimport { ServerReleaseService } from \"@/services/core/server-release.service\";\nimport { MonsterPiService } from \"@/services/core/monsterpi.service\";\nimport type { Request, Response } from \"express\";\n\n@route(AppConstants.apiRoute)\nexport class ServerPublicController {\n constructor(\n private readonly settingsStore: SettingsStore,\n private readonly serverVersion: string,\n private readonly serverReleaseService: ServerReleaseService,\n private readonly monsterPiService: MonsterPiService,\n ) {}\n\n @GET()\n @route(\"/\")\n @before([authenticate(), permission(PERMS.ServerInfo.Get)])\n async welcome(req: Request, res: Response) {\n this.settingsStore.getSettings();\n\n if (!(await this.settingsStore.getLoginRequired())) {\n return res.send({\n message: \"Login disabled. Please load the Vue app.\",\n apiDocs: \"http://localhost:4000/api-docs/\",\n swaggerJson: \"http://localhost:4000/api-docs/swagger.json\",\n });\n }\n\n return res.send({\n message: \"Login required. Please load the Vue app.\",\n apiDocs: \"http://localhost:4000/api-docs/\",\n swaggerJson: \"http://localhost:4000/api-docs/swagger.json\",\n });\n }\n\n @GET()\n @route(\"/features\")\n @before([authenticate()])\n getFeatures(req: Request, res: Response) {\n const serverSettings = this.settingsStore.getServerSettings();\n const moonrakerEnabled = serverSettings.experimentalMoonrakerSupport;\n const prusaLinkEnabled = serverSettings.experimentalPrusaLinkSupport;\n const bambuEnabled = serverSettings.experimentalBambuSupport;\n res.send({\n multiplePrinterServices: {\n available: true,\n version: 1,\n subFeatures: {\n types: [\n \"octoprint\",\n ...(moonrakerEnabled ? [\"klipper\"] : []),\n ...(prusaLinkEnabled ? [\"prusaLink\"] : []),\n ...(bambuEnabled ? [\"bambu\"] : []),\n ],\n },\n },\n });\n }\n\n @GET()\n @route(\"/version\")\n @before([authenticate(), permission(PERMS.ServerInfo.Get)])\n async getVersion(req: Request, res: Response) {\n const updateState = this.serverReleaseService.getState();\n const monsterPiVersion = this.monsterPiService.getMonsterPiVersionSafe();\n\n res.json({\n version: this.serverVersion,\n isNode: isNode(),\n os: process.env.OS,\n monsterPi: monsterPiVersion,\n update: {\n synced: updateState.synced,\n updateAvailable: updateState.updateAvailable,\n airGapped: updateState.airGapped,\n },\n });\n }\n\n @GET()\n @route(\"/test\")\n async test(req: Request, res: Response) {\n res.send({\n message: \"Test successful. Please load the Vue app.\",\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAWO,IAAA,yBAAA,MAAM,uBAAuB;CAClC,YACE,eACA,eACA,sBACA,kBACA;AAJiB,OAAA,gBAAA;AACA,OAAA,gBAAA;AACA,OAAA,uBAAA;AACA,OAAA,mBAAA;;CAGnB,MAGM,QAAQ,KAAc,KAAe;AACzC,OAAK,cAAc,aAAa;AAEhC,MAAI,CAAE,MAAM,KAAK,cAAc,kBAAkB,CAC/C,QAAO,IAAI,KAAK;GACd,SAAS;GACT,SAAS;GACT,aAAa;GACd,CAAC;AAGJ,SAAO,IAAI,KAAK;GACd,SAAS;GACT,SAAS;GACT,aAAa;GACd,CAAC;;CAGJ,YAGY,KAAc,KAAe;EACvC,MAAM,iBAAiB,KAAK,cAAc,mBAAmB;EAC7D,MAAM,mBAAmB,eAAe;EACxC,MAAM,mBAAmB,eAAe;EACxC,MAAM,eAAe,eAAe;AACpC,MAAI,KAAK,EACP,yBAAyB;GACvB,WAAW;GACX,SAAS;GACT,aAAa,EACX,OAAO;IACL;IACA,GAAI,mBAAmB,CAAC,UAAU,GAAG,EAAE;IACvC,GAAI,mBAAmB,CAAC,YAAY,GAAG,EAAE;IACzC,GAAI,eAAe,CAAC,QAAQ,GAAG,EAAE;IAClC,EACF;GACF,EACF,CAAC;;CAGJ,MAGM,WAAW,KAAc,KAAe;EAC5C,MAAM,cAAc,KAAK,qBAAqB,UAAU;EACxD,MAAM,mBAAmB,KAAK,iBAAiB,yBAAyB;AAExE,MAAI,KAAK;GACP,SAAS,KAAK;GACd,QAAQ,QAAQ;GAChB,IAAI,QAAQ,IAAI;GAChB,WAAW;GACX,QAAQ;IACN,QAAQ,YAAY;IACpB,iBAAiB,YAAY;IAC7B,WAAW,YAAY;IACxB;GACF,CAAC;;CAGJ,MAEM,KAAK,KAAc,KAAe;AACtC,MAAI,KAAK,EACP,SAAS,6CACV,CAAC;;;;CAtEH,KAAK;CACL,MAAM,IAAI;CACV,OAAO,CAAC,cAAc,EAAE,WAAW,MAAM,WAAW,IAAI,CAAC,CAAC;;;;;;CAmB1D,KAAK;CACL,MAAM,YAAY;CAClB,OAAO,CAAC,cAAc,CAAC,CAAC;;;;;;CAsBxB,KAAK;CACL,MAAM,WAAW;CACjB,OAAO,CAAC,cAAc,EAAE,WAAW,MAAM,WAAW,IAAI,CAAC,CAAC;;;;;;CAkB1D,KAAK;CACL,MAAM,QAAQ;;;;;qCA3EhB,MAAM,aAAa,SAAS,EAAA,mBAAA,qBAAA"}
1
+ {"version":3,"file":"server-public.controller.js","names":[],"sources":["../../src/controllers/server-public.controller.ts"],"sourcesContent":["import { before, GET, route } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport { isNode } from \"@/utils/env.utils\";\nimport { authenticate, permission } from \"@/middleware/authenticate\";\nimport { PERMS } from \"@/constants/authorization.constants\";\nimport { SettingsStore } from \"@/state/settings.store\";\nimport { ServerReleaseService } from \"@/services/core/server-release.service\";\nimport { MonsterPiService } from \"@/services/core/monsterpi.service\";\nimport type { Request, Response } from \"express\";\n\n@route(AppConstants.apiRoute)\nexport class ServerPublicController {\n constructor(\n private readonly settingsStore: SettingsStore,\n private readonly serverVersion: string,\n private readonly serverReleaseService: ServerReleaseService,\n private readonly monsterPiService: MonsterPiService,\n ) {}\n\n @GET()\n @route(\"/\")\n @before([authenticate(), permission(PERMS.ServerInfo.Get)])\n async welcome(req: Request, res: Response) {\n this.settingsStore.getSettings();\n\n if (!(await this.settingsStore.getLoginRequired())) {\n return res.send({\n message: \"Login disabled. Please load the Vue app.\",\n apiDocs: \"http://localhost:4000/api-docs/\",\n swaggerJson: \"http://localhost:4000/api-docs/swagger.json\",\n });\n }\n\n return res.send({\n message: \"Login required. Please load the Vue app.\",\n apiDocs: \"http://localhost:4000/api-docs/\",\n swaggerJson: \"http://localhost:4000/api-docs/swagger.json\",\n });\n }\n\n @GET()\n @route(\"/features\")\n @before([authenticate()])\n getFeatures(req: Request, res: Response) {\n const serverSettings = this.settingsStore.getServerSettings();\n const moonrakerEnabled = serverSettings.experimentalMoonrakerSupport;\n const prusaLinkEnabled = serverSettings.experimentalPrusaLinkSupport;\n const bambuEnabled = serverSettings.experimentalBambuSupport;\n res.send({\n multiplePrinterServices: {\n available: true,\n version: 1,\n subFeatures: {\n types: [\n \"octoprint\",\n ...(moonrakerEnabled ? [\"klipper\"] : []),\n ...(prusaLinkEnabled ? [\"prusaLink\"] : []),\n ...(bambuEnabled ? [\"bambu\"] : []),\n ],\n },\n },\n });\n }\n\n @GET()\n @route(\"/version\")\n @before([authenticate(), permission(PERMS.ServerInfo.Get)])\n async getVersion(req: Request, res: Response) {\n const updateState = this.serverReleaseService.getState();\n const monsterPiVersion = this.monsterPiService.getMonsterPiVersionSafe();\n\n res.json({\n version: this.serverVersion,\n isNode: isNode(),\n os: process.env.OS,\n monsterPi: monsterPiVersion,\n update: {\n synced: updateState.synced,\n updateAvailable: updateState.updateAvailable,\n airGapped: updateState.airGapped,\n },\n });\n }\n\n @GET()\n @route(\"/test\")\n async test(req: Request, res: Response) {\n res.send({\n message: \"Test successful. Please load the Vue app.\",\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAWO,IAAA,yBAAA,MAAM,uBAAuB;CAClC,YACE,eACA,eACA,sBACA,kBACA;EAJiB,KAAA,gBAAA;EACA,KAAA,gBAAA;EACA,KAAA,uBAAA;EACA,KAAA,mBAAA;;CAGnB,MAGM,QAAQ,KAAc,KAAe;EACzC,KAAK,cAAc,aAAa;EAEhC,IAAI,CAAE,MAAM,KAAK,cAAc,kBAAkB,EAC/C,OAAO,IAAI,KAAK;GACd,SAAS;GACT,SAAS;GACT,aAAa;GACd,CAAC;EAGJ,OAAO,IAAI,KAAK;GACd,SAAS;GACT,SAAS;GACT,aAAa;GACd,CAAC;;CAGJ,YAGY,KAAc,KAAe;EACvC,MAAM,iBAAiB,KAAK,cAAc,mBAAmB;EAC7D,MAAM,mBAAmB,eAAe;EACxC,MAAM,mBAAmB,eAAe;EACxC,MAAM,eAAe,eAAe;EACpC,IAAI,KAAK,EACP,yBAAyB;GACvB,WAAW;GACX,SAAS;GACT,aAAa,EACX,OAAO;IACL;IACA,GAAI,mBAAmB,CAAC,UAAU,GAAG,EAAE;IACvC,GAAI,mBAAmB,CAAC,YAAY,GAAG,EAAE;IACzC,GAAI,eAAe,CAAC,QAAQ,GAAG,EAAE;IAClC,EACF;GACF,EACF,CAAC;;CAGJ,MAGM,WAAW,KAAc,KAAe;EAC5C,MAAM,cAAc,KAAK,qBAAqB,UAAU;EACxD,MAAM,mBAAmB,KAAK,iBAAiB,yBAAyB;EAExE,IAAI,KAAK;GACP,SAAS,KAAK;GACd,QAAQ,QAAQ;GAChB,IAAI,QAAQ,IAAI;GAChB,WAAW;GACX,QAAQ;IACN,QAAQ,YAAY;IACpB,iBAAiB,YAAY;IAC7B,WAAW,YAAY;IACxB;GACF,CAAC;;CAGJ,MAEM,KAAK,KAAc,KAAe;EACtC,IAAI,KAAK,EACP,SAAS,6CACV,CAAC;;;;CAtEH,KAAK;CACL,MAAM,IAAI;CACV,OAAO,CAAC,cAAc,EAAE,WAAW,MAAM,WAAW,IAAI,CAAC,CAAC;;;;;;CAmB1D,KAAK;CACL,MAAM,YAAY;CAClB,OAAO,CAAC,cAAc,CAAC,CAAC;;;;;;CAsBxB,KAAK;CACL,MAAM,WAAW;CACjB,OAAO,CAAC,cAAc,EAAE,WAAW,MAAM,WAAW,IAAI,CAAC,CAAC;;;;;;CAkB1D,KAAK;CACL,MAAM,QAAQ;;;;;qCA3EhB,MAAM,aAAa,SAAS,EAAA,mBAAA,qBAAA"}
@@ -1,6 +1,6 @@
1
1
  import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
3
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
2
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
3
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
4
4
  import "../services/printer-api.interface.js";
5
5
  import { validateInput } from "../handlers/validators.js";
6
6
  import { AppConstants } from "../server.constants.js";
@@ -1 +1 @@
1
- {"version":3,"file":"settings.controller.js","names":[],"sources":["../../src/controllers/settings.controller.ts"],"sourcesContent":["import { DELETE, GET, PATCH, POST, PUT, route, before } from \"awilix-express\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport { AppConstants } from \"@/server.constants\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { validateInput } from \"@/handlers/validators\";\nimport {\n credentialCoreSettingUpdateSchema,\n frontendSettingsUpdateSchema,\n moonrakerSupportSchema,\n prusaLinkSupportSchema,\n sentryDiagnosticsEnabledSchema,\n timeoutSettingsUpdateSchema,\n bambuSupportSchema,\n} from \"@/services/validators/settings-service.validation\";\nimport { SettingsStore } from \"@/state/settings.store\";\nimport type { Request, Response } from \"express\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { demoUserNotAllowed } from \"@/middleware/demo.middleware\";\nimport { PrinterCache } from \"@/state/printer.cache\";\nimport { BambuType, PrusaLinkType, MoonrakerType } from \"@/services/printer-api.interface\";\nimport type { IPrinterService } from \"@/services/interfaces/printer.service.interface\";\nimport { PrinterThumbnailCache } from \"@/state/printer-thumbnail.cache\";\nimport { loginRequiredSchema, registrationEnabledSchema } from \"@/controllers/validation/setting.validation\";\n\n@route(AppConstants.apiRoute + \"/settings\")\n@before([authenticate()])\nexport class SettingsController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly serverVersion: string,\n private readonly printerCache: PrinterCache,\n private readonly printerService: IPrinterService,\n private readonly settingsStore: SettingsStore,\n private readonly printerThumbnailCache: PrinterThumbnailCache,\n ) {\n this.logger = loggerFactory(SettingsController.name);\n }\n\n @GET()\n @route(\"/\")\n async getSettings(req: Request, res: Response) {\n let connection;\n try {\n connection = {\n clientIp: req.socket?.remoteAddress,\n version: this.serverVersion,\n };\n } catch (e) {\n this.logger.warn(\"Could not fetch server IP address\");\n }\n const settings = this.settingsStore.getSettings();\n res.send({ ...settings, connection });\n }\n\n @GET()\n @route(\"/sensitive\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async getSettingsSensitive(req: Request, res: Response) {\n const settings = this.settingsStore.getSettingsSensitive();\n res.send(settings);\n }\n\n @PATCH()\n @route(\"/sentry-diagnostics\")\n @before([demoUserNotAllowed])\n async updateSentryDiagnosticsEnabled(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, sentryDiagnosticsEnabledSchema);\n const result = this.settingsStore.setSentryDiagnosticsEnabled(enabled);\n res.send(result);\n }\n\n @PUT()\n @route(\"/experimental-moonraker-support\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateMoonrakerSupport(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, moonrakerSupportSchema);\n const result = await this.settingsStore.setExperimentalMoonrakerSupport(enabled);\n\n if (!enabled) {\n const printers = await this.printerCache.listCachedPrinters(false);\n const klipperPrinters = printers.filter((p) => p.printerType === MoonrakerType);\n for (const printer of klipperPrinters) {\n await this.printerService.updateEnabled(printer.id, false);\n }\n }\n res.send(result);\n }\n\n @PUT()\n @route(\"/experimental-prusa-link-support\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updatePrusaLinkSupport(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, prusaLinkSupportSchema);\n const result = await this.settingsStore.setExperimentalPrusaLinkSupport(enabled);\n\n if (!enabled) {\n const printers = await this.printerCache.listCachedPrinters(false);\n const prusaLinkPrinters = printers.filter((p) => p.printerType === PrusaLinkType);\n for (const printer of prusaLinkPrinters) {\n await this.printerService.updateEnabled(printer.id, false);\n }\n }\n res.send(result);\n }\n\n @PUT()\n @route(\"/experimental-bambu-support\")\n async updateBambuSupport(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, bambuSupportSchema);\n const result = await this.settingsStore.setExperimentalBambuSupport(enabled);\n\n if (!enabled) {\n const printers = await this.printerCache.listCachedPrinters(false);\n const bambuPrinters = printers.filter((p) => p.printerType === BambuType);\n for (const printer of bambuPrinters) {\n await this.printerService.updateEnabled(printer.id, false);\n }\n }\n res.send(result);\n }\n\n @PUT()\n @route(\"/frontend\")\n @before([authorizeRoles([ROLES.ADMIN])])\n async updateFrontendSettings(req: Request, res: Response) {\n const validatedInput = await validateInput(req.body, frontendSettingsUpdateSchema);\n const result = await this.settingsStore.updateFrontendSettings(validatedInput);\n res.send(result);\n }\n\n @PUT()\n @route(\"/login-required\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateLoginRequiredSettings(req: Request, res: Response) {\n const { loginRequired } = await validateInput(req.body, loginRequiredSchema);\n const result = await this.settingsStore.setLoginRequired(loginRequired);\n res.send(result);\n }\n\n @PUT()\n @route(\"/registration-enabled\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateRegistrationEnabledSettings(req: Request, res: Response) {\n const { registrationEnabled } = await validateInput(req.body, registrationEnabledSchema);\n const result = await this.settingsStore.setRegistrationEnabled(registrationEnabled);\n res.send(result);\n }\n\n @PUT()\n @route(\"/credential\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateCredentialSettings(req: Request, res: Response) {\n const validatedInput = await validateInput(req.body, credentialCoreSettingUpdateSchema);\n await this.settingsStore.updateCoreCredentialSettings(validatedInput);\n res.send();\n }\n\n @PUT()\n @route(\"/timeout\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateTimeoutSettings(req: Request, res: Response) {\n const validatedInput = await validateInput(req.body, timeoutSettingsUpdateSchema);\n const result = await this.settingsStore.updateTimeoutSettings(validatedInput);\n res.send(result);\n }\n\n @GET()\n @route(\"/slicer-api-key\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async getSlicerApiKey(req: Request, res: Response) {\n const apiKey = this.settingsStore.getSlicerApiKey();\n res.send({ slicerApiKey: apiKey });\n }\n\n @POST()\n @route(\"/slicer-api-key/regenerate\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async regenerateSlicerApiKey(req: Request, res: Response) {\n const newApiKey = await this.settingsStore.generateSlicerApiKey();\n this.logger.log(\"Slicer API key regenerated\");\n res.send({ slicerApiKey: newApiKey });\n }\n\n @DELETE()\n @route(\"/slicer-api-key\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async deleteSlicerApiKey(req: Request, res: Response) {\n await this.settingsStore.deleteSlicerApiKey();\n this.logger.log(\"Slicer API key deleted\");\n res.send({ slicerApiKey: null });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"settings.controller.js","names":[],"sources":["../../src/controllers/settings.controller.ts"],"sourcesContent":["import { DELETE, GET, PATCH, POST, PUT, route, before } from \"awilix-express\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport { AppConstants } from \"@/server.constants\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { validateInput } from \"@/handlers/validators\";\nimport {\n credentialCoreSettingUpdateSchema,\n frontendSettingsUpdateSchema,\n moonrakerSupportSchema,\n prusaLinkSupportSchema,\n sentryDiagnosticsEnabledSchema,\n timeoutSettingsUpdateSchema,\n bambuSupportSchema,\n} from \"@/services/validators/settings-service.validation\";\nimport { SettingsStore } from \"@/state/settings.store\";\nimport type { Request, Response } from \"express\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { demoUserNotAllowed } from \"@/middleware/demo.middleware\";\nimport { PrinterCache } from \"@/state/printer.cache\";\nimport { BambuType, PrusaLinkType, MoonrakerType } from \"@/services/printer-api.interface\";\nimport type { IPrinterService } from \"@/services/interfaces/printer.service.interface\";\nimport { PrinterThumbnailCache } from \"@/state/printer-thumbnail.cache\";\nimport { loginRequiredSchema, registrationEnabledSchema } from \"@/controllers/validation/setting.validation\";\n\n@route(AppConstants.apiRoute + \"/settings\")\n@before([authenticate()])\nexport class SettingsController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly serverVersion: string,\n private readonly printerCache: PrinterCache,\n private readonly printerService: IPrinterService,\n private readonly settingsStore: SettingsStore,\n private readonly printerThumbnailCache: PrinterThumbnailCache,\n ) {\n this.logger = loggerFactory(SettingsController.name);\n }\n\n @GET()\n @route(\"/\")\n async getSettings(req: Request, res: Response) {\n let connection;\n try {\n connection = {\n clientIp: req.socket?.remoteAddress,\n version: this.serverVersion,\n };\n } catch (e) {\n this.logger.warn(\"Could not fetch server IP address\");\n }\n const settings = this.settingsStore.getSettings();\n res.send({ ...settings, connection });\n }\n\n @GET()\n @route(\"/sensitive\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async getSettingsSensitive(req: Request, res: Response) {\n const settings = this.settingsStore.getSettingsSensitive();\n res.send(settings);\n }\n\n @PATCH()\n @route(\"/sentry-diagnostics\")\n @before([demoUserNotAllowed])\n async updateSentryDiagnosticsEnabled(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, sentryDiagnosticsEnabledSchema);\n const result = this.settingsStore.setSentryDiagnosticsEnabled(enabled);\n res.send(result);\n }\n\n @PUT()\n @route(\"/experimental-moonraker-support\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateMoonrakerSupport(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, moonrakerSupportSchema);\n const result = await this.settingsStore.setExperimentalMoonrakerSupport(enabled);\n\n if (!enabled) {\n const printers = await this.printerCache.listCachedPrinters(false);\n const klipperPrinters = printers.filter((p) => p.printerType === MoonrakerType);\n for (const printer of klipperPrinters) {\n await this.printerService.updateEnabled(printer.id, false);\n }\n }\n res.send(result);\n }\n\n @PUT()\n @route(\"/experimental-prusa-link-support\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updatePrusaLinkSupport(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, prusaLinkSupportSchema);\n const result = await this.settingsStore.setExperimentalPrusaLinkSupport(enabled);\n\n if (!enabled) {\n const printers = await this.printerCache.listCachedPrinters(false);\n const prusaLinkPrinters = printers.filter((p) => p.printerType === PrusaLinkType);\n for (const printer of prusaLinkPrinters) {\n await this.printerService.updateEnabled(printer.id, false);\n }\n }\n res.send(result);\n }\n\n @PUT()\n @route(\"/experimental-bambu-support\")\n async updateBambuSupport(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, bambuSupportSchema);\n const result = await this.settingsStore.setExperimentalBambuSupport(enabled);\n\n if (!enabled) {\n const printers = await this.printerCache.listCachedPrinters(false);\n const bambuPrinters = printers.filter((p) => p.printerType === BambuType);\n for (const printer of bambuPrinters) {\n await this.printerService.updateEnabled(printer.id, false);\n }\n }\n res.send(result);\n }\n\n @PUT()\n @route(\"/frontend\")\n @before([authorizeRoles([ROLES.ADMIN])])\n async updateFrontendSettings(req: Request, res: Response) {\n const validatedInput = await validateInput(req.body, frontendSettingsUpdateSchema);\n const result = await this.settingsStore.updateFrontendSettings(validatedInput);\n res.send(result);\n }\n\n @PUT()\n @route(\"/login-required\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateLoginRequiredSettings(req: Request, res: Response) {\n const { loginRequired } = await validateInput(req.body, loginRequiredSchema);\n const result = await this.settingsStore.setLoginRequired(loginRequired);\n res.send(result);\n }\n\n @PUT()\n @route(\"/registration-enabled\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateRegistrationEnabledSettings(req: Request, res: Response) {\n const { registrationEnabled } = await validateInput(req.body, registrationEnabledSchema);\n const result = await this.settingsStore.setRegistrationEnabled(registrationEnabled);\n res.send(result);\n }\n\n @PUT()\n @route(\"/credential\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateCredentialSettings(req: Request, res: Response) {\n const validatedInput = await validateInput(req.body, credentialCoreSettingUpdateSchema);\n await this.settingsStore.updateCoreCredentialSettings(validatedInput);\n res.send();\n }\n\n @PUT()\n @route(\"/timeout\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateTimeoutSettings(req: Request, res: Response) {\n const validatedInput = await validateInput(req.body, timeoutSettingsUpdateSchema);\n const result = await this.settingsStore.updateTimeoutSettings(validatedInput);\n res.send(result);\n }\n\n @GET()\n @route(\"/slicer-api-key\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async getSlicerApiKey(req: Request, res: Response) {\n const apiKey = this.settingsStore.getSlicerApiKey();\n res.send({ slicerApiKey: apiKey });\n }\n\n @POST()\n @route(\"/slicer-api-key/regenerate\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async regenerateSlicerApiKey(req: Request, res: Response) {\n const newApiKey = await this.settingsStore.generateSlicerApiKey();\n this.logger.log(\"Slicer API key regenerated\");\n res.send({ slicerApiKey: newApiKey });\n }\n\n @DELETE()\n @route(\"/slicer-api-key\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async deleteSlicerApiKey(req: Request, res: Response) {\n await this.settingsStore.deleteSlicerApiKey();\n this.logger.log(\"Slicer API key deleted\");\n res.send({ slicerApiKey: null });\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
3
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
2
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
3
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
4
4
  import { AppConstants } from "../server.constants.js";
5
5
  import { MulterService } from "../services/core/multer.service.js";
6
6
  import { FileStorageService } from "../services/file-storage.service.js";
@@ -1 +1 @@
1
- {"version":3,"file":"slicer-compat.controller.js","names":[],"sources":["../../src/controllers/slicer-compat.controller.ts"],"sourcesContent":["import { GET, POST, route, before } from \"awilix-express\";\nimport type { Request, Response } from \"express\";\nimport { FileStorageService } from \"@/services/file-storage.service\";\nimport { FileAnalysisService } from \"@/services/file-analysis.service\";\nimport { MulterService } from \"@/services/core/multer.service\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { AppConstants } from \"@/server.constants\";\nimport { slicerApiKeyAuth } from \"@/middleware/slicer-api-key.middleware\";\n\n/**\n * OctoPrint-compatible API for PrusaSlicer and other slicer integration\n * Implements minimal OctoPrint API surface for file upload\n *\n * File operations require authentication\n */\n@route(\"/api\")\n@before([slicerApiKeyAuth()])\nexport class SlicerCompatController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly fileStorageService: FileStorageService,\n private readonly fileAnalysisService: FileAnalysisService,\n private readonly multerService: MulterService,\n ) {\n this.logger = loggerFactory(SlicerCompatController.name);\n }\n\n /**\n * OctoPrint version endpoint\n * GET /api/version\n */\n @GET()\n @route(\"/version\")\n async getVersion(req: Request, res: Response) {\n res.send({\n api: \"0.1\",\n server: \"1.9.0\",\n text: \"OctoPrint 1.9.3\",\n });\n }\n\n /**\n * OctoPrint files endpoint - Upload file\n * POST /api/files/local\n *\n * This endpoint mimics OctoPrint's file upload API for slicer compatibility\n * PrusaSlicer uses: POST /api/files/local with multipart form data\n */\n @POST()\n @route(\"/files/local\")\n async uploadFile(req: Request, res: Response) {\n let files: Express.Multer.File[] | undefined;\n\n try {\n // Accept all common 3D printer file formats\n const acceptedExtensions = [\n ...AppConstants.defaultAcceptedGcodeExtensions,\n ...AppConstants.defaultAcceptedBambuExtensions,\n ];\n\n // Load uploaded file using multer\n files = await this.multerService.multerLoadFileAsync(req, res, acceptedExtensions, true);\n\n if (!files?.length) {\n res.status(400).send({\n error: \"No file uploaded\",\n });\n return;\n }\n\n const file = files[0];\n\n await this.fileStorageService.validateUniqueFilename(file.originalname);\n\n const fileHash = await this.fileStorageService.calculateFileHash(file.path);\n const fileStorageId = await this.fileStorageService.saveFile(file, fileHash);\n const filePath = this.fileStorageService.getFilePath(fileStorageId);\n\n let metadata: any = {};\n let thumbnails: any[] = [];\n\n try {\n const analysisResult = await this.fileAnalysisService.analyzeFile(filePath);\n metadata = analysisResult.metadata;\n thumbnails = analysisResult.thumbnails || [];\n\n const thumbnailMetadata =\n thumbnails.length > 0 ? await this.fileStorageService.saveThumbnails(fileStorageId, thumbnails) : [];\n\n await this.fileStorageService.saveMetadata(\n fileStorageId,\n metadata,\n fileHash,\n file.originalname,\n thumbnailMetadata,\n );\n } catch (analysisError) {\n this.logger.error(`Failed to analyze uploaded file: ${analysisError}`);\n }\n\n try {\n this.multerService.clearUploadedFile(file);\n } catch (e) {\n this.logger.error(`Could not remove uploaded file from temporary storage`);\n }\n\n // Return OctoPrint-compatible response\n res.status(201).send({\n files: {\n local: {\n name: file.originalname,\n origin: \"local\",\n refs: {\n resource: `/api/files/local/${fileStorageId}`,\n download: `/api/files/local/${fileStorageId}`,\n },\n },\n },\n done: true,\n // Additional FDM Monster metadata\n _fdmMonster: {\n fileStorageId,\n fileHash,\n analyzed: Object.keys(metadata).length > 0,\n thumbnailCount: thumbnails.length,\n printTime: metadata.gcodePrintTimeSeconds,\n filament: metadata.filamentUsedGrams,\n },\n });\n\n this.logger.log(`File uploaded to printer: ${file.originalname} -> ${fileStorageId}`);\n } catch (error) {\n // Clean up temp file if it exists\n if (files?.[0]?.path) {\n try {\n this.multerService.clearUploadedFile(files[0]);\n } catch (e) {\n this.logger.error(`Could not remove uploaded file from temporary storage`);\n }\n }\n\n // Re-throw to let exception filter handle it properly\n throw error;\n }\n }\n\n /**\n * Files list endpoint\n * GET /api/files\n */\n @GET()\n @route(\"/files\")\n async listFiles(req: Request, res: Response) {\n try {\n const files = await this.fileStorageService.listAllFiles();\n\n // Convert to known format\n const knownFiles = files.map((file) => ({\n name: file.metadata?._originalFileName || file.fileName,\n path: file.fileStorageId,\n type: \"machinecode\",\n typePath: [\"machinecode\", file.fileFormat],\n origin: \"local\",\n refs: {\n resource: `/api/files/local/${file.fileStorageId}`,\n download: `/api/files/local/${file.fileStorageId}`,\n },\n gcodeAnalysis: file.metadata\n ? {\n estimatedPrintTime: file.metadata.gcodePrintTimeSeconds,\n filament: {\n tool0: {\n length: file.metadata.filamentUsedMm,\n volume: file.metadata.filamentUsedCm3,\n },\n },\n }\n : undefined,\n date: Math.floor(file.createdAt.getTime() / 1000),\n size: file.fileSize,\n }));\n\n res.send({\n files: knownFiles,\n free: 0, // Not applicable\n total: 0, // Not applicable\n });\n } catch (error) {\n this.logger.error(`Failed to list files via printer API: ${error}`);\n throw error;\n }\n }\n\n /**\n * Server endpoint (for compatibility checks)\n * GET /api/server\n */\n @GET()\n @route(\"/server\")\n async getServer(req: Request, res: Response) {\n res.send({\n version: \"1.9.0\",\n safemode: null,\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"slicer-compat.controller.js","names":[],"sources":["../../src/controllers/slicer-compat.controller.ts"],"sourcesContent":["import { GET, POST, route, before } from \"awilix-express\";\nimport type { Request, Response } from \"express\";\nimport { FileStorageService } from \"@/services/file-storage.service\";\nimport { FileAnalysisService } from \"@/services/file-analysis.service\";\nimport { MulterService } from \"@/services/core/multer.service\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { AppConstants } from \"@/server.constants\";\nimport { slicerApiKeyAuth } from \"@/middleware/slicer-api-key.middleware\";\n\n/**\n * OctoPrint-compatible API for PrusaSlicer and other slicer integration\n * Implements minimal OctoPrint API surface for file upload\n *\n * File operations require authentication\n */\n@route(\"/api\")\n@before([slicerApiKeyAuth()])\nexport class SlicerCompatController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly fileStorageService: FileStorageService,\n private readonly fileAnalysisService: FileAnalysisService,\n private readonly multerService: MulterService,\n ) {\n this.logger = loggerFactory(SlicerCompatController.name);\n }\n\n /**\n * OctoPrint version endpoint\n * GET /api/version\n */\n @GET()\n @route(\"/version\")\n async getVersion(req: Request, res: Response) {\n res.send({\n api: \"0.1\",\n server: \"1.9.0\",\n text: \"OctoPrint 1.9.3\",\n });\n }\n\n /**\n * OctoPrint files endpoint - Upload file\n * POST /api/files/local\n *\n * This endpoint mimics OctoPrint's file upload API for slicer compatibility\n * PrusaSlicer uses: POST /api/files/local with multipart form data\n */\n @POST()\n @route(\"/files/local\")\n async uploadFile(req: Request, res: Response) {\n let files: Express.Multer.File[] | undefined;\n\n try {\n // Accept all common 3D printer file formats\n const acceptedExtensions = [\n ...AppConstants.defaultAcceptedGcodeExtensions,\n ...AppConstants.defaultAcceptedBambuExtensions,\n ];\n\n // Load uploaded file using multer\n files = await this.multerService.multerLoadFileAsync(req, res, acceptedExtensions, true);\n\n if (!files?.length) {\n res.status(400).send({\n error: \"No file uploaded\",\n });\n return;\n }\n\n const file = files[0];\n\n await this.fileStorageService.validateUniqueFilename(file.originalname);\n\n const fileHash = await this.fileStorageService.calculateFileHash(file.path);\n const fileStorageId = await this.fileStorageService.saveFile(file, fileHash);\n const filePath = this.fileStorageService.getFilePath(fileStorageId);\n\n let metadata: any = {};\n let thumbnails: any[] = [];\n\n try {\n const analysisResult = await this.fileAnalysisService.analyzeFile(filePath);\n metadata = analysisResult.metadata;\n thumbnails = analysisResult.thumbnails || [];\n\n const thumbnailMetadata =\n thumbnails.length > 0 ? await this.fileStorageService.saveThumbnails(fileStorageId, thumbnails) : [];\n\n await this.fileStorageService.saveMetadata(\n fileStorageId,\n metadata,\n fileHash,\n file.originalname,\n thumbnailMetadata,\n );\n } catch (analysisError) {\n this.logger.error(`Failed to analyze uploaded file: ${analysisError}`);\n }\n\n try {\n this.multerService.clearUploadedFile(file);\n } catch (e) {\n this.logger.error(`Could not remove uploaded file from temporary storage`);\n }\n\n // Return OctoPrint-compatible response\n res.status(201).send({\n files: {\n local: {\n name: file.originalname,\n origin: \"local\",\n refs: {\n resource: `/api/files/local/${fileStorageId}`,\n download: `/api/files/local/${fileStorageId}`,\n },\n },\n },\n done: true,\n // Additional FDM Monster metadata\n _fdmMonster: {\n fileStorageId,\n fileHash,\n analyzed: Object.keys(metadata).length > 0,\n thumbnailCount: thumbnails.length,\n printTime: metadata.gcodePrintTimeSeconds,\n filament: metadata.filamentUsedGrams,\n },\n });\n\n this.logger.log(`File uploaded to printer: ${file.originalname} -> ${fileStorageId}`);\n } catch (error) {\n // Clean up temp file if it exists\n if (files?.[0]?.path) {\n try {\n this.multerService.clearUploadedFile(files[0]);\n } catch (e) {\n this.logger.error(`Could not remove uploaded file from temporary storage`);\n }\n }\n\n // Re-throw to let exception filter handle it properly\n throw error;\n }\n }\n\n /**\n * Files list endpoint\n * GET /api/files\n */\n @GET()\n @route(\"/files\")\n async listFiles(req: Request, res: Response) {\n try {\n const files = await this.fileStorageService.listAllFiles();\n\n // Convert to known format\n const knownFiles = files.map((file) => ({\n name: file.metadata?._originalFileName || file.fileName,\n path: file.fileStorageId,\n type: \"machinecode\",\n typePath: [\"machinecode\", file.fileFormat],\n origin: \"local\",\n refs: {\n resource: `/api/files/local/${file.fileStorageId}`,\n download: `/api/files/local/${file.fileStorageId}`,\n },\n gcodeAnalysis: file.metadata\n ? {\n estimatedPrintTime: file.metadata.gcodePrintTimeSeconds,\n filament: {\n tool0: {\n length: file.metadata.filamentUsedMm,\n volume: file.metadata.filamentUsedCm3,\n },\n },\n }\n : undefined,\n date: Math.floor(file.createdAt.getTime() / 1000),\n size: file.fileSize,\n }));\n\n res.send({\n files: knownFiles,\n free: 0, // Not applicable\n total: 0, // Not applicable\n });\n } catch (error) {\n this.logger.error(`Failed to list files via printer API: ${error}`);\n throw error;\n }\n }\n\n /**\n * Server endpoint (for compatibility checks)\n * GET /api/server\n */\n @GET()\n @route(\"/server\")\n async getServer(req: Request, res: Response) {\n res.send({\n version: \"1.9.0\",\n safemode: null,\n });\n }\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
3
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
2
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
3
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
4
4
  import { BadRequestException, ForbiddenError } from "../exceptions/runtime.exceptions.js";
5
5
  import { validateInput, validateMiddleware } from "../handlers/validators.js";
6
6
  import { AppConstants } from "../server.constants.js";
@@ -1 +1 @@
1
- {"version":3,"file":"user.controller.js","names":[],"sources":["../../src/controllers/user.controller.ts"],"sourcesContent":["import type { Request, Response } from \"express\";\nimport { AppConstants } from \"@/server.constants\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { validateInput, validateMiddleware } from \"@/handlers/validators\";\nimport { BadRequestException, ForbiddenError } from \"@/exceptions/runtime.exceptions\";\nimport type { IConfigService } from \"@/services/core/config.service\";\nimport type { IUserService } from \"@/services/interfaces/user-service.interface\";\nimport { demoUserNotAllowed } from \"@/middleware/demo.middleware\";\nimport type { IRoleService } from \"@/services/interfaces/role-service.interface\";\nimport type { IAuthService } from \"@/services/interfaces/auth.service.interface\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { errorSummary } from \"@/utils/error.utils\";\nimport { SettingsStore } from \"@/state/settings.store\";\nimport { before, DELETE, GET, POST, route } from \"awilix-express\";\nimport {\n changePasswordSchema,\n isRootUserSchema,\n isVerifiedSchema,\n registerUserWithRolesSchema,\n setUserRolesSchema,\n usernameSchema,\n} from \"@/controllers/validation/user-controller.validation\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\n\n@route(AppConstants.apiRoute + \"/user\")\n@before([authenticate()])\nexport class UserController {\n logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly userService: IUserService,\n private readonly configService: IConfigService,\n private readonly roleService: IRoleService,\n private readonly authService: IAuthService,\n private readonly settingsStore: SettingsStore,\n ) {\n this.logger = loggerFactory(UserController.name);\n }\n\n @GET()\n @route(\"/\")\n @before([authorizeRoles([ROLES.ADMIN])])\n async list(req: Request, res: Response) {\n const users = await this.userService.listUsers();\n res.send(users.map((u) => this.userService.toDto(u)));\n }\n\n @POST()\n @route(\"/\")\n @before([authorizeRoles([ROLES.ADMIN])])\n async create(req: Request, res: Response) {\n const { username, password, roles } = await validateMiddleware(req, registerUserWithRolesSchema);\n if (\n username.toLowerCase().includes(\"admin\") ||\n username.toLowerCase().includes(\"root\") ||\n username.toLowerCase() === \"demo\"\n ) {\n throw new BadRequestException(\"Username is not allowed\");\n }\n\n await this.userService.register({\n username,\n password,\n roles,\n needsPasswordChange: false,\n isDemoUser: false,\n isRootUser: false,\n // An admin needs to verify the user first\n isVerified: true,\n });\n res.send();\n }\n\n @GET()\n @route(\"/roles\")\n async listRoles(req: Request, res: Response) {\n const roleDtos = this.roleService.roles.map((r) => this.roleService.toDto(r));\n res.send(roleDtos);\n }\n\n @GET()\n @route(\"/profile\")\n async profile(req: Request, res: Response) {\n if (!req.user?.id) {\n res.send({});\n return;\n }\n\n const user = await this.userService.getUser(req.user?.id);\n res.send(this.userService.toDto(user));\n }\n\n @GET()\n @route(\"/:id\")\n @before([authorizeRoles([ROLES.ADMIN]), ParamId(\"id\")])\n async get(req: Request, res: Response) {\n const user = await this.userService.getUser(req.local.id);\n res.send(this.userService.toDto(user));\n }\n\n @DELETE()\n @route(\"/:id\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed, ParamId(\"id\")])\n async delete(req: Request, res: Response) {\n const deletedUserId = req.local.id;\n const ownUserId = req.user?.id;\n if (ownUserId == deletedUserId) {\n throw new ForbiddenError(\"Not allowed to delete own account\");\n }\n\n const isRootUser = await this.userService.isUserRootUser(deletedUserId);\n if (isRootUser) {\n throw new ForbiddenError(\"Not allowed to delete root user\");\n }\n\n if (this.configService.isDemoMode()) {\n const demoUserId = await this.userService.getDemoUserId();\n if (deletedUserId === demoUserId) {\n this.throwIfDemoMode();\n }\n }\n\n await this.userService.deleteUser(deletedUserId);\n\n try {\n await this.authService.logoutUserId(deletedUserId);\n } catch (e) {\n this.logger.error(errorSummary(e));\n }\n\n res.send();\n }\n\n @POST()\n @route(\"/:id/change-username\")\n @before([demoUserNotAllowed, ParamId(\"id\")])\n async changeUsername(req: Request, res: Response) {\n const changedUserId = req.local.id;\n\n if (req.user?.id != changedUserId && (await this.settingsStore.getLoginRequired())) {\n throw new ForbiddenError(\"Not allowed to change username of other users\");\n }\n\n const { username } = await validateInput(req.body, usernameSchema);\n await this.userService.updateUsernameById(changedUserId, username);\n res.send();\n }\n\n @POST()\n @route(\"/:id/change-password\")\n @before([demoUserNotAllowed, ParamId(\"id\")])\n async changePassword(req: Request, res: Response) {\n const changedUserId = req.local.id;\n\n if (req.user?.id != changedUserId && (await this.settingsStore.getLoginRequired())) {\n throw new ForbiddenError(\"Not allowed to change password of other users\");\n }\n\n const { oldPassword, newPassword } = await validateInput(req.body, changePasswordSchema);\n await this.userService.updatePasswordById(changedUserId, oldPassword, newPassword);\n res.send();\n }\n\n @POST()\n @route(\"/:id/set-user-roles\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed, ParamId(\"id\")])\n async setUserRoles(req: Request, res: Response) {\n const changedUserId = req.local.id;\n\n const ownUserId = req.user?.id;\n if (!ownUserId) {\n throw new ForbiddenError(\"Need to be logged in, in order to set user roles\");\n }\n\n const ownUser = await this.userService.getUser(ownUserId);\n const mappedUser = this.userService.toDto(ownUser);\n\n const ownUserRoles = mappedUser.roles;\n\n if (ownUserId == changedUserId && !ownUserRoles.includes(ROLES.ADMIN) && !mappedUser.isRootUser) {\n throw new ForbiddenError(\"Only an ADMIN or OWNER user is allowed to change its own roles\");\n }\n\n const { roles } = await validateInput(req.body, setUserRolesSchema);\n\n if (ownUserId == changedUserId && !roles.includes(ROLES.ADMIN)) {\n if (mappedUser.isRootUser) {\n throw new BadRequestException(\"It does not make sense to remove ADMIN role from an OWNER user.\");\n } else {\n throw new BadRequestException(\"An ADMIN user cannot remove its ADMIN role.\");\n }\n }\n\n await this.userService.setUserRoles(changedUserId, roles);\n res.send();\n }\n\n @POST()\n @route(\"/:id/set-verified\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed, ParamId(\"id\")])\n async setVerified(req: Request, res: Response) {\n const changedUserId = req.local.id;\n\n const ownUserId = req.user?.id;\n if (ownUserId == changedUserId) {\n throw new ForbiddenError(\"Not allowed to change own verified status\");\n }\n\n const isRootUser = await this.userService.isUserRootUser(changedUserId);\n if (isRootUser) {\n throw new ForbiddenError(\"Not allowed to change root user to unverified\");\n }\n\n const { isVerified } = await validateInput(req.body, isVerifiedSchema);\n await this.userService.setVerifiedById(changedUserId, isVerified);\n\n res.send();\n }\n\n @POST()\n @route(\"/:id/set-root-user\")\n @before([demoUserNotAllowed, ParamId(\"id\")])\n async setRootUser(req: Request, res: Response) {\n const changedUserId = req.local.id;\n\n const userId = req.user?.id;\n if (userId) {\n const isRootUser = await this.userService.isUserRootUser(userId);\n if (!isRootUser) {\n throw new ForbiddenError(\"Not allowed to change owner without being owner yourself\");\n }\n }\n const { isRootUser } = await validateInput(req.body, isRootUserSchema);\n await this.userService.setIsRootUserById(changedUserId, isRootUser);\n res.send();\n }\n\n throwIfDemoMode() {\n const isDemoMode = this.configService.isDemoMode();\n if (isDemoMode) {\n throw new ForbiddenError(\"Not allowed in demo mode\");\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"user.controller.js","names":[],"sources":["../../src/controllers/user.controller.ts"],"sourcesContent":["import type { Request, Response } from \"express\";\nimport { AppConstants } from \"@/server.constants\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { validateInput, validateMiddleware } from \"@/handlers/validators\";\nimport { BadRequestException, ForbiddenError } from \"@/exceptions/runtime.exceptions\";\nimport type { IConfigService } from \"@/services/core/config.service\";\nimport type { IUserService } from \"@/services/interfaces/user-service.interface\";\nimport { demoUserNotAllowed } from \"@/middleware/demo.middleware\";\nimport type { IRoleService } from \"@/services/interfaces/role-service.interface\";\nimport type { IAuthService } from \"@/services/interfaces/auth.service.interface\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { errorSummary } from \"@/utils/error.utils\";\nimport { SettingsStore } from \"@/state/settings.store\";\nimport { before, DELETE, GET, POST, route } from \"awilix-express\";\nimport {\n changePasswordSchema,\n isRootUserSchema,\n isVerifiedSchema,\n registerUserWithRolesSchema,\n setUserRolesSchema,\n usernameSchema,\n} from \"@/controllers/validation/user-controller.validation\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\n\n@route(AppConstants.apiRoute + \"/user\")\n@before([authenticate()])\nexport class UserController {\n logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly userService: IUserService,\n private readonly configService: IConfigService,\n private readonly roleService: IRoleService,\n private readonly authService: IAuthService,\n private readonly settingsStore: SettingsStore,\n ) {\n this.logger = loggerFactory(UserController.name);\n }\n\n @GET()\n @route(\"/\")\n @before([authorizeRoles([ROLES.ADMIN])])\n async list(req: Request, res: Response) {\n const users = await this.userService.listUsers();\n res.send(users.map((u) => this.userService.toDto(u)));\n }\n\n @POST()\n @route(\"/\")\n @before([authorizeRoles([ROLES.ADMIN])])\n async create(req: Request, res: Response) {\n const { username, password, roles } = await validateMiddleware(req, registerUserWithRolesSchema);\n if (\n username.toLowerCase().includes(\"admin\") ||\n username.toLowerCase().includes(\"root\") ||\n username.toLowerCase() === \"demo\"\n ) {\n throw new BadRequestException(\"Username is not allowed\");\n }\n\n await this.userService.register({\n username,\n password,\n roles,\n needsPasswordChange: false,\n isDemoUser: false,\n isRootUser: false,\n // An admin needs to verify the user first\n isVerified: true,\n });\n res.send();\n }\n\n @GET()\n @route(\"/roles\")\n async listRoles(req: Request, res: Response) {\n const roleDtos = this.roleService.roles.map((r) => this.roleService.toDto(r));\n res.send(roleDtos);\n }\n\n @GET()\n @route(\"/profile\")\n async profile(req: Request, res: Response) {\n if (!req.user?.id) {\n res.send({});\n return;\n }\n\n const user = await this.userService.getUser(req.user?.id);\n res.send(this.userService.toDto(user));\n }\n\n @GET()\n @route(\"/:id\")\n @before([authorizeRoles([ROLES.ADMIN]), ParamId(\"id\")])\n async get(req: Request, res: Response) {\n const user = await this.userService.getUser(req.local.id);\n res.send(this.userService.toDto(user));\n }\n\n @DELETE()\n @route(\"/:id\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed, ParamId(\"id\")])\n async delete(req: Request, res: Response) {\n const deletedUserId = req.local.id;\n const ownUserId = req.user?.id;\n if (ownUserId == deletedUserId) {\n throw new ForbiddenError(\"Not allowed to delete own account\");\n }\n\n const isRootUser = await this.userService.isUserRootUser(deletedUserId);\n if (isRootUser) {\n throw new ForbiddenError(\"Not allowed to delete root user\");\n }\n\n if (this.configService.isDemoMode()) {\n const demoUserId = await this.userService.getDemoUserId();\n if (deletedUserId === demoUserId) {\n this.throwIfDemoMode();\n }\n }\n\n await this.userService.deleteUser(deletedUserId);\n\n try {\n await this.authService.logoutUserId(deletedUserId);\n } catch (e) {\n this.logger.error(errorSummary(e));\n }\n\n res.send();\n }\n\n @POST()\n @route(\"/:id/change-username\")\n @before([demoUserNotAllowed, ParamId(\"id\")])\n async changeUsername(req: Request, res: Response) {\n const changedUserId = req.local.id;\n\n if (req.user?.id != changedUserId && (await this.settingsStore.getLoginRequired())) {\n throw new ForbiddenError(\"Not allowed to change username of other users\");\n }\n\n const { username } = await validateInput(req.body, usernameSchema);\n await this.userService.updateUsernameById(changedUserId, username);\n res.send();\n }\n\n @POST()\n @route(\"/:id/change-password\")\n @before([demoUserNotAllowed, ParamId(\"id\")])\n async changePassword(req: Request, res: Response) {\n const changedUserId = req.local.id;\n\n if (req.user?.id != changedUserId && (await this.settingsStore.getLoginRequired())) {\n throw new ForbiddenError(\"Not allowed to change password of other users\");\n }\n\n const { oldPassword, newPassword } = await validateInput(req.body, changePasswordSchema);\n await this.userService.updatePasswordById(changedUserId, oldPassword, newPassword);\n res.send();\n }\n\n @POST()\n @route(\"/:id/set-user-roles\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed, ParamId(\"id\")])\n async setUserRoles(req: Request, res: Response) {\n const changedUserId = req.local.id;\n\n const ownUserId = req.user?.id;\n if (!ownUserId) {\n throw new ForbiddenError(\"Need to be logged in, in order to set user roles\");\n }\n\n const ownUser = await this.userService.getUser(ownUserId);\n const mappedUser = this.userService.toDto(ownUser);\n\n const ownUserRoles = mappedUser.roles;\n\n if (ownUserId == changedUserId && !ownUserRoles.includes(ROLES.ADMIN) && !mappedUser.isRootUser) {\n throw new ForbiddenError(\"Only an ADMIN or OWNER user is allowed to change its own roles\");\n }\n\n const { roles } = await validateInput(req.body, setUserRolesSchema);\n\n if (ownUserId == changedUserId && !roles.includes(ROLES.ADMIN)) {\n if (mappedUser.isRootUser) {\n throw new BadRequestException(\"It does not make sense to remove ADMIN role from an OWNER user.\");\n } else {\n throw new BadRequestException(\"An ADMIN user cannot remove its ADMIN role.\");\n }\n }\n\n await this.userService.setUserRoles(changedUserId, roles);\n res.send();\n }\n\n @POST()\n @route(\"/:id/set-verified\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed, ParamId(\"id\")])\n async setVerified(req: Request, res: Response) {\n const changedUserId = req.local.id;\n\n const ownUserId = req.user?.id;\n if (ownUserId == changedUserId) {\n throw new ForbiddenError(\"Not allowed to change own verified status\");\n }\n\n const isRootUser = await this.userService.isUserRootUser(changedUserId);\n if (isRootUser) {\n throw new ForbiddenError(\"Not allowed to change root user to unverified\");\n }\n\n const { isVerified } = await validateInput(req.body, isVerifiedSchema);\n await this.userService.setVerifiedById(changedUserId, isVerified);\n\n res.send();\n }\n\n @POST()\n @route(\"/:id/set-root-user\")\n @before([demoUserNotAllowed, ParamId(\"id\")])\n async setRootUser(req: Request, res: Response) {\n const changedUserId = req.local.id;\n\n const userId = req.user?.id;\n if (userId) {\n const isRootUser = await this.userService.isUserRootUser(userId);\n if (!isRootUser) {\n throw new ForbiddenError(\"Not allowed to change owner without being owner yourself\");\n }\n }\n const { isRootUser } = await validateInput(req.body, isRootUserSchema);\n await this.userService.setIsRootUserById(changedUserId, isRootUser);\n res.send();\n }\n\n throwIfDemoMode() {\n const isDemoMode = this.configService.isDemoMode();\n if (isDemoMode) {\n throw new ForbiddenError(\"Not allowed in demo mode\");\n }\n }\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
1
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
3
3
  import { Role } from "./role.entity.js";
4
4
  import { User } from "./user.entity.js";
5
5
  import { Column, CreateDateColumn, Entity, Index, JoinColumn, JoinTable, ManyToMany, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
1
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
3
3
  import { Printer } from "./printer.entity.js";
4
4
  import { Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn } from "typeorm";
5
5
  //#region src/entities/camera-stream.entity.ts
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
1
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
3
3
  import { Printer } from "./printer.entity.js";
4
4
  import { Floor } from "./floor.entity.js";
5
5
  import { Column, Entity, JoinColumn, ManyToOne, OneToOne, PrimaryGeneratedColumn, Unique } from "typeorm";
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
1
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
3
3
  import { FloorPosition } from "./floor-position.entity.js";
4
4
  import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm";
5
5
  //#region src/entities/floor.entity.ts
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
1
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
3
3
  import { Printer } from "./printer.entity.js";
4
4
  import { Column, CreateDateColumn, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from "typeorm";
5
5
  //#region src/entities/print-job.entity.ts
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
1
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
3
3
  import { Printer } from "./printer.entity.js";
4
4
  import { User } from "./user.entity.js";
5
5
  import { Column, CreateDateColumn, Entity, Index, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
1
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
3
3
  import { Tag } from "./tag.entity.js";
4
4
  import { Printer } from "./printer.entity.js";
5
5
  import { Column, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn, Unique } from "typeorm";
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
1
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
3
3
  import { PrinterTag } from "./printer-tag.entity.js";
4
4
  import "../services/printer-api.interface.js";
5
5
  import { IsAlphanumeric } from "class-validator";
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
1
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
3
3
  import { User } from "./user.entity.js";
4
4
  import { Column, CreateDateColumn, Entity, JoinColumn, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
5
5
  //#region src/entities/refresh-token.entity.ts
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
1
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
3
3
  import { UserRole } from "./user-role.entity.js";
4
4
  import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm";
5
5
  //#region src/entities/role.entity.ts
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
1
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
3
3
  import { credentialSettingsKey, frontendSettingKey, serverSettingsKey, timeoutSettingKey, wizardSettingKey } from "../constants/server-settings.constants.js";
4
4
  import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
5
5
  //#region src/entities/settings.entity.ts
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
1
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
3
3
  import { Length } from "class-validator";
4
4
  import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
5
5
  //#region src/entities/tag.entity.ts
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
1
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
3
3
  import { Role } from "./role.entity.js";
4
4
  import { User } from "./user.entity.js";
5
5
  import { Column, CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn, Unique } from "typeorm";
@@ -1,5 +1,5 @@
1
- import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorateMetadata.js";
2
- import { __decorate } from "../_virtual/_@oxc-project_runtime@0.127.0/helpers/decorate.js";
1
+ import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorateMetadata.js";
2
+ import { __decorate } from "../_virtual/_@oxc-project_runtime@0.129.0/helpers/decorate.js";
3
3
  import { RefreshToken } from "./refresh-token.entity.js";
4
4
  import { UserRole } from "./user-role.entity.js";
5
5
  import { Column, CreateDateColumn, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm";
@@ -1 +1 @@
1
- {"version":3,"file":"failed-dependency.exception.js","names":[],"sources":["../../src/exceptions/failed-dependency.exception.ts"],"sourcesContent":["export class FailedDependencyException extends Error {\n serviceCode?: number;\n constructor(message: string, serviceCode?: number) {\n super(message);\n this.name = FailedDependencyException.name;\n this.serviceCode = serviceCode;\n }\n}\n"],"mappings":";AAAA,IAAa,4BAAb,MAAa,kCAAkC,MAAM;CACnD;CACA,YAAY,SAAiB,aAAsB;AACjD,QAAM,QAAQ;AACd,OAAK,OAAO,0BAA0B;AACtC,OAAK,cAAc"}
1
+ {"version":3,"file":"failed-dependency.exception.js","names":[],"sources":["../../src/exceptions/failed-dependency.exception.ts"],"sourcesContent":["export class FailedDependencyException extends Error {\n serviceCode?: number;\n constructor(message: string, serviceCode?: number) {\n super(message);\n this.name = FailedDependencyException.name;\n this.serviceCode = serviceCode;\n }\n}\n"],"mappings":";AAAA,IAAa,4BAAb,MAAa,kCAAkC,MAAM;CACnD;CACA,YAAY,SAAiB,aAAsB;EACjD,MAAM,QAAQ;EACd,KAAK,OAAO,0BAA0B;EACtC,KAAK,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"job.exceptions.js","names":[],"sources":["../../src/exceptions/job.exceptions.ts"],"sourcesContent":["export class JobValidationException extends Error {\n constructor(message: string, taskId: string) {\n super(message);\n this.name = `JobValidationError [${taskId || \"anonymous\"}]`;\n }\n}\n"],"mappings":";AAAA,IAAa,yBAAb,cAA4C,MAAM;CAChD,YAAY,SAAiB,QAAgB;AAC3C,QAAM,QAAQ;AACd,OAAK,OAAO,uBAAuB,UAAU,YAAY"}
1
+ {"version":3,"file":"job.exceptions.js","names":[],"sources":["../../src/exceptions/job.exceptions.ts"],"sourcesContent":["export class JobValidationException extends Error {\n constructor(message: string, taskId: string) {\n super(message);\n this.name = `JobValidationError [${taskId || \"anonymous\"}]`;\n }\n}\n"],"mappings":";AAAA,IAAa,yBAAb,cAA4C,MAAM;CAChD,YAAY,SAAiB,QAAgB;EAC3C,MAAM,QAAQ;EACd,KAAK,OAAO,uBAAuB,UAAU,YAAY"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.exceptions.js","names":[],"sources":["../../src/exceptions/runtime.exceptions.ts"],"sourcesContent":["export class NotImplementedException extends Error {\n constructor(message?: string) {\n super(message);\n this.name = NotImplementedException.name;\n }\n}\n\nexport class AuthenticationError extends Error {\n reasonCode: string;\n\n constructor(error?: string, reasonCode = \"\") {\n super(error);\n this.name = AuthenticationError.name;\n this.reasonCode = reasonCode;\n }\n}\n\nexport class ForbiddenError extends Error {\n constructor(error?: string) {\n super(error);\n this.name = ForbiddenError.name;\n }\n}\n\nexport class AuthorizationError extends Error {\n permissions?: string[] = [];\n roles?: string[] = [];\n reason?: string;\n\n constructor({ permissions, roles, reason }: { permissions?: string[]; roles?: string[]; reason?: string }) {\n super(\"Authorization failed\");\n this.name = AuthorizationError.name;\n this.reason = reason;\n this.permissions = permissions;\n this.roles = roles;\n }\n}\n\nexport class BadRequestException extends Error {\n constructor(message: string) {\n super(message);\n this.name = BadRequestException.name;\n }\n}\n\nexport class ConflictException extends Error {\n existingResourceId?: string;\n\n constructor(message: string, existingResourceId?: string) {\n super(message);\n this.name = ConflictException.name;\n this.existingResourceId = existingResourceId;\n }\n}\n\nexport class NotFoundException extends Error {\n path?: string;\n\n constructor(message: string, path?: string) {\n super(message);\n this.name = NotFoundException.name;\n this.path = path;\n }\n}\n\nexport class ValidationException<T = any> extends Error {\n errors: T;\n\n constructor(validationObject: T) {\n super(JSON.stringify(validationObject));\n this.name = ValidationException.name;\n this.errors = validationObject;\n }\n}\n\nexport class ExternalServiceError extends Error {\n error: any;\n serviceType?: string;\n\n constructor(responseObject: any, serviceType?: string) {\n super(JSON.stringify(responseObject));\n this.name = ExternalServiceError.name;\n this.error = responseObject;\n this.serviceType = serviceType;\n }\n}\n\nexport class InternalServerException extends Error {\n constructor(message: string, stack?: any) {\n super(message);\n this.name = InternalServerException.name;\n this.stack = stack;\n }\n}\n"],"mappings":";AAAA,IAAa,0BAAb,MAAa,gCAAgC,MAAM;CACjD,YAAY,SAAkB;AAC5B,QAAM,QAAQ;AACd,OAAK,OAAO,wBAAwB;;;AAIxC,IAAa,sBAAb,MAAa,4BAA4B,MAAM;CAC7C;CAEA,YAAY,OAAgB,aAAa,IAAI;AAC3C,QAAM,MAAM;AACZ,OAAK,OAAO,oBAAoB;AAChC,OAAK,aAAa;;;AAItB,IAAa,iBAAb,MAAa,uBAAuB,MAAM;CACxC,YAAY,OAAgB;AAC1B,QAAM,MAAM;AACZ,OAAK,OAAO,eAAe;;;AAI/B,IAAa,qBAAb,MAAa,2BAA2B,MAAM;CAC5C,cAAyB,EAAE;CAC3B,QAAmB,EAAE;CACrB;CAEA,YAAY,EAAE,aAAa,OAAO,UAAyE;AACzG,QAAM,uBAAuB;AAC7B,OAAK,OAAO,mBAAmB;AAC/B,OAAK,SAAS;AACd,OAAK,cAAc;AACnB,OAAK,QAAQ;;;AAIjB,IAAa,sBAAb,MAAa,4BAA4B,MAAM;CAC7C,YAAY,SAAiB;AAC3B,QAAM,QAAQ;AACd,OAAK,OAAO,oBAAoB;;;AAIpC,IAAa,oBAAb,MAAa,0BAA0B,MAAM;CAC3C;CAEA,YAAY,SAAiB,oBAA6B;AACxD,QAAM,QAAQ;AACd,OAAK,OAAO,kBAAkB;AAC9B,OAAK,qBAAqB;;;AAI9B,IAAa,oBAAb,MAAa,0BAA0B,MAAM;CAC3C;CAEA,YAAY,SAAiB,MAAe;AAC1C,QAAM,QAAQ;AACd,OAAK,OAAO,kBAAkB;AAC9B,OAAK,OAAO;;;AAIhB,IAAa,sBAAb,MAAa,4BAAqC,MAAM;CACtD;CAEA,YAAY,kBAAqB;AAC/B,QAAM,KAAK,UAAU,iBAAiB,CAAC;AACvC,OAAK,OAAO,oBAAoB;AAChC,OAAK,SAAS;;;AAIlB,IAAa,uBAAb,MAAa,6BAA6B,MAAM;CAC9C;CACA;CAEA,YAAY,gBAAqB,aAAsB;AACrD,QAAM,KAAK,UAAU,eAAe,CAAC;AACrC,OAAK,OAAO,qBAAqB;AACjC,OAAK,QAAQ;AACb,OAAK,cAAc;;;AAIvB,IAAa,0BAAb,MAAa,gCAAgC,MAAM;CACjD,YAAY,SAAiB,OAAa;AACxC,QAAM,QAAQ;AACd,OAAK,OAAO,wBAAwB;AACpC,OAAK,QAAQ"}
1
+ {"version":3,"file":"runtime.exceptions.js","names":[],"sources":["../../src/exceptions/runtime.exceptions.ts"],"sourcesContent":["export class NotImplementedException extends Error {\n constructor(message?: string) {\n super(message);\n this.name = NotImplementedException.name;\n }\n}\n\nexport class AuthenticationError extends Error {\n reasonCode: string;\n\n constructor(error?: string, reasonCode = \"\") {\n super(error);\n this.name = AuthenticationError.name;\n this.reasonCode = reasonCode;\n }\n}\n\nexport class ForbiddenError extends Error {\n constructor(error?: string) {\n super(error);\n this.name = ForbiddenError.name;\n }\n}\n\nexport class AuthorizationError extends Error {\n permissions?: string[] = [];\n roles?: string[] = [];\n reason?: string;\n\n constructor({ permissions, roles, reason }: { permissions?: string[]; roles?: string[]; reason?: string }) {\n super(\"Authorization failed\");\n this.name = AuthorizationError.name;\n this.reason = reason;\n this.permissions = permissions;\n this.roles = roles;\n }\n}\n\nexport class BadRequestException extends Error {\n constructor(message: string) {\n super(message);\n this.name = BadRequestException.name;\n }\n}\n\nexport class ConflictException extends Error {\n existingResourceId?: string;\n\n constructor(message: string, existingResourceId?: string) {\n super(message);\n this.name = ConflictException.name;\n this.existingResourceId = existingResourceId;\n }\n}\n\nexport class NotFoundException extends Error {\n path?: string;\n\n constructor(message: string, path?: string) {\n super(message);\n this.name = NotFoundException.name;\n this.path = path;\n }\n}\n\nexport class ValidationException<T = any> extends Error {\n errors: T;\n\n constructor(validationObject: T) {\n super(JSON.stringify(validationObject));\n this.name = ValidationException.name;\n this.errors = validationObject;\n }\n}\n\nexport class ExternalServiceError extends Error {\n error: any;\n serviceType?: string;\n\n constructor(responseObject: any, serviceType?: string) {\n super(JSON.stringify(responseObject));\n this.name = ExternalServiceError.name;\n this.error = responseObject;\n this.serviceType = serviceType;\n }\n}\n\nexport class InternalServerException extends Error {\n constructor(message: string, stack?: any) {\n super(message);\n this.name = InternalServerException.name;\n this.stack = stack;\n }\n}\n"],"mappings":";AAAA,IAAa,0BAAb,MAAa,gCAAgC,MAAM;CACjD,YAAY,SAAkB;EAC5B,MAAM,QAAQ;EACd,KAAK,OAAO,wBAAwB;;;AAIxC,IAAa,sBAAb,MAAa,4BAA4B,MAAM;CAC7C;CAEA,YAAY,OAAgB,aAAa,IAAI;EAC3C,MAAM,MAAM;EACZ,KAAK,OAAO,oBAAoB;EAChC,KAAK,aAAa;;;AAItB,IAAa,iBAAb,MAAa,uBAAuB,MAAM;CACxC,YAAY,OAAgB;EAC1B,MAAM,MAAM;EACZ,KAAK,OAAO,eAAe;;;AAI/B,IAAa,qBAAb,MAAa,2BAA2B,MAAM;CAC5C,cAAyB,EAAE;CAC3B,QAAmB,EAAE;CACrB;CAEA,YAAY,EAAE,aAAa,OAAO,UAAyE;EACzG,MAAM,uBAAuB;EAC7B,KAAK,OAAO,mBAAmB;EAC/B,KAAK,SAAS;EACd,KAAK,cAAc;EACnB,KAAK,QAAQ;;;AAIjB,IAAa,sBAAb,MAAa,4BAA4B,MAAM;CAC7C,YAAY,SAAiB;EAC3B,MAAM,QAAQ;EACd,KAAK,OAAO,oBAAoB;;;AAIpC,IAAa,oBAAb,MAAa,0BAA0B,MAAM;CAC3C;CAEA,YAAY,SAAiB,oBAA6B;EACxD,MAAM,QAAQ;EACd,KAAK,OAAO,kBAAkB;EAC9B,KAAK,qBAAqB;;;AAI9B,IAAa,oBAAb,MAAa,0BAA0B,MAAM;CAC3C;CAEA,YAAY,SAAiB,MAAe;EAC1C,MAAM,QAAQ;EACd,KAAK,OAAO,kBAAkB;EAC9B,KAAK,OAAO;;;AAIhB,IAAa,sBAAb,MAAa,4BAAqC,MAAM;CACtD;CAEA,YAAY,kBAAqB;EAC/B,MAAM,KAAK,UAAU,iBAAiB,CAAC;EACvC,KAAK,OAAO,oBAAoB;EAChC,KAAK,SAAS;;;AAIlB,IAAa,uBAAb,MAAa,6BAA6B,MAAM;CAC9C;CACA;CAEA,YAAY,gBAAqB,aAAsB;EACrD,MAAM,KAAK,UAAU,eAAe,CAAC;EACrC,KAAK,OAAO,qBAAqB;EACjC,KAAK,QAAQ;EACb,KAAK,cAAc;;;AAIvB,IAAa,0BAAb,MAAa,gCAAgC,MAAM;CACjD,YAAY,SAAiB,OAAa;EACxC,MAAM,QAAQ;EACd,KAAK,OAAO,wBAAwB;EACpC,KAAK,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"event-emitter.js","names":[],"sources":["../../src/handlers/event-emitter.ts"],"sourcesContent":["import EventEmitter2 from \"eventemitter2\";\n\nexport function configureEventEmitter() {\n return new EventEmitter2({\n // set this to `true` to use wildcards\n wildcard: true,\n\n // the delimiter used to segment namespaces\n delimiter: \".\",\n\n // set this to `true` if you want to emit the newListener event\n newListener: false,\n\n // set this to `true` if you want to emit the removeListener event\n removeListener: false,\n\n // the maximum amount of listeners that can be assigned to an event\n maxListeners: 10,\n\n // show event name in memory leak message when more than maximum amount of listeners is assigned\n verboseMemoryLeak: true,\n\n // disable throwing uncaughtException if an error event is emitted and it has no listeners\n ignoreErrors: false,\n });\n}\n"],"mappings":";;AAEA,SAAgB,wBAAwB;AACtC,QAAO,IAAI,cAAc;EAEvB,UAAU;EAGV,WAAW;EAGX,aAAa;EAGb,gBAAgB;EAGhB,cAAc;EAGd,mBAAmB;EAGnB,cAAc;EACf,CAAC"}
1
+ {"version":3,"file":"event-emitter.js","names":[],"sources":["../../src/handlers/event-emitter.ts"],"sourcesContent":["import EventEmitter2 from \"eventemitter2\";\n\nexport function configureEventEmitter() {\n return new EventEmitter2({\n // set this to `true` to use wildcards\n wildcard: true,\n\n // the delimiter used to segment namespaces\n delimiter: \".\",\n\n // set this to `true` if you want to emit the newListener event\n newListener: false,\n\n // set this to `true` if you want to emit the removeListener event\n removeListener: false,\n\n // the maximum amount of listeners that can be assigned to an event\n maxListeners: 10,\n\n // show event name in memory leak message when more than maximum amount of listeners is assigned\n verboseMemoryLeak: true,\n\n // disable throwing uncaughtException if an error event is emitted and it has no listeners\n ignoreErrors: false,\n });\n}\n"],"mappings":";;AAEA,SAAgB,wBAAwB;CACtC,OAAO,IAAI,cAAc;EAEvB,UAAU;EAGV,WAAW;EAGX,aAAa;EAGb,gBAAgB;EAGhB,cAAc;EAGd,mBAAmB;EAGnB,cAAc;EACf,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"logger-factory.js","names":[],"sources":["../../src/handlers/logger-factory.ts"],"sourcesContent":["import { LoggerService } from \"./logger\";\n\nexport type ILoggerFactory = (name: string) => LoggerService;\n\nexport function LoggerFactory(): ILoggerFactory {\n return (name: string) => {\n return new LoggerService(name);\n };\n}\n"],"mappings":";;AAIA,SAAgB,gBAAgC;AAC9C,SAAQ,SAAiB;AACvB,SAAO,IAAI,cAAc,KAAK"}
1
+ {"version":3,"file":"logger-factory.js","names":[],"sources":["../../src/handlers/logger-factory.ts"],"sourcesContent":["import { LoggerService } from \"./logger\";\n\nexport type ILoggerFactory = (name: string) => LoggerService;\n\nexport function LoggerFactory(): ILoggerFactory {\n return (name: string) => {\n return new LoggerService(name);\n };\n}\n"],"mappings":";;AAIA,SAAgB,gBAAgC;CAC9C,QAAQ,SAAiB;EACvB,OAAO,IAAI,cAAc,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","names":[],"sources":["../../src/handlers/logger.ts"],"sourcesContent":["import winston from \"winston\";\nimport { getStaticLogger, logContextClassProperty } from \"@/handlers/logging/static.logger\";\n\nexport class LoggerService {\n logger: winston.Logger;\n\n constructor(private readonly name: string) {\n this.logger = getStaticLogger().child({ [logContextClassProperty]: this.name });\n }\n\n newDebug(object: any) {\n this.logger.debug(object);\n }\n\n log(message: string, meta?: any) {\n this.logger.log(\"info\", message, meta);\n }\n\n warn(message: string, meta?: any) {\n this.logger.log(\"warn\", message, meta);\n }\n\n debug(message: string, meta?: any) {\n this.logger.log(\"debug\", message, meta);\n }\n\n error(message: string, meta?: any) {\n this.logger.log(\"error\", message, meta);\n }\n}\n"],"mappings":";;AAGA,IAAa,gBAAb,MAA2B;CACzB;CAEA,YAAY,MAA+B;AAAd,OAAA,OAAA;AAC3B,OAAK,SAAS,iBAAiB,CAAC,MAAM,GAAG,0BAA0B,KAAK,MAAM,CAAC;;CAGjF,SAAS,QAAa;AACpB,OAAK,OAAO,MAAM,OAAO;;CAG3B,IAAI,SAAiB,MAAY;AAC/B,OAAK,OAAO,IAAI,QAAQ,SAAS,KAAK;;CAGxC,KAAK,SAAiB,MAAY;AAChC,OAAK,OAAO,IAAI,QAAQ,SAAS,KAAK;;CAGxC,MAAM,SAAiB,MAAY;AACjC,OAAK,OAAO,IAAI,SAAS,SAAS,KAAK;;CAGzC,MAAM,SAAiB,MAAY;AACjC,OAAK,OAAO,IAAI,SAAS,SAAS,KAAK"}
1
+ {"version":3,"file":"logger.js","names":[],"sources":["../../src/handlers/logger.ts"],"sourcesContent":["import winston from \"winston\";\nimport { getStaticLogger, logContextClassProperty } from \"@/handlers/logging/static.logger\";\n\nexport class LoggerService {\n logger: winston.Logger;\n\n constructor(private readonly name: string) {\n this.logger = getStaticLogger().child({ [logContextClassProperty]: this.name });\n }\n\n newDebug(object: any) {\n this.logger.debug(object);\n }\n\n log(message: string, meta?: any) {\n this.logger.log(\"info\", message, meta);\n }\n\n warn(message: string, meta?: any) {\n this.logger.log(\"warn\", message, meta);\n }\n\n debug(message: string, meta?: any) {\n this.logger.log(\"debug\", message, meta);\n }\n\n error(message: string, meta?: any) {\n this.logger.log(\"error\", message, meta);\n }\n}\n"],"mappings":";;AAGA,IAAa,gBAAb,MAA2B;CACzB;CAEA,YAAY,MAA+B;EAAd,KAAA,OAAA;EAC3B,KAAK,SAAS,iBAAiB,CAAC,MAAM,GAAG,0BAA0B,KAAK,MAAM,CAAC;;CAGjF,SAAS,QAAa;EACpB,KAAK,OAAO,MAAM,OAAO;;CAG3B,IAAI,SAAiB,MAAY;EAC/B,KAAK,OAAO,IAAI,QAAQ,SAAS,KAAK;;CAGxC,KAAK,SAAiB,MAAY;EAChC,KAAK,OAAO,IAAI,QAAQ,SAAS,KAAK;;CAGxC,MAAM,SAAiB,MAAY;EACjC,KAAK,OAAO,IAAI,SAAS,SAAS,KAAK;;CAGzC,MAAM,SAAiB,MAAY;EACjC,KAAK,OAAO,IAAI,SAAS,SAAS,KAAK"}
@@ -2,11 +2,10 @@ import { AppConstants } from "../../server.constants.js";
2
2
  import { getMediaPath } from "../../utils/fs.utils.js";
3
3
  import { join } from "node:path";
4
4
  import winston from "winston";
5
- import { DateTime } from "luxon";
6
5
  //#region src/handlers/logging/file-logging.transport.ts
7
6
  function createFileLoggingTransport(options) {
8
7
  if (!options.enabled) return;
9
- const date = DateTime.now().toISODate();
8
+ const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
10
9
  const logFilePath = join(getMediaPath(), AppConstants.defaultLogsFolder, `${AppConstants.logAppName}-${date}.log`);
11
10
  return new winston.transports.File({
12
11
  level: options.isTest ? "warn" : "info",
@@ -1 +1 @@
1
- {"version":3,"file":"file-logging.transport.js","names":[],"sources":["../../../src/handlers/logging/file-logging.transport.ts"],"sourcesContent":["import { DateTime } from \"luxon\";\nimport { join } from \"node:path\";\nimport { getMediaPath } from \"@/utils/fs.utils\";\nimport { AppConstants } from \"@/server.constants\";\nimport winston from \"winston\";\n\nexport interface FileLoggerOptions {\n enabled: boolean;\n isTest: boolean;\n}\n\nexport function createFileLoggingTransport(options: FileLoggerOptions): winston.transport | undefined {\n if (!options.enabled) {\n return;\n }\n\n const date = DateTime.now().toISODate();\n const logFilePath = join(getMediaPath(), AppConstants.defaultLogsFolder, `${AppConstants.logAppName}-${date}.log`);\n\n return new winston.transports.File({\n level: options.isTest ? \"warn\" : \"info\",\n filename: logFilePath,\n maxsize: 5000000,\n maxFiles: 5,\n });\n}\n"],"mappings":";;;;;;AAWA,SAAgB,2BAA2B,SAA2D;AACpG,KAAI,CAAC,QAAQ,QACX;CAGF,MAAM,OAAO,SAAS,KAAK,CAAC,WAAW;CACvC,MAAM,cAAc,KAAK,cAAc,EAAE,aAAa,mBAAmB,GAAG,aAAa,WAAW,GAAG,KAAK,MAAM;AAElH,QAAO,IAAI,QAAQ,WAAW,KAAK;EACjC,OAAO,QAAQ,SAAS,SAAS;EACjC,UAAU;EACV,SAAS;EACT,UAAU;EACX,CAAC"}
1
+ {"version":3,"file":"file-logging.transport.js","names":[],"sources":["../../../src/handlers/logging/file-logging.transport.ts"],"sourcesContent":["import { join } from \"node:path\";\nimport { getMediaPath } from \"@/utils/fs.utils\";\nimport { AppConstants } from \"@/server.constants\";\nimport winston from \"winston\";\n\nexport interface FileLoggerOptions {\n enabled: boolean;\n isTest: boolean;\n}\n\nexport function createFileLoggingTransport(options: FileLoggerOptions): winston.transport | undefined {\n if (!options.enabled) {\n return;\n }\n const date = new Date().toISOString().slice(0, 10);\n const logFilePath = join(getMediaPath(), AppConstants.defaultLogsFolder, `${AppConstants.logAppName}-${date}.log`);\n\n return new winston.transports.File({\n level: options.isTest ? \"warn\" : \"info\",\n filename: logFilePath,\n maxsize: 5000000,\n maxFiles: 5,\n });\n}\n"],"mappings":";;;;;AAUA,SAAgB,2BAA2B,SAA2D;CACpG,IAAI,CAAC,QAAQ,SACX;CAEF,MAAM,wBAAO,IAAI,MAAM,EAAC,aAAa,CAAC,MAAM,GAAG,GAAG;CAClD,MAAM,cAAc,KAAK,cAAc,EAAE,aAAa,mBAAmB,GAAG,aAAa,WAAW,GAAG,KAAK,MAAM;CAElH,OAAO,IAAI,QAAQ,WAAW,KAAK;EACjC,OAAO,QAAQ,SAAS,SAAS;EACjC,UAAU;EACV,SAAS;EACT,UAAU;EACX,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"loki-logging.transport.js","names":[],"sources":["../../../src/handlers/logging/loki-logging.transport.ts"],"sourcesContent":["import LokiTransport from \"winston-loki\";\nimport winston from \"winston\";\nimport process from \"node:process\";\nimport { AppConstants } from \"@/server.constants\";\nimport { z } from \"zod\";\n\nexport interface LokiLoggerOptions {\n logLevel: string;\n}\n\nconst lokiValidationSchema = z.object({\n lokiEnabled: z.boolean(),\n lokiAddress: z.string().url(),\n lokiTimeoutSeconds: z.coerce.number().positive().default(30),\n lokiInterval: z.coerce.number().positive().default(15),\n});\n\nexport function createLokiLoggingTransport(options: LokiLoggerOptions) {\n const lokiConfigValidationResult = lokiValidationSchema.safeParse({\n lokiEnabled: process.env[AppConstants.ENABLE_LOKI_LOGGING] === \"true\",\n lokiTimeoutSeconds: process.env[AppConstants.LOKI_TIMEOUT_SECONDS],\n lokiAddress: process.env[AppConstants.LOKI_ADDRESS],\n lokiInterval: process.env[AppConstants.LOKI_INTERVAL],\n });\n\n if (!lokiConfigValidationResult.success || !lokiConfigValidationResult.data.lokiEnabled) {\n return;\n }\n\n return new LokiTransport({\n level: options.logLevel ?? \"info\",\n host: lokiConfigValidationResult.data.lokiAddress,\n interval: lokiConfigValidationResult.data.lokiInterval,\n timeout: lokiConfigValidationResult.data.lokiTimeoutSeconds,\n handleExceptions: true,\n onConnectionError(error: unknown) {\n console.debug(`Loki logger enabled, but connection failed. ${error}`);\n },\n // The labels,json, useWinstonMetaAsLabels, format settings plays well with Loki + Grafana\n labels: {\n app: \"fdm-monster-server\",\n },\n // When set to false, uses protobuf\n json: false,\n // When set to false, the labels column cardinality is kept low (better for performance)\n useWinstonMetaAsLabels: false,\n // Other formats like simple cause string + json, and are thus harder to work with\n format: winston.format.json(),\n });\n}\n"],"mappings":";;;;;;AAUA,MAAM,uBAAuB,EAAE,OAAO;CACpC,aAAa,EAAE,SAAS;CACxB,aAAa,EAAE,QAAQ,CAAC,KAAK;CAC7B,oBAAoB,EAAE,OAAO,QAAQ,CAAC,UAAU,CAAC,QAAQ,GAAG;CAC5D,cAAc,EAAE,OAAO,QAAQ,CAAC,UAAU,CAAC,QAAQ,GAAG;CACvD,CAAC;AAEF,SAAgB,2BAA2B,SAA4B;CACrE,MAAM,6BAA6B,qBAAqB,UAAU;EAChE,aAAa,QAAQ,IAAI,aAAa,yBAAyB;EAC/D,oBAAoB,QAAQ,IAAI,aAAa;EAC7C,aAAa,QAAQ,IAAI,aAAa;EACtC,cAAc,QAAQ,IAAI,aAAa;EACxC,CAAC;AAEF,KAAI,CAAC,2BAA2B,WAAW,CAAC,2BAA2B,KAAK,YAC1E;AAGF,QAAO,IAAI,cAAc;EACvB,OAAO,QAAQ,YAAY;EAC3B,MAAM,2BAA2B,KAAK;EACtC,UAAU,2BAA2B,KAAK;EAC1C,SAAS,2BAA2B,KAAK;EACzC,kBAAkB;EAClB,kBAAkB,OAAgB;AAChC,WAAQ,MAAM,+CAA+C,QAAQ;;EAGvE,QAAQ,EACN,KAAK,sBACN;EAED,MAAM;EAEN,wBAAwB;EAExB,QAAQ,QAAQ,OAAO,MAAM;EAC9B,CAAC"}
1
+ {"version":3,"file":"loki-logging.transport.js","names":[],"sources":["../../../src/handlers/logging/loki-logging.transport.ts"],"sourcesContent":["import LokiTransport from \"winston-loki\";\nimport winston from \"winston\";\nimport process from \"node:process\";\nimport { AppConstants } from \"@/server.constants\";\nimport { z } from \"zod\";\n\nexport interface LokiLoggerOptions {\n logLevel: string;\n}\n\nconst lokiValidationSchema = z.object({\n lokiEnabled: z.boolean(),\n lokiAddress: z.string().url(),\n lokiTimeoutSeconds: z.coerce.number().positive().default(30),\n lokiInterval: z.coerce.number().positive().default(15),\n});\n\nexport function createLokiLoggingTransport(options: LokiLoggerOptions) {\n const lokiConfigValidationResult = lokiValidationSchema.safeParse({\n lokiEnabled: process.env[AppConstants.ENABLE_LOKI_LOGGING] === \"true\",\n lokiTimeoutSeconds: process.env[AppConstants.LOKI_TIMEOUT_SECONDS],\n lokiAddress: process.env[AppConstants.LOKI_ADDRESS],\n lokiInterval: process.env[AppConstants.LOKI_INTERVAL],\n });\n\n if (!lokiConfigValidationResult.success || !lokiConfigValidationResult.data.lokiEnabled) {\n return;\n }\n\n return new LokiTransport({\n level: options.logLevel ?? \"info\",\n host: lokiConfigValidationResult.data.lokiAddress,\n interval: lokiConfigValidationResult.data.lokiInterval,\n timeout: lokiConfigValidationResult.data.lokiTimeoutSeconds,\n handleExceptions: true,\n onConnectionError(error: unknown) {\n console.debug(`Loki logger enabled, but connection failed. ${error}`);\n },\n // The labels,json, useWinstonMetaAsLabels, format settings plays well with Loki + Grafana\n labels: {\n app: \"fdm-monster-server\",\n },\n // When set to false, uses protobuf\n json: false,\n // When set to false, the labels column cardinality is kept low (better for performance)\n useWinstonMetaAsLabels: false,\n // Other formats like simple cause string + json, and are thus harder to work with\n format: winston.format.json(),\n });\n}\n"],"mappings":";;;;;;AAUA,MAAM,uBAAuB,EAAE,OAAO;CACpC,aAAa,EAAE,SAAS;CACxB,aAAa,EAAE,QAAQ,CAAC,KAAK;CAC7B,oBAAoB,EAAE,OAAO,QAAQ,CAAC,UAAU,CAAC,QAAQ,GAAG;CAC5D,cAAc,EAAE,OAAO,QAAQ,CAAC,UAAU,CAAC,QAAQ,GAAG;CACvD,CAAC;AAEF,SAAgB,2BAA2B,SAA4B;CACrE,MAAM,6BAA6B,qBAAqB,UAAU;EAChE,aAAa,QAAQ,IAAI,aAAa,yBAAyB;EAC/D,oBAAoB,QAAQ,IAAI,aAAa;EAC7C,aAAa,QAAQ,IAAI,aAAa;EACtC,cAAc,QAAQ,IAAI,aAAa;EACxC,CAAC;CAEF,IAAI,CAAC,2BAA2B,WAAW,CAAC,2BAA2B,KAAK,aAC1E;CAGF,OAAO,IAAI,cAAc;EACvB,OAAO,QAAQ,YAAY;EAC3B,MAAM,2BAA2B,KAAK;EACtC,UAAU,2BAA2B,KAAK;EAC1C,SAAS,2BAA2B,KAAK;EACzC,kBAAkB;EAClB,kBAAkB,OAAgB;GAChC,QAAQ,MAAM,+CAA+C,QAAQ;;EAGvE,QAAQ,EACN,KAAK,sBACN;EAED,MAAM;EAEN,wBAAwB;EAExB,QAAQ,QAAQ,OAAO,MAAM;EAC9B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"static.logger.js","names":[],"sources":["../../../src/handlers/logging/static.logger.ts"],"sourcesContent":["import winston from \"winston\";\nimport process from \"node:process\";\nimport { AppConstants } from \"@/server.constants\";\nimport { createLokiLoggingTransport } from \"@/handlers/logging/loki-logging.transport\";\nimport { createFileLoggingTransport } from \"@/handlers/logging/file-logging.transport\";\nimport { isDevelopmentEnvironment } from \"@/utils/env.utils\";\n\nlet staticLogger: winston.Logger | null = null;\n\nexport interface StaticLoggerConfig {\n enableFileLogs: boolean;\n}\n\nconst levelMap: Record<string, string> = {\n error: \"ERR\",\n warn: \"WRN\",\n info: \"INF\",\n debug: \"DBG\",\n http: \"HTT\",\n verbose: \"VRB\",\n silly: \"SLY\",\n};\n\nexport const logContextClassProperty = \"class\";\n\nexport function getStaticLogger() {\n if (!staticLogger) {\n throw new Error(\"Logger not yet initialized.\");\n }\n\n return staticLogger;\n}\n\nexport function createStaticLogger(config: StaticLoggerConfig) {\n if (staticLogger) {\n return;\n }\n\n const isProd = process.env[AppConstants.NODE_ENV_KEY] === AppConstants.defaultProductionEnv;\n const isTest = process.env[AppConstants.NODE_ENV_KEY] === AppConstants.defaultTestEnv;\n\n const effectiveLogLevel = isProd || isTest ? \"warn\" : \"debug\";\n\n const lokiTransport = createLokiLoggingTransport({\n logLevel: effectiveLogLevel,\n });\n\n const extraWinstonTransports: winston.transport[] = [];\n if (lokiTransport) {\n extraWinstonTransports.push(lokiTransport);\n }\n\n const fileLoggerTransport = createFileLoggingTransport({\n enabled: config.enableFileLogs,\n isTest,\n });\n if (fileLoggerTransport) {\n extraWinstonTransports.push(fileLoggerTransport);\n }\n\n staticLogger = winston.createLogger({\n transports: [\n ...extraWinstonTransports,\n // Always include console transport\n new winston.transports.Console({\n level: effectiveLogLevel,\n format: winston.format.combine(\n ...(isDevelopmentEnvironment() && process.env[AppConstants.ENABLE_COLORED_LOGS_KEY] == \"true\"\n ? [\n // Store the original level before colorization\n winston.format((info) => {\n info.rawLevel = info.level;\n return info;\n })(),\n winston.format.colorize({\n colors: {\n error: \"red\",\n warn: \"yellow\",\n info: \"white\",\n debug: \"gray\",\n http: \"magenta\",\n verbose: \"cyan\",\n silly: \"gray\",\n },\n level: true,\n message: true, // Don't colorize the whole message\n all: false,\n }),\n winston.format.printf((info) => {\n // Format timestamp similar to Serilog (ISO with milliseconds)\n const now = new Date();\n const timestamp = `${now.toISOString().split(\"T\")[0]} ${now.toTimeString().split(\" \")[0]}.${now.getMilliseconds().toString().padStart(3, \"0\")}`;\n\n // Get colored level from winston\n // @ts-ignore\n const levelAbbr = levelMap[info.rawLevel] ?? info.rawLevel.substring(0, 3).toUpperCase();\n\n // Apply custom coloring using ANSI color codes\n const gray = \"\\x1b[90m\"; // Dim/gray\n const reset = (info.message as string).substring(0, 5) ?? \"\\x1b[0m\"; // Reset\n const numberRegex = /\\b\\d+\\b/g;\n\n // Apply purple color to numbers in the message\n const coloredMessage = (info.message as string).replace(\n numberRegex,\n (match) => `\\x1b[35m${match}${reset}`,\n );\n\n const serviceName = info[logContextClassProperty] ?? \"unknown\";\n\n // Format the log entry with gray timestamp and brackets, colored level, and message with purple numbers\n let logEntry = `${gray}[${timestamp} ${reset}${levelAbbr}${reset}${gray}]${reset} ${gray}[${reset}${serviceName}${gray}]${reset} ${coloredMessage}`;\n\n // Add metadata if present\n if (info.meta) {\n // Add metadata with numbers colorized in purple\n const metaString = JSON.stringify(info.meta);\n const coloredMeta = metaString.replace(numberRegex, (match) => `\\x1b[35m${match}${reset}`);\n logEntry += ` ${coloredMeta}`;\n }\n\n return logEntry;\n }),\n ]\n : []),\n ),\n }),\n ],\n format: winston.format.printf((info) => {\n // Format timestamp similar to Serilog (ISO with milliseconds)\n const now = new Date();\n const timestamp = `${now.toISOString().split(\"T\")[0]} ${now.toTimeString().split(\" \")[0]}.${now.getMilliseconds().toString().padStart(3, \"0\")}`;\n\n const levelAbbr = levelMap[info.level] || `[${info.level.substring(0, 3).toUpperCase()}]`;\n\n const serviceName = info[logContextClassProperty] ?? \"unknown\";\n let message = `[${timestamp} ${levelAbbr}] [${serviceName}] ${info.message}`;\n\n // Add metadata if present, without dash separator\n if (info.meta) {\n // Convert camelCase to PascalCase for C# style\n const pascalCaseMeta = Object.entries(info.meta).reduce(\n (acc, [key, value]) => {\n const pascalKey = key.charAt(0).toUpperCase() + key.slice(1);\n acc[pascalKey] = value;\n return acc;\n },\n {} as Record<string, any>,\n );\n\n message += ` ${JSON.stringify(pascalCaseMeta)}`;\n }\n\n return message;\n }),\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"static.logger.js","names":[],"sources":["../../../src/handlers/logging/static.logger.ts"],"sourcesContent":["import winston from \"winston\";\nimport process from \"node:process\";\nimport { AppConstants } from \"@/server.constants\";\nimport { createLokiLoggingTransport } from \"@/handlers/logging/loki-logging.transport\";\nimport { createFileLoggingTransport } from \"@/handlers/logging/file-logging.transport\";\nimport { isDevelopmentEnvironment } from \"@/utils/env.utils\";\n\nlet staticLogger: winston.Logger | null = null;\n\nexport interface StaticLoggerConfig {\n enableFileLogs: boolean;\n}\n\nconst levelMap: Record<string, string> = {\n error: \"ERR\",\n warn: \"WRN\",\n info: \"INF\",\n debug: \"DBG\",\n http: \"HTT\",\n verbose: \"VRB\",\n silly: \"SLY\",\n};\n\nexport const logContextClassProperty = \"class\";\n\nexport function getStaticLogger() {\n if (!staticLogger) {\n throw new Error(\"Logger not yet initialized.\");\n }\n\n return staticLogger;\n}\n\nexport function createStaticLogger(config: StaticLoggerConfig) {\n if (staticLogger) {\n return;\n }\n\n const isProd = process.env[AppConstants.NODE_ENV_KEY] === AppConstants.defaultProductionEnv;\n const isTest = process.env[AppConstants.NODE_ENV_KEY] === AppConstants.defaultTestEnv;\n\n const effectiveLogLevel = isProd || isTest ? \"warn\" : \"debug\";\n\n const lokiTransport = createLokiLoggingTransport({\n logLevel: effectiveLogLevel,\n });\n\n const extraWinstonTransports: winston.transport[] = [];\n if (lokiTransport) {\n extraWinstonTransports.push(lokiTransport);\n }\n\n const fileLoggerTransport = createFileLoggingTransport({\n enabled: config.enableFileLogs,\n isTest,\n });\n if (fileLoggerTransport) {\n extraWinstonTransports.push(fileLoggerTransport);\n }\n\n staticLogger = winston.createLogger({\n transports: [\n ...extraWinstonTransports,\n // Always include console transport\n new winston.transports.Console({\n level: effectiveLogLevel,\n format: winston.format.combine(\n ...(isDevelopmentEnvironment() && process.env[AppConstants.ENABLE_COLORED_LOGS_KEY] == \"true\"\n ? [\n // Store the original level before colorization\n winston.format((info) => {\n info.rawLevel = info.level;\n return info;\n })(),\n winston.format.colorize({\n colors: {\n error: \"red\",\n warn: \"yellow\",\n info: \"white\",\n debug: \"gray\",\n http: \"magenta\",\n verbose: \"cyan\",\n silly: \"gray\",\n },\n level: true,\n message: true, // Don't colorize the whole message\n all: false,\n }),\n winston.format.printf((info) => {\n // Format timestamp similar to Serilog (ISO with milliseconds)\n const now = new Date();\n const timestamp = `${now.toISOString().split(\"T\")[0]} ${now.toTimeString().split(\" \")[0]}.${now.getMilliseconds().toString().padStart(3, \"0\")}`;\n\n // Get colored level from winston\n // @ts-ignore\n const levelAbbr = levelMap[info.rawLevel] ?? info.rawLevel.substring(0, 3).toUpperCase();\n\n // Apply custom coloring using ANSI color codes\n const gray = \"\\x1b[90m\"; // Dim/gray\n const reset = (info.message as string).substring(0, 5) ?? \"\\x1b[0m\"; // Reset\n const numberRegex = /\\b\\d+\\b/g;\n\n // Apply purple color to numbers in the message\n const coloredMessage = (info.message as string).replace(\n numberRegex,\n (match) => `\\x1b[35m${match}${reset}`,\n );\n\n const serviceName = info[logContextClassProperty] ?? \"unknown\";\n\n // Format the log entry with gray timestamp and brackets, colored level, and message with purple numbers\n let logEntry = `${gray}[${timestamp} ${reset}${levelAbbr}${reset}${gray}]${reset} ${gray}[${reset}${serviceName}${gray}]${reset} ${coloredMessage}`;\n\n // Add metadata if present\n if (info.meta) {\n // Add metadata with numbers colorized in purple\n const metaString = JSON.stringify(info.meta);\n const coloredMeta = metaString.replace(numberRegex, (match) => `\\x1b[35m${match}${reset}`);\n logEntry += ` ${coloredMeta}`;\n }\n\n return logEntry;\n }),\n ]\n : []),\n ),\n }),\n ],\n format: winston.format.printf((info) => {\n // Format timestamp similar to Serilog (ISO with milliseconds)\n const now = new Date();\n const timestamp = `${now.toISOString().split(\"T\")[0]} ${now.toTimeString().split(\" \")[0]}.${now.getMilliseconds().toString().padStart(3, \"0\")}`;\n\n const levelAbbr = levelMap[info.level] || `[${info.level.substring(0, 3).toUpperCase()}]`;\n\n const serviceName = info[logContextClassProperty] ?? \"unknown\";\n let message = `[${timestamp} ${levelAbbr}] [${serviceName}] ${info.message}`;\n\n // Add metadata if present, without dash separator\n if (info.meta) {\n // Convert camelCase to PascalCase for C# style\n const pascalCaseMeta = Object.entries(info.meta).reduce(\n (acc, [key, value]) => {\n const pascalKey = key.charAt(0).toUpperCase() + key.slice(1);\n acc[pascalKey] = value;\n return acc;\n },\n {} as Record<string, any>,\n );\n\n message += ` ${JSON.stringify(pascalCaseMeta)}`;\n }\n\n return message;\n }),\n });\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"validators.js","names":[],"sources":["../../src/handlers/validators.ts"],"sourcesContent":["import type { Request } from \"express\";\nimport { ValidationException } from \"@/exceptions/runtime.exceptions\";\nimport { ZodSchema } from \"zod\";\n\nexport async function validateInput<I, S>(data: I, zodSchema: ZodSchema<S>): Promise<S> {\n const result = await zodSchema.safeParseAsync(data);\n\n if (!result.success) {\n throw new ValidationException(result.error);\n }\n return result.data;\n}\n\nexport async function validateMiddleware<I, S>(req: Request<I>, zodSchema: ZodSchema<S>): Promise<S> {\n return validateInput(req.body, zodSchema);\n}\n"],"mappings":";;AAIA,eAAsB,cAAoB,MAAS,WAAqC;CACtF,MAAM,SAAS,MAAM,UAAU,eAAe,KAAK;AAEnD,KAAI,CAAC,OAAO,QACV,OAAM,IAAI,oBAAoB,OAAO,MAAM;AAE7C,QAAO,OAAO;;AAGhB,eAAsB,mBAAyB,KAAiB,WAAqC;AACnG,QAAO,cAAc,IAAI,MAAM,UAAU"}
1
+ {"version":3,"file":"validators.js","names":[],"sources":["../../src/handlers/validators.ts"],"sourcesContent":["import type { Request } from \"express\";\nimport { ValidationException } from \"@/exceptions/runtime.exceptions\";\nimport { ZodSchema } from \"zod\";\n\nexport async function validateInput<I, S>(data: I, zodSchema: ZodSchema<S>): Promise<S> {\n const result = await zodSchema.safeParseAsync(data);\n\n if (!result.success) {\n throw new ValidationException(result.error);\n }\n return result.data;\n}\n\nexport async function validateMiddleware<I, S>(req: Request<I>, zodSchema: ZodSchema<S>): Promise<S> {\n return validateInput(req.body, zodSchema);\n}\n"],"mappings":";;AAIA,eAAsB,cAAoB,MAAS,WAAqC;CACtF,MAAM,SAAS,MAAM,UAAU,eAAe,KAAK;CAEnD,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,oBAAoB,OAAO,MAAM;CAE7C,OAAO,OAAO;;AAGhB,eAAsB,mBAAyB,KAAiB,WAAqC;CACnG,OAAO,cAAc,IAAI,MAAM,UAAU"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["Logger"],"sources":["../src/index.ts"],"sourcesContent":["import { captureException, flush } from \"@sentry/node\";\nimport { setupEnvConfig } from \"./server.env\";\nimport { setupServer } from \"./server.core\";\nimport { DITokens } from \"./container.tokens\";\nimport { ServerHost } from \"@/server.host\";\nimport { LoggerService as Logger } from \"@/handlers/logger\";\nimport { createStaticLogger } from \"@/handlers/logging/static.logger\";\n\ncreateStaticLogger({ enableFileLogs: true });\nconst logger = new Logger(\"FDM-Environment\");\nlogger.log(\"✓ Parsed environment with (optional) .env file, created static logger\");\n\nsetupEnvConfig();\n\nprocess.on(\"uncaughtException\", (err) => {\n logger.error(\"Uncaught exception\", err);\n});\n\nprocess.on(\"unhandledRejection\", (reason) => {\n logger.error(\"Unhandled promise rejection\", reason);\n});\n\nsetupServer().then(({ httpServer, container }) => {\n container\n .resolve<ServerHost>(DITokens.serverHost)\n .boot(httpServer)\n .catch(async (e: Error) => {\n console.error(\"Server has crashed unintentionally - please report this\", e);\n\n captureException(e);\n await flush(0);\n process.exit(1);\n });\n});\n"],"mappings":";;;;;;;AAQA,mBAAmB,EAAE,gBAAgB,MAAM,CAAC;AAC5C,MAAM,SAAS,IAAIA,cAAO,kBAAkB;AAC5C,OAAO,IAAI,wEAAwE;AAEnF,gBAAgB;AAEhB,QAAQ,GAAG,sBAAsB,QAAQ;AACvC,QAAO,MAAM,sBAAsB,IAAI;EACvC;AAEF,QAAQ,GAAG,uBAAuB,WAAW;AAC3C,QAAO,MAAM,+BAA+B,OAAO;EACnD;AAEF,aAAa,CAAC,MAAM,EAAE,YAAY,gBAAgB;AAChD,WACG,QAAoB,SAAS,WAAW,CACxC,KAAK,WAAW,CAChB,MAAM,OAAO,MAAa;AACzB,UAAQ,MAAM,2DAA2D,EAAE;AAE3E,mBAAiB,EAAE;AACnB,QAAM,MAAM,EAAE;AACd,UAAQ,KAAK,EAAE;GACf;EACJ"}
1
+ {"version":3,"file":"index.js","names":["Logger"],"sources":["../src/index.ts"],"sourcesContent":["import { captureException, flush } from \"@sentry/node\";\nimport { setupEnvConfig } from \"./server.env\";\nimport { setupServer } from \"./server.core\";\nimport { DITokens } from \"./container.tokens\";\nimport { ServerHost } from \"@/server.host\";\nimport { LoggerService as Logger } from \"@/handlers/logger\";\nimport { createStaticLogger } from \"@/handlers/logging/static.logger\";\n\ncreateStaticLogger({ enableFileLogs: true });\nconst logger = new Logger(\"FDM-Environment\");\nlogger.log(\"✓ Parsed environment with (optional) .env file, created static logger\");\n\nsetupEnvConfig();\n\nprocess.on(\"uncaughtException\", (err) => {\n logger.error(\"Uncaught exception\", err);\n});\n\nprocess.on(\"unhandledRejection\", (reason) => {\n logger.error(\"Unhandled promise rejection\", reason);\n});\n\nsetupServer().then(({ httpServer, container }) => {\n container\n .resolve<ServerHost>(DITokens.serverHost)\n .boot(httpServer)\n .catch(async (e: Error) => {\n console.error(\"Server has crashed unintentionally - please report this\", e);\n\n captureException(e);\n await flush(0);\n process.exit(1);\n });\n});\n"],"mappings":";;;;;;;AAQA,mBAAmB,EAAE,gBAAgB,MAAM,CAAC;AAC5C,MAAM,SAAS,IAAIA,cAAO,kBAAkB;AAC5C,OAAO,IAAI,wEAAwE;AAEnF,gBAAgB;AAEhB,QAAQ,GAAG,sBAAsB,QAAQ;CACvC,OAAO,MAAM,sBAAsB,IAAI;EACvC;AAEF,QAAQ,GAAG,uBAAuB,WAAW;CAC3C,OAAO,MAAM,+BAA+B,OAAO;EACnD;AAEF,aAAa,CAAC,MAAM,EAAE,YAAY,gBAAgB;CAChD,UACG,QAAoB,SAAS,WAAW,CACxC,KAAK,WAAW,CAChB,MAAM,OAAO,MAAa;EACzB,QAAQ,MAAM,2DAA2D,EAAE;EAE3E,iBAAiB,EAAE;EACnB,MAAM,MAAM,EAAE;EACd,QAAQ,KAAK,EAAE;GACf;EACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"api-key.strategy.js","names":[],"sources":["../../src/middleware/api-key.strategy.ts"],"sourcesContent":["import { Strategy } from \"passport\";\nimport type { Request } from \"express\";\nimport type { IApiKeyService } from \"@/services/interfaces/api-key.service.interface\";\nimport type { UserDto } from \"@/services/interfaces/user.dto\";\nimport type { RoleName } from \"@/constants/authorization.constants\";\n\n/**\n * Passport strategy for API-key bearer auth. Slotted between JWT and Anonymous\n * so a request with no auth header still falls through to anonymous.\n *\n * Important: we do NOT look up the bound user. The api_key_role join is the\n * sole permission source for the request — keys are self-contained credentials,\n * not user impersonation. `req.user.isApiKey === true` and `req.user.id = -1`\n * are how downstream audit/branching code can detect an api-key principal.\n */\nexport class ApiKeyStrategy extends Strategy {\n name = \"api-key\";\n\n constructor(private readonly apiKeyService: IApiKeyService) {\n super();\n }\n\n async authenticate(req: Request, _options?: any): Promise<void> {\n const header = req.headers.authorization;\n const token = header?.startsWith(\"Bearer \") ? header.slice(\"Bearer \".length) : undefined;\n if (!token || !this.apiKeyService.looksLikeApiKey(token)) {\n return this.pass();\n }\n\n try {\n const apiKey = await this.apiKeyService.verify(token);\n if (!apiKey) {\n return this.fail({ message: \"Invalid API key\" }, 401);\n }\n const principal: UserDto = {\n id: -1,\n username: `api-key:${apiKey.id}`,\n isDemoUser: false,\n isRootUser: false,\n isVerified: true,\n needsPasswordChange: false,\n createdAt: apiKey.createdAt,\n roles: (apiKey.roles ?? []).map((r) => r.name as RoleName),\n isApiKey: true,\n };\n return this.success(principal);\n } catch (err) {\n return this.error(err instanceof Error ? err : new Error(String(err)));\n }\n }\n}\n"],"mappings":";;;;;;;;;;;AAeA,IAAa,iBAAb,cAAoC,SAAS;CAC3C,OAAO;CAEP,YAAY,eAAgD;AAC1D,SAAO;AADoB,OAAA,gBAAA;;CAI7B,MAAM,aAAa,KAAc,UAA+B;EAC9D,MAAM,SAAS,IAAI,QAAQ;EAC3B,MAAM,QAAQ,QAAQ,WAAW,UAAU,GAAG,OAAO,MAAM,EAAiB,GAAG,KAAA;AAC/E,MAAI,CAAC,SAAS,CAAC,KAAK,cAAc,gBAAgB,MAAM,CACtD,QAAO,KAAK,MAAM;AAGpB,MAAI;GACF,MAAM,SAAS,MAAM,KAAK,cAAc,OAAO,MAAM;AACrD,OAAI,CAAC,OACH,QAAO,KAAK,KAAK,EAAE,SAAS,mBAAmB,EAAE,IAAI;GAEvD,MAAM,YAAqB;IACzB,IAAI;IACJ,UAAU,WAAW,OAAO;IAC5B,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,qBAAqB;IACrB,WAAW,OAAO;IAClB,QAAQ,OAAO,SAAS,EAAE,EAAE,KAAK,MAAM,EAAE,KAAiB;IAC1D,UAAU;IACX;AACD,UAAO,KAAK,QAAQ,UAAU;WACvB,KAAK;AACZ,UAAO,KAAK,MAAM,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC,CAAC"}
1
+ {"version":3,"file":"api-key.strategy.js","names":[],"sources":["../../src/middleware/api-key.strategy.ts"],"sourcesContent":["import { Strategy } from \"passport\";\nimport type { Request } from \"express\";\nimport type { IApiKeyService } from \"@/services/interfaces/api-key.service.interface\";\nimport type { UserDto } from \"@/services/interfaces/user.dto\";\nimport type { RoleName } from \"@/constants/authorization.constants\";\n\n/**\n * Passport strategy for API-key bearer auth. Slotted between JWT and Anonymous\n * so a request with no auth header still falls through to anonymous.\n *\n * Important: we do NOT look up the bound user. The api_key_role join is the\n * sole permission source for the request — keys are self-contained credentials,\n * not user impersonation. `req.user.isApiKey === true` and `req.user.id = -1`\n * are how downstream audit/branching code can detect an api-key principal.\n */\nexport class ApiKeyStrategy extends Strategy {\n name = \"api-key\";\n\n constructor(private readonly apiKeyService: IApiKeyService) {\n super();\n }\n\n async authenticate(req: Request, _options?: any): Promise<void> {\n const header = req.headers.authorization;\n const token = header?.startsWith(\"Bearer \") ? header.slice(\"Bearer \".length) : undefined;\n if (!token || !this.apiKeyService.looksLikeApiKey(token)) {\n return this.pass();\n }\n\n try {\n const apiKey = await this.apiKeyService.verify(token);\n if (!apiKey) {\n return this.fail({ message: \"Invalid API key\" }, 401);\n }\n const principal: UserDto = {\n id: -1,\n username: `api-key:${apiKey.id}`,\n isDemoUser: false,\n isRootUser: false,\n isVerified: true,\n needsPasswordChange: false,\n createdAt: apiKey.createdAt,\n roles: (apiKey.roles ?? []).map((r) => r.name as RoleName),\n isApiKey: true,\n };\n return this.success(principal);\n } catch (err) {\n return this.error(err instanceof Error ? err : new Error(String(err)));\n }\n }\n}\n"],"mappings":";;;;;;;;;;;AAeA,IAAa,iBAAb,cAAoC,SAAS;CAC3C,OAAO;CAEP,YAAY,eAAgD;EAC1D,OAAO;EADoB,KAAA,gBAAA;;CAI7B,MAAM,aAAa,KAAc,UAA+B;EAC9D,MAAM,SAAS,IAAI,QAAQ;EAC3B,MAAM,QAAQ,QAAQ,WAAW,UAAU,GAAG,OAAO,MAAM,EAAiB,GAAG,KAAA;EAC/E,IAAI,CAAC,SAAS,CAAC,KAAK,cAAc,gBAAgB,MAAM,EACtD,OAAO,KAAK,MAAM;EAGpB,IAAI;GACF,MAAM,SAAS,MAAM,KAAK,cAAc,OAAO,MAAM;GACrD,IAAI,CAAC,QACH,OAAO,KAAK,KAAK,EAAE,SAAS,mBAAmB,EAAE,IAAI;GAEvD,MAAM,YAAqB;IACzB,IAAI;IACJ,UAAU,WAAW,OAAO;IAC5B,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,qBAAqB;IACrB,WAAW,OAAO;IAClB,QAAQ,OAAO,SAAS,EAAE,EAAE,KAAK,MAAM,EAAE,KAAiB;IAC1D,UAAU;IACX;GACD,OAAO,KAAK,QAAQ,UAAU;WACvB,KAAK;GACZ,OAAO,KAAK,MAAM,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC,CAAC"}