@fdm-monster/server 2.0.11 → 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.
- package/.yarn/install-state.gz +0 -0
- package/.yarn/releases/{yarn-4.13.0.cjs → yarn-4.14.1.cjs} +288 -288
- package/.yarnrc.yml +5 -1
- package/README.md +2 -1
- package/RELEASE_NOTES.MD +153 -2
- package/dist/_virtual/{_@oxc-project_runtime@0.127.0 → _@oxc-project_runtime@0.129.0}/helpers/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.127.0 → _@oxc-project_runtime@0.129.0}/helpers/decorateMetadata.js +1 -1
- package/dist/_virtual/_virtual_controllers.js +2 -0
- package/dist/consoles/typeorm-create.js.map +1 -1
- package/dist/consoles/typeorm-generate.js.map +1 -1
- package/dist/consoles/typeorm-migrate.js.map +1 -1
- package/dist/constants/authorization.constants.js.map +1 -1
- package/dist/container.js +2 -0
- package/dist/container.js.map +1 -1
- package/dist/container.tokens.js +1 -0
- package/dist/container.tokens.js.map +1 -1
- package/dist/controllers/api-key.controller.js +72 -0
- package/dist/controllers/api-key.controller.js.map +1 -0
- package/dist/controllers/auth.controller.js +6 -4
- package/dist/controllers/auth.controller.js.map +1 -1
- package/dist/controllers/batch-call.controller.js +2 -2
- package/dist/controllers/batch-call.controller.js.map +1 -1
- package/dist/controllers/camera-stream.controller.js +2 -2
- package/dist/controllers/camera-stream.controller.js.map +1 -1
- package/dist/controllers/file-storage.controller.js +2 -2
- package/dist/controllers/file-storage.controller.js.map +1 -1
- package/dist/controllers/first-time-setup.controller.js +2 -2
- package/dist/controllers/first-time-setup.controller.js.map +1 -1
- package/dist/controllers/floor.controller.js +2 -2
- package/dist/controllers/floor.controller.js.map +1 -1
- package/dist/controllers/metrics.controller.js +2 -2
- package/dist/controllers/metrics.controller.js.map +1 -1
- package/dist/controllers/print-job.controller.js +2 -2
- package/dist/controllers/print-job.controller.js.map +1 -1
- package/dist/controllers/print-queue.controller.js +2 -2
- package/dist/controllers/print-queue.controller.js.map +1 -1
- package/dist/controllers/printer-files.controller.js +2 -2
- package/dist/controllers/printer-files.controller.js.map +1 -1
- package/dist/controllers/printer-maintenance-log.controller.js +2 -2
- package/dist/controllers/printer-maintenance-log.controller.js.map +1 -1
- package/dist/controllers/printer-settings.controller.js +2 -2
- package/dist/controllers/printer-settings.controller.js.map +1 -1
- package/dist/controllers/printer-tag.controller.js +2 -2
- package/dist/controllers/printer-tag.controller.js.map +1 -1
- package/dist/controllers/printer.controller.js +2 -2
- package/dist/controllers/printer.controller.js.map +1 -1
- package/dist/controllers/server-private.controller.js +2 -2
- package/dist/controllers/server-private.controller.js.map +1 -1
- package/dist/controllers/server-public.controller.js +2 -2
- package/dist/controllers/server-public.controller.js.map +1 -1
- package/dist/controllers/settings.controller.js +2 -2
- package/dist/controllers/settings.controller.js.map +1 -1
- package/dist/controllers/slicer-compat.controller.js +2 -2
- package/dist/controllers/slicer-compat.controller.js.map +1 -1
- package/dist/controllers/user.controller.js +2 -2
- package/dist/controllers/user.controller.js.map +1 -1
- package/dist/controllers/validation/api-key-controller.validation.js +11 -0
- package/dist/controllers/validation/api-key-controller.validation.js.map +1 -0
- package/dist/data-source.js +6 -2
- package/dist/data-source.js.map +1 -1
- package/dist/entities/api-key.entity.js +60 -0
- package/dist/entities/api-key.entity.js.map +1 -0
- package/dist/entities/camera-stream.entity.js +2 -2
- package/dist/entities/floor-position.entity.js +2 -2
- package/dist/entities/floor.entity.js +2 -2
- package/dist/entities/index.js +2 -1
- package/dist/entities/print-job.entity.js +2 -2
- package/dist/entities/printer-maintenance-log.entity.js +2 -2
- package/dist/entities/printer-tag.entity.js +2 -2
- package/dist/entities/printer.entity.js +2 -2
- package/dist/entities/refresh-token.entity.js +2 -2
- package/dist/entities/role.entity.js +2 -2
- package/dist/entities/settings.entity.js +2 -2
- package/dist/entities/tag.entity.js +2 -2
- package/dist/entities/user-role.entity.js +2 -2
- package/dist/entities/user.entity.js +2 -2
- package/dist/exceptions/failed-dependency.exception.js.map +1 -1
- package/dist/exceptions/job.exceptions.js.map +1 -1
- package/dist/exceptions/runtime.exceptions.js.map +1 -1
- package/dist/handlers/event-emitter.js.map +1 -1
- package/dist/handlers/logger-factory.js.map +1 -1
- package/dist/handlers/logger.js.map +1 -1
- package/dist/handlers/logging/file-logging.transport.js +1 -2
- package/dist/handlers/logging/file-logging.transport.js.map +1 -1
- package/dist/handlers/logging/loki-logging.transport.js.map +1 -1
- package/dist/handlers/logging/static.logger.js.map +1 -1
- package/dist/handlers/validators.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/api-key.strategy.js +45 -0
- package/dist/middleware/api-key.strategy.js.map +1 -0
- package/dist/middleware/authenticate.js.map +1 -1
- package/dist/middleware/database.js.map +1 -1
- package/dist/middleware/demo.middleware.js.map +1 -1
- package/dist/middleware/exception.filter.js.map +1 -1
- package/dist/middleware/global.middleware.js.map +1 -1
- package/dist/middleware/param-converter.middleware.js.map +1 -1
- package/dist/middleware/passport.js +3 -0
- package/dist/middleware/passport.js.map +1 -1
- package/dist/middleware/printer-resolver.js.map +1 -1
- package/dist/middleware/printer.js.map +1 -1
- package/dist/middleware/slicer-api-key.middleware.js.map +1 -1
- package/dist/middleware/socketio.middleware.js.map +1 -1
- package/dist/migrations/1706829146617-InitSqlite.js.map +1 -1
- package/dist/migrations/1707494762198-PrinterGroup.js.map +1 -1
- package/dist/migrations/1708465930665-ChangePrintCompletionDeletePrinterCascade.js.map +1 -1
- package/dist/migrations/1713300747465-ChangeRoleNameUnique.js.map +1 -1
- package/dist/migrations/1713897879622-AddPrinterType.js.map +1 -1
- package/dist/migrations/1720338804844-RemovePrinterFile.js.map +1 -1
- package/dist/migrations/1745141688926-AddPrinterUsernamePassword.js.map +1 -1
- package/dist/migrations/1766576698569-DropPermissions.js.map +1 -1
- package/dist/migrations/1767278216516-ChangeCameraPrinterOnDeleteSetNull.js.map +1 -1
- package/dist/migrations/1767279607392-DropCustomGcode.js.map +1 -1
- package/dist/migrations/1767291804417-DropPrintCompletions.js.map +1 -1
- package/dist/migrations/1767352862576-DropSettingsFileClean.js.map +1 -1
- package/dist/migrations/1767355639023-ChangeFloorLevelToOrder.js.map +1 -1
- package/dist/migrations/1767370191762-ChangeFloorNonUniqueOrder.js.map +1 -1
- package/dist/migrations/1767432108916-RenameGroupToTag.js.map +1 -1
- package/dist/migrations/1767451444137-AddPrintJob.js.map +1 -1
- package/dist/migrations/1767909428129-AddPrinterMaintenanceLog.js.map +1 -1
- package/dist/migrations/1778446203015-AddApiKey.js +49 -0
- package/dist/migrations/1778446203015-AddApiKey.js.map +1 -0
- package/dist/plugins/controllers-plugin.js.map +1 -1
- package/dist/server.constants.js +2 -1
- package/dist/server.constants.js.map +1 -1
- package/dist/server.core.js +6 -2
- package/dist/server.core.js.map +1 -1
- package/dist/server.env.js.map +1 -1
- package/dist/server.host.js.map +1 -1
- package/dist/services/authentication/auth.service.js.map +1 -1
- package/dist/services/authentication/jwt.service.js.map +1 -1
- package/dist/services/bambu/bambu-ftp.adapter.js.map +1 -1
- package/dist/services/bambu/bambu-mqtt.adapter.js.map +1 -1
- package/dist/services/bambu/bambu.client.js.map +1 -1
- package/dist/services/bambu.api.js.map +1 -1
- package/dist/services/core/batch-call.service.js.map +1 -1
- package/dist/services/core/client-bundle.service.js.map +1 -1
- package/dist/services/core/config.service.js +4 -0
- package/dist/services/core/config.service.js.map +1 -1
- package/dist/services/core/cradle.service.js.map +1 -1
- package/dist/services/core/github.service.js.map +1 -1
- package/dist/services/core/http-client.factory.js.map +1 -1
- package/dist/services/core/logs-manager.service.js.map +1 -1
- package/dist/services/core/monsterpi.service.js.map +1 -1
- package/dist/services/core/multer.service.js.map +1 -1
- package/dist/services/core/server-release.service.js.map +1 -1
- package/dist/services/core/yaml.service.js.map +1 -1
- package/dist/services/file-analysis.service.js.map +1 -1
- package/dist/services/file-storage.service.js.map +1 -1
- package/dist/services/interfaces/api-key.dto.js +19 -0
- package/dist/services/interfaces/api-key.dto.js.map +1 -0
- package/dist/services/interfaces/api-key.service.interface.js +1 -0
- package/dist/services/interfaces/user.dto.js +2 -0
- package/dist/services/interfaces/user.dto.js.map +1 -1
- package/dist/services/moonraker/moonraker-websocket.adapter.js.map +1 -1
- package/dist/services/moonraker/moonraker.client.js.map +1 -1
- package/dist/services/moonraker.api.js.map +1 -1
- package/dist/services/octoprint/octoprint-api.routes.js.map +1 -1
- package/dist/services/octoprint/octoprint-websocket.adapter.js.map +1 -1
- package/dist/services/octoprint/octoprint.client.js.map +1 -1
- package/dist/services/octoprint/utils/api.utils.js.map +1 -1
- package/dist/services/octoprint/utils/file.utils.js.map +1 -1
- package/dist/services/octoprint/utils/octoprint-http-client.builder.js.map +1 -1
- package/dist/services/octoprint.api.js.map +1 -1
- package/dist/services/orm/api-key.service.js +90 -0
- package/dist/services/orm/api-key.service.js.map +1 -0
- package/dist/services/orm/base.service.js.map +1 -1
- package/dist/services/orm/camera-stream.service.js.map +1 -1
- package/dist/services/orm/floor-position.service.js.map +1 -1
- package/dist/services/orm/floor.service.js.map +1 -1
- package/dist/services/orm/permission.service.js.map +1 -1
- package/dist/services/orm/print-job.service.js.map +1 -1
- package/dist/services/orm/printer-maintenance-log.service.js.map +1 -1
- package/dist/services/orm/printer-tag.service.js.map +1 -1
- package/dist/services/orm/printer.service.js.map +1 -1
- package/dist/services/orm/refresh-token.service.js.map +1 -1
- package/dist/services/orm/role.service.js.map +1 -1
- package/dist/services/orm/settings.service.js.map +1 -1
- package/dist/services/orm/user-role.service.js.map +1 -1
- package/dist/services/orm/user.service.js.map +1 -1
- package/dist/services/print-file-downloader.service.js.map +1 -1
- package/dist/services/print-queue.service.js.map +1 -1
- package/dist/services/printer-api.factory.js.map +1 -1
- package/dist/services/printer-api.interface.js.map +1 -1
- package/dist/services/prusa-link/prusa-link-http-polling.adapter.js.map +1 -1
- package/dist/services/prusa-link/prusa-link.api.js.map +1 -1
- package/dist/services/prusa-link/utils/digest-auth.util.js +19 -12
- package/dist/services/prusa-link/utils/digest-auth.util.js.map +1 -1
- package/dist/services/prusa-link/utils/prusa-link-http-client.builder.js +45 -11
- package/dist/services/prusa-link/utils/prusa-link-http-client.builder.js.map +1 -1
- package/dist/services/socket.factory.js.map +1 -1
- package/dist/services/task-manager.service.js.map +1 -1
- package/dist/services/typeorm/typeorm.service.js.map +1 -1
- package/dist/services/validators/printer-service.validation.js.map +1 -1
- package/dist/shared/default-http-client.builder.js.map +1 -1
- package/dist/shared/load-controllers.js.map +1 -1
- package/dist/shared/runtime-settings.migration.js.map +1 -1
- package/dist/shared/websocket-rpc-extended.adapter.js.map +1 -1
- package/dist/shared/websocket.adapter.js.map +1 -1
- package/dist/state/file-upload-tracker.cache.js.map +1 -1
- package/dist/state/floor.store.js.map +1 -1
- package/dist/state/printer-events.cache.js.map +1 -1
- package/dist/state/printer-socket.store.js.map +1 -1
- package/dist/state/printer-thumbnail.cache.js.map +1 -1
- package/dist/state/printer.cache.js.map +1 -1
- package/dist/state/settings.store.js.map +1 -1
- package/dist/state/socket-io.gateway.js.map +1 -1
- package/dist/state/test-printer-socket.store.js.map +1 -1
- package/dist/tasks/boot.task.js.map +1 -1
- package/dist/tasks/client-bundle.task.js.map +1 -1
- package/dist/tasks/print-job-analysis.task.js.map +1 -1
- package/dist/tasks/printer-websocket-restore.task.js.map +1 -1
- package/dist/tasks/printer-websocket.task.js.map +1 -1
- package/dist/tasks/socketio.task.js.map +1 -1
- package/dist/tasks/software-update.task.js.map +1 -1
- package/dist/tasks.js.map +1 -1
- package/dist/utils/array.util.js.map +1 -1
- package/dist/utils/bgcode/bgcode-thumbnail.parser.js.map +1 -1
- package/dist/utils/bgcode/bgcode.utils.js.map +1 -1
- package/dist/utils/bgcode/heatshrink-decoder.js.map +1 -1
- package/dist/utils/bgcode/png-encoder.js.map +1 -1
- package/dist/utils/bgcode/qoi-decoder.js.map +1 -1
- package/dist/utils/cache/key-diff.cache.js.map +1 -1
- package/dist/utils/correlation-token.util.js.map +1 -1
- package/dist/utils/crypto.utils.js.map +1 -1
- package/dist/utils/env.utils.js.map +1 -1
- package/dist/utils/error.utils.js.map +1 -1
- package/dist/utils/fs.utils.js.map +1 -1
- package/dist/utils/gcode.utils.js.map +1 -1
- package/dist/utils/image-dimensions.js.map +1 -1
- package/dist/utils/job-stats.util.js.map +1 -1
- package/dist/utils/normalize-url.js.map +1 -1
- package/dist/utils/parsers/3mf.parser.js.map +1 -1
- package/dist/utils/parsers/bgcode.parser.js.map +1 -1
- package/dist/utils/parsers/gcode.parser.js.map +1 -1
- package/dist/utils/pretty-print.utils.js.map +1 -1
- package/dist/utils/semver.utils.js.map +1 -1
- package/dist/utils/swagger/decorators.js.map +1 -1
- package/dist/utils/swagger/generator.js.map +1 -1
- package/dist/utils/swagger/swagger.js.map +1 -1
- package/dist/utils/thumbnail.util.js.map +1 -1
- package/dist/utils/time.utils.js.map +1 -1
- package/dist/utils/url.utils.js.map +1 -1
- package/package.json +17 -14
- package/packages/consoles/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.controller.js","names":[],"sources":["../../src/controllers/auth.controller.ts"],"sourcesContent":["import { before, GET, POST, route } from \"awilix-express\";\nimport { BadRequestException } from \"@/exceptions/runtime.exceptions\";\nimport { AppConstants } from \"@/server.constants\";\nimport { refreshTokenSchema } from \"./validation/auth-controller.validation\";\nimport { authenticate } from \"@/middleware/authenticate\";\nimport { SettingsStore } from \"@/state/settings.store\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport type { Request, Response } from \"express\";\nimport type { IUserService } from \"@/services/interfaces/user-service.interface\";\nimport type { IAuthService } from \"@/services/interfaces/auth.service.interface\";\nimport type { IRoleService } from \"@/services/interfaces/role-service.interface\";\nimport { demoUserNotAllowed } from \"@/middleware/demo.middleware\";\nimport type { IConfigService } from \"@/services/core/config.service\";\nimport { registerUserSchema } from \"@/controllers/validation/user-controller.validation\";\nimport { validateMiddleware } from \"@/handlers/validators\";\n\n@route(AppConstants.apiRoute + \"/auth\")\nexport class AuthController {\n logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly authService: IAuthService,\n private readonly settingsStore: SettingsStore,\n private readonly userService: IUserService,\n private readonly roleService: IRoleService,\n private readonly configService: IConfigService,\n ) {\n this.logger = loggerFactory(AuthController.name);\n }\n\n @POST()\n @route(\"/login\")\n async login(req: Request, res: Response) {\n this.logger.debug(`Login attempt from IP ${req.ip} and user-agent ${req.headers[\"user-agent\"]}`);\n const tokens = await this.authService.loginUser(req.body.username, req.body.password);\n return res.send(tokens);\n }\n\n @GET()\n @route(\"/login-required\")\n async getLoginRequired(req: Request, res: Response) {\n const loginRequired = await this.settingsStore.getLoginRequired();\n const registration = this.settingsStore.isRegistrationEnabled();\n let wizardState = this.settingsStore.getWizardState();\n const isDemoMode = this.configService.isDemoMode();\n wizardState = {\n ...wizardState,\n wizardCompleted: isDemoMode ? true : wizardState.wizardCompleted,\n };\n res.send({ loginRequired, registration, wizardState, isDemoMode });\n }\n\n @POST()\n @route(\"/verify\")\n @before([authenticate()])\n async verifyLogin(req: Request, res: Response) {\n return res.send({ success: true });\n }\n\n @POST()\n @route(\"/needs-password-change\")\n async needsPasswordChange(req: Request, res: Response) {\n const registration = this.settingsStore.isRegistrationEnabled();\n const isLoginRequired = await this.settingsStore.getLoginRequired();\n if (!isLoginRequired) {\n return res.send({\n loginRequired: isLoginRequired,\n registration,\n needsPasswordChange: false,\n authenticated: true,\n });\n }\n\n if (req.isAuthenticated()) {\n return res.send({\n loginRequired: isLoginRequired,\n registration,\n needsPasswordChange: req.user?.needsPasswordChange,\n authenticated: true,\n });\n }\n\n return res.send({\n loginRequired: isLoginRequired,\n needsPasswordChange: null,\n authenticated: false,\n });\n }\n\n @POST()\n @route(\"/refresh\")\n async refreshLogin(req: Request, res: Response) {\n const { refreshToken } = await validateMiddleware(req, refreshTokenSchema);\n this.logger.debug(`Refresh login attempt from IP ${req.ip} and user-agent ${req.headers[\"user-agent\"]}`);\n const idToken = await this.authService.renewLoginByRefreshToken(refreshToken);\n return res.send({ token: idToken });\n }\n\n @POST()\n @route(\"/logout\")\n @before([authenticate()])\n async logout(req: Request, res: Response) {\n const isLoginRequired = await this.settingsStore.getLoginRequired();\n if (!isLoginRequired) {\n return res.end();\n }\n\n // Get token from header\n const jwtToken = req.headers.authorization?.replace(\"Bearer \", \"\") || undefined;\n const userId = req.user!.id;\n await this.authService.logoutUserId(userId, jwtToken);\n res.end();\n }\n\n @POST()\n @route(\"/register\")\n @before([demoUserNotAllowed])\n async register(req: Request, res: Response) {\n let registrationEnabled = this.settingsStore.isRegistrationEnabled();\n if (!registrationEnabled) {\n throw new BadRequestException(\"Registration is disabled. Cant register user\");\n }\n const { username, password } = await validateMiddleware(req, registerUserSchema);\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 const roles = await this.roleService.getAppDefaultRoleNames();\n const result = 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: false,\n });\n const userDto = this.userService.toDto(result);\n res.send(userDto);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAkBO,IAAA,iBAAA,kBAAA,MAAM,eAAe;CAC1B;CAEA,YACE,eACA,aACA,eACA,aACA,aACA,eACA;
|
|
1
|
+
{"version":3,"file":"auth.controller.js","names":[],"sources":["../../src/controllers/auth.controller.ts"],"sourcesContent":["import { before, GET, POST, route } from \"awilix-express\";\nimport { BadRequestException } from \"@/exceptions/runtime.exceptions\";\nimport { AppConstants } from \"@/server.constants\";\nimport { refreshTokenSchema } from \"./validation/auth-controller.validation\";\nimport { authenticate } from \"@/middleware/authenticate\";\nimport { SettingsStore } from \"@/state/settings.store\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport type { Request, Response } from \"express\";\nimport type { IUserService } from \"@/services/interfaces/user-service.interface\";\nimport type { IAuthService } from \"@/services/interfaces/auth.service.interface\";\nimport type { IRoleService } from \"@/services/interfaces/role-service.interface\";\nimport { demoUserNotAllowed } from \"@/middleware/demo.middleware\";\nimport type { IConfigService } from \"@/services/core/config.service\";\nimport { registerUserSchema } from \"@/controllers/validation/user-controller.validation\";\nimport { validateMiddleware } from \"@/handlers/validators\";\n\n@route(AppConstants.apiRoute + \"/auth\")\nexport class AuthController {\n logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly authService: IAuthService,\n private readonly settingsStore: SettingsStore,\n private readonly userService: IUserService,\n private readonly roleService: IRoleService,\n private readonly configService: IConfigService,\n ) {\n this.logger = loggerFactory(AuthController.name);\n }\n\n @POST()\n @route(\"/login\")\n async login(req: Request, res: Response) {\n this.logger.debug(`Login attempt from IP ${req.ip} and user-agent ${req.headers[\"user-agent\"]}`);\n const tokens = await this.authService.loginUser(req.body.username, req.body.password);\n return res.send(tokens);\n }\n\n @GET()\n @route(\"/login-required\")\n async getLoginRequired(req: Request, res: Response) {\n const loginRequired = await this.settingsStore.getLoginRequired();\n const registration = this.settingsStore.isRegistrationEnabled();\n let wizardState = this.settingsStore.getWizardState();\n const isDemoMode = this.configService.isDemoMode();\n const instanceLabel = this.configService.instanceLabel();\n wizardState = {\n ...wizardState,\n wizardCompleted: isDemoMode ? true : wizardState.wizardCompleted,\n };\n res.send({ loginRequired, registration, wizardState, isDemoMode, instanceLabel });\n }\n\n @POST()\n @route(\"/verify\")\n @before([authenticate()])\n async verifyLogin(req: Request, res: Response) {\n return res.send({ success: true });\n }\n\n @POST()\n @route(\"/needs-password-change\")\n async needsPasswordChange(req: Request, res: Response) {\n const registration = this.settingsStore.isRegistrationEnabled();\n const isLoginRequired = await this.settingsStore.getLoginRequired();\n if (!isLoginRequired) {\n return res.send({\n loginRequired: isLoginRequired,\n registration,\n needsPasswordChange: false,\n authenticated: true,\n });\n }\n\n if (req.isAuthenticated()) {\n return res.send({\n loginRequired: isLoginRequired,\n registration,\n needsPasswordChange: req.user?.needsPasswordChange,\n authenticated: true,\n });\n }\n\n return res.send({\n loginRequired: isLoginRequired,\n needsPasswordChange: null,\n authenticated: false,\n });\n }\n\n @POST()\n @route(\"/refresh\")\n async refreshLogin(req: Request, res: Response) {\n const { refreshToken } = await validateMiddleware(req, refreshTokenSchema);\n this.logger.debug(`Refresh login attempt from IP ${req.ip} and user-agent ${req.headers[\"user-agent\"]}`);\n const idToken = await this.authService.renewLoginByRefreshToken(refreshToken);\n return res.send({ token: idToken });\n }\n\n @POST()\n @route(\"/logout\")\n @before([authenticate()])\n async logout(req: Request, res: Response) {\n const isLoginRequired = await this.settingsStore.getLoginRequired();\n if (!isLoginRequired) {\n return res.end();\n }\n\n // Get token from header\n const jwtToken = req.headers.authorization?.replace(\"Bearer \", \"\") || undefined;\n const userId = req.user!.id;\n await this.authService.logoutUserId(userId, jwtToken);\n res.end();\n }\n\n @POST()\n @route(\"/register\")\n @before([demoUserNotAllowed])\n async register(req: Request, res: Response) {\n let registrationEnabled = this.settingsStore.isRegistrationEnabled();\n if (!registrationEnabled) {\n throw new BadRequestException(\"Registration is disabled. Cant register user\");\n }\n const { username, password } = await validateMiddleware(req, registerUserSchema);\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 const roles = await this.roleService.getAppDefaultRoleNames();\n const result = 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: false,\n });\n const userDto = this.userService.toDto(result);\n res.send(userDto);\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.
|
|
3
|
-
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.
|
|
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 { validateInput } from "../handlers/validators.js";
|
|
5
5
|
import { AppConstants } from "../server.constants.js";
|
|
6
6
|
import { ROLES } from "../constants/authorization.constants.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-call.controller.js","names":[],"sources":["../../src/controllers/batch-call.controller.ts"],"sourcesContent":["import { before, POST, route } from \"awilix-express\";\nimport { validateInput } from \"@/handlers/validators\";\nimport {\n batchPrinterSchema,\n batchPrintersEnabledSchema,\n executeBatchRePrinterSchema,\n} from \"./validation/batch-controller.validation\";\nimport { AppConstants } from \"@/server.constants\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { BatchCallService } from \"@/services/core/batch-call.service\";\nimport type { Request, Response } from \"express\";\n\n@route(AppConstants.apiRoute + \"/batch\")\n@before([authenticate(), authorizeRoles([ROLES.ADMIN, ROLES.OPERATOR])])\nexport class BatchCallController {\n constructor(private readonly batchCallService: BatchCallService) {}\n\n @POST()\n @route(\"/connect/usb\")\n async batchConnectUsb(req: Request, res: Response) {\n const { printerIds } = await validateInput(req.body, batchPrinterSchema);\n const results = await this.batchCallService.batchConnectUsb(printerIds);\n res.send(results);\n }\n\n @POST()\n @route(\"/connect/socket\")\n async batchConnectSocket(req: Request, res: Response) {\n const { printerIds } = await validateInput(req.body, batchPrinterSchema);\n this.batchCallService.batchConnectSocket(printerIds);\n res.send({});\n }\n\n @POST()\n @route(\"/reprint/list\")\n async getLastPrintedFiles(req: Request, res: Response) {\n const { printerIds } = await validateInput(req.body, batchPrinterSchema);\n const files = await this.batchCallService.getBatchPrinterReprintFile(printerIds);\n res.send(files);\n }\n\n @POST()\n @route(\"/reprint/execute\")\n async batchReprintFiles(req: Request, res: Response) {\n const { prints } = await validateInput(req.body, executeBatchRePrinterSchema);\n const files = await this.batchCallService.batchReprintCalls(prints);\n res.send(files);\n }\n\n @POST()\n @route(\"/toggle-enabled\")\n async batchTogglePrintersEnabled(req: Request, res: Response) {\n const { printerIds, enabled } = await validateInput(req.body, batchPrintersEnabledSchema);\n const results = await this.batchCallService.batchTogglePrintersEnabled(printerIds, enabled);\n res.send(results);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAeO,IAAA,sBAAA,MAAM,oBAAoB;CAC/B,YAAY,kBAAqD;
|
|
1
|
+
{"version":3,"file":"batch-call.controller.js","names":[],"sources":["../../src/controllers/batch-call.controller.ts"],"sourcesContent":["import { before, POST, route } from \"awilix-express\";\nimport { validateInput } from \"@/handlers/validators\";\nimport {\n batchPrinterSchema,\n batchPrintersEnabledSchema,\n executeBatchRePrinterSchema,\n} from \"./validation/batch-controller.validation\";\nimport { AppConstants } from \"@/server.constants\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { BatchCallService } from \"@/services/core/batch-call.service\";\nimport type { Request, Response } from \"express\";\n\n@route(AppConstants.apiRoute + \"/batch\")\n@before([authenticate(), authorizeRoles([ROLES.ADMIN, ROLES.OPERATOR])])\nexport class BatchCallController {\n constructor(private readonly batchCallService: BatchCallService) {}\n\n @POST()\n @route(\"/connect/usb\")\n async batchConnectUsb(req: Request, res: Response) {\n const { printerIds } = await validateInput(req.body, batchPrinterSchema);\n const results = await this.batchCallService.batchConnectUsb(printerIds);\n res.send(results);\n }\n\n @POST()\n @route(\"/connect/socket\")\n async batchConnectSocket(req: Request, res: Response) {\n const { printerIds } = await validateInput(req.body, batchPrinterSchema);\n this.batchCallService.batchConnectSocket(printerIds);\n res.send({});\n }\n\n @POST()\n @route(\"/reprint/list\")\n async getLastPrintedFiles(req: Request, res: Response) {\n const { printerIds } = await validateInput(req.body, batchPrinterSchema);\n const files = await this.batchCallService.getBatchPrinterReprintFile(printerIds);\n res.send(files);\n }\n\n @POST()\n @route(\"/reprint/execute\")\n async batchReprintFiles(req: Request, res: Response) {\n const { prints } = await validateInput(req.body, executeBatchRePrinterSchema);\n const files = await this.batchCallService.batchReprintCalls(prints);\n res.send(files);\n }\n\n @POST()\n @route(\"/toggle-enabled\")\n async batchTogglePrintersEnabled(req: Request, res: Response) {\n const { printerIds, enabled } = await validateInput(req.body, batchPrintersEnabledSchema);\n const results = await this.batchCallService.batchTogglePrintersEnabled(printerIds, enabled);\n res.send(results);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAeO,IAAA,sBAAA,MAAM,oBAAoB;CAC/B,YAAY,kBAAqD;EAApC,KAAA,mBAAA;;CAE7B,MAEM,gBAAgB,KAAc,KAAe;EACjD,MAAM,EAAE,eAAe,MAAM,cAAc,IAAI,MAAM,mBAAmB;EACxE,MAAM,UAAU,MAAM,KAAK,iBAAiB,gBAAgB,WAAW;EACvE,IAAI,KAAK,QAAQ;;CAGnB,MAEM,mBAAmB,KAAc,KAAe;EACpD,MAAM,EAAE,eAAe,MAAM,cAAc,IAAI,MAAM,mBAAmB;EACxE,KAAK,iBAAiB,mBAAmB,WAAW;EACpD,IAAI,KAAK,EAAE,CAAC;;CAGd,MAEM,oBAAoB,KAAc,KAAe;EACrD,MAAM,EAAE,eAAe,MAAM,cAAc,IAAI,MAAM,mBAAmB;EACxE,MAAM,QAAQ,MAAM,KAAK,iBAAiB,2BAA2B,WAAW;EAChF,IAAI,KAAK,MAAM;;CAGjB,MAEM,kBAAkB,KAAc,KAAe;EACnD,MAAM,EAAE,WAAW,MAAM,cAAc,IAAI,MAAM,4BAA4B;EAC7E,MAAM,QAAQ,MAAM,KAAK,iBAAiB,kBAAkB,OAAO;EACnE,IAAI,KAAK,MAAM;;CAGjB,MAEM,2BAA2B,KAAc,KAAe;EAC5D,MAAM,EAAE,YAAY,YAAY,MAAM,cAAc,IAAI,MAAM,2BAA2B;EACzF,MAAM,UAAU,MAAM,KAAK,iBAAiB,2BAA2B,YAAY,QAAQ;EAC3F,IAAI,KAAK,QAAQ;;;;CArClB,MAAM;CACN,MAAM,eAAe;;;;;;CAOrB,MAAM;CACN,MAAM,kBAAkB;;;;;;CAOxB,MAAM;CACN,MAAM,gBAAgB;;;;;;CAOtB,MAAM;CACN,MAAM,mBAAmB;;;;;;CAOzB,MAAM;CACN,MAAM,kBAAkB;;;;;;CAtC1B,MAAM,aAAa,WAAW,SAAS;CACvC,OAAO,CAAC,cAAc,EAAE,eAAe,CAAC,MAAM,OAAO,MAAM,SAAS,CAAC,CAAC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
-
import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.
|
|
3
|
-
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.
|
|
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 { ROLES } from "../constants/authorization.constants.js";
|
|
6
6
|
import { authenticate, authorizeRoles } from "../middleware/authenticate.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"camera-stream.controller.js","names":[],"sources":["../../src/controllers/camera-stream.controller.ts"],"sourcesContent":["import { route, GET, POST, PUT, DELETE, before } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport type { Request, Response } from \"express\";\nimport type { ICameraStreamService } from \"@/services/interfaces/camera-stream.service.interface\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\n\n@route(`${AppConstants.apiRoute}/camera-stream`)\n@before([authenticate(), authorizeRoles([ROLES.OPERATOR, ROLES.ADMIN])])\nexport class CameraStreamController {\n constructor(private readonly cameraStreamService: ICameraStreamService) {}\n @GET()\n @route(\"/\")\n async list(req: Request, res: Response) {\n const result = await this.cameraStreamService.list();\n res.send(result.map((item) => this.cameraStreamService.toDto(item)));\n }\n\n @GET()\n @route(\"/:id\")\n @before([ParamId(\"id\")])\n async get(req: Request, res: Response) {\n const result = await this.cameraStreamService.get(req.local.id);\n res.send(this.cameraStreamService.toDto(result));\n }\n\n @POST()\n @route(\"/\")\n async create(req: Request, res: Response) {\n const result = await this.cameraStreamService.create(req.body);\n res.send(this.cameraStreamService.toDto(result));\n }\n\n @PUT()\n @route(\"/:id\")\n @before([ParamId(\"id\")])\n async update(req: Request, res: Response) {\n const result = await this.cameraStreamService.update(req.local.id, req.body);\n res.send(this.cameraStreamService.toDto(result));\n }\n\n @DELETE()\n @route(\"/:id\")\n @before([ParamId(\"id\")])\n async delete(req: Request, res: Response) {\n await this.cameraStreamService.delete(req.local.id);\n res.send();\n }\n}\n"],"mappings":";;;;;;;;;;AAUO,IAAA,yBAAA,MAAM,uBAAuB;CAClC,YAAY,qBAA4D;
|
|
1
|
+
{"version":3,"file":"camera-stream.controller.js","names":[],"sources":["../../src/controllers/camera-stream.controller.ts"],"sourcesContent":["import { route, GET, POST, PUT, DELETE, before } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport type { Request, Response } from \"express\";\nimport type { ICameraStreamService } from \"@/services/interfaces/camera-stream.service.interface\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\n\n@route(`${AppConstants.apiRoute}/camera-stream`)\n@before([authenticate(), authorizeRoles([ROLES.OPERATOR, ROLES.ADMIN])])\nexport class CameraStreamController {\n constructor(private readonly cameraStreamService: ICameraStreamService) {}\n @GET()\n @route(\"/\")\n async list(req: Request, res: Response) {\n const result = await this.cameraStreamService.list();\n res.send(result.map((item) => this.cameraStreamService.toDto(item)));\n }\n\n @GET()\n @route(\"/:id\")\n @before([ParamId(\"id\")])\n async get(req: Request, res: Response) {\n const result = await this.cameraStreamService.get(req.local.id);\n res.send(this.cameraStreamService.toDto(result));\n }\n\n @POST()\n @route(\"/\")\n async create(req: Request, res: Response) {\n const result = await this.cameraStreamService.create(req.body);\n res.send(this.cameraStreamService.toDto(result));\n }\n\n @PUT()\n @route(\"/:id\")\n @before([ParamId(\"id\")])\n async update(req: Request, res: Response) {\n const result = await this.cameraStreamService.update(req.local.id, req.body);\n res.send(this.cameraStreamService.toDto(result));\n }\n\n @DELETE()\n @route(\"/:id\")\n @before([ParamId(\"id\")])\n async delete(req: Request, res: Response) {\n await this.cameraStreamService.delete(req.local.id);\n res.send();\n }\n}\n"],"mappings":";;;;;;;;;;AAUO,IAAA,yBAAA,MAAM,uBAAuB;CAClC,YAAY,qBAA4D;EAA3C,KAAA,sBAAA;;CAC7B,MAEM,KAAK,KAAc,KAAe;EACtC,MAAM,SAAS,MAAM,KAAK,oBAAoB,MAAM;EACpD,IAAI,KAAK,OAAO,KAAK,SAAS,KAAK,oBAAoB,MAAM,KAAK,CAAC,CAAC;;CAGtE,MAGM,IAAI,KAAc,KAAe;EACrC,MAAM,SAAS,MAAM,KAAK,oBAAoB,IAAI,IAAI,MAAM,GAAG;EAC/D,IAAI,KAAK,KAAK,oBAAoB,MAAM,OAAO,CAAC;;CAGlD,MAEM,OAAO,KAAc,KAAe;EACxC,MAAM,SAAS,MAAM,KAAK,oBAAoB,OAAO,IAAI,KAAK;EAC9D,IAAI,KAAK,KAAK,oBAAoB,MAAM,OAAO,CAAC;;CAGlD,MAGM,OAAO,KAAc,KAAe;EACxC,MAAM,SAAS,MAAM,KAAK,oBAAoB,OAAO,IAAI,MAAM,IAAI,IAAI,KAAK;EAC5E,IAAI,KAAK,KAAK,oBAAoB,MAAM,OAAO,CAAC;;CAGlD,MAGM,OAAO,KAAc,KAAe;EACxC,MAAM,KAAK,oBAAoB,OAAO,IAAI,MAAM,GAAG;EACnD,IAAI,MAAM;;;;CAnCX,KAAK;CACL,MAAM,IAAI;;;;;;CAMV,KAAK;CACL,MAAM,OAAO;CACb,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC;;;;;;CAMvB,MAAM;CACN,MAAM,IAAI;;;;;;CAMV,KAAK;CACL,MAAM,OAAO;CACb,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC;;;;;;CAMvB,QAAQ;CACR,MAAM,OAAO;CACb,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC;;;;;;CApCzB,MAAM,GAAG,aAAa,SAAS,gBAAgB;CAC/C,OAAO,CAAC,cAAc,EAAE,eAAe,CAAC,MAAM,UAAU,MAAM,MAAM,CAAC,CAAC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
-
import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.
|
|
3
|
-
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.
|
|
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 } from "../exceptions/runtime.exceptions.js";
|
|
5
5
|
import { AppConstants } from "../server.constants.js";
|
|
6
6
|
import { ROLES } from "../constants/authorization.constants.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-storage.controller.js","names":[],"sources":["../../src/controllers/file-storage.controller.ts"],"sourcesContent":["import { before, DELETE, GET, POST, route } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport type { Request, Response } from \"express\";\nimport { authorizeRoles, authenticate } from \"@/middleware/authenticate\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { FileStorageService } from \"@/services/file-storage.service\";\nimport { MulterService } from \"@/services/core/multer.service\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { FileAnalysisService } from \"@/services/file-analysis.service\";\nimport { BadRequestException } from \"@/exceptions/runtime.exceptions\";\nimport { copyFileSync, existsSync, unlinkSync } from \"node:fs\";\nimport { extname } from \"node:path\";\n\n@route(AppConstants.apiRoute + \"/file-storage\")\n@before([authenticate(), authorizeRoles([ROLES.ADMIN, ROLES.OPERATOR])])\nexport class FileStorageController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly fileStorageService: FileStorageService,\n private readonly multerService: MulterService,\n private readonly fileAnalysisService: FileAnalysisService,\n ) {\n this.logger = loggerFactory(FileStorageController.name);\n }\n\n @GET()\n async listFiles(req: Request, res: Response) {\n try {\n const files = await this.fileStorageService.listAllFiles();\n\n res.send({\n files: files.map((file) => {\n const thumbnails = (file.metadata?._thumbnails || []).map((thumb: any) => ({\n index: thumb.index,\n width: thumb.width,\n height: thumb.height,\n format: thumb.format,\n size: thumb.size,\n }));\n return {\n fileStorageId: file.fileStorageId,\n fileName: file.fileName,\n fileFormat: file.fileFormat,\n fileSize: file.fileSize,\n fileHash: file.fileHash,\n createdAt: file.createdAt,\n thumbnails,\n metadata: file.metadata,\n };\n }),\n totalCount: files.length,\n });\n } catch (error) {\n this.logger.error(`Failed to list files: ${error}`);\n res.status(500).send({ error: \"Failed to list files\" });\n }\n }\n\n /**\n * Get file metadata\n * GET /api/file-storage/:fileStorageId\n */\n @GET()\n @route(\"/:fileStorageId\")\n async getFileMetadata(req: Request, res: Response) {\n const { fileStorageId } = req.params as { fileStorageId: string };\n\n try {\n const file = await this.fileStorageService.getFileInfo(fileStorageId);\n\n if (!file) {\n res.status(404).send({ error: \"File not found\" });\n return;\n }\n\n const thumbnails = (file.metadata?._thumbnails || []).map((thumb: any) => ({\n index: thumb.index,\n width: thumb.width,\n height: thumb.height,\n format: thumb.format,\n size: thumb.size,\n }));\n\n res.send({\n fileStorageId: file.fileStorageId,\n fileName: file.fileName,\n fileFormat: file.fileFormat,\n fileSize: file.fileSize,\n fileHash: file.fileHash,\n createdAt: file.createdAt,\n thumbnails,\n metadata: file.metadata,\n });\n } catch (error) {\n this.logger.error(`Failed to get file metadata for ${fileStorageId}: ${error}`);\n res.status(500).send({ error: \"Failed to get file metadata\" });\n }\n }\n\n /**\n * Delete a stored file and its thumbnails\n * DELETE /api/file-storage/:fileStorageId\n */\n @DELETE()\n @route(\"/:fileStorageId\")\n async deleteFile(req: Request, res: Response) {\n const { fileStorageId } = req.params as { fileStorageId: string };\n\n try {\n await this.fileStorageService.deleteFile(fileStorageId);\n\n this.logger.log(`Deleted file ${fileStorageId}`);\n res.send({ message: \"File deleted successfully\", fileStorageId });\n } catch (error) {\n this.logger.error(`Failed to delete file ${fileStorageId}: ${error}`);\n res.status(500).send({ error: \"Failed to delete file\" });\n }\n }\n\n @POST()\n @route(\"/:fileStorageId/analyze\")\n async analyzeFile(req: Request, res: Response) {\n const { fileStorageId } = req.params as { fileStorageId: string };\n\n try {\n const filePath = this.fileStorageService.getFilePath(fileStorageId);\n const fileExists = await this.fileStorageService.fileExists(fileStorageId);\n if (!fileExists) {\n res.status(404).send({ error: \"File not found\" });\n return;\n }\n this.logger.log(`Analyzing file: ${fileStorageId}`);\n\n // Load existing metadata to preserve original filename\n const existingMetadata = await this.fileStorageService.loadMetadata(fileStorageId);\n\n const analysisResult = await this.fileAnalysisService.analyzeFile(filePath);\n const metadata = analysisResult.metadata;\n const thumbnails = analysisResult.thumbnails;\n\n this.logger.log(\n `Analysis complete for ${fileStorageId}: format=${metadata.fileFormat}, layers=${metadata.totalLayers}, time=${metadata.gcodePrintTimeSeconds}s, thumbnails=${thumbnails.length}`,\n );\n\n const fileHash = await this.fileStorageService.calculateFileHash(filePath);\n const originalFileName = existingMetadata?._originalFileName || fileStorageId;\n\n metadata.fileName = originalFileName;\n\n let thumbnailMetadata: any[] = [];\n if (thumbnails.length > 0) {\n thumbnailMetadata = await this.fileStorageService.saveThumbnails(fileStorageId, thumbnails);\n this.logger.log(`Saved ${thumbnailMetadata.length} thumbnails for ${fileStorageId}`);\n }\n\n await this.fileStorageService.saveMetadata(\n fileStorageId,\n metadata,\n fileHash,\n originalFileName,\n thumbnailMetadata,\n );\n\n res.send({\n message: \"File analyzed successfully\",\n fileStorageId,\n metadata,\n thumbnailCount: thumbnails.length,\n });\n } catch (error) {\n this.logger.error(`Failed to analyze file ${fileStorageId}: ${error}`);\n res.status(500).send({ error: `Failed to analyze file: ${error}` });\n }\n }\n\n @GET()\n @route(\"/:fileStorageId/thumbnail/:index\")\n async getThumbnailByIndex(req: Request, res: Response) {\n const { fileStorageId, index } = req.params as { fileStorageId: string; index: string };\n const thumbnailIndex = Number.parseInt(index);\n\n if (Number.isNaN(thumbnailIndex)) {\n res.status(400).send({ error: \"Invalid thumbnail index\" });\n return;\n }\n\n try {\n const thumbnail = await this.fileStorageService.getThumbnail(fileStorageId, thumbnailIndex);\n\n if (!thumbnail) {\n res.status(404).send({ error: \"Thumbnail not found\" });\n return;\n }\n\n // Determine content type from magic bytes\n const isJPG = thumbnail[0] === 0xff && thumbnail[1] === 0xd8;\n const isQOI = thumbnail[0] === 0x71 && thumbnail[1] === 0x6f && thumbnail[2] === 0x69 && thumbnail[3] === 0x66;\n\n // QOI format not supported by browser\n if (isQOI) {\n res.status(404).send({ error: \"Thumbnail format not supported (QOI)\" });\n return;\n }\n\n const mimeType = isJPG ? \"image/jpeg\" : \"image/png\";\n const base64 = thumbnail.toString(\"base64\");\n res.send({\n thumbnailBase64: `data:${mimeType};base64,${base64}`,\n });\n } catch (error) {\n this.logger.error(`Failed to get thumbnail ${thumbnailIndex} for ${fileStorageId}: ${error}`);\n res.status(500).send({ error: \"Failed to get thumbnail\" });\n }\n }\n\n /**\n * Upload a file to storage and analyze it\n * POST /api/file-storage/upload\n */\n @POST()\n @route(\"/upload\")\n async uploadFile(req: Request, res: Response) {\n const acceptedExtensions = [\".gcode\", \".3mf\", \".bgcode\"];\n const files = await this.multerService.multerLoadFileAsync(req, res, acceptedExtensions, true);\n\n if (!files?.length) {\n throw new BadRequestException(\"No file uploaded\");\n }\n\n if (files.length > 1) {\n throw new BadRequestException(\"Only 1 file can be uploaded at a time\");\n }\n\n const file = files[0];\n await this.fileStorageService.validateUniqueFilename(file.originalname);\n\n const ext = extname(file.originalname);\n const tempPathWithExt = file.path + ext;\n\n try {\n copyFileSync(file.path, tempPathWithExt);\n\n const fileHash = await this.fileStorageService.calculateFileHash(tempPathWithExt);\n this.logger.log(`Analyzing ${file.originalname}`);\n const analysisResult = await this.fileAnalysisService.analyzeFile(tempPathWithExt);\n const { metadata, thumbnails } = analysisResult;\n\n const fileStorageId = await this.fileStorageService.saveFile(file, fileHash);\n this.logger.log(`Saved ${file.originalname} as ${fileStorageId}`);\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\n res.send({\n message: \"File uploaded successfully\",\n fileStorageId,\n fileName: file.originalname,\n fileSize: file.size,\n fileHash,\n metadata,\n thumbnailCount: thumbnails.length,\n });\n } finally {\n if (existsSync(tempPathWithExt)) {\n unlinkSync(tempPathWithExt);\n }\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"file-storage.controller.js","names":[],"sources":["../../src/controllers/file-storage.controller.ts"],"sourcesContent":["import { before, DELETE, GET, POST, route } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport type { Request, Response } from \"express\";\nimport { authorizeRoles, authenticate } from \"@/middleware/authenticate\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { FileStorageService } from \"@/services/file-storage.service\";\nimport { MulterService } from \"@/services/core/multer.service\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { FileAnalysisService } from \"@/services/file-analysis.service\";\nimport { BadRequestException } from \"@/exceptions/runtime.exceptions\";\nimport { copyFileSync, existsSync, unlinkSync } from \"node:fs\";\nimport { extname } from \"node:path\";\n\n@route(AppConstants.apiRoute + \"/file-storage\")\n@before([authenticate(), authorizeRoles([ROLES.ADMIN, ROLES.OPERATOR])])\nexport class FileStorageController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly fileStorageService: FileStorageService,\n private readonly multerService: MulterService,\n private readonly fileAnalysisService: FileAnalysisService,\n ) {\n this.logger = loggerFactory(FileStorageController.name);\n }\n\n @GET()\n async listFiles(req: Request, res: Response) {\n try {\n const files = await this.fileStorageService.listAllFiles();\n\n res.send({\n files: files.map((file) => {\n const thumbnails = (file.metadata?._thumbnails || []).map((thumb: any) => ({\n index: thumb.index,\n width: thumb.width,\n height: thumb.height,\n format: thumb.format,\n size: thumb.size,\n }));\n return {\n fileStorageId: file.fileStorageId,\n fileName: file.fileName,\n fileFormat: file.fileFormat,\n fileSize: file.fileSize,\n fileHash: file.fileHash,\n createdAt: file.createdAt,\n thumbnails,\n metadata: file.metadata,\n };\n }),\n totalCount: files.length,\n });\n } catch (error) {\n this.logger.error(`Failed to list files: ${error}`);\n res.status(500).send({ error: \"Failed to list files\" });\n }\n }\n\n /**\n * Get file metadata\n * GET /api/file-storage/:fileStorageId\n */\n @GET()\n @route(\"/:fileStorageId\")\n async getFileMetadata(req: Request, res: Response) {\n const { fileStorageId } = req.params as { fileStorageId: string };\n\n try {\n const file = await this.fileStorageService.getFileInfo(fileStorageId);\n\n if (!file) {\n res.status(404).send({ error: \"File not found\" });\n return;\n }\n\n const thumbnails = (file.metadata?._thumbnails || []).map((thumb: any) => ({\n index: thumb.index,\n width: thumb.width,\n height: thumb.height,\n format: thumb.format,\n size: thumb.size,\n }));\n\n res.send({\n fileStorageId: file.fileStorageId,\n fileName: file.fileName,\n fileFormat: file.fileFormat,\n fileSize: file.fileSize,\n fileHash: file.fileHash,\n createdAt: file.createdAt,\n thumbnails,\n metadata: file.metadata,\n });\n } catch (error) {\n this.logger.error(`Failed to get file metadata for ${fileStorageId}: ${error}`);\n res.status(500).send({ error: \"Failed to get file metadata\" });\n }\n }\n\n /**\n * Delete a stored file and its thumbnails\n * DELETE /api/file-storage/:fileStorageId\n */\n @DELETE()\n @route(\"/:fileStorageId\")\n async deleteFile(req: Request, res: Response) {\n const { fileStorageId } = req.params as { fileStorageId: string };\n\n try {\n await this.fileStorageService.deleteFile(fileStorageId);\n\n this.logger.log(`Deleted file ${fileStorageId}`);\n res.send({ message: \"File deleted successfully\", fileStorageId });\n } catch (error) {\n this.logger.error(`Failed to delete file ${fileStorageId}: ${error}`);\n res.status(500).send({ error: \"Failed to delete file\" });\n }\n }\n\n @POST()\n @route(\"/:fileStorageId/analyze\")\n async analyzeFile(req: Request, res: Response) {\n const { fileStorageId } = req.params as { fileStorageId: string };\n\n try {\n const filePath = this.fileStorageService.getFilePath(fileStorageId);\n const fileExists = await this.fileStorageService.fileExists(fileStorageId);\n if (!fileExists) {\n res.status(404).send({ error: \"File not found\" });\n return;\n }\n this.logger.log(`Analyzing file: ${fileStorageId}`);\n\n // Load existing metadata to preserve original filename\n const existingMetadata = await this.fileStorageService.loadMetadata(fileStorageId);\n\n const analysisResult = await this.fileAnalysisService.analyzeFile(filePath);\n const metadata = analysisResult.metadata;\n const thumbnails = analysisResult.thumbnails;\n\n this.logger.log(\n `Analysis complete for ${fileStorageId}: format=${metadata.fileFormat}, layers=${metadata.totalLayers}, time=${metadata.gcodePrintTimeSeconds}s, thumbnails=${thumbnails.length}`,\n );\n\n const fileHash = await this.fileStorageService.calculateFileHash(filePath);\n const originalFileName = existingMetadata?._originalFileName || fileStorageId;\n\n metadata.fileName = originalFileName;\n\n let thumbnailMetadata: any[] = [];\n if (thumbnails.length > 0) {\n thumbnailMetadata = await this.fileStorageService.saveThumbnails(fileStorageId, thumbnails);\n this.logger.log(`Saved ${thumbnailMetadata.length} thumbnails for ${fileStorageId}`);\n }\n\n await this.fileStorageService.saveMetadata(\n fileStorageId,\n metadata,\n fileHash,\n originalFileName,\n thumbnailMetadata,\n );\n\n res.send({\n message: \"File analyzed successfully\",\n fileStorageId,\n metadata,\n thumbnailCount: thumbnails.length,\n });\n } catch (error) {\n this.logger.error(`Failed to analyze file ${fileStorageId}: ${error}`);\n res.status(500).send({ error: `Failed to analyze file: ${error}` });\n }\n }\n\n @GET()\n @route(\"/:fileStorageId/thumbnail/:index\")\n async getThumbnailByIndex(req: Request, res: Response) {\n const { fileStorageId, index } = req.params as { fileStorageId: string; index: string };\n const thumbnailIndex = Number.parseInt(index);\n\n if (Number.isNaN(thumbnailIndex)) {\n res.status(400).send({ error: \"Invalid thumbnail index\" });\n return;\n }\n\n try {\n const thumbnail = await this.fileStorageService.getThumbnail(fileStorageId, thumbnailIndex);\n\n if (!thumbnail) {\n res.status(404).send({ error: \"Thumbnail not found\" });\n return;\n }\n\n // Determine content type from magic bytes\n const isJPG = thumbnail[0] === 0xff && thumbnail[1] === 0xd8;\n const isQOI = thumbnail[0] === 0x71 && thumbnail[1] === 0x6f && thumbnail[2] === 0x69 && thumbnail[3] === 0x66;\n\n // QOI format not supported by browser\n if (isQOI) {\n res.status(404).send({ error: \"Thumbnail format not supported (QOI)\" });\n return;\n }\n\n const mimeType = isJPG ? \"image/jpeg\" : \"image/png\";\n const base64 = thumbnail.toString(\"base64\");\n res.send({\n thumbnailBase64: `data:${mimeType};base64,${base64}`,\n });\n } catch (error) {\n this.logger.error(`Failed to get thumbnail ${thumbnailIndex} for ${fileStorageId}: ${error}`);\n res.status(500).send({ error: \"Failed to get thumbnail\" });\n }\n }\n\n /**\n * Upload a file to storage and analyze it\n * POST /api/file-storage/upload\n */\n @POST()\n @route(\"/upload\")\n async uploadFile(req: Request, res: Response) {\n const acceptedExtensions = [\".gcode\", \".3mf\", \".bgcode\"];\n const files = await this.multerService.multerLoadFileAsync(req, res, acceptedExtensions, true);\n\n if (!files?.length) {\n throw new BadRequestException(\"No file uploaded\");\n }\n\n if (files.length > 1) {\n throw new BadRequestException(\"Only 1 file can be uploaded at a time\");\n }\n\n const file = files[0];\n await this.fileStorageService.validateUniqueFilename(file.originalname);\n\n const ext = extname(file.originalname);\n const tempPathWithExt = file.path + ext;\n\n try {\n copyFileSync(file.path, tempPathWithExt);\n\n const fileHash = await this.fileStorageService.calculateFileHash(tempPathWithExt);\n this.logger.log(`Analyzing ${file.originalname}`);\n const analysisResult = await this.fileAnalysisService.analyzeFile(tempPathWithExt);\n const { metadata, thumbnails } = analysisResult;\n\n const fileStorageId = await this.fileStorageService.saveFile(file, fileHash);\n this.logger.log(`Saved ${file.originalname} as ${fileStorageId}`);\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\n res.send({\n message: \"File uploaded successfully\",\n fileStorageId,\n fileName: file.originalname,\n fileSize: file.size,\n fileHash,\n metadata,\n thumbnailCount: thumbnails.length,\n });\n } finally {\n if (existsSync(tempPathWithExt)) {\n unlinkSync(tempPathWithExt);\n }\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBO,IAAA,wBAAA,yBAAA,MAAM,sBAAsB;CACjC;CAEA,YACE,eACA,oBACA,eACA,qBACA;EAHiB,KAAA,qBAAA;EACA,KAAA,gBAAA;EACA,KAAA,sBAAA;EAEjB,KAAK,SAAS,cAAA,uBAAoC,KAAK;;CAGzD,MACM,UAAU,KAAc,KAAe;EAC3C,IAAI;GACF,MAAM,QAAQ,MAAM,KAAK,mBAAmB,cAAc;GAE1D,IAAI,KAAK;IACP,OAAO,MAAM,KAAK,SAAS;KACzB,MAAM,cAAc,KAAK,UAAU,eAAe,EAAE,EAAE,KAAK,WAAgB;MACzE,OAAO,MAAM;MACb,OAAO,MAAM;MACb,QAAQ,MAAM;MACd,QAAQ,MAAM;MACd,MAAM,MAAM;MACb,EAAE;KACH,OAAO;MACL,eAAe,KAAK;MACpB,UAAU,KAAK;MACf,YAAY,KAAK;MACjB,UAAU,KAAK;MACf,UAAU,KAAK;MACf,WAAW,KAAK;MAChB;MACA,UAAU,KAAK;MAChB;MACD;IACF,YAAY,MAAM;IACnB,CAAC;WACK,OAAO;GACd,KAAK,OAAO,MAAM,yBAAyB,QAAQ;GACnD,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,wBAAwB,CAAC;;;;;;;CAQ3D,MAEM,gBAAgB,KAAc,KAAe;EACjD,MAAM,EAAE,kBAAkB,IAAI;EAE9B,IAAI;GACF,MAAM,OAAO,MAAM,KAAK,mBAAmB,YAAY,cAAc;GAErE,IAAI,CAAC,MAAM;IACT,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,kBAAkB,CAAC;IACjD;;GAGF,MAAM,cAAc,KAAK,UAAU,eAAe,EAAE,EAAE,KAAK,WAAgB;IACzE,OAAO,MAAM;IACb,OAAO,MAAM;IACb,QAAQ,MAAM;IACd,QAAQ,MAAM;IACd,MAAM,MAAM;IACb,EAAE;GAEH,IAAI,KAAK;IACP,eAAe,KAAK;IACpB,UAAU,KAAK;IACf,YAAY,KAAK;IACjB,UAAU,KAAK;IACf,UAAU,KAAK;IACf,WAAW,KAAK;IAChB;IACA,UAAU,KAAK;IAChB,CAAC;WACK,OAAO;GACd,KAAK,OAAO,MAAM,mCAAmC,cAAc,IAAI,QAAQ;GAC/E,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,+BAA+B,CAAC;;;;;;;CAQlE,MAEM,WAAW,KAAc,KAAe;EAC5C,MAAM,EAAE,kBAAkB,IAAI;EAE9B,IAAI;GACF,MAAM,KAAK,mBAAmB,WAAW,cAAc;GAEvD,KAAK,OAAO,IAAI,gBAAgB,gBAAgB;GAChD,IAAI,KAAK;IAAE,SAAS;IAA6B;IAAe,CAAC;WAC1D,OAAO;GACd,KAAK,OAAO,MAAM,yBAAyB,cAAc,IAAI,QAAQ;GACrE,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,yBAAyB,CAAC;;;CAI5D,MAEM,YAAY,KAAc,KAAe;EAC7C,MAAM,EAAE,kBAAkB,IAAI;EAE9B,IAAI;GACF,MAAM,WAAW,KAAK,mBAAmB,YAAY,cAAc;GAEnE,IAAI,CAAC,MADoB,KAAK,mBAAmB,WAAW,cAAc,EACzD;IACf,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,kBAAkB,CAAC;IACjD;;GAEF,KAAK,OAAO,IAAI,mBAAmB,gBAAgB;GAGnD,MAAM,mBAAmB,MAAM,KAAK,mBAAmB,aAAa,cAAc;GAElF,MAAM,iBAAiB,MAAM,KAAK,oBAAoB,YAAY,SAAS;GAC3E,MAAM,WAAW,eAAe;GAChC,MAAM,aAAa,eAAe;GAElC,KAAK,OAAO,IACV,yBAAyB,cAAc,WAAW,SAAS,WAAW,WAAW,SAAS,YAAY,SAAS,SAAS,sBAAsB,gBAAgB,WAAW,SAC1K;GAED,MAAM,WAAW,MAAM,KAAK,mBAAmB,kBAAkB,SAAS;GAC1E,MAAM,mBAAmB,kBAAkB,qBAAqB;GAEhE,SAAS,WAAW;GAEpB,IAAI,oBAA2B,EAAE;GACjC,IAAI,WAAW,SAAS,GAAG;IACzB,oBAAoB,MAAM,KAAK,mBAAmB,eAAe,eAAe,WAAW;IAC3F,KAAK,OAAO,IAAI,SAAS,kBAAkB,OAAO,kBAAkB,gBAAgB;;GAGtF,MAAM,KAAK,mBAAmB,aAC5B,eACA,UACA,UACA,kBACA,kBACD;GAED,IAAI,KAAK;IACP,SAAS;IACT;IACA;IACA,gBAAgB,WAAW;IAC5B,CAAC;WACK,OAAO;GACd,KAAK,OAAO,MAAM,0BAA0B,cAAc,IAAI,QAAQ;GACtE,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,2BAA2B,SAAS,CAAC;;;CAIvE,MAEM,oBAAoB,KAAc,KAAe;EACrD,MAAM,EAAE,eAAe,UAAU,IAAI;EACrC,MAAM,iBAAiB,OAAO,SAAS,MAAM;EAE7C,IAAI,OAAO,MAAM,eAAe,EAAE;GAChC,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,2BAA2B,CAAC;GAC1D;;EAGF,IAAI;GACF,MAAM,YAAY,MAAM,KAAK,mBAAmB,aAAa,eAAe,eAAe;GAE3F,IAAI,CAAC,WAAW;IACd,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,uBAAuB,CAAC;IACtD;;GAIF,MAAM,QAAQ,UAAU,OAAO,OAAQ,UAAU,OAAO;GAIxD,IAHc,UAAU,OAAO,OAAQ,UAAU,OAAO,OAAQ,UAAU,OAAO,OAAQ,UAAU,OAAO,KAG/F;IACT,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,wCAAwC,CAAC;IACvE;;GAGF,MAAM,WAAW,QAAQ,eAAe;GACxC,MAAM,SAAS,UAAU,SAAS,SAAS;GAC3C,IAAI,KAAK,EACP,iBAAiB,QAAQ,SAAS,UAAU,UAC7C,CAAC;WACK,OAAO;GACd,KAAK,OAAO,MAAM,2BAA2B,eAAe,OAAO,cAAc,IAAI,QAAQ;GAC7F,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,2BAA2B,CAAC;;;;;;;CAQ9D,MAEM,WAAW,KAAc,KAAe;EAE5C,MAAM,QAAQ,MAAM,KAAK,cAAc,oBAAoB,KAAK,KAAK;GADzC;GAAU;GAAQ;GACyC,EAAE,KAAK;EAE9F,IAAI,CAAC,OAAO,QACV,MAAM,IAAI,oBAAoB,mBAAmB;EAGnD,IAAI,MAAM,SAAS,GACjB,MAAM,IAAI,oBAAoB,wCAAwC;EAGxE,MAAM,OAAO,MAAM;EACnB,MAAM,KAAK,mBAAmB,uBAAuB,KAAK,aAAa;EAEvE,MAAM,MAAM,QAAQ,KAAK,aAAa;EACtC,MAAM,kBAAkB,KAAK,OAAO;EAEpC,IAAI;GACF,aAAa,KAAK,MAAM,gBAAgB;GAExC,MAAM,WAAW,MAAM,KAAK,mBAAmB,kBAAkB,gBAAgB;GACjF,KAAK,OAAO,IAAI,aAAa,KAAK,eAAe;GAEjD,MAAM,EAAE,UAAU,eAAe,MADJ,KAAK,oBAAoB,YAAY,gBAAgB;GAGlF,MAAM,gBAAgB,MAAM,KAAK,mBAAmB,SAAS,MAAM,SAAS;GAC5E,KAAK,OAAO,IAAI,SAAS,KAAK,aAAa,MAAM,gBAAgB;GAEjE,MAAM,oBACJ,WAAW,SAAS,IAAI,MAAM,KAAK,mBAAmB,eAAe,eAAe,WAAW,GAAG,EAAE;GAEtG,MAAM,KAAK,mBAAmB,aAC5B,eACA,UACA,UACA,KAAK,cACL,kBACD;GAED,IAAI,KAAK;IACP,SAAS;IACT;IACA,UAAU,KAAK;IACf,UAAU,KAAK;IACf;IACA;IACA,gBAAgB,WAAW;IAC5B,CAAC;YACM;GACR,IAAI,WAAW,gBAAgB,EAC7B,WAAW,gBAAgB;;;;;CAvPhC,KAAK;;;;;;CAqCL,KAAK;CACL,MAAM,kBAAkB;;;;;;CAwCxB,QAAQ;CACR,MAAM,kBAAkB;;;;;;CAexB,MAAM;CACN,MAAM,0BAA0B;;;;;;CAuDhC,KAAK;CACL,MAAM,mCAAmC;;;;;;CA2CzC,MAAM;CACN,MAAM,UAAU;;;;;;CAjNlB,MAAM,aAAa,WAAW,gBAAgB;CAC9C,OAAO,CAAC,cAAc,EAAE,eAAe,CAAC,MAAM,OAAO,MAAM,SAAS,CAAC,CAAC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
-
import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.
|
|
3
|
-
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.
|
|
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 { validateMiddleware } from "../handlers/validators.js";
|
|
6
6
|
import { AppConstants } from "../server.constants.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"first-time-setup.controller.js","names":[],"sources":["../../src/controllers/first-time-setup.controller.ts"],"sourcesContent":["import { POST, route } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport { validateMiddleware } from \"@/handlers/validators\";\nimport { wizardSettingsSchema } from \"./validation/setting.validation\";\nimport { BadRequestException, ForbiddenError } from \"@/exceptions/runtime.exceptions\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { SettingsStore } from \"@/state/settings.store\";\nimport type { Request, Response } from \"express\";\nimport type { IUserService } from \"@/services/interfaces/user-service.interface\";\nimport type { IRoleService } from \"@/services/interfaces/role-service.interface\";\nimport { YamlService } from \"@/services/core/yaml.service\";\nimport { MulterService } from \"@/services/core/multer.service\";\n\n@route(AppConstants.apiRoute + \"/first-time-setup\")\nexport class FirstTimeSetupController {\n constructor(\n private readonly settingsStore: SettingsStore,\n private readonly roleService: IRoleService,\n private readonly userService: IUserService,\n private readonly yamlService: YamlService,\n private readonly multerService: MulterService,\n ) {}\n\n @POST()\n @route(\"/validate\")\n async validateWizard(req: Request, res: Response) {\n const { rootUsername } = await validateMiddleware(req, wizardSettingsSchema);\n await this.roleService.getSynchronizedRoleByName(ROLES.ADMIN);\n\n if (this.settingsStore.isWizardCompleted()) {\n throw new ForbiddenError(\"Wizard already completed\");\n }\n\n const user = await this.userService.findRawByUsername(rootUsername?.toLowerCase());\n if (user) {\n throw new BadRequestException(\"This user already exists\");\n }\n\n return res.send();\n }\n\n @POST()\n @route(\"/complete\")\n async completeWizard(req: Request, res: Response) {\n const { loginRequired, registration, rootUsername, rootPassword } = await validateMiddleware(\n req,\n wizardSettingsSchema,\n );\n\n if (this.settingsStore.isWizardCompleted()) {\n throw new ForbiddenError(\"Wizard already completed\");\n }\n\n await this.roleService.getSynchronizedRoleByName(ROLES.ADMIN);\n const user = await this.userService.findRawByUsername(rootUsername?.toLowerCase());\n if (user) {\n throw new BadRequestException(\"This user already exists\");\n }\n\n await this.userService.register({\n username: rootUsername,\n password: rootPassword,\n roles: [ROLES.ADMIN],\n isRootUser: true,\n isVerified: true,\n isDemoUser: false,\n needsPasswordChange: false,\n });\n await this.settingsStore.setLoginRequired(loginRequired);\n await this.settingsStore.setRegistrationEnabled(registration);\n await this.settingsStore.setWizardCompleted(AppConstants.currentWizardVersion);\n\n return res.send();\n }\n\n @POST()\n @route(\"/yaml-import\")\n async importYamlFile(req: Request, res: Response) {\n if (this.settingsStore.isWizardCompleted()) {\n throw new ForbiddenError(\n \"Wizard already completed. Cannot import during first-time setup once wizard is complete.\",\n );\n }\n\n const files = await this.multerService.multerLoadFileAsync(req, res, [\".yaml\", \".yml\"], false);\n const firstFile = files[0];\n\n await this.yamlService.importYaml(firstFile.buffer.toString());\n\n return res.send({\n success: true,\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAcO,IAAA,2BAAA,MAAM,yBAAyB;CACpC,YACE,eACA,aACA,aACA,aACA,eACA;
|
|
1
|
+
{"version":3,"file":"first-time-setup.controller.js","names":[],"sources":["../../src/controllers/first-time-setup.controller.ts"],"sourcesContent":["import { POST, route } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport { validateMiddleware } from \"@/handlers/validators\";\nimport { wizardSettingsSchema } from \"./validation/setting.validation\";\nimport { BadRequestException, ForbiddenError } from \"@/exceptions/runtime.exceptions\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { SettingsStore } from \"@/state/settings.store\";\nimport type { Request, Response } from \"express\";\nimport type { IUserService } from \"@/services/interfaces/user-service.interface\";\nimport type { IRoleService } from \"@/services/interfaces/role-service.interface\";\nimport { YamlService } from \"@/services/core/yaml.service\";\nimport { MulterService } from \"@/services/core/multer.service\";\n\n@route(AppConstants.apiRoute + \"/first-time-setup\")\nexport class FirstTimeSetupController {\n constructor(\n private readonly settingsStore: SettingsStore,\n private readonly roleService: IRoleService,\n private readonly userService: IUserService,\n private readonly yamlService: YamlService,\n private readonly multerService: MulterService,\n ) {}\n\n @POST()\n @route(\"/validate\")\n async validateWizard(req: Request, res: Response) {\n const { rootUsername } = await validateMiddleware(req, wizardSettingsSchema);\n await this.roleService.getSynchronizedRoleByName(ROLES.ADMIN);\n\n if (this.settingsStore.isWizardCompleted()) {\n throw new ForbiddenError(\"Wizard already completed\");\n }\n\n const user = await this.userService.findRawByUsername(rootUsername?.toLowerCase());\n if (user) {\n throw new BadRequestException(\"This user already exists\");\n }\n\n return res.send();\n }\n\n @POST()\n @route(\"/complete\")\n async completeWizard(req: Request, res: Response) {\n const { loginRequired, registration, rootUsername, rootPassword } = await validateMiddleware(\n req,\n wizardSettingsSchema,\n );\n\n if (this.settingsStore.isWizardCompleted()) {\n throw new ForbiddenError(\"Wizard already completed\");\n }\n\n await this.roleService.getSynchronizedRoleByName(ROLES.ADMIN);\n const user = await this.userService.findRawByUsername(rootUsername?.toLowerCase());\n if (user) {\n throw new BadRequestException(\"This user already exists\");\n }\n\n await this.userService.register({\n username: rootUsername,\n password: rootPassword,\n roles: [ROLES.ADMIN],\n isRootUser: true,\n isVerified: true,\n isDemoUser: false,\n needsPasswordChange: false,\n });\n await this.settingsStore.setLoginRequired(loginRequired);\n await this.settingsStore.setRegistrationEnabled(registration);\n await this.settingsStore.setWizardCompleted(AppConstants.currentWizardVersion);\n\n return res.send();\n }\n\n @POST()\n @route(\"/yaml-import\")\n async importYamlFile(req: Request, res: Response) {\n if (this.settingsStore.isWizardCompleted()) {\n throw new ForbiddenError(\n \"Wizard already completed. Cannot import during first-time setup once wizard is complete.\",\n );\n }\n\n const files = await this.multerService.multerLoadFileAsync(req, res, [\".yaml\", \".yml\"], false);\n const firstFile = files[0];\n\n await this.yamlService.importYaml(firstFile.buffer.toString());\n\n return res.send({\n success: true,\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAcO,IAAA,2BAAA,MAAM,yBAAyB;CACpC,YACE,eACA,aACA,aACA,aACA,eACA;EALiB,KAAA,gBAAA;EACA,KAAA,cAAA;EACA,KAAA,cAAA;EACA,KAAA,cAAA;EACA,KAAA,gBAAA;;CAGnB,MAEM,eAAe,KAAc,KAAe;EAChD,MAAM,EAAE,iBAAiB,MAAM,mBAAmB,KAAK,qBAAqB;EAC5E,MAAM,KAAK,YAAY,0BAA0B,MAAM,MAAM;EAE7D,IAAI,KAAK,cAAc,mBAAmB,EACxC,MAAM,IAAI,eAAe,2BAA2B;EAItD,IAAI,MADe,KAAK,YAAY,kBAAkB,cAAc,aAAa,CAAC,EAEhF,MAAM,IAAI,oBAAoB,2BAA2B;EAG3D,OAAO,IAAI,MAAM;;CAGnB,MAEM,eAAe,KAAc,KAAe;EAChD,MAAM,EAAE,eAAe,cAAc,cAAc,iBAAiB,MAAM,mBACxE,KACA,qBACD;EAED,IAAI,KAAK,cAAc,mBAAmB,EACxC,MAAM,IAAI,eAAe,2BAA2B;EAGtD,MAAM,KAAK,YAAY,0BAA0B,MAAM,MAAM;EAE7D,IAAI,MADe,KAAK,YAAY,kBAAkB,cAAc,aAAa,CAAC,EAEhF,MAAM,IAAI,oBAAoB,2BAA2B;EAG3D,MAAM,KAAK,YAAY,SAAS;GAC9B,UAAU;GACV,UAAU;GACV,OAAO,CAAC,MAAM,MAAM;GACpB,YAAY;GACZ,YAAY;GACZ,YAAY;GACZ,qBAAqB;GACtB,CAAC;EACF,MAAM,KAAK,cAAc,iBAAiB,cAAc;EACxD,MAAM,KAAK,cAAc,uBAAuB,aAAa;EAC7D,MAAM,KAAK,cAAc,mBAAmB,aAAa,qBAAqB;EAE9E,OAAO,IAAI,MAAM;;CAGnB,MAEM,eAAe,KAAc,KAAe;EAChD,IAAI,KAAK,cAAc,mBAAmB,EACxC,MAAM,IAAI,eACR,2FACD;EAIH,MAAM,aAAY,MADE,KAAK,cAAc,oBAAoB,KAAK,KAAK,CAAC,SAAS,OAAO,EAAE,MAAM,EACtE;EAExB,MAAM,KAAK,YAAY,WAAW,UAAU,OAAO,UAAU,CAAC;EAE9D,OAAO,IAAI,KAAK,EACd,SAAS,MACV,CAAC;;;;CApEH,MAAM;CACN,MAAM,YAAY;;;;;;CAiBlB,MAAM;CACN,MAAM,YAAY;;;;;;CAiClB,MAAM;CACN,MAAM,eAAe;;;;;uCA/DvB,MAAM,aAAa,WAAW,oBAAoB,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.
|
|
3
|
-
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.
|
|
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 { PERMS } from "../constants/authorization.constants.js";
|
|
6
6
|
import { authenticate, permission } from "../middleware/authenticate.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floor.controller.js","names":[],"sources":["../../src/controllers/floor.controller.ts"],"sourcesContent":["import type { Request, Response } from \"express\";\nimport { FloorStore } from \"@/state/floor.store\";\nimport { PERMS } from \"@/constants/authorization.constants\";\nimport { AppConstants } from \"@/server.constants\";\nimport { before, DELETE, GET, PATCH, POST, route } from \"awilix-express\";\nimport { authenticate, permission } from \"@/middleware/authenticate\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\n\n@route(AppConstants.apiRoute + \"/floor\")\n@before([authenticate()])\nexport class FloorController {\n constructor(private readonly floorStore: FloorStore) {}\n\n @GET()\n @route(\"/\")\n @before([permission(PERMS.Floors.List)])\n async list(req: Request, res: Response) {\n const floors = await this.floorStore.listCache();\n res.send(floors);\n }\n\n @GET()\n @route(\"/:id\")\n @before([permission(PERMS.Floors.Get), ParamId(\"id\")])\n async get(req: Request, res: Response) {\n const floor = await this.floorStore.getFloor(req.local.id);\n res.send(floor);\n }\n\n @DELETE()\n @route(\"/:id\")\n @before([permission(PERMS.Floors.Delete), ParamId(\"id\")])\n async delete(req: Request, res: Response) {\n await this.floorStore.delete(req.local.id);\n res.send();\n }\n\n @POST()\n @route(\"/\")\n @before([permission(PERMS.Floors.Create)])\n async create(req: Request, res: Response) {\n const floor = await this.floorStore.create(req.body);\n res.send(floor);\n }\n\n @PATCH()\n @route(\"/:id/name\")\n @before([permission(PERMS.Floors.Update), ParamId(\"id\")])\n async updateName(req: Request, res: Response) {\n const floor = await this.floorStore.updateName(req.local.id, req.body.name);\n res.send(floor);\n }\n\n @PATCH()\n @route(\"/:id/floor-order\")\n @before([permission(PERMS.Floors.Update), ParamId(\"id\")])\n async updateFloorOrder(req: Request, res: Response) {\n const floor = await this.floorStore.updateFloorOrder(req.local.id, req.body.order);\n res.send(floor);\n }\n\n @POST()\n @route(\"/:id/printer\")\n @before([permission(PERMS.Floors.Update), ParamId(\"id\")])\n async addPrinterToFloor(req: Request, res: Response) {\n const floor = await this.floorStore.addOrUpdatePrinter(req.local.id, req.body);\n res.send(floor);\n }\n\n @DELETE()\n @route(\"/:id/printer\")\n @before([permission(PERMS.Floors.Update), ParamId(\"id\")])\n async removePrinterFromFloor(req: Request, res: Response) {\n const floor = await this.floorStore.removePrinter(req.local.id, req.body.printerId);\n res.send(floor);\n }\n}\n"],"mappings":";;;;;;;;;;;;AAUO,IAAA,kBAAA,MAAM,gBAAgB;CAC3B,YAAY,YAAyC;
|
|
1
|
+
{"version":3,"file":"floor.controller.js","names":[],"sources":["../../src/controllers/floor.controller.ts"],"sourcesContent":["import type { Request, Response } from \"express\";\nimport { FloorStore } from \"@/state/floor.store\";\nimport { PERMS } from \"@/constants/authorization.constants\";\nimport { AppConstants } from \"@/server.constants\";\nimport { before, DELETE, GET, PATCH, POST, route } from \"awilix-express\";\nimport { authenticate, permission } from \"@/middleware/authenticate\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\n\n@route(AppConstants.apiRoute + \"/floor\")\n@before([authenticate()])\nexport class FloorController {\n constructor(private readonly floorStore: FloorStore) {}\n\n @GET()\n @route(\"/\")\n @before([permission(PERMS.Floors.List)])\n async list(req: Request, res: Response) {\n const floors = await this.floorStore.listCache();\n res.send(floors);\n }\n\n @GET()\n @route(\"/:id\")\n @before([permission(PERMS.Floors.Get), ParamId(\"id\")])\n async get(req: Request, res: Response) {\n const floor = await this.floorStore.getFloor(req.local.id);\n res.send(floor);\n }\n\n @DELETE()\n @route(\"/:id\")\n @before([permission(PERMS.Floors.Delete), ParamId(\"id\")])\n async delete(req: Request, res: Response) {\n await this.floorStore.delete(req.local.id);\n res.send();\n }\n\n @POST()\n @route(\"/\")\n @before([permission(PERMS.Floors.Create)])\n async create(req: Request, res: Response) {\n const floor = await this.floorStore.create(req.body);\n res.send(floor);\n }\n\n @PATCH()\n @route(\"/:id/name\")\n @before([permission(PERMS.Floors.Update), ParamId(\"id\")])\n async updateName(req: Request, res: Response) {\n const floor = await this.floorStore.updateName(req.local.id, req.body.name);\n res.send(floor);\n }\n\n @PATCH()\n @route(\"/:id/floor-order\")\n @before([permission(PERMS.Floors.Update), ParamId(\"id\")])\n async updateFloorOrder(req: Request, res: Response) {\n const floor = await this.floorStore.updateFloorOrder(req.local.id, req.body.order);\n res.send(floor);\n }\n\n @POST()\n @route(\"/:id/printer\")\n @before([permission(PERMS.Floors.Update), ParamId(\"id\")])\n async addPrinterToFloor(req: Request, res: Response) {\n const floor = await this.floorStore.addOrUpdatePrinter(req.local.id, req.body);\n res.send(floor);\n }\n\n @DELETE()\n @route(\"/:id/printer\")\n @before([permission(PERMS.Floors.Update), ParamId(\"id\")])\n async removePrinterFromFloor(req: Request, res: Response) {\n const floor = await this.floorStore.removePrinter(req.local.id, req.body.printerId);\n res.send(floor);\n }\n}\n"],"mappings":";;;;;;;;;;;;AAUO,IAAA,kBAAA,MAAM,gBAAgB;CAC3B,YAAY,YAAyC;EAAxB,KAAA,aAAA;;CAE7B,MAGM,KAAK,KAAc,KAAe;EACtC,MAAM,SAAS,MAAM,KAAK,WAAW,WAAW;EAChD,IAAI,KAAK,OAAO;;CAGlB,MAGM,IAAI,KAAc,KAAe;EACrC,MAAM,QAAQ,MAAM,KAAK,WAAW,SAAS,IAAI,MAAM,GAAG;EAC1D,IAAI,KAAK,MAAM;;CAGjB,MAGM,OAAO,KAAc,KAAe;EACxC,MAAM,KAAK,WAAW,OAAO,IAAI,MAAM,GAAG;EAC1C,IAAI,MAAM;;CAGZ,MAGM,OAAO,KAAc,KAAe;EACxC,MAAM,QAAQ,MAAM,KAAK,WAAW,OAAO,IAAI,KAAK;EACpD,IAAI,KAAK,MAAM;;CAGjB,MAGM,WAAW,KAAc,KAAe;EAC5C,MAAM,QAAQ,MAAM,KAAK,WAAW,WAAW,IAAI,MAAM,IAAI,IAAI,KAAK,KAAK;EAC3E,IAAI,KAAK,MAAM;;CAGjB,MAGM,iBAAiB,KAAc,KAAe;EAClD,MAAM,QAAQ,MAAM,KAAK,WAAW,iBAAiB,IAAI,MAAM,IAAI,IAAI,KAAK,MAAM;EAClF,IAAI,KAAK,MAAM;;CAGjB,MAGM,kBAAkB,KAAc,KAAe;EACnD,MAAM,QAAQ,MAAM,KAAK,WAAW,mBAAmB,IAAI,MAAM,IAAI,IAAI,KAAK;EAC9E,IAAI,KAAK,MAAM;;CAGjB,MAGM,uBAAuB,KAAc,KAAe;EACxD,MAAM,QAAQ,MAAM,KAAK,WAAW,cAAc,IAAI,MAAM,IAAI,IAAI,KAAK,UAAU;EACnF,IAAI,KAAK,MAAM;;;;CA7DhB,KAAK;CACL,MAAM,IAAI;CACV,OAAO,CAAC,WAAW,MAAM,OAAO,KAAK,CAAC,CAAC;;;;;;CAMvC,KAAK;CACL,MAAM,OAAO;CACb,OAAO,CAAC,WAAW,MAAM,OAAO,IAAI,EAAE,QAAQ,KAAK,CAAC,CAAC;;;;;;CAMrD,QAAQ;CACR,MAAM,OAAO;CACb,OAAO,CAAC,WAAW,MAAM,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,CAAC;;;;;;CAMxD,MAAM;CACN,MAAM,IAAI;CACV,OAAO,CAAC,WAAW,MAAM,OAAO,OAAO,CAAC,CAAC;;;;;;CAMzC,OAAO;CACP,MAAM,YAAY;CAClB,OAAO,CAAC,WAAW,MAAM,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,CAAC;;;;;;CAMxD,OAAO;CACP,MAAM,mBAAmB;CACzB,OAAO,CAAC,WAAW,MAAM,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,CAAC;;;;;;CAMxD,MAAM;CACN,MAAM,eAAe;CACrB,OAAO,CAAC,WAAW,MAAM,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,CAAC;;;;;;CAMxD,QAAQ;CACR,MAAM,eAAe;CACrB,OAAO,CAAC,WAAW,MAAM,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,CAAC;;;;;;CA/D1D,MAAM,aAAa,WAAW,SAAS;CACvC,OAAO,CAAC,cAAc,CAAC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
-
import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.
|
|
3
|
-
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.
|
|
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 { register } from "prom-client";
|
|
6
6
|
import { GET, route } from "awilix-express";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics.controller.js","names":[],"sources":["../../src/controllers/metrics.controller.ts"],"sourcesContent":["import { GET, route } from \"awilix-express\";\nimport { register } from \"prom-client\";\nimport type { Request, Response } from \"express\";\nimport type { IConfigService } from \"@/services/core/config.service\";\nimport { AppConstants } from \"@/server.constants\";\n\n@route(\"/metrics\")\nexport class MetricsController {\n constructor(private readonly configService: IConfigService) {}\n\n @GET()\n @route(\"\")\n async getMetrics(req: Request, res: Response) {\n if (this.configService.get<string>(AppConstants.ENABLE_PROMETHEUS_METRICS) !== \"true\") {\n return res.status(404).send(\"Metrics disabled\");\n }\n res.setHeader(\"Content-Type\", register.contentType);\n res.end(await register.metrics());\n }\n}\n"],"mappings":";;;;;;;;AAOO,IAAA,oBAAA,MAAM,kBAAkB;CAC7B,YAAY,eAAgD;
|
|
1
|
+
{"version":3,"file":"metrics.controller.js","names":[],"sources":["../../src/controllers/metrics.controller.ts"],"sourcesContent":["import { GET, route } from \"awilix-express\";\nimport { register } from \"prom-client\";\nimport type { Request, Response } from \"express\";\nimport type { IConfigService } from \"@/services/core/config.service\";\nimport { AppConstants } from \"@/server.constants\";\n\n@route(\"/metrics\")\nexport class MetricsController {\n constructor(private readonly configService: IConfigService) {}\n\n @GET()\n @route(\"\")\n async getMetrics(req: Request, res: Response) {\n if (this.configService.get<string>(AppConstants.ENABLE_PROMETHEUS_METRICS) !== \"true\") {\n return res.status(404).send(\"Metrics disabled\");\n }\n res.setHeader(\"Content-Type\", register.contentType);\n res.end(await register.metrics());\n }\n}\n"],"mappings":";;;;;;;;AAOO,IAAA,oBAAA,MAAM,kBAAkB;CAC7B,YAAY,eAAgD;EAA/B,KAAA,gBAAA;;CAE7B,MAEM,WAAW,KAAc,KAAe;EAC5C,IAAI,KAAK,cAAc,IAAY,aAAa,0BAA0B,KAAK,QAC7E,OAAO,IAAI,OAAO,IAAI,CAAC,KAAK,mBAAmB;EAEjD,IAAI,UAAU,gBAAgB,SAAS,YAAY;EACnD,IAAI,IAAI,MAAM,SAAS,SAAS,CAAC;;;;CAPlC,KAAK;CACL,MAAM,GAAG;;;;;gCALX,MAAM,WAAW,EAAA,mBAAA,qBAAA,CAAA,OAAA,CAAA,CAAA,EAAA,kBAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
-
import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.
|
|
3
|
-
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.
|
|
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 { NotFoundException } from "../exceptions/runtime.exceptions.js";
|
|
5
5
|
import { validateInput } from "../handlers/validators.js";
|
|
6
6
|
import { AppConstants } from "../server.constants.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"print-job.controller.js","names":[],"sources":["../../src/controllers/print-job.controller.ts"],"sourcesContent":["import { before, DELETE, GET, POST, route } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport type { Request, Response } from \"express\";\nimport { authorizeRoles, authenticate } from \"@/middleware/authenticate\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { searchJobsSchema, searchJobsPagedSchema } from \"@/services/validators/print-job.validation\";\nimport { validateInput } from \"@/handlers/validators\";\nimport { PrintJobService } from \"@/services/orm/print-job.service\";\nimport { FileAnalysisService } from \"@/services/file-analysis.service\";\nimport { FileStorageService } from \"@/services/file-storage.service\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\nimport { NotFoundException } from \"@/exceptions/runtime.exceptions\";\nimport { extractThumbnailsFromMetadata } from \"@/utils/thumbnail.util\";\n\n@route(AppConstants.apiRoute + \"/print-jobs\")\n@before([authenticate(), authorizeRoles([ROLES.ADMIN])])\nexport class PrintJobController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly printJobService: PrintJobService,\n private readonly fileAnalysisService: FileAnalysisService,\n private readonly fileStorageService: FileStorageService,\n ) {\n this.logger = loggerFactory(PrintJobController.name);\n }\n\n @GET()\n @route(\"/search\")\n async searchJobs(req: Request, res: Response) {\n const { searchPrinter, searchFile, startDate, endDate } = await validateInput(req.query, searchJobsSchema);\n\n const endDateObj = endDate ? this.toEndOfDay(new Date(endDate)) : undefined;\n\n const result = await this.printJobService.searchPrintJobs(\n searchPrinter,\n searchFile,\n startDate ? new Date(startDate) : undefined,\n endDateObj,\n );\n res.send(result);\n }\n\n @GET()\n @route(\"/search-paged\")\n async searchJobsPaged(req: Request, res: Response) {\n const { page, pageSize, searchPrinter, searchFile, startDate, endDate } = await validateInput(\n req.query,\n searchJobsPagedSchema,\n );\n\n const endDateObj = endDate ? this.toEndOfDay(new Date(endDate)) : undefined;\n\n const [items, count] = await this.printJobService.searchPrintJobsPaged(\n searchPrinter,\n searchFile,\n startDate ? new Date(startDate) : undefined,\n endDateObj,\n page,\n pageSize,\n );\n\n const itemsWithThumbnails = await Promise.all(\n items.map(async (job) => {\n let thumbnails: any[] = [];\n if (job.fileStorageId) {\n try {\n const metadata = await this.fileStorageService.loadMetadata(job.fileStorageId);\n thumbnails = extractThumbnailsFromMetadata(metadata);\n } catch {}\n }\n return { ...job, thumbnails };\n }),\n );\n\n res.send({ items: itemsWithThumbnails, count, pages: Math.ceil(count / pageSize) });\n }\n\n @GET()\n @route(\"/:id\")\n @before([ParamId(\"id\")])\n async getJob(req: Request, res: Response) {\n const jobId = req.local.id;\n\n const job = await this.printJobService.getJobByIdOrFail(jobId, [\"printer\"]);\n\n try {\n let thumbnails: any[] = [];\n if (job.fileStorageId) {\n const metadata = await this.fileStorageService.loadMetadata(job.fileStorageId);\n thumbnails = extractThumbnailsFromMetadata(metadata);\n }\n\n res.send({\n ...job,\n thumbnails,\n });\n } catch (error) {\n this.logger.error(`Failed to get job ${jobId}: ${error}`);\n res.status(500).send({ error: \"Failed to get job\" });\n }\n }\n\n @POST()\n @route(\"/:id/set-completed\")\n @before([ParamId(\"id\")])\n async setCompleted(req: Request, res: Response) {\n const jobId = req.local.id;\n const job = await this.printJobService.getJobByIdOrFail(jobId);\n\n try {\n if ([\"PENDING\", \"QUEUED\"].includes(job.status)) {\n res.status(400).send({\n error: 'Can only mark jobs which are not \"PENDING\" | \"QUEUED\" as completed',\n currentStatus: job.status,\n suggestion: \"This endpoint is for resolving jobs with unknown state\",\n });\n return;\n }\n\n const previousStatus = job.status;\n await this.printJobService.markAsCompleted(jobId);\n\n res.send({\n message: \"Job marked as completed\",\n jobId,\n previousStatus,\n newStatus: \"COMPLETED\",\n });\n } catch (error) {\n this.logger.error(`Failed to mark job ${jobId} as completed: ${error}`);\n res.status(500).send({\n error: \"Failed to update job status\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @POST()\n @route(\"/:id/set-failed\")\n @before([ParamId(\"id\")])\n async setFailed(req: Request, res: Response) {\n const jobId = req.local.id;\n const job = await this.printJobService.getJobByIdOrFail(jobId);\n\n const previousStatus = job.status;\n\n if (![\"UNKNOWN\", \"PRINTING\", \"CANCELLED\", \"COMPLETED\"].includes(job.status)) {\n res.status(400).send({\n error: \"Can only mark UNKNOWN, PRINTING, CANCELLED, or COMPLETED jobs as failed\",\n currentStatus: job.status,\n });\n return;\n }\n\n try {\n await this.printJobService.markAsFailed(jobId, \"Manually marked as failed by user\");\n\n res.send({\n message: \"Job marked as failed\",\n jobId,\n previousStatus,\n newStatus: \"FAILED\",\n });\n } catch (error) {\n this.logger.error(`Failed to mark job ${jobId} as failed: ${error}`);\n res.status(500).send({\n error: \"Failed to update job status\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @POST()\n @route(\"/:id/set-cancelled\")\n @before([ParamId(\"id\")])\n async setCancelled(req: Request, res: Response) {\n const jobId = req.local.id;\n const job = await this.printJobService.getJobByIdOrFail(jobId);\n\n const previousStatus = job.status;\n\n if (![\"UNKNOWN\", \"PRINTING\", \"PAUSED\"].includes(job.status)) {\n res.status(400).send({\n error: \"Can only mark UNKNOWN, PRINTING, or PAUSED jobs as cancelled\",\n currentStatus: job.status,\n });\n return;\n }\n\n try {\n await this.printJobService.markAsCancelled(jobId, \"Manually marked as cancelled by user\");\n\n res.send({\n message: \"Job marked as cancelled\",\n jobId,\n previousStatus,\n newStatus: \"CANCELLED\",\n });\n } catch (error) {\n this.logger.error(`Failed to mark job ${jobId} as cancelled: ${error}`);\n res.status(500).send({\n error: \"Failed to update job status\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @POST()\n @route(\"/:id/set-unknown\")\n @before([ParamId(\"id\")])\n async setUnknown(req: Request, res: Response) {\n const jobId = req.local.id;\n const job = await this.printJobService.getJobByIdOrFail(jobId);\n\n const previousStatus = job.status;\n\n if (![\"PRINTING\", \"PAUSED\"].includes(job.status)) {\n res.status(400).send({\n error: \"Can only mark PRINTING or PAUSED jobs as unknown\",\n currentStatus: job.status,\n suggestion: \"This endpoint is for marking jobs with uncertain state (e.g., after connection loss)\",\n });\n return;\n }\n\n try {\n await this.printJobService.markAsUnknown(jobId);\n\n res.send({\n message: \"Job marked as unknown\",\n jobId,\n previousStatus,\n newStatus: \"UNKNOWN\",\n });\n } catch (error) {\n this.logger.error(`Failed to mark job ${jobId} as unknown: ${error}`);\n res.status(500).send({\n error: \"Failed to update job status\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @POST()\n @route(\"/:id/re-analyze\")\n @before([ParamId(\"id\")])\n async reAnalyzeJob(req: Request, res: Response) {\n const jobId = req.local.id;\n const job = await this.printJobService.getJobByIdOrFail(jobId);\n\n this.logger.log(`Re-analyzing job ${jobId}`);\n\n try {\n if (!job.fileStorageId) {\n this.logger.log(`Job ${jobId} has no fileStorageId - triggering download and analysis`);\n await this.printJobService.triggerFileAnalysis(jobId);\n\n res.send({\n message: \"File download and analysis triggered (async)\",\n jobId,\n status: \"pending\",\n });\n return;\n }\n\n const filePath = this.fileStorageService.getFilePath(job.fileStorageId);\n const exists = await this.fileAnalysisService.needsAnalysis(filePath);\n if (!exists) {\n throw new NotFoundException(`File not found in storage: ${job.fileStorageId}`);\n }\n\n this.logger.log(`Re-analyzing file for job ${jobId}: ${filePath}`);\n\n job.analysisState = \"ANALYZING\";\n await this.printJobService.updateJob(job);\n\n const { metadata, thumbnails } = await this.fileAnalysisService.analyzeFile(filePath);\n\n let thumbnailMetadata: any[] = [];\n if (thumbnails && thumbnails.length > 0) {\n thumbnailMetadata = await this.fileStorageService.saveThumbnails(job.fileStorageId, thumbnails);\n this.logger.log(`Saved ${thumbnailMetadata.length} thumbnail(s) for job ${jobId}`);\n }\n\n await this.printJobService.handleFileAnalyzed(jobId, metadata, thumbnails);\n\n const fileHash = job.fileHash || undefined;\n await this.fileStorageService.saveMetadata(\n job.fileStorageId,\n metadata,\n fileHash,\n job.fileName,\n thumbnailMetadata,\n );\n\n this.logger.log(`Successfully re-analyzed job ${jobId}`);\n\n res.send({\n message: \"File re-analyzed successfully\",\n jobId,\n status: \"analyzed\",\n metadata,\n thumbnailCount: thumbnails?.length || 0,\n });\n } catch (error) {\n this.logger.error(`Failed to re-analyze job ${jobId}: ${error}`);\n res.status(500).send({\n error: \"Re-analysis failed\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @DELETE()\n @route(\"/:id\")\n @before([ParamId(\"id\")])\n async deleteJob(req: Request, res: Response) {\n const jobId = req.local.id;\n const job = await this.printJobService.getJobByIdOrFail(jobId);\n const deleteFileParam = req.query.deleteFile === \"true\";\n\n if (job.status === \"PRINTING\" || job.status === \"PAUSED\") {\n res.status(400).send({\n error: \"Cannot delete active print job\",\n status: job.status,\n suggestion: \"Wait for print to complete or cancel it first\",\n });\n return;\n }\n\n try {\n const fileStorageId = job.fileStorageId;\n const fileName = job.fileName;\n\n await this.printJobService.deleteJob(job);\n this.logger.log(`Deleted job ${jobId}: ${fileName}`);\n\n if (fileStorageId && deleteFileParam) {\n const otherJobs = await this.printJobService.countJobsReferencingFile(fileStorageId);\n\n if (otherJobs === 0) {\n try {\n await this.fileStorageService.deleteFile(fileStorageId);\n this.logger.log(`Deleted file as requested: ${fileStorageId}`);\n res.send({\n message: \"Job and associated file deleted\",\n jobId,\n fileDeleted: true,\n });\n } catch (error) {\n this.logger.warn(`Failed to delete file ${fileStorageId}: ${error}`);\n res.send({\n message: \"Job deleted, but file deletion failed\",\n jobId,\n fileDeleted: false,\n });\n }\n } else {\n this.logger.log(`File ${fileStorageId} still referenced by ${otherJobs} other job(s) - keeping file`);\n res.send({\n message: \"Job deleted (file kept - still used by other jobs)\",\n jobId,\n fileDeleted: false,\n remainingReferences: otherJobs,\n });\n }\n } else {\n res.send({\n message: \"Job deleted\",\n jobId,\n fileDeleted: false,\n });\n }\n } catch (error) {\n this.logger.error(`Failed to delete job ${jobId}: ${error}`);\n res.status(500).send({\n error: \"Delete failed\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n private toEndOfDay(date: Date): Date {\n const endOfDay = new Date(date);\n endOfDay.setHours(23, 59, 59, 999);\n return endOfDay;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"print-job.controller.js","names":[],"sources":["../../src/controllers/print-job.controller.ts"],"sourcesContent":["import { before, DELETE, GET, POST, route } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport type { Request, Response } from \"express\";\nimport { authorizeRoles, authenticate } from \"@/middleware/authenticate\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { searchJobsSchema, searchJobsPagedSchema } from \"@/services/validators/print-job.validation\";\nimport { validateInput } from \"@/handlers/validators\";\nimport { PrintJobService } from \"@/services/orm/print-job.service\";\nimport { FileAnalysisService } from \"@/services/file-analysis.service\";\nimport { FileStorageService } from \"@/services/file-storage.service\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\nimport { NotFoundException } from \"@/exceptions/runtime.exceptions\";\nimport { extractThumbnailsFromMetadata } from \"@/utils/thumbnail.util\";\n\n@route(AppConstants.apiRoute + \"/print-jobs\")\n@before([authenticate(), authorizeRoles([ROLES.ADMIN])])\nexport class PrintJobController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly printJobService: PrintJobService,\n private readonly fileAnalysisService: FileAnalysisService,\n private readonly fileStorageService: FileStorageService,\n ) {\n this.logger = loggerFactory(PrintJobController.name);\n }\n\n @GET()\n @route(\"/search\")\n async searchJobs(req: Request, res: Response) {\n const { searchPrinter, searchFile, startDate, endDate } = await validateInput(req.query, searchJobsSchema);\n\n const endDateObj = endDate ? this.toEndOfDay(new Date(endDate)) : undefined;\n\n const result = await this.printJobService.searchPrintJobs(\n searchPrinter,\n searchFile,\n startDate ? new Date(startDate) : undefined,\n endDateObj,\n );\n res.send(result);\n }\n\n @GET()\n @route(\"/search-paged\")\n async searchJobsPaged(req: Request, res: Response) {\n const { page, pageSize, searchPrinter, searchFile, startDate, endDate } = await validateInput(\n req.query,\n searchJobsPagedSchema,\n );\n\n const endDateObj = endDate ? this.toEndOfDay(new Date(endDate)) : undefined;\n\n const [items, count] = await this.printJobService.searchPrintJobsPaged(\n searchPrinter,\n searchFile,\n startDate ? new Date(startDate) : undefined,\n endDateObj,\n page,\n pageSize,\n );\n\n const itemsWithThumbnails = await Promise.all(\n items.map(async (job) => {\n let thumbnails: any[] = [];\n if (job.fileStorageId) {\n try {\n const metadata = await this.fileStorageService.loadMetadata(job.fileStorageId);\n thumbnails = extractThumbnailsFromMetadata(metadata);\n } catch {}\n }\n return { ...job, thumbnails };\n }),\n );\n\n res.send({ items: itemsWithThumbnails, count, pages: Math.ceil(count / pageSize) });\n }\n\n @GET()\n @route(\"/:id\")\n @before([ParamId(\"id\")])\n async getJob(req: Request, res: Response) {\n const jobId = req.local.id;\n\n const job = await this.printJobService.getJobByIdOrFail(jobId, [\"printer\"]);\n\n try {\n let thumbnails: any[] = [];\n if (job.fileStorageId) {\n const metadata = await this.fileStorageService.loadMetadata(job.fileStorageId);\n thumbnails = extractThumbnailsFromMetadata(metadata);\n }\n\n res.send({\n ...job,\n thumbnails,\n });\n } catch (error) {\n this.logger.error(`Failed to get job ${jobId}: ${error}`);\n res.status(500).send({ error: \"Failed to get job\" });\n }\n }\n\n @POST()\n @route(\"/:id/set-completed\")\n @before([ParamId(\"id\")])\n async setCompleted(req: Request, res: Response) {\n const jobId = req.local.id;\n const job = await this.printJobService.getJobByIdOrFail(jobId);\n\n try {\n if ([\"PENDING\", \"QUEUED\"].includes(job.status)) {\n res.status(400).send({\n error: 'Can only mark jobs which are not \"PENDING\" | \"QUEUED\" as completed',\n currentStatus: job.status,\n suggestion: \"This endpoint is for resolving jobs with unknown state\",\n });\n return;\n }\n\n const previousStatus = job.status;\n await this.printJobService.markAsCompleted(jobId);\n\n res.send({\n message: \"Job marked as completed\",\n jobId,\n previousStatus,\n newStatus: \"COMPLETED\",\n });\n } catch (error) {\n this.logger.error(`Failed to mark job ${jobId} as completed: ${error}`);\n res.status(500).send({\n error: \"Failed to update job status\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @POST()\n @route(\"/:id/set-failed\")\n @before([ParamId(\"id\")])\n async setFailed(req: Request, res: Response) {\n const jobId = req.local.id;\n const job = await this.printJobService.getJobByIdOrFail(jobId);\n\n const previousStatus = job.status;\n\n if (![\"UNKNOWN\", \"PRINTING\", \"CANCELLED\", \"COMPLETED\"].includes(job.status)) {\n res.status(400).send({\n error: \"Can only mark UNKNOWN, PRINTING, CANCELLED, or COMPLETED jobs as failed\",\n currentStatus: job.status,\n });\n return;\n }\n\n try {\n await this.printJobService.markAsFailed(jobId, \"Manually marked as failed by user\");\n\n res.send({\n message: \"Job marked as failed\",\n jobId,\n previousStatus,\n newStatus: \"FAILED\",\n });\n } catch (error) {\n this.logger.error(`Failed to mark job ${jobId} as failed: ${error}`);\n res.status(500).send({\n error: \"Failed to update job status\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @POST()\n @route(\"/:id/set-cancelled\")\n @before([ParamId(\"id\")])\n async setCancelled(req: Request, res: Response) {\n const jobId = req.local.id;\n const job = await this.printJobService.getJobByIdOrFail(jobId);\n\n const previousStatus = job.status;\n\n if (![\"UNKNOWN\", \"PRINTING\", \"PAUSED\"].includes(job.status)) {\n res.status(400).send({\n error: \"Can only mark UNKNOWN, PRINTING, or PAUSED jobs as cancelled\",\n currentStatus: job.status,\n });\n return;\n }\n\n try {\n await this.printJobService.markAsCancelled(jobId, \"Manually marked as cancelled by user\");\n\n res.send({\n message: \"Job marked as cancelled\",\n jobId,\n previousStatus,\n newStatus: \"CANCELLED\",\n });\n } catch (error) {\n this.logger.error(`Failed to mark job ${jobId} as cancelled: ${error}`);\n res.status(500).send({\n error: \"Failed to update job status\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @POST()\n @route(\"/:id/set-unknown\")\n @before([ParamId(\"id\")])\n async setUnknown(req: Request, res: Response) {\n const jobId = req.local.id;\n const job = await this.printJobService.getJobByIdOrFail(jobId);\n\n const previousStatus = job.status;\n\n if (![\"PRINTING\", \"PAUSED\"].includes(job.status)) {\n res.status(400).send({\n error: \"Can only mark PRINTING or PAUSED jobs as unknown\",\n currentStatus: job.status,\n suggestion: \"This endpoint is for marking jobs with uncertain state (e.g., after connection loss)\",\n });\n return;\n }\n\n try {\n await this.printJobService.markAsUnknown(jobId);\n\n res.send({\n message: \"Job marked as unknown\",\n jobId,\n previousStatus,\n newStatus: \"UNKNOWN\",\n });\n } catch (error) {\n this.logger.error(`Failed to mark job ${jobId} as unknown: ${error}`);\n res.status(500).send({\n error: \"Failed to update job status\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @POST()\n @route(\"/:id/re-analyze\")\n @before([ParamId(\"id\")])\n async reAnalyzeJob(req: Request, res: Response) {\n const jobId = req.local.id;\n const job = await this.printJobService.getJobByIdOrFail(jobId);\n\n this.logger.log(`Re-analyzing job ${jobId}`);\n\n try {\n if (!job.fileStorageId) {\n this.logger.log(`Job ${jobId} has no fileStorageId - triggering download and analysis`);\n await this.printJobService.triggerFileAnalysis(jobId);\n\n res.send({\n message: \"File download and analysis triggered (async)\",\n jobId,\n status: \"pending\",\n });\n return;\n }\n\n const filePath = this.fileStorageService.getFilePath(job.fileStorageId);\n const exists = await this.fileAnalysisService.needsAnalysis(filePath);\n if (!exists) {\n throw new NotFoundException(`File not found in storage: ${job.fileStorageId}`);\n }\n\n this.logger.log(`Re-analyzing file for job ${jobId}: ${filePath}`);\n\n job.analysisState = \"ANALYZING\";\n await this.printJobService.updateJob(job);\n\n const { metadata, thumbnails } = await this.fileAnalysisService.analyzeFile(filePath);\n\n let thumbnailMetadata: any[] = [];\n if (thumbnails && thumbnails.length > 0) {\n thumbnailMetadata = await this.fileStorageService.saveThumbnails(job.fileStorageId, thumbnails);\n this.logger.log(`Saved ${thumbnailMetadata.length} thumbnail(s) for job ${jobId}`);\n }\n\n await this.printJobService.handleFileAnalyzed(jobId, metadata, thumbnails);\n\n const fileHash = job.fileHash || undefined;\n await this.fileStorageService.saveMetadata(\n job.fileStorageId,\n metadata,\n fileHash,\n job.fileName,\n thumbnailMetadata,\n );\n\n this.logger.log(`Successfully re-analyzed job ${jobId}`);\n\n res.send({\n message: \"File re-analyzed successfully\",\n jobId,\n status: \"analyzed\",\n metadata,\n thumbnailCount: thumbnails?.length || 0,\n });\n } catch (error) {\n this.logger.error(`Failed to re-analyze job ${jobId}: ${error}`);\n res.status(500).send({\n error: \"Re-analysis failed\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @DELETE()\n @route(\"/:id\")\n @before([ParamId(\"id\")])\n async deleteJob(req: Request, res: Response) {\n const jobId = req.local.id;\n const job = await this.printJobService.getJobByIdOrFail(jobId);\n const deleteFileParam = req.query.deleteFile === \"true\";\n\n if (job.status === \"PRINTING\" || job.status === \"PAUSED\") {\n res.status(400).send({\n error: \"Cannot delete active print job\",\n status: job.status,\n suggestion: \"Wait for print to complete or cancel it first\",\n });\n return;\n }\n\n try {\n const fileStorageId = job.fileStorageId;\n const fileName = job.fileName;\n\n await this.printJobService.deleteJob(job);\n this.logger.log(`Deleted job ${jobId}: ${fileName}`);\n\n if (fileStorageId && deleteFileParam) {\n const otherJobs = await this.printJobService.countJobsReferencingFile(fileStorageId);\n\n if (otherJobs === 0) {\n try {\n await this.fileStorageService.deleteFile(fileStorageId);\n this.logger.log(`Deleted file as requested: ${fileStorageId}`);\n res.send({\n message: \"Job and associated file deleted\",\n jobId,\n fileDeleted: true,\n });\n } catch (error) {\n this.logger.warn(`Failed to delete file ${fileStorageId}: ${error}`);\n res.send({\n message: \"Job deleted, but file deletion failed\",\n jobId,\n fileDeleted: false,\n });\n }\n } else {\n this.logger.log(`File ${fileStorageId} still referenced by ${otherJobs} other job(s) - keeping file`);\n res.send({\n message: \"Job deleted (file kept - still used by other jobs)\",\n jobId,\n fileDeleted: false,\n remainingReferences: otherJobs,\n });\n }\n } else {\n res.send({\n message: \"Job deleted\",\n jobId,\n fileDeleted: false,\n });\n }\n } catch (error) {\n this.logger.error(`Failed to delete job ${jobId}: ${error}`);\n res.status(500).send({\n error: \"Delete failed\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n private toEndOfDay(date: Date): Date {\n const endOfDay = new Date(date);\n endOfDay.setHours(23, 59, 59, 999);\n return endOfDay;\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.
|
|
3
|
-
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.
|
|
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 { NotFoundException } from "../exceptions/runtime.exceptions.js";
|
|
5
5
|
import { AppConstants } from "../server.constants.js";
|
|
6
6
|
import { ROLES } from "../constants/authorization.constants.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"print-queue.controller.js","names":[],"sources":["../../src/controllers/print-queue.controller.ts"],"sourcesContent":["import { before, DELETE, GET, POST, PUT, route } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport type { Request, Response } from \"express\";\nimport { authorizeRoles, authenticate } from \"@/middleware/authenticate\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { PrintQueueService } from \"@/services/print-queue.service\";\nimport { PrintJobService } from \"@/services/orm/print-job.service\";\nimport { FileStorageService } from \"@/services/file-storage.service\";\nimport { PrinterCache } from \"@/state/printer.cache\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\nimport { NotFoundException } from \"@/exceptions/runtime.exceptions\";\n\n@route(AppConstants.apiRoute + \"/print-queue\")\n@before([authenticate(), authorizeRoles([ROLES.ADMIN, ROLES.OPERATOR])])\nexport class PrintQueueController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly printQueueService: PrintQueueService,\n private readonly printJobService: PrintJobService,\n private readonly fileStorageService: FileStorageService,\n private readonly printerCache: PrinterCache,\n ) {\n this.logger = loggerFactory(PrintQueueController.name);\n }\n\n @GET()\n async getGlobalQueue(req: Request, res: Response) {\n try {\n const page = Number.parseInt(req.query.page as string) || 1;\n const pageSize = Number.parseInt(req.query.pageSize as string) || 50;\n\n if (page < 1 || pageSize < 1 || pageSize > 200) {\n res.status(400).send({ error: \"Invalid page or pageSize parameters\" });\n return;\n }\n\n const [jobs, totalCount] = await this.printQueueService.getGlobalQueuePaged(page, pageSize);\n\n const queueItems = jobs.map((job) => ({\n jobId: job.id,\n fileName: job.fileName,\n printerId: job.printerId,\n printerName: job.printerName || job.printer?.name,\n queuePosition: job.queuePosition,\n status: job.status,\n createdAt: job.createdAt,\n estimatedTimeSeconds: (job.metadata as any)?.gcodePrintTimeSeconds,\n filamentGrams: (job.metadata as any)?.filamentUsedGrams,\n }));\n\n res.send({\n items: queueItems,\n page,\n pageSize,\n totalCount,\n totalPages: Math.ceil(totalCount / pageSize),\n });\n } catch (error) {\n this.logger.error(`Failed to get global queue: ${error}`);\n res.status(500).send({ error: \"Failed to get global queue\" });\n }\n }\n\n @GET()\n @route(\"/:printerId\")\n @before([ParamId(\"printerId\")])\n async getQueue(req: Request, res: Response) {\n const printerId = req.local.printerId;\n\n try {\n const queue = await this.printQueueService.getQueue(printerId);\n res.send({\n printerId,\n queue,\n count: queue.length,\n });\n } catch (error) {\n this.logger.error(`Failed to get queue for printer ${printerId}: ${error}`);\n res.status(500).send({ error: \"Failed to get queue\" });\n }\n }\n\n @POST()\n @route(\"/:printerId/add/:jobId\")\n @before([ParamId(\"printerId\"), ParamId(\"jobId\")])\n async addToQueue(req: Request, res: Response) {\n const printerId = req.local.printerId;\n const jobId = req.local.jobId;\n const position = req.body.position === undefined ? undefined : Number.parseInt(req.body.position);\n\n try {\n await this.printQueueService.addToQueue(printerId, jobId, position);\n const queue = await this.printQueueService.getQueue(printerId);\n\n res.send({\n message: \"Job added to queue\",\n printerId,\n jobId,\n position,\n queue,\n });\n } catch (error) {\n this.logger.error(`Failed to add job ${jobId} to queue: ${error}`);\n res.status(500).send({\n error: \"Failed to add to queue\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @PUT()\n @route(\"/:printerId/reorder\")\n @before([ParamId(\"printerId\")])\n async reorderQueue(req: Request, res: Response) {\n const printerId = req.local.printerId;\n const jobIds = req.body.jobIds;\n\n if (!Array.isArray(jobIds)) {\n res.status(400).send({ error: \"jobIds must be an array\" });\n return;\n }\n\n try {\n await this.printQueueService.reorderQueue(printerId, jobIds);\n const queue = await this.printQueueService.getQueue(printerId);\n\n res.send({\n message: \"Queue reordered\",\n printerId,\n queue,\n });\n } catch (error) {\n this.logger.error(`Failed to reorder queue for printer ${printerId}: ${error}`);\n res.status(500).send({\n error: \"Failed to reorder queue\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @DELETE()\n @route(\"/:printerId/clear\")\n @before([ParamId(\"printerId\")])\n async clearQueue(req: Request, res: Response) {\n const printerId = req.local.printerId;\n\n try {\n await this.printQueueService.clearQueue(printerId);\n\n res.send({\n message: \"Queue cleared\",\n printerId,\n });\n } catch (error) {\n this.logger.error(`Failed to clear queue for printer ${printerId}: ${error}`);\n res.status(500).send({\n error: \"Failed to clear queue\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @DELETE()\n @route(\"/:printerId/:jobId\")\n @before([ParamId(\"printerId\"), ParamId(\"jobId\")])\n async removeFromQueue(req: Request, res: Response) {\n const printerId = req.local.printerId;\n const jobId = req.local.jobId;\n\n try {\n await this.printQueueService.removeFromQueue(jobId);\n const queue = await this.printQueueService.getQueue(printerId);\n\n res.send({\n message: \"Job removed from queue\",\n printerId,\n jobId,\n queue,\n });\n } catch (error) {\n this.logger.error(`Failed to remove job ${jobId} from queue: ${error}`);\n res.status(500).send({\n error: \"Failed to remove from queue\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @GET()\n @route(\"/:printerId/next\")\n @before([ParamId(\"printerId\")])\n async getNextInQueue(req: Request, res: Response) {\n const printerId = req.local.printerId;\n\n try {\n const nextJob = await this.printQueueService.getNextInQueue(printerId);\n\n res.send({\n printerId,\n nextJob,\n });\n } catch (error) {\n this.logger.error(`Failed to get next job for printer ${printerId}: ${error}`);\n res.status(500).send({ error: \"Failed to get next job\" });\n }\n }\n\n @POST()\n @route(\"/:printerId/process\")\n @before([ParamId(\"printerId\")])\n async processQueue(req: Request, res: Response) {\n const printerId = req.local.printerId;\n\n try {\n const nextJob = await this.printQueueService.processQueue(printerId);\n\n if (!nextJob) {\n res.send({\n message: \"Queue is empty\",\n printerId,\n nextJob: null,\n });\n return;\n }\n\n res.send({\n message: \"Processing next job in queue\",\n printerId,\n nextJob,\n });\n } catch (error) {\n this.logger.error(`Failed to process queue for printer ${printerId}: ${error}`);\n res.status(500).send({\n error: \"Failed to process queue\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @POST()\n @route(\"/:printerId/from-file\")\n @before([ParamId(\"printerId\")])\n async createJobFromFile(req: Request, res: Response) {\n const printerId = req.local.printerId;\n const { fileStorageId, addToQueue = true, position } = req.body;\n\n if (!fileStorageId) {\n res.status(400).send({ error: \"fileStorageId is required\" });\n return;\n }\n\n try {\n const fileExists = await this.fileStorageService.fileExists(fileStorageId);\n if (!fileExists) {\n throw new NotFoundException(\"File not found in storage\");\n }\n\n const metadata = await this.fileStorageService.loadMetadata(fileStorageId);\n if (!metadata) {\n res.status(400).send({ error: \"File has no metadata. Please analyze the file first.\" });\n return;\n }\n\n const printer = await this.printerCache.getCachedPrinterOrThrowAsync(printerId);\n\n const job = await this.printJobService.createPendingJob(\n printerId,\n metadata._originalFileName || metadata.fileName || \"Unknown\",\n metadata,\n printer.name,\n );\n\n job.fileStorageId = fileStorageId;\n job.fileHash = metadata._fileHash;\n job.analysisState = \"ANALYZED\";\n job.analyzedAt = new Date();\n\n if (metadata.fileFormat) {\n job.fileFormat = metadata.fileFormat;\n }\n\n await this.printJobService.updateJob(job);\n\n if (addToQueue) {\n await this.printQueueService.addToQueue(printerId, job.id, position);\n }\n\n this.logger.log(\n `Created job ${job.id} from file storage ${fileStorageId} for printer ${printerId}${addToQueue ? \" and added to queue\" : \"\"}`,\n );\n\n res.send({\n id: job.id,\n printerId: job.printerId,\n printerName: job.printerName,\n fileName: job.fileName,\n fileStorageId: job.fileStorageId,\n status: job.status,\n analysisState: job.analysisState,\n createdAt: job.createdAt,\n addedToQueue: addToQueue,\n });\n } catch (error) {\n this.logger.error(`Failed to create job from file ${fileStorageId}: ${error}`);\n res.status(500).send({ error: \"Failed to create job from file\" });\n }\n }\n\n @POST()\n @route(\"/:printerId/submit/:jobId\")\n @before([ParamId(\"printerId\"), ParamId(\"jobId\")])\n async submitToPrinter(req: Request, res: Response) {\n const printerId = req.local.printerId;\n const jobId = req.local.jobId;\n\n try {\n await this.printQueueService.submitToPrinter(printerId, jobId);\n\n res.send({\n message: \"Job submitted to printer for printing\",\n printerId,\n jobId,\n });\n } catch (error) {\n this.logger.error(`Failed to submit job ${jobId} to printer ${printerId}: ${error}`);\n res.status(500).send({\n error: \"Failed to submit job to printer\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"print-queue.controller.js","names":[],"sources":["../../src/controllers/print-queue.controller.ts"],"sourcesContent":["import { before, DELETE, GET, POST, PUT, route } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport type { Request, Response } from \"express\";\nimport { authorizeRoles, authenticate } from \"@/middleware/authenticate\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { PrintQueueService } from \"@/services/print-queue.service\";\nimport { PrintJobService } from \"@/services/orm/print-job.service\";\nimport { FileStorageService } from \"@/services/file-storage.service\";\nimport { PrinterCache } from \"@/state/printer.cache\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\nimport { NotFoundException } from \"@/exceptions/runtime.exceptions\";\n\n@route(AppConstants.apiRoute + \"/print-queue\")\n@before([authenticate(), authorizeRoles([ROLES.ADMIN, ROLES.OPERATOR])])\nexport class PrintQueueController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly printQueueService: PrintQueueService,\n private readonly printJobService: PrintJobService,\n private readonly fileStorageService: FileStorageService,\n private readonly printerCache: PrinterCache,\n ) {\n this.logger = loggerFactory(PrintQueueController.name);\n }\n\n @GET()\n async getGlobalQueue(req: Request, res: Response) {\n try {\n const page = Number.parseInt(req.query.page as string) || 1;\n const pageSize = Number.parseInt(req.query.pageSize as string) || 50;\n\n if (page < 1 || pageSize < 1 || pageSize > 200) {\n res.status(400).send({ error: \"Invalid page or pageSize parameters\" });\n return;\n }\n\n const [jobs, totalCount] = await this.printQueueService.getGlobalQueuePaged(page, pageSize);\n\n const queueItems = jobs.map((job) => ({\n jobId: job.id,\n fileName: job.fileName,\n printerId: job.printerId,\n printerName: job.printerName || job.printer?.name,\n queuePosition: job.queuePosition,\n status: job.status,\n createdAt: job.createdAt,\n estimatedTimeSeconds: (job.metadata as any)?.gcodePrintTimeSeconds,\n filamentGrams: (job.metadata as any)?.filamentUsedGrams,\n }));\n\n res.send({\n items: queueItems,\n page,\n pageSize,\n totalCount,\n totalPages: Math.ceil(totalCount / pageSize),\n });\n } catch (error) {\n this.logger.error(`Failed to get global queue: ${error}`);\n res.status(500).send({ error: \"Failed to get global queue\" });\n }\n }\n\n @GET()\n @route(\"/:printerId\")\n @before([ParamId(\"printerId\")])\n async getQueue(req: Request, res: Response) {\n const printerId = req.local.printerId;\n\n try {\n const queue = await this.printQueueService.getQueue(printerId);\n res.send({\n printerId,\n queue,\n count: queue.length,\n });\n } catch (error) {\n this.logger.error(`Failed to get queue for printer ${printerId}: ${error}`);\n res.status(500).send({ error: \"Failed to get queue\" });\n }\n }\n\n @POST()\n @route(\"/:printerId/add/:jobId\")\n @before([ParamId(\"printerId\"), ParamId(\"jobId\")])\n async addToQueue(req: Request, res: Response) {\n const printerId = req.local.printerId;\n const jobId = req.local.jobId;\n const position = req.body.position === undefined ? undefined : Number.parseInt(req.body.position);\n\n try {\n await this.printQueueService.addToQueue(printerId, jobId, position);\n const queue = await this.printQueueService.getQueue(printerId);\n\n res.send({\n message: \"Job added to queue\",\n printerId,\n jobId,\n position,\n queue,\n });\n } catch (error) {\n this.logger.error(`Failed to add job ${jobId} to queue: ${error}`);\n res.status(500).send({\n error: \"Failed to add to queue\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @PUT()\n @route(\"/:printerId/reorder\")\n @before([ParamId(\"printerId\")])\n async reorderQueue(req: Request, res: Response) {\n const printerId = req.local.printerId;\n const jobIds = req.body.jobIds;\n\n if (!Array.isArray(jobIds)) {\n res.status(400).send({ error: \"jobIds must be an array\" });\n return;\n }\n\n try {\n await this.printQueueService.reorderQueue(printerId, jobIds);\n const queue = await this.printQueueService.getQueue(printerId);\n\n res.send({\n message: \"Queue reordered\",\n printerId,\n queue,\n });\n } catch (error) {\n this.logger.error(`Failed to reorder queue for printer ${printerId}: ${error}`);\n res.status(500).send({\n error: \"Failed to reorder queue\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @DELETE()\n @route(\"/:printerId/clear\")\n @before([ParamId(\"printerId\")])\n async clearQueue(req: Request, res: Response) {\n const printerId = req.local.printerId;\n\n try {\n await this.printQueueService.clearQueue(printerId);\n\n res.send({\n message: \"Queue cleared\",\n printerId,\n });\n } catch (error) {\n this.logger.error(`Failed to clear queue for printer ${printerId}: ${error}`);\n res.status(500).send({\n error: \"Failed to clear queue\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @DELETE()\n @route(\"/:printerId/:jobId\")\n @before([ParamId(\"printerId\"), ParamId(\"jobId\")])\n async removeFromQueue(req: Request, res: Response) {\n const printerId = req.local.printerId;\n const jobId = req.local.jobId;\n\n try {\n await this.printQueueService.removeFromQueue(jobId);\n const queue = await this.printQueueService.getQueue(printerId);\n\n res.send({\n message: \"Job removed from queue\",\n printerId,\n jobId,\n queue,\n });\n } catch (error) {\n this.logger.error(`Failed to remove job ${jobId} from queue: ${error}`);\n res.status(500).send({\n error: \"Failed to remove from queue\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @GET()\n @route(\"/:printerId/next\")\n @before([ParamId(\"printerId\")])\n async getNextInQueue(req: Request, res: Response) {\n const printerId = req.local.printerId;\n\n try {\n const nextJob = await this.printQueueService.getNextInQueue(printerId);\n\n res.send({\n printerId,\n nextJob,\n });\n } catch (error) {\n this.logger.error(`Failed to get next job for printer ${printerId}: ${error}`);\n res.status(500).send({ error: \"Failed to get next job\" });\n }\n }\n\n @POST()\n @route(\"/:printerId/process\")\n @before([ParamId(\"printerId\")])\n async processQueue(req: Request, res: Response) {\n const printerId = req.local.printerId;\n\n try {\n const nextJob = await this.printQueueService.processQueue(printerId);\n\n if (!nextJob) {\n res.send({\n message: \"Queue is empty\",\n printerId,\n nextJob: null,\n });\n return;\n }\n\n res.send({\n message: \"Processing next job in queue\",\n printerId,\n nextJob,\n });\n } catch (error) {\n this.logger.error(`Failed to process queue for printer ${printerId}: ${error}`);\n res.status(500).send({\n error: \"Failed to process queue\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\n }\n }\n\n @POST()\n @route(\"/:printerId/from-file\")\n @before([ParamId(\"printerId\")])\n async createJobFromFile(req: Request, res: Response) {\n const printerId = req.local.printerId;\n const { fileStorageId, addToQueue = true, position } = req.body;\n\n if (!fileStorageId) {\n res.status(400).send({ error: \"fileStorageId is required\" });\n return;\n }\n\n try {\n const fileExists = await this.fileStorageService.fileExists(fileStorageId);\n if (!fileExists) {\n throw new NotFoundException(\"File not found in storage\");\n }\n\n const metadata = await this.fileStorageService.loadMetadata(fileStorageId);\n if (!metadata) {\n res.status(400).send({ error: \"File has no metadata. Please analyze the file first.\" });\n return;\n }\n\n const printer = await this.printerCache.getCachedPrinterOrThrowAsync(printerId);\n\n const job = await this.printJobService.createPendingJob(\n printerId,\n metadata._originalFileName || metadata.fileName || \"Unknown\",\n metadata,\n printer.name,\n );\n\n job.fileStorageId = fileStorageId;\n job.fileHash = metadata._fileHash;\n job.analysisState = \"ANALYZED\";\n job.analyzedAt = new Date();\n\n if (metadata.fileFormat) {\n job.fileFormat = metadata.fileFormat;\n }\n\n await this.printJobService.updateJob(job);\n\n if (addToQueue) {\n await this.printQueueService.addToQueue(printerId, job.id, position);\n }\n\n this.logger.log(\n `Created job ${job.id} from file storage ${fileStorageId} for printer ${printerId}${addToQueue ? \" and added to queue\" : \"\"}`,\n );\n\n res.send({\n id: job.id,\n printerId: job.printerId,\n printerName: job.printerName,\n fileName: job.fileName,\n fileStorageId: job.fileStorageId,\n status: job.status,\n analysisState: job.analysisState,\n createdAt: job.createdAt,\n addedToQueue: addToQueue,\n });\n } catch (error) {\n this.logger.error(`Failed to create job from file ${fileStorageId}: ${error}`);\n res.status(500).send({ error: \"Failed to create job from file\" });\n }\n }\n\n @POST()\n @route(\"/:printerId/submit/:jobId\")\n @before([ParamId(\"printerId\"), ParamId(\"jobId\")])\n async submitToPrinter(req: Request, res: Response) {\n const printerId = req.local.printerId;\n const jobId = req.local.jobId;\n\n try {\n await this.printQueueService.submitToPrinter(printerId, jobId);\n\n res.send({\n message: \"Job submitted to printer for printing\",\n printerId,\n jobId,\n });\n } catch (error) {\n this.logger.error(`Failed to submit job ${jobId} to printer ${printerId}: ${error}`);\n res.status(500).send({\n error: \"Failed to submit job to printer\",\n message: error instanceof Error ? error.message : \"Unknown error\",\n });\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.
|
|
3
|
-
import { __decorate } from "../_virtual/_@oxc-project_runtime@0.
|
|
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 { NotFoundException, ValidationException } from "../exceptions/runtime.exceptions.js";
|
|
6
6
|
import { validateInput } from "../handlers/validators.js";
|