@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":"printer-files.controller.js","names":[],"sources":["../../src/controllers/printer-files.controller.ts"],"sourcesContent":["import { before, DELETE, GET, POST, route } from \"awilix-express\";\nimport { authenticate, authorizeRoles, permission } from \"@/middleware/authenticate\";\nimport { validateInput } from \"@/handlers/validators\";\nimport { AppConstants } from \"@/server.constants\";\nimport {\n downloadFileSchema,\n getFileSchema,\n getFilesSchema,\n startPrintFileSchema,\n uploadFileSchema,\n} from \"./validation/printer-files-controller.validation\";\nimport { NotFoundException, ValidationException } from \"@/exceptions/runtime.exceptions\";\nimport { printerResolveMiddleware } from \"@/middleware/printer\";\nimport { PERMS, ROLES } from \"@/constants/authorization.constants\";\nimport { MulterService } from \"@/services/core/multer.service\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport type { Request, Response } from \"express\";\nimport { BambuType, type IPrinterApi } from \"@/services/printer-api.interface\";\nimport { PrinterThumbnailCache } from \"@/state/printer-thumbnail.cache\";\nimport { captureException } from \"@sentry/node\";\nimport { errorSummary } from \"@/utils/error.utils\";\nimport { getScopedPrinter } from \"@/middleware/printer-resolver\";\nimport { FileAnalysisService } from \"@/services/file-analysis.service\";\nimport { FileStorageService } from \"@/services/file-storage.service\";\nimport { copyFileSync, createReadStream, existsSync, unlinkSync } from \"node:fs\";\nimport { PrintJobService } from \"@/services/orm/print-job.service\";\nimport { extname } from \"node:path\";\n\n@route(AppConstants.apiRoute + \"/printer-files\")\n@before([authenticate(), authorizeRoles([ROLES.ADMIN, ROLES.OPERATOR]), printerResolveMiddleware()])\nexport class PrinterFilesController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly printerApi: IPrinterApi,\n private readonly printJobService: PrintJobService,\n private readonly fileAnalysisService: FileAnalysisService,\n private readonly fileStorageService: FileStorageService,\n private readonly multerService: MulterService,\n private readonly printerThumbnailCache: PrinterThumbnailCache,\n ) {\n this.logger = loggerFactory(PrinterFilesController.name);\n }\n\n @GET()\n @route(\"/thumbnails\")\n @before(permission(PERMS.PrinterFiles.Get))\n async getThumbnails(req: Request, res: Response) {\n const thumbnails = await this.printerThumbnailCache.getAllValues();\n res.send(thumbnails);\n }\n\n @GET()\n @route(\"/:id\")\n @before(permission(PERMS.PrinterFiles.Get))\n async getFiles(req: Request, res: Response) {\n const { printerApi } = getScopedPrinter(req);\n const { recursive: recursiveStr, startDir } = await validateInput(req.query, getFilesSchema);\n const recursive = recursiveStr === \"true\";\n\n const files = await printerApi.getFiles(recursive, startDir);\n res.send(files);\n }\n\n @POST()\n /**\n * @obsolete /:id/select, removed in v2\n */\n @route(\"/:id/select\")\n @route(\"/:id/print\")\n @before(permission(PERMS.PrinterFiles.Actions))\n async startPrintFile(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n const { filePath } = await validateInput(req.body, startPrintFileSchema);\n const encodedFilePath = filePath.split(\"/\").map(encodeURIComponent).join(\"/\");\n await this.printerApi.startPrint(encodedFilePath);\n\n this.logger.log(`Started print for printer ${currentPrinterId}`);\n\n res.send();\n }\n\n @GET()\n @route(\"/:id/download/:path\")\n @before(permission(PERMS.PrinterFiles.Get))\n async downloadFile(req: Request, res: Response) {\n this.logger.log(`Downloading file ${req.params.path}`);\n const { path } = await validateInput(req.params, downloadFileSchema);\n const encodedFilePath = path.split(\"/\").map(encodeURIComponent).join(\"/\");\n\n const response = await this.printerApi.downloadFile(encodedFilePath);\n res.setHeader(\"Content-Type\", response.headers[\"content-type\"]);\n res.setHeader(\"Content-Length\", response.headers[\"content-length\"]);\n res.setHeader(\"Content-Disposition\", response.headers[\"content-disposition\"]);\n if (response.headers[\"etag\"]?.length) {\n res.setHeader(\"ETag\", response.headers[\"etag\"]);\n }\n response.data.pipe(res);\n }\n\n @DELETE()\n @route(\"/:id\")\n @before(permission(PERMS.PrinterFiles.Delete))\n async deleteFileOrFolder(req: Request, res: Response) {\n const { path } = await validateInput(req.query, getFileSchema);\n const encodedFilePath = path.split(\"/\").map(encodeURIComponent).join(\"/\");\n\n const result = await this.printerApi.deleteFile(encodedFilePath);\n res.send(result);\n }\n\n @GET()\n @route(\"/:id/thumbnail\")\n @before(permission(PERMS.PrinterFiles.Get))\n async getPrinterThumbnail(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n const printerThumbnail = await this.printerThumbnailCache.getValue(currentPrinterId);\n res.send(printerThumbnail);\n }\n\n @POST()\n @route(\"/:id/upload\")\n @before(permission(PERMS.PrinterFiles.Upload))\n async uploadPrinterFile(req: Request, res: Response) {\n const { currentPrinterId, currentPrinter } = getScopedPrinter(req);\n\n const acceptedExtensions = this.getAcceptedFileExtensions(currentPrinter.printerType);\n const files = await this.multerService.multerLoadFileAsync(req, res, acceptedExtensions, true);\n\n // FormData has key-values with type string only\n const { startPrint: startPrintString } = await validateInput(req.body, uploadFileSchema);\n const startPrint = startPrintString === \"true\";\n\n if (!files?.length) {\n throw new ValidationException({\n error: `No file was available for upload. Did you upload files with one of these extensions: ${acceptedExtensions.join(\n \", \",\n )}?`,\n });\n }\n if (files.length > 1) {\n throw new ValidationException({\n error: \"Only 1 file can be uploaded at a time\",\n });\n }\n\n const uploadedFile = files[0];\n const token = this.multerService.startTrackingSession(uploadedFile, currentPrinterId);\n\n await this.printerApi\n .uploadFile({\n stream: createReadStream(uploadedFile.path),\n fileName: uploadedFile.originalname,\n contentLength: uploadedFile.size,\n startPrint,\n uploadToken: token,\n })\n .catch((e) => {\n try {\n this.multerService.clearUploadedFile(uploadedFile);\n } catch (e) {\n this.logger.error(`Could not remove uploaded file from temporary storage ${errorSummary(e)}`);\n }\n throw e;\n });\n\n // Process file: analyze, store, create job\n const ext = extname(uploadedFile.originalname);\n const tempPathWithExt = uploadedFile.path + ext;\n\n try {\n this.logger.log(`Processing uploaded file: ${uploadedFile.originalname} (ext: ${ext})`);\n\n // Copy file with proper extension for hash calculation and analysis\n if (!existsSync(uploadedFile.path)) {\n throw new NotFoundException(`Upload file does not exist: ${uploadedFile.path}`);\n }\n\n copyFileSync(uploadedFile.path, tempPathWithExt);\n\n // Calculate hash for deduplication\n const fileHash = await this.fileStorageService.calculateFileHash(tempPathWithExt);\n this.logger.log(`File hash: ${fileHash.substring(0, 12)}...`);\n\n // Check if file already analyzed (by hash)\n const existingJob = await this.fileStorageService.findDuplicateByHash(fileHash);\n\n let metadata;\n let fileStorageId;\n\n if (existingJob && existingJob.fileStorageId) {\n // Found duplicate by hash - REUSE existing storage file\n const cachedMetadata = await this.fileStorageService.loadMetadata(existingJob.fileStorageId);\n\n if (cachedMetadata) {\n // Use cached metadata from JSON file (fastest - no re-analysis, no re-storage)\n this.logger.log(\n `Duplicate file detected (job ${existingJob.id}, hash match) - reusing storage ${existingJob.fileStorageId}`,\n );\n metadata = {\n ...cachedMetadata,\n fileName: uploadedFile.originalname, // Update filename to current upload\n };\n fileStorageId = existingJob.fileStorageId; // REUSE existing storage!\n } else if (existingJob.analysisState === \"ANALYZED\" && existingJob.metadata) {\n // No JSON cache, but have metadata in DB - use it and create JSON\n this.logger.log(\n `Duplicate file with DB metadata (job ${existingJob.id}) - reusing storage ${existingJob.fileStorageId}`,\n );\n metadata = {\n ...existingJob.metadata,\n fileName: uploadedFile.originalname,\n };\n fileStorageId = existingJob.fileStorageId; // REUSE existing storage!\n\n // Save metadata JSON for future deduplication (preserve original filename)\n await this.fileStorageService.saveMetadata(fileStorageId, metadata, fileHash, uploadedFile.originalname);\n } else {\n // Duplicate hash but not analyzed - reuse storage, analyze file\n this.logger.log(`Duplicate file not analyzed - reusing storage ${existingJob.fileStorageId}, analyzing now`);\n\n // Get existing file for analysis\n const existingFilePath = this.fileStorageService.getFilePath(existingJob.fileStorageId);\n const analysisResult = await this.fileAnalysisService.analyzeFile(existingFilePath);\n metadata = analysisResult.metadata;\n\n fileStorageId = existingJob.fileStorageId; // REUSE existing storage!\n await this.fileStorageService.saveMetadata(fileStorageId, metadata, fileHash, uploadedFile.originalname);\n this.logger.log(`Analysis complete and cached: ${fileStorageId}`);\n }\n } else {\n // New file - analyze BEFORE saving (saveFile moves the original!)\n this.logger.log(`Analyzing new file: ${uploadedFile.originalname}`);\n const analysisResult = await this.fileAnalysisService.analyzeFile(tempPathWithExt);\n metadata = analysisResult.metadata;\n const thumbnails = analysisResult.thumbnails;\n this.logger.log(\n `Analysis complete: format=${metadata.fileFormat}, layers=${metadata.totalLayers}, time=${metadata.gcodePrintTimeSeconds}s, filament=${metadata.filamentUsedGrams}g, thumbnails=${thumbnails.length}`,\n );\n\n // Now save file to storage with deterministic ID (moves file from temp to permanent storage)\n fileStorageId = await this.fileStorageService.saveFile(uploadedFile, fileHash);\n this.logger.log(`Saved file to storage: ${fileStorageId} (deterministic from hash+name)`);\n\n // Save thumbnails\n let thumbnailMetadata: any[] = [];\n if (thumbnails.length > 0) {\n thumbnailMetadata = await this.fileStorageService.saveThumbnails(fileStorageId, thumbnails);\n this.logger.log(`Saved ${thumbnailMetadata.length} thumbnail(s) for ${fileStorageId}`);\n }\n\n // Save metadata JSON with thumbnail index\n await this.fileStorageService.saveMetadata(\n fileStorageId,\n metadata,\n fileHash,\n uploadedFile.originalname,\n thumbnailMetadata,\n );\n this.logger.log(`Saved metadata JSON for ${fileStorageId}`);\n }\n\n // Create job with analyzed metadata, hash, and storageId\n const job = await this.printJobService.createPendingJob(\n currentPrinterId,\n uploadedFile.originalname,\n metadata,\n currentPrinter.name,\n );\n\n job.fileStorageId = fileStorageId;\n job.fileHash = fileHash;\n await this.printJobService.updateJob(job);\n\n this.logger.log(\n `Created job ${job.id}: format=${job.fileFormat}, ` +\n `state=${job.analysisState}, ` +\n `storageId=${fileStorageId}, ` +\n `hash=${fileHash.substring(0, 8)}...`,\n );\n\n // Clean up temp analysis file\n if (existsSync(tempPathWithExt)) {\n unlinkSync(tempPathWithExt);\n }\n\n // Thumbnail will be automatically loaded from the analyzed print job\n // by the PrinterThumbnailCache when the job is analyzed\n } catch (error) {\n this.logger.error(`File processing failed: ${errorSummary(error)}`);\n captureException(error);\n // Don't throw - allow upload to succeed even if analysis/storage fails\n } finally {\n // Always clean up temp file\n try {\n this.multerService.clearUploadedFile(uploadedFile);\n } catch (e) {\n this.logger.error(`Could not remove uploaded file from temporary storage ${errorSummary(e)}`);\n }\n }\n\n res.send();\n }\n\n private getAcceptedFileExtensions(printerType: number): string[] {\n if (printerType === BambuType) {\n return AppConstants.defaultAcceptedBambuExtensions;\n }\n return AppConstants.defaultAcceptedGcodeExtensions;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"printer-files.controller.js","names":[],"sources":["../../src/controllers/printer-files.controller.ts"],"sourcesContent":["import { before, DELETE, GET, POST, route } from \"awilix-express\";\nimport { authenticate, authorizeRoles, permission } from \"@/middleware/authenticate\";\nimport { validateInput } from \"@/handlers/validators\";\nimport { AppConstants } from \"@/server.constants\";\nimport {\n downloadFileSchema,\n getFileSchema,\n getFilesSchema,\n startPrintFileSchema,\n uploadFileSchema,\n} from \"./validation/printer-files-controller.validation\";\nimport { NotFoundException, ValidationException } from \"@/exceptions/runtime.exceptions\";\nimport { printerResolveMiddleware } from \"@/middleware/printer\";\nimport { PERMS, ROLES } from \"@/constants/authorization.constants\";\nimport { MulterService } from \"@/services/core/multer.service\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport type { Request, Response } from \"express\";\nimport { BambuType, type IPrinterApi } from \"@/services/printer-api.interface\";\nimport { PrinterThumbnailCache } from \"@/state/printer-thumbnail.cache\";\nimport { captureException } from \"@sentry/node\";\nimport { errorSummary } from \"@/utils/error.utils\";\nimport { getScopedPrinter } from \"@/middleware/printer-resolver\";\nimport { FileAnalysisService } from \"@/services/file-analysis.service\";\nimport { FileStorageService } from \"@/services/file-storage.service\";\nimport { copyFileSync, createReadStream, existsSync, unlinkSync } from \"node:fs\";\nimport { PrintJobService } from \"@/services/orm/print-job.service\";\nimport { extname } from \"node:path\";\n\n@route(AppConstants.apiRoute + \"/printer-files\")\n@before([authenticate(), authorizeRoles([ROLES.ADMIN, ROLES.OPERATOR]), printerResolveMiddleware()])\nexport class PrinterFilesController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly printerApi: IPrinterApi,\n private readonly printJobService: PrintJobService,\n private readonly fileAnalysisService: FileAnalysisService,\n private readonly fileStorageService: FileStorageService,\n private readonly multerService: MulterService,\n private readonly printerThumbnailCache: PrinterThumbnailCache,\n ) {\n this.logger = loggerFactory(PrinterFilesController.name);\n }\n\n @GET()\n @route(\"/thumbnails\")\n @before(permission(PERMS.PrinterFiles.Get))\n async getThumbnails(req: Request, res: Response) {\n const thumbnails = await this.printerThumbnailCache.getAllValues();\n res.send(thumbnails);\n }\n\n @GET()\n @route(\"/:id\")\n @before(permission(PERMS.PrinterFiles.Get))\n async getFiles(req: Request, res: Response) {\n const { printerApi } = getScopedPrinter(req);\n const { recursive: recursiveStr, startDir } = await validateInput(req.query, getFilesSchema);\n const recursive = recursiveStr === \"true\";\n\n const files = await printerApi.getFiles(recursive, startDir);\n res.send(files);\n }\n\n @POST()\n /**\n * @obsolete /:id/select, removed in v2\n */\n @route(\"/:id/select\")\n @route(\"/:id/print\")\n @before(permission(PERMS.PrinterFiles.Actions))\n async startPrintFile(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n const { filePath } = await validateInput(req.body, startPrintFileSchema);\n const encodedFilePath = filePath.split(\"/\").map(encodeURIComponent).join(\"/\");\n await this.printerApi.startPrint(encodedFilePath);\n\n this.logger.log(`Started print for printer ${currentPrinterId}`);\n\n res.send();\n }\n\n @GET()\n @route(\"/:id/download/:path\")\n @before(permission(PERMS.PrinterFiles.Get))\n async downloadFile(req: Request, res: Response) {\n this.logger.log(`Downloading file ${req.params.path}`);\n const { path } = await validateInput(req.params, downloadFileSchema);\n const encodedFilePath = path.split(\"/\").map(encodeURIComponent).join(\"/\");\n\n const response = await this.printerApi.downloadFile(encodedFilePath);\n res.setHeader(\"Content-Type\", response.headers[\"content-type\"]);\n res.setHeader(\"Content-Length\", response.headers[\"content-length\"]);\n res.setHeader(\"Content-Disposition\", response.headers[\"content-disposition\"]);\n if (response.headers[\"etag\"]?.length) {\n res.setHeader(\"ETag\", response.headers[\"etag\"]);\n }\n response.data.pipe(res);\n }\n\n @DELETE()\n @route(\"/:id\")\n @before(permission(PERMS.PrinterFiles.Delete))\n async deleteFileOrFolder(req: Request, res: Response) {\n const { path } = await validateInput(req.query, getFileSchema);\n const encodedFilePath = path.split(\"/\").map(encodeURIComponent).join(\"/\");\n\n const result = await this.printerApi.deleteFile(encodedFilePath);\n res.send(result);\n }\n\n @GET()\n @route(\"/:id/thumbnail\")\n @before(permission(PERMS.PrinterFiles.Get))\n async getPrinterThumbnail(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n const printerThumbnail = await this.printerThumbnailCache.getValue(currentPrinterId);\n res.send(printerThumbnail);\n }\n\n @POST()\n @route(\"/:id/upload\")\n @before(permission(PERMS.PrinterFiles.Upload))\n async uploadPrinterFile(req: Request, res: Response) {\n const { currentPrinterId, currentPrinter } = getScopedPrinter(req);\n\n const acceptedExtensions = this.getAcceptedFileExtensions(currentPrinter.printerType);\n const files = await this.multerService.multerLoadFileAsync(req, res, acceptedExtensions, true);\n\n // FormData has key-values with type string only\n const { startPrint: startPrintString } = await validateInput(req.body, uploadFileSchema);\n const startPrint = startPrintString === \"true\";\n\n if (!files?.length) {\n throw new ValidationException({\n error: `No file was available for upload. Did you upload files with one of these extensions: ${acceptedExtensions.join(\n \", \",\n )}?`,\n });\n }\n if (files.length > 1) {\n throw new ValidationException({\n error: \"Only 1 file can be uploaded at a time\",\n });\n }\n\n const uploadedFile = files[0];\n const token = this.multerService.startTrackingSession(uploadedFile, currentPrinterId);\n\n await this.printerApi\n .uploadFile({\n stream: createReadStream(uploadedFile.path),\n fileName: uploadedFile.originalname,\n contentLength: uploadedFile.size,\n startPrint,\n uploadToken: token,\n })\n .catch((e) => {\n try {\n this.multerService.clearUploadedFile(uploadedFile);\n } catch (e) {\n this.logger.error(`Could not remove uploaded file from temporary storage ${errorSummary(e)}`);\n }\n throw e;\n });\n\n // Process file: analyze, store, create job\n const ext = extname(uploadedFile.originalname);\n const tempPathWithExt = uploadedFile.path + ext;\n\n try {\n this.logger.log(`Processing uploaded file: ${uploadedFile.originalname} (ext: ${ext})`);\n\n // Copy file with proper extension for hash calculation and analysis\n if (!existsSync(uploadedFile.path)) {\n throw new NotFoundException(`Upload file does not exist: ${uploadedFile.path}`);\n }\n\n copyFileSync(uploadedFile.path, tempPathWithExt);\n\n // Calculate hash for deduplication\n const fileHash = await this.fileStorageService.calculateFileHash(tempPathWithExt);\n this.logger.log(`File hash: ${fileHash.substring(0, 12)}...`);\n\n // Check if file already analyzed (by hash)\n const existingJob = await this.fileStorageService.findDuplicateByHash(fileHash);\n\n let metadata;\n let fileStorageId;\n\n if (existingJob && existingJob.fileStorageId) {\n // Found duplicate by hash - REUSE existing storage file\n const cachedMetadata = await this.fileStorageService.loadMetadata(existingJob.fileStorageId);\n\n if (cachedMetadata) {\n // Use cached metadata from JSON file (fastest - no re-analysis, no re-storage)\n this.logger.log(\n `Duplicate file detected (job ${existingJob.id}, hash match) - reusing storage ${existingJob.fileStorageId}`,\n );\n metadata = {\n ...cachedMetadata,\n fileName: uploadedFile.originalname, // Update filename to current upload\n };\n fileStorageId = existingJob.fileStorageId; // REUSE existing storage!\n } else if (existingJob.analysisState === \"ANALYZED\" && existingJob.metadata) {\n // No JSON cache, but have metadata in DB - use it and create JSON\n this.logger.log(\n `Duplicate file with DB metadata (job ${existingJob.id}) - reusing storage ${existingJob.fileStorageId}`,\n );\n metadata = {\n ...existingJob.metadata,\n fileName: uploadedFile.originalname,\n };\n fileStorageId = existingJob.fileStorageId; // REUSE existing storage!\n\n // Save metadata JSON for future deduplication (preserve original filename)\n await this.fileStorageService.saveMetadata(fileStorageId, metadata, fileHash, uploadedFile.originalname);\n } else {\n // Duplicate hash but not analyzed - reuse storage, analyze file\n this.logger.log(`Duplicate file not analyzed - reusing storage ${existingJob.fileStorageId}, analyzing now`);\n\n // Get existing file for analysis\n const existingFilePath = this.fileStorageService.getFilePath(existingJob.fileStorageId);\n const analysisResult = await this.fileAnalysisService.analyzeFile(existingFilePath);\n metadata = analysisResult.metadata;\n\n fileStorageId = existingJob.fileStorageId; // REUSE existing storage!\n await this.fileStorageService.saveMetadata(fileStorageId, metadata, fileHash, uploadedFile.originalname);\n this.logger.log(`Analysis complete and cached: ${fileStorageId}`);\n }\n } else {\n // New file - analyze BEFORE saving (saveFile moves the original!)\n this.logger.log(`Analyzing new file: ${uploadedFile.originalname}`);\n const analysisResult = await this.fileAnalysisService.analyzeFile(tempPathWithExt);\n metadata = analysisResult.metadata;\n const thumbnails = analysisResult.thumbnails;\n this.logger.log(\n `Analysis complete: format=${metadata.fileFormat}, layers=${metadata.totalLayers}, time=${metadata.gcodePrintTimeSeconds}s, filament=${metadata.filamentUsedGrams}g, thumbnails=${thumbnails.length}`,\n );\n\n // Now save file to storage with deterministic ID (moves file from temp to permanent storage)\n fileStorageId = await this.fileStorageService.saveFile(uploadedFile, fileHash);\n this.logger.log(`Saved file to storage: ${fileStorageId} (deterministic from hash+name)`);\n\n // Save thumbnails\n let thumbnailMetadata: any[] = [];\n if (thumbnails.length > 0) {\n thumbnailMetadata = await this.fileStorageService.saveThumbnails(fileStorageId, thumbnails);\n this.logger.log(`Saved ${thumbnailMetadata.length} thumbnail(s) for ${fileStorageId}`);\n }\n\n // Save metadata JSON with thumbnail index\n await this.fileStorageService.saveMetadata(\n fileStorageId,\n metadata,\n fileHash,\n uploadedFile.originalname,\n thumbnailMetadata,\n );\n this.logger.log(`Saved metadata JSON for ${fileStorageId}`);\n }\n\n // Create job with analyzed metadata, hash, and storageId\n const job = await this.printJobService.createPendingJob(\n currentPrinterId,\n uploadedFile.originalname,\n metadata,\n currentPrinter.name,\n );\n\n job.fileStorageId = fileStorageId;\n job.fileHash = fileHash;\n await this.printJobService.updateJob(job);\n\n this.logger.log(\n `Created job ${job.id}: format=${job.fileFormat}, ` +\n `state=${job.analysisState}, ` +\n `storageId=${fileStorageId}, ` +\n `hash=${fileHash.substring(0, 8)}...`,\n );\n\n // Clean up temp analysis file\n if (existsSync(tempPathWithExt)) {\n unlinkSync(tempPathWithExt);\n }\n\n // Thumbnail will be automatically loaded from the analyzed print job\n // by the PrinterThumbnailCache when the job is analyzed\n } catch (error) {\n this.logger.error(`File processing failed: ${errorSummary(error)}`);\n captureException(error);\n // Don't throw - allow upload to succeed even if analysis/storage fails\n } finally {\n // Always clean up temp file\n try {\n this.multerService.clearUploadedFile(uploadedFile);\n } catch (e) {\n this.logger.error(`Could not remove uploaded file from temporary storage ${errorSummary(e)}`);\n }\n }\n\n res.send();\n }\n\n private getAcceptedFileExtensions(printerType: number): string[] {\n if (printerType === BambuType) {\n return AppConstants.defaultAcceptedBambuExtensions;\n }\n return AppConstants.defaultAcceptedGcodeExtensions;\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 { PrinterMaintenanceLogService } from "../services/orm/printer-maintenance-log.service.js";
|
|
6
6
|
import { AppConstants } from "../server.constants.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"printer-maintenance-log.controller.js","names":[],"sources":["../../src/controllers/printer-maintenance-log.controller.ts"],"sourcesContent":["import { before, DELETE, GET, POST, route } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport type { Request, Response } from \"express\";\nimport { authenticate, permission } from \"@/middleware/authenticate\";\nimport { PERMS } from \"@/constants/authorization.constants\";\nimport { PrinterMaintenanceLogService } from \"@/services/orm/printer-maintenance-log.service\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { validateInput } from \"@/handlers/validators\";\nimport {\n completeMaintenanceLogSchema,\n createMaintenanceLogSchema,\n getMaintenanceLogsQuerySchema,\n} from \"@/services/validators/printer-maintenance-log.validation\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\n\n@route(AppConstants.apiRoute + \"/printer-maintenance-log\")\n@before([authenticate()])\nexport class PrinterMaintenanceLogController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly printerMaintenanceLogService: PrinterMaintenanceLogService,\n ) {\n this.logger = loggerFactory(PrinterMaintenanceLogController.name);\n }\n\n @GET()\n @route(\"/\")\n @before([permission(PERMS.PrinterMaintenanceLog.List)])\n async list(req: Request, res: Response) {\n const query = await validateInput(req.query, getMaintenanceLogsQuerySchema);\n const result = await this.printerMaintenanceLogService.list(query);\n\n res.send({\n logs: result.logs.map((log) => this.printerMaintenanceLogService.toDto(log)),\n total: result.total,\n page: query.page,\n pageSize: query.pageSize,\n });\n }\n\n @GET()\n @route(\"/:id\")\n @before([permission(PERMS.PrinterMaintenanceLog.Get), ParamId(\"id\")])\n async get(req: Request, res: Response) {\n const logId = req.params.id as unknown as number;\n const log = await this.printerMaintenanceLogService.get(logId);\n res.send(this.printerMaintenanceLogService.toDto(log));\n }\n\n @GET()\n @route(\"/printer/:printerId/active\")\n @before([permission(PERMS.PrinterMaintenanceLog.Get), ParamId(\"printerId\")])\n async getActiveByPrinterId(req: Request, res: Response) {\n const printerId = req.params.printerId as unknown as number;\n const log = await this.printerMaintenanceLogService.getActiveByPrinterId(printerId);\n res.send(log ? this.printerMaintenanceLogService.toDto(log) : null);\n }\n\n @POST()\n @route(\"/\")\n @before([permission(PERMS.PrinterMaintenanceLog.Create)])\n async create(req: Request, res: Response) {\n const data = await validateInput(req.body, createMaintenanceLogSchema);\n const userId = req.user?.id ?? null;\n const username = req.user?.username || \"system\";\n\n const log = await this.printerMaintenanceLogService.create(data, userId, username);\n res.send(this.printerMaintenanceLogService.toDto(log));\n }\n\n @POST()\n @route(\"/:id/complete\")\n @before([permission(PERMS.PrinterMaintenanceLog.Complete), ParamId(\"id\")])\n async complete(req: Request, res: Response) {\n const logId = req.params.id as unknown as number;\n const data = await validateInput(req.body, completeMaintenanceLogSchema);\n const userId = req.user?.id ?? null;\n const username = req.user?.username || \"system\";\n\n const log = await this.printerMaintenanceLogService.complete(logId, data, userId, username);\n res.send(this.printerMaintenanceLogService.toDto(log));\n }\n\n @DELETE()\n @route(\"/:id\")\n @before([permission(PERMS.PrinterMaintenanceLog.Delete), ParamId(\"id\")])\n async delete(req: Request, res: Response) {\n const logId = req.params.id as unknown as number;\n await this.printerMaintenanceLogService.delete(logId);\n res.send({ success: true });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAkBO,IAAA,kCAAA,mCAAA,MAAM,gCAAgC;CAC3C;CAEA,YACE,eACA,8BACA;
|
|
1
|
+
{"version":3,"file":"printer-maintenance-log.controller.js","names":[],"sources":["../../src/controllers/printer-maintenance-log.controller.ts"],"sourcesContent":["import { before, DELETE, GET, POST, route } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport type { Request, Response } from \"express\";\nimport { authenticate, permission } from \"@/middleware/authenticate\";\nimport { PERMS } from \"@/constants/authorization.constants\";\nimport { PrinterMaintenanceLogService } from \"@/services/orm/printer-maintenance-log.service\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { validateInput } from \"@/handlers/validators\";\nimport {\n completeMaintenanceLogSchema,\n createMaintenanceLogSchema,\n getMaintenanceLogsQuerySchema,\n} from \"@/services/validators/printer-maintenance-log.validation\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\n\n@route(AppConstants.apiRoute + \"/printer-maintenance-log\")\n@before([authenticate()])\nexport class PrinterMaintenanceLogController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly printerMaintenanceLogService: PrinterMaintenanceLogService,\n ) {\n this.logger = loggerFactory(PrinterMaintenanceLogController.name);\n }\n\n @GET()\n @route(\"/\")\n @before([permission(PERMS.PrinterMaintenanceLog.List)])\n async list(req: Request, res: Response) {\n const query = await validateInput(req.query, getMaintenanceLogsQuerySchema);\n const result = await this.printerMaintenanceLogService.list(query);\n\n res.send({\n logs: result.logs.map((log) => this.printerMaintenanceLogService.toDto(log)),\n total: result.total,\n page: query.page,\n pageSize: query.pageSize,\n });\n }\n\n @GET()\n @route(\"/:id\")\n @before([permission(PERMS.PrinterMaintenanceLog.Get), ParamId(\"id\")])\n async get(req: Request, res: Response) {\n const logId = req.params.id as unknown as number;\n const log = await this.printerMaintenanceLogService.get(logId);\n res.send(this.printerMaintenanceLogService.toDto(log));\n }\n\n @GET()\n @route(\"/printer/:printerId/active\")\n @before([permission(PERMS.PrinterMaintenanceLog.Get), ParamId(\"printerId\")])\n async getActiveByPrinterId(req: Request, res: Response) {\n const printerId = req.params.printerId as unknown as number;\n const log = await this.printerMaintenanceLogService.getActiveByPrinterId(printerId);\n res.send(log ? this.printerMaintenanceLogService.toDto(log) : null);\n }\n\n @POST()\n @route(\"/\")\n @before([permission(PERMS.PrinterMaintenanceLog.Create)])\n async create(req: Request, res: Response) {\n const data = await validateInput(req.body, createMaintenanceLogSchema);\n const userId = req.user?.id ?? null;\n const username = req.user?.username || \"system\";\n\n const log = await this.printerMaintenanceLogService.create(data, userId, username);\n res.send(this.printerMaintenanceLogService.toDto(log));\n }\n\n @POST()\n @route(\"/:id/complete\")\n @before([permission(PERMS.PrinterMaintenanceLog.Complete), ParamId(\"id\")])\n async complete(req: Request, res: Response) {\n const logId = req.params.id as unknown as number;\n const data = await validateInput(req.body, completeMaintenanceLogSchema);\n const userId = req.user?.id ?? null;\n const username = req.user?.username || \"system\";\n\n const log = await this.printerMaintenanceLogService.complete(logId, data, userId, username);\n res.send(this.printerMaintenanceLogService.toDto(log));\n }\n\n @DELETE()\n @route(\"/:id\")\n @before([permission(PERMS.PrinterMaintenanceLog.Delete), ParamId(\"id\")])\n async delete(req: Request, res: Response) {\n const logId = req.params.id as unknown as number;\n await this.printerMaintenanceLogService.delete(logId);\n res.send({ success: true });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAkBO,IAAA,kCAAA,mCAAA,MAAM,gCAAgC;CAC3C;CAEA,YACE,eACA,8BACA;EADiB,KAAA,+BAAA;EAEjB,KAAK,SAAS,cAAA,iCAA8C,KAAK;;CAGnE,MAGM,KAAK,KAAc,KAAe;EACtC,MAAM,QAAQ,MAAM,cAAc,IAAI,OAAO,8BAA8B;EAC3E,MAAM,SAAS,MAAM,KAAK,6BAA6B,KAAK,MAAM;EAElE,IAAI,KAAK;GACP,MAAM,OAAO,KAAK,KAAK,QAAQ,KAAK,6BAA6B,MAAM,IAAI,CAAC;GAC5E,OAAO,OAAO;GACd,MAAM,MAAM;GACZ,UAAU,MAAM;GACjB,CAAC;;CAGJ,MAGM,IAAI,KAAc,KAAe;EACrC,MAAM,QAAQ,IAAI,OAAO;EACzB,MAAM,MAAM,MAAM,KAAK,6BAA6B,IAAI,MAAM;EAC9D,IAAI,KAAK,KAAK,6BAA6B,MAAM,IAAI,CAAC;;CAGxD,MAGM,qBAAqB,KAAc,KAAe;EACtD,MAAM,YAAY,IAAI,OAAO;EAC7B,MAAM,MAAM,MAAM,KAAK,6BAA6B,qBAAqB,UAAU;EACnF,IAAI,KAAK,MAAM,KAAK,6BAA6B,MAAM,IAAI,GAAG,KAAK;;CAGrE,MAGM,OAAO,KAAc,KAAe;EACxC,MAAM,OAAO,MAAM,cAAc,IAAI,MAAM,2BAA2B;EACtE,MAAM,SAAS,IAAI,MAAM,MAAM;EAC/B,MAAM,WAAW,IAAI,MAAM,YAAY;EAEvC,MAAM,MAAM,MAAM,KAAK,6BAA6B,OAAO,MAAM,QAAQ,SAAS;EAClF,IAAI,KAAK,KAAK,6BAA6B,MAAM,IAAI,CAAC;;CAGxD,MAGM,SAAS,KAAc,KAAe;EAC1C,MAAM,QAAQ,IAAI,OAAO;EACzB,MAAM,OAAO,MAAM,cAAc,IAAI,MAAM,6BAA6B;EACxE,MAAM,SAAS,IAAI,MAAM,MAAM;EAC/B,MAAM,WAAW,IAAI,MAAM,YAAY;EAEvC,MAAM,MAAM,MAAM,KAAK,6BAA6B,SAAS,OAAO,MAAM,QAAQ,SAAS;EAC3F,IAAI,KAAK,KAAK,6BAA6B,MAAM,IAAI,CAAC;;CAGxD,MAGM,OAAO,KAAc,KAAe;EACxC,MAAM,QAAQ,IAAI,OAAO;EACzB,MAAM,KAAK,6BAA6B,OAAO,MAAM;EACrD,IAAI,KAAK,EAAE,SAAS,MAAM,CAAC;;;;CAhE5B,KAAK;CACL,MAAM,IAAI;CACV,OAAO,CAAC,WAAW,MAAM,sBAAsB,KAAK,CAAC,CAAC;;;;;;CAatD,KAAK;CACL,MAAM,OAAO;CACb,OAAO,CAAC,WAAW,MAAM,sBAAsB,IAAI,EAAE,QAAQ,KAAK,CAAC,CAAC;;;;;;CAOpE,KAAK;CACL,MAAM,6BAA6B;CACnC,OAAO,CAAC,WAAW,MAAM,sBAAsB,IAAI,EAAE,QAAQ,YAAY,CAAC,CAAC;;;;;;CAO3E,MAAM;CACN,MAAM,IAAI;CACV,OAAO,CAAC,WAAW,MAAM,sBAAsB,OAAO,CAAC,CAAC;;;;;;CAUxD,MAAM;CACN,MAAM,gBAAgB;CACtB,OAAO,CAAC,WAAW,MAAM,sBAAsB,SAAS,EAAE,QAAQ,KAAK,CAAC,CAAC;;;;;;CAWzE,QAAQ;CACR,MAAM,OAAO;CACb,OAAO,CAAC,WAAW,MAAM,sBAAsB,OAAO,EAAE,QAAQ,KAAK,CAAC,CAAC;;;;;;CAxEzE,MAAM,aAAa,WAAW,2BAA2B;CACzD,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 { PERMS } from "../constants/authorization.constants.js";
|
|
6
6
|
import { authenticate, permission } from "../middleware/authenticate.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"printer-settings.controller.js","names":[],"sources":["../../src/controllers/printer-settings.controller.ts"],"sourcesContent":["import { before, GET, POST, route } from \"awilix-express\";\nimport { authenticate, permission } from \"@/middleware/authenticate\";\nimport { AppConstants } from \"@/server.constants\";\nimport { PERMS } from \"@/constants/authorization.constants\";\nimport { OctoprintClient } from \"@/services/octoprint/octoprint.client\";\nimport { PrinterCache } from \"@/state/printer.cache\";\nimport type { Request, Response } from \"express\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\n\n@route(AppConstants.apiRoute + \"/printer-settings\")\n@before([authenticate()])\nexport class PrinterSettingsController {\n constructor(\n private readonly printerCache: PrinterCache,\n private readonly octoprintClient: OctoprintClient,\n ) {}\n\n @GET()\n @route(\"/:id\")\n @before([permission(PERMS.PrinterSettings.Get), ParamId(\"id\")])\n async get(req: Request, res: Response) {\n const loginDto = await this.printerCache.getLoginDtoAsync(req.local.id);\n const settings = await this.octoprintClient.getSettings(loginDto);\n res.send(settings.data);\n }\n\n @POST()\n @route(\"/:id/sync-printername\")\n @before([ParamId(\"id\")])\n async syncPrinterName(req: Request, res: Response) {\n const printerLogin = await this.printerCache.getLoginDtoAsync(req.local.id);\n const name = await this.printerCache.getNameAsync(req.local.id);\n const settings = await this.octoprintClient.updatePrinterNameSetting(printerLogin, name);\n res.send(settings.data);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAWO,IAAA,4BAAA,MAAM,0BAA0B;CACrC,YACE,cACA,iBACA;
|
|
1
|
+
{"version":3,"file":"printer-settings.controller.js","names":[],"sources":["../../src/controllers/printer-settings.controller.ts"],"sourcesContent":["import { before, GET, POST, route } from \"awilix-express\";\nimport { authenticate, permission } from \"@/middleware/authenticate\";\nimport { AppConstants } from \"@/server.constants\";\nimport { PERMS } from \"@/constants/authorization.constants\";\nimport { OctoprintClient } from \"@/services/octoprint/octoprint.client\";\nimport { PrinterCache } from \"@/state/printer.cache\";\nimport type { Request, Response } from \"express\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\n\n@route(AppConstants.apiRoute + \"/printer-settings\")\n@before([authenticate()])\nexport class PrinterSettingsController {\n constructor(\n private readonly printerCache: PrinterCache,\n private readonly octoprintClient: OctoprintClient,\n ) {}\n\n @GET()\n @route(\"/:id\")\n @before([permission(PERMS.PrinterSettings.Get), ParamId(\"id\")])\n async get(req: Request, res: Response) {\n const loginDto = await this.printerCache.getLoginDtoAsync(req.local.id);\n const settings = await this.octoprintClient.getSettings(loginDto);\n res.send(settings.data);\n }\n\n @POST()\n @route(\"/:id/sync-printername\")\n @before([ParamId(\"id\")])\n async syncPrinterName(req: Request, res: Response) {\n const printerLogin = await this.printerCache.getLoginDtoAsync(req.local.id);\n const name = await this.printerCache.getNameAsync(req.local.id);\n const settings = await this.octoprintClient.updatePrinterNameSetting(printerLogin, name);\n res.send(settings.data);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAWO,IAAA,4BAAA,MAAM,0BAA0B;CACrC,YACE,cACA,iBACA;EAFiB,KAAA,eAAA;EACA,KAAA,kBAAA;;CAGnB,MAGM,IAAI,KAAc,KAAe;EACrC,MAAM,WAAW,MAAM,KAAK,aAAa,iBAAiB,IAAI,MAAM,GAAG;EACvE,MAAM,WAAW,MAAM,KAAK,gBAAgB,YAAY,SAAS;EACjE,IAAI,KAAK,SAAS,KAAK;;CAGzB,MAGM,gBAAgB,KAAc,KAAe;EACjD,MAAM,eAAe,MAAM,KAAK,aAAa,iBAAiB,IAAI,MAAM,GAAG;EAC3E,MAAM,OAAO,MAAM,KAAK,aAAa,aAAa,IAAI,MAAM,GAAG;EAC/D,MAAM,WAAW,MAAM,KAAK,gBAAgB,yBAAyB,cAAc,KAAK;EACxF,IAAI,KAAK,SAAS,KAAK;;;;CAhBxB,KAAK;CACL,MAAM,OAAO;CACb,OAAO,CAAC,WAAW,MAAM,gBAAgB,IAAI,EAAE,QAAQ,KAAK,CAAC,CAAC;;;;;;CAO9D,MAAM;CACN,MAAM,wBAAwB;CAC9B,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC;;;;;;CAnBzB,MAAM,aAAa,WAAW,oBAAoB;CAClD,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 { ROLES } from "../constants/authorization.constants.js";
|
|
6
6
|
import { authenticate, authorizeRoles } from "../middleware/authenticate.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"printer-tag.controller.js","names":[],"sources":["../../src/controllers/printer-tag.controller.ts"],"sourcesContent":["import type { IPrinterTagService } from \"@/services/interfaces/printer-tag.service.interface\";\nimport { AppConstants } from \"@/server.constants\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport type { Request, Response } from \"express\";\nimport { route, before, GET, POST, DELETE, PATCH } from \"awilix-express\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\n\n@route(AppConstants.apiRoute + \"/printer-tag\")\n@before([authenticate(), authorizeRoles([ROLES.OPERATOR, ROLES.ADMIN])])\nexport class PrinterTagController {\n constructor(private readonly printerTagService: IPrinterTagService) {}\n\n @GET()\n @route(\"/\")\n async listTags(req: Request, res: Response) {\n res.send(await this.printerTagService.listTags());\n }\n\n @GET()\n @route(\"/:id\")\n @before([ParamId(\"id\")])\n async getTagWithPrinters(req: Request, res: Response) {\n res.send(await this.printerTagService.getPrintersByTag(req.local.id));\n }\n\n @POST()\n @route(\"/\")\n async createTag(req: Request, res: Response) {\n // Safety mechanism against updating\n if (req.body.id) {\n delete req.body.id;\n }\n const entity = await this.printerTagService.createTag(req.body);\n res.send(entity);\n }\n\n @PATCH()\n @route(\"/:id/name\")\n @before([ParamId(\"id\")])\n async updateTagName(req: Request, res: Response) {\n const entity = await this.printerTagService.updateTagName(req.local.id, req.body.name);\n res.send(entity);\n }\n\n @PATCH()\n @route(\"/:id/color\")\n @before([ParamId(\"id\")])\n async updateTagColor(req: Request, res: Response) {\n const entity = await this.printerTagService.updateTagColor(req.local.id, req.body.color);\n res.send(entity);\n }\n\n @DELETE()\n @route(\"/:id\")\n @before([ParamId(\"id\")])\n async deleteTag(req: Request, res: Response) {\n res.send(await this.printerTagService.deleteTag(req.local.id));\n }\n\n @POST()\n @route(\"/:id/printer\")\n @before([ParamId(\"id\")])\n async addPrinterToTag(req: Request, res: Response) {\n const entity = await this.printerTagService.addPrinterToTag(req.local.id, req.body.printerId);\n res.send(this.printerTagService.toDto(entity));\n }\n\n @DELETE()\n @route(\"/:id/printer\")\n @before([ParamId(\"id\")])\n async removePrinterFromTag(req: Request, res: Response) {\n res.send(await this.printerTagService.removePrinterFromTag(req.local.id, req.body.printerId));\n }\n}\n"],"mappings":";;;;;;;;;;AAUO,IAAA,uBAAA,MAAM,qBAAqB;CAChC,YAAY,mBAAwD;
|
|
1
|
+
{"version":3,"file":"printer-tag.controller.js","names":[],"sources":["../../src/controllers/printer-tag.controller.ts"],"sourcesContent":["import type { IPrinterTagService } from \"@/services/interfaces/printer-tag.service.interface\";\nimport { AppConstants } from \"@/server.constants\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport type { Request, Response } from \"express\";\nimport { route, before, GET, POST, DELETE, PATCH } from \"awilix-express\";\nimport { ParamId } from \"@/middleware/param-converter.middleware\";\n\n@route(AppConstants.apiRoute + \"/printer-tag\")\n@before([authenticate(), authorizeRoles([ROLES.OPERATOR, ROLES.ADMIN])])\nexport class PrinterTagController {\n constructor(private readonly printerTagService: IPrinterTagService) {}\n\n @GET()\n @route(\"/\")\n async listTags(req: Request, res: Response) {\n res.send(await this.printerTagService.listTags());\n }\n\n @GET()\n @route(\"/:id\")\n @before([ParamId(\"id\")])\n async getTagWithPrinters(req: Request, res: Response) {\n res.send(await this.printerTagService.getPrintersByTag(req.local.id));\n }\n\n @POST()\n @route(\"/\")\n async createTag(req: Request, res: Response) {\n // Safety mechanism against updating\n if (req.body.id) {\n delete req.body.id;\n }\n const entity = await this.printerTagService.createTag(req.body);\n res.send(entity);\n }\n\n @PATCH()\n @route(\"/:id/name\")\n @before([ParamId(\"id\")])\n async updateTagName(req: Request, res: Response) {\n const entity = await this.printerTagService.updateTagName(req.local.id, req.body.name);\n res.send(entity);\n }\n\n @PATCH()\n @route(\"/:id/color\")\n @before([ParamId(\"id\")])\n async updateTagColor(req: Request, res: Response) {\n const entity = await this.printerTagService.updateTagColor(req.local.id, req.body.color);\n res.send(entity);\n }\n\n @DELETE()\n @route(\"/:id\")\n @before([ParamId(\"id\")])\n async deleteTag(req: Request, res: Response) {\n res.send(await this.printerTagService.deleteTag(req.local.id));\n }\n\n @POST()\n @route(\"/:id/printer\")\n @before([ParamId(\"id\")])\n async addPrinterToTag(req: Request, res: Response) {\n const entity = await this.printerTagService.addPrinterToTag(req.local.id, req.body.printerId);\n res.send(this.printerTagService.toDto(entity));\n }\n\n @DELETE()\n @route(\"/:id/printer\")\n @before([ParamId(\"id\")])\n async removePrinterFromTag(req: Request, res: Response) {\n res.send(await this.printerTagService.removePrinterFromTag(req.local.id, req.body.printerId));\n }\n}\n"],"mappings":";;;;;;;;;;AAUO,IAAA,uBAAA,MAAM,qBAAqB;CAChC,YAAY,mBAAwD;EAAvC,KAAA,oBAAA;;CAE7B,MAEM,SAAS,KAAc,KAAe;EAC1C,IAAI,KAAK,MAAM,KAAK,kBAAkB,UAAU,CAAC;;CAGnD,MAGM,mBAAmB,KAAc,KAAe;EACpD,IAAI,KAAK,MAAM,KAAK,kBAAkB,iBAAiB,IAAI,MAAM,GAAG,CAAC;;CAGvE,MAEM,UAAU,KAAc,KAAe;EAE3C,IAAI,IAAI,KAAK,IACX,OAAO,IAAI,KAAK;EAElB,MAAM,SAAS,MAAM,KAAK,kBAAkB,UAAU,IAAI,KAAK;EAC/D,IAAI,KAAK,OAAO;;CAGlB,MAGM,cAAc,KAAc,KAAe;EAC/C,MAAM,SAAS,MAAM,KAAK,kBAAkB,cAAc,IAAI,MAAM,IAAI,IAAI,KAAK,KAAK;EACtF,IAAI,KAAK,OAAO;;CAGlB,MAGM,eAAe,KAAc,KAAe;EAChD,MAAM,SAAS,MAAM,KAAK,kBAAkB,eAAe,IAAI,MAAM,IAAI,IAAI,KAAK,MAAM;EACxF,IAAI,KAAK,OAAO;;CAGlB,MAGM,UAAU,KAAc,KAAe;EAC3C,IAAI,KAAK,MAAM,KAAK,kBAAkB,UAAU,IAAI,MAAM,GAAG,CAAC;;CAGhE,MAGM,gBAAgB,KAAc,KAAe;EACjD,MAAM,SAAS,MAAM,KAAK,kBAAkB,gBAAgB,IAAI,MAAM,IAAI,IAAI,KAAK,UAAU;EAC7F,IAAI,KAAK,KAAK,kBAAkB,MAAM,OAAO,CAAC;;CAGhD,MAGM,qBAAqB,KAAc,KAAe;EACtD,IAAI,KAAK,MAAM,KAAK,kBAAkB,qBAAqB,IAAI,MAAM,IAAI,IAAI,KAAK,UAAU,CAAC;;;;CA3D9F,KAAK;CACL,MAAM,IAAI;;;;;;CAKV,KAAK;CACL,MAAM,OAAO;CACb,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC;;;;;;CAKvB,MAAM;CACN,MAAM,IAAI;;;;;;CAUV,OAAO;CACP,MAAM,YAAY;CAClB,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC;;;;;;CAMvB,OAAO;CACP,MAAM,aAAa;CACnB,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC;;;;;;CAMvB,QAAQ;CACR,MAAM,OAAO;CACb,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC;;;;;;CAKvB,MAAM;CACN,MAAM,eAAe;CACrB,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC;;;;;;CAMvB,QAAQ;CACR,MAAM,eAAe;CACrB,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC;;;;;;CA9DzB,MAAM,aAAa,WAAW,eAAe;CAC7C,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 { InternalServerException } from "../exceptions/runtime.exceptions.js";
|
|
5
5
|
import { validateInput, validateMiddleware } from "../handlers/validators.js";
|
|
6
6
|
import { defaultHttpProtocol } from "../utils/url.utils.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"printer.controller.js","names":[],"sources":["../../src/controllers/printer.controller.ts"],"sourcesContent":["import { before, DELETE, GET, PATCH, POST, route } from \"awilix-express\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport { validateInput, validateMiddleware } from \"@/handlers/validators\";\nimport {\n feedRateSchema,\n flowRateSchema,\n testPrinterApiSchema,\n updatePrinterDisabledReasonSchema,\n updatePrinterEnabledSchema,\n} from \"./validation/printer-controller.validation\";\nimport { AppConstants } from \"@/server.constants\";\nimport { printerResolveMiddleware } from \"@/middleware/printer\";\nimport { generateCorrelationToken } from \"@/utils/correlation-token.util\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { PrinterSocketStore } from \"@/state/printer-socket.store\";\nimport { TestPrinterSocketStore } from \"@/state/test-printer-socket.store\";\nimport { PrinterCache } from \"@/state/printer.cache\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { PrinterEventsCache } from \"@/state/printer-events.cache\";\nimport { FloorStore } from \"@/state/floor.store\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport type { Request, Response } from \"express\";\nimport type { IPrinterService } from \"@/services/interfaces/printer.service.interface\";\nimport type { LoginDto } from \"@/services/interfaces/login.dto\";\nimport { AxiosError } from \"axios\";\nimport { FailedDependencyException } from \"@/exceptions/failed-dependency.exception\";\nimport { InternalServerException } from \"@/exceptions/runtime.exceptions\";\nimport type { IPrinterApi } from \"@/services/printer-api.interface\";\nimport { PrinterApiFactory } from \"@/services/printer-api.factory\";\nimport { normalizeUrl } from \"@/utils/normalize-url\";\nimport { defaultHttpProtocol } from \"@/utils/url.utils\";\nimport { getScopedPrinter } from \"@/middleware/printer-resolver\";\n\n@route(AppConstants.apiRoute + \"/printer\")\n@before([authenticate(), authorizeRoles([ROLES.OPERATOR, ROLES.ADMIN]), printerResolveMiddleware()])\nexport class PrinterController {\n logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly printerApiFactory: PrinterApiFactory,\n private readonly printerSocketStore: PrinterSocketStore,\n private readonly testPrinterSocketStore: TestPrinterSocketStore,\n private readonly printerService: IPrinterService,\n private readonly printerCache: PrinterCache,\n private readonly printerEventsCache: PrinterEventsCache,\n private readonly printerApi: IPrinterApi,\n private readonly floorStore: FloorStore,\n ) {\n this.logger = loggerFactory(PrinterController.name);\n }\n\n @GET()\n @route(\"/\")\n async list(req: Request, res: Response) {\n res.send(await this.printerCache.listCachedPrinters(true));\n }\n\n @POST()\n @route(\"/\")\n async create(req: Request, res: Response) {\n const newPrinter = req.body;\n if (req.query.forceSave !== \"true\") {\n await this.testPrintApiConnection(newPrinter);\n }\n\n // Has internal validation, but might add some here above as well\n const createdPrinter = await this.printerService.create(newPrinter);\n res.send(await this.printerCache.getCachedPrinterOrThrowAsync(createdPrinter.id));\n }\n\n @POST()\n @route(\"/batch\")\n async createBatch(req: Request, res: Response) {\n const importResult = await this.printerService.batchImport(req.body);\n res.send(importResult);\n }\n\n @GET()\n @route(\"/:id\")\n async getPrinter(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n res.send(await this.printerCache.getCachedPrinterOrThrowAsync(currentPrinterId));\n }\n\n @GET()\n @route(\"/:id/socket\")\n async getPrinterSocketInfo(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n res.send(await this.printerEventsCache.getPrinterSocketEvents(currentPrinterId));\n }\n\n @PATCH()\n @route(\"/:id\")\n async update(req: Request, res: Response) {\n const forceSave = req.query.forceSave === \"true\";\n\n // Update the printer entity: printerURL, name, apiKey, enabled\n const { currentPrinterId } = getScopedPrinter(req);\n const updatedPrinter = req.body;\n if (!forceSave) {\n await this.testPrintApiConnection(updatedPrinter);\n }\n\n await this.printerService.update(currentPrinterId, updatedPrinter);\n res.send(await this.printerCache.getCachedPrinterOrThrowAsync(currentPrinterId));\n }\n\n @DELETE()\n @route(\"/:id\")\n async delete(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n await this.printerService.delete(currentPrinterId);\n await this.floorStore.removePrinterFromAnyFloor(currentPrinterId);\n res.send();\n }\n\n @PATCH()\n @route(\"/:id/enabled\")\n async updateEnabled(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n const data = await validateMiddleware(req, updatePrinterEnabledSchema);\n await this.printerService.updateEnabled(currentPrinterId, data.enabled);\n res.send({});\n }\n\n @PATCH()\n @route(\"/:id/disabled-reason\")\n async updatePrinterDisabledReason(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n const data = await validateMiddleware(req, updatePrinterDisabledReasonSchema);\n await this.printerService.updateDisabledReason(currentPrinterId, data.disabledReason);\n res.send({});\n }\n\n @POST()\n @route(\"/:id/refresh-socket\")\n async refreshPrinterSocket(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n this.printerSocketStore.reconnectPrinterAdapter(currentPrinterId);\n await this.printerEventsCache.deletePrinterSocketEvents(currentPrinterId);\n res.send({});\n }\n\n @POST()\n @route(\"/test-connection\")\n async testConnection(req: Request, res: Response) {\n if (req.body.printerURL?.length) {\n req.body.printerURL = normalizeUrl(req.body.printerURL, { defaultProtocol: defaultHttpProtocol });\n }\n const newPrinter = await validateMiddleware(req, testPrinterApiSchema);\n const printerCorrelationToken = generateCorrelationToken();\n this.logger.log(`Testing printer with correlation token ${printerCorrelationToken}`);\n\n try {\n await this.testPrinterSocketStore.setupTestPrinter(printerCorrelationToken, newPrinter);\n } catch (e) {\n res.send({ correlationToken: printerCorrelationToken, failure: true, error: (e as Error).toString() });\n return;\n }\n res.send({ correlationToken: printerCorrelationToken });\n }\n\n @GET()\n @route(\"/:id/login-details\")\n async getPrinterLoginDetails(req: Request, res: Response) {\n const { printerLogin } = getScopedPrinter(req);\n res.send(printerLogin);\n }\n\n /**\n * Sends gcode according to https://docs.octoprint.org/en/master/api/printer.html#send-an-arbitrary-command-to-the-printer\n */\n @POST()\n @route(\"/:id/send-emergency-m112\")\n async sendEmergencyM112(req: Request, res: Response) {\n const { printerApi } = getScopedPrinter(req);\n await printerApi.quickStop();\n res.send();\n }\n\n @POST()\n @route(\"/:id/serial-connect\")\n async sendSerialConnectCommand(req: Request, res: Response) {\n await this.printerApi.connect();\n res.send({});\n }\n\n @POST()\n @route(\"/:id/serial-disconnect\")\n async sendSerialDisconnectCommand(req: Request, res: Response) {\n await this.printerApi.disconnect();\n res.send({});\n }\n\n @POST()\n @route(\"/:id/jog\")\n @route(\"/:id/move\")\n async movePrintHead(req: Request, res: Response) {\n await this.printerApi.movePrintHead(req.body);\n res.send({});\n }\n\n @POST()\n @route(\"/:id/home\")\n async homeAxes(req: Request, res: Response) {\n await this.printerApi.homeAxes(req.body);\n res.send({});\n }\n\n @POST()\n @route(\"/:id/job/pause\")\n async pausePrint(req: Request, res: Response) {\n await this.printerApi.pausePrint();\n res.send({});\n }\n\n @POST()\n @route(\"/:id/job/resume\")\n async resumePrint(req: Request, res: Response) {\n await this.printerApi.resumePrint();\n res.send({});\n }\n\n @POST()\n @route(\"/:id/job/stop\")\n @route(\"/:id/job/cancel\")\n async cancelPrint(req: Request, res: Response) {\n await this.printerApi.cancelPrint();\n res.send({});\n }\n\n @POST()\n @route(\"/:id/octoprint/server/restart\")\n @route(\"/:id/server/restart\")\n async restartServer(req: Request, res: Response) {\n await this.printerApi.restartServer();\n res.send();\n }\n\n @PATCH()\n @route(\"/:id/feed-rate\")\n async setFeedRate(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n const data = await validateMiddleware(req, feedRateSchema);\n\n await this.printerService.updateFeedRate(currentPrinterId, data.feedRate);\n res.send({});\n }\n\n @PATCH()\n @route(\"/:id/flow-rate\")\n async setFlowRate(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n const data = await validateMiddleware(req, flowRateSchema);\n await this.printerService.updateFlowRate(currentPrinterId, data.flowRate);\n res.send({});\n }\n\n private async testPrintApiConnection(inputLoginDto: LoginDto) {\n await validateInput(inputLoginDto, testPrinterApiSchema);\n\n this.logger.debug(`Testing API connection for printer type: ${inputLoginDto.printerType}`, inputLoginDto);\n\n try {\n const printerApi = this.printerApiFactory.getScopedPrinter(inputLoginDto);\n await printerApi.validateConnection();\n this.logger.debug(\"Connection validation completed successfully\");\n } catch (e) {\n this.logger.log(\"Printer connection validation failed\");\n this.logger.debug(`Error details: ${e}`);\n\n if (e instanceof AxiosError) {\n this.logger.debug(e.message + \" \" + e.status + \" \" + e.response?.status);\n switch (e.response?.status) {\n case 404:\n // Bad code design or wrong service type\n break;\n case 401:\n case 403: {\n throw new FailedDependencyException(\"Authentication failed\", e.response?.status);\n }\n case 0:\n case 502:\n case 503: {\n throw new FailedDependencyException(\"Printer service unreachable\", e.response?.status);\n }\n default: {\n if (e.response?.status) {\n throw new FailedDependencyException(\n `Reaching Printer service failed with status (code ${e.code})`,\n e.response?.status,\n );\n } else {\n // F.e. http://localhost:1324\n // ENOTFOUND: DNS problem\n // ECONNREFUSED: Port has no socket bound\n // ERR_BAD_REQUEST\n throw new FailedDependencyException(`Reaching Printer service failed without status (code ${e.code})`);\n }\n }\n }\n }\n\n throw new InternalServerException(`Could not call Printer service, internal problem`, (e as Error).stack);\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"printer.controller.js","names":[],"sources":["../../src/controllers/printer.controller.ts"],"sourcesContent":["import { before, DELETE, GET, PATCH, POST, route } from \"awilix-express\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport { validateInput, validateMiddleware } from \"@/handlers/validators\";\nimport {\n feedRateSchema,\n flowRateSchema,\n testPrinterApiSchema,\n updatePrinterDisabledReasonSchema,\n updatePrinterEnabledSchema,\n} from \"./validation/printer-controller.validation\";\nimport { AppConstants } from \"@/server.constants\";\nimport { printerResolveMiddleware } from \"@/middleware/printer\";\nimport { generateCorrelationToken } from \"@/utils/correlation-token.util\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { PrinterSocketStore } from \"@/state/printer-socket.store\";\nimport { TestPrinterSocketStore } from \"@/state/test-printer-socket.store\";\nimport { PrinterCache } from \"@/state/printer.cache\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { PrinterEventsCache } from \"@/state/printer-events.cache\";\nimport { FloorStore } from \"@/state/floor.store\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport type { Request, Response } from \"express\";\nimport type { IPrinterService } from \"@/services/interfaces/printer.service.interface\";\nimport type { LoginDto } from \"@/services/interfaces/login.dto\";\nimport { AxiosError } from \"axios\";\nimport { FailedDependencyException } from \"@/exceptions/failed-dependency.exception\";\nimport { InternalServerException } from \"@/exceptions/runtime.exceptions\";\nimport type { IPrinterApi } from \"@/services/printer-api.interface\";\nimport { PrinterApiFactory } from \"@/services/printer-api.factory\";\nimport { normalizeUrl } from \"@/utils/normalize-url\";\nimport { defaultHttpProtocol } from \"@/utils/url.utils\";\nimport { getScopedPrinter } from \"@/middleware/printer-resolver\";\n\n@route(AppConstants.apiRoute + \"/printer\")\n@before([authenticate(), authorizeRoles([ROLES.OPERATOR, ROLES.ADMIN]), printerResolveMiddleware()])\nexport class PrinterController {\n logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly printerApiFactory: PrinterApiFactory,\n private readonly printerSocketStore: PrinterSocketStore,\n private readonly testPrinterSocketStore: TestPrinterSocketStore,\n private readonly printerService: IPrinterService,\n private readonly printerCache: PrinterCache,\n private readonly printerEventsCache: PrinterEventsCache,\n private readonly printerApi: IPrinterApi,\n private readonly floorStore: FloorStore,\n ) {\n this.logger = loggerFactory(PrinterController.name);\n }\n\n @GET()\n @route(\"/\")\n async list(req: Request, res: Response) {\n res.send(await this.printerCache.listCachedPrinters(true));\n }\n\n @POST()\n @route(\"/\")\n async create(req: Request, res: Response) {\n const newPrinter = req.body;\n if (req.query.forceSave !== \"true\") {\n await this.testPrintApiConnection(newPrinter);\n }\n\n // Has internal validation, but might add some here above as well\n const createdPrinter = await this.printerService.create(newPrinter);\n res.send(await this.printerCache.getCachedPrinterOrThrowAsync(createdPrinter.id));\n }\n\n @POST()\n @route(\"/batch\")\n async createBatch(req: Request, res: Response) {\n const importResult = await this.printerService.batchImport(req.body);\n res.send(importResult);\n }\n\n @GET()\n @route(\"/:id\")\n async getPrinter(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n res.send(await this.printerCache.getCachedPrinterOrThrowAsync(currentPrinterId));\n }\n\n @GET()\n @route(\"/:id/socket\")\n async getPrinterSocketInfo(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n res.send(await this.printerEventsCache.getPrinterSocketEvents(currentPrinterId));\n }\n\n @PATCH()\n @route(\"/:id\")\n async update(req: Request, res: Response) {\n const forceSave = req.query.forceSave === \"true\";\n\n // Update the printer entity: printerURL, name, apiKey, enabled\n const { currentPrinterId } = getScopedPrinter(req);\n const updatedPrinter = req.body;\n if (!forceSave) {\n await this.testPrintApiConnection(updatedPrinter);\n }\n\n await this.printerService.update(currentPrinterId, updatedPrinter);\n res.send(await this.printerCache.getCachedPrinterOrThrowAsync(currentPrinterId));\n }\n\n @DELETE()\n @route(\"/:id\")\n async delete(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n await this.printerService.delete(currentPrinterId);\n await this.floorStore.removePrinterFromAnyFloor(currentPrinterId);\n res.send();\n }\n\n @PATCH()\n @route(\"/:id/enabled\")\n async updateEnabled(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n const data = await validateMiddleware(req, updatePrinterEnabledSchema);\n await this.printerService.updateEnabled(currentPrinterId, data.enabled);\n res.send({});\n }\n\n @PATCH()\n @route(\"/:id/disabled-reason\")\n async updatePrinterDisabledReason(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n const data = await validateMiddleware(req, updatePrinterDisabledReasonSchema);\n await this.printerService.updateDisabledReason(currentPrinterId, data.disabledReason);\n res.send({});\n }\n\n @POST()\n @route(\"/:id/refresh-socket\")\n async refreshPrinterSocket(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n this.printerSocketStore.reconnectPrinterAdapter(currentPrinterId);\n await this.printerEventsCache.deletePrinterSocketEvents(currentPrinterId);\n res.send({});\n }\n\n @POST()\n @route(\"/test-connection\")\n async testConnection(req: Request, res: Response) {\n if (req.body.printerURL?.length) {\n req.body.printerURL = normalizeUrl(req.body.printerURL, { defaultProtocol: defaultHttpProtocol });\n }\n const newPrinter = await validateMiddleware(req, testPrinterApiSchema);\n const printerCorrelationToken = generateCorrelationToken();\n this.logger.log(`Testing printer with correlation token ${printerCorrelationToken}`);\n\n try {\n await this.testPrinterSocketStore.setupTestPrinter(printerCorrelationToken, newPrinter);\n } catch (e) {\n res.send({ correlationToken: printerCorrelationToken, failure: true, error: (e as Error).toString() });\n return;\n }\n res.send({ correlationToken: printerCorrelationToken });\n }\n\n @GET()\n @route(\"/:id/login-details\")\n async getPrinterLoginDetails(req: Request, res: Response) {\n const { printerLogin } = getScopedPrinter(req);\n res.send(printerLogin);\n }\n\n /**\n * Sends gcode according to https://docs.octoprint.org/en/master/api/printer.html#send-an-arbitrary-command-to-the-printer\n */\n @POST()\n @route(\"/:id/send-emergency-m112\")\n async sendEmergencyM112(req: Request, res: Response) {\n const { printerApi } = getScopedPrinter(req);\n await printerApi.quickStop();\n res.send();\n }\n\n @POST()\n @route(\"/:id/serial-connect\")\n async sendSerialConnectCommand(req: Request, res: Response) {\n await this.printerApi.connect();\n res.send({});\n }\n\n @POST()\n @route(\"/:id/serial-disconnect\")\n async sendSerialDisconnectCommand(req: Request, res: Response) {\n await this.printerApi.disconnect();\n res.send({});\n }\n\n @POST()\n @route(\"/:id/jog\")\n @route(\"/:id/move\")\n async movePrintHead(req: Request, res: Response) {\n await this.printerApi.movePrintHead(req.body);\n res.send({});\n }\n\n @POST()\n @route(\"/:id/home\")\n async homeAxes(req: Request, res: Response) {\n await this.printerApi.homeAxes(req.body);\n res.send({});\n }\n\n @POST()\n @route(\"/:id/job/pause\")\n async pausePrint(req: Request, res: Response) {\n await this.printerApi.pausePrint();\n res.send({});\n }\n\n @POST()\n @route(\"/:id/job/resume\")\n async resumePrint(req: Request, res: Response) {\n await this.printerApi.resumePrint();\n res.send({});\n }\n\n @POST()\n @route(\"/:id/job/stop\")\n @route(\"/:id/job/cancel\")\n async cancelPrint(req: Request, res: Response) {\n await this.printerApi.cancelPrint();\n res.send({});\n }\n\n @POST()\n @route(\"/:id/octoprint/server/restart\")\n @route(\"/:id/server/restart\")\n async restartServer(req: Request, res: Response) {\n await this.printerApi.restartServer();\n res.send();\n }\n\n @PATCH()\n @route(\"/:id/feed-rate\")\n async setFeedRate(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n const data = await validateMiddleware(req, feedRateSchema);\n\n await this.printerService.updateFeedRate(currentPrinterId, data.feedRate);\n res.send({});\n }\n\n @PATCH()\n @route(\"/:id/flow-rate\")\n async setFlowRate(req: Request, res: Response) {\n const { currentPrinterId } = getScopedPrinter(req);\n const data = await validateMiddleware(req, flowRateSchema);\n await this.printerService.updateFlowRate(currentPrinterId, data.flowRate);\n res.send({});\n }\n\n private async testPrintApiConnection(inputLoginDto: LoginDto) {\n await validateInput(inputLoginDto, testPrinterApiSchema);\n\n this.logger.debug(`Testing API connection for printer type: ${inputLoginDto.printerType}`, inputLoginDto);\n\n try {\n const printerApi = this.printerApiFactory.getScopedPrinter(inputLoginDto);\n await printerApi.validateConnection();\n this.logger.debug(\"Connection validation completed successfully\");\n } catch (e) {\n this.logger.log(\"Printer connection validation failed\");\n this.logger.debug(`Error details: ${e}`);\n\n if (e instanceof AxiosError) {\n this.logger.debug(e.message + \" \" + e.status + \" \" + e.response?.status);\n switch (e.response?.status) {\n case 404:\n // Bad code design or wrong service type\n break;\n case 401:\n case 403: {\n throw new FailedDependencyException(\"Authentication failed\", e.response?.status);\n }\n case 0:\n case 502:\n case 503: {\n throw new FailedDependencyException(\"Printer service unreachable\", e.response?.status);\n }\n default: {\n if (e.response?.status) {\n throw new FailedDependencyException(\n `Reaching Printer service failed with status (code ${e.code})`,\n e.response?.status,\n );\n } else {\n // F.e. http://localhost:1324\n // ENOTFOUND: DNS problem\n // ECONNREFUSED: Port has no socket bound\n // ERR_BAD_REQUEST\n throw new FailedDependencyException(`Reaching Printer service failed without status (code ${e.code})`);\n }\n }\n }\n }\n\n throw new InternalServerException(`Could not call Printer service, internal problem`, (e as Error).stack);\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 { validateMiddleware } from "../handlers/validators.js";
|
|
5
5
|
import { AppConstants } from "../server.constants.js";
|
|
6
6
|
import { ServerReleaseService } from "../services/core/server-release.service.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-private.controller.js","names":[],"sources":["../../src/controllers/server-private.controller.ts"],"sourcesContent":["import { PassThrough } from \"node:stream\";\nimport { before, DELETE, GET, POST, route } from \"awilix-express\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport { AppConstants } from \"@/server.constants\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { validateMiddleware } from \"@/handlers/validators\";\nimport { ServerReleaseService } from \"@/services/core/server-release.service\";\nimport { ClientBundleService } from \"@/services/core/client-bundle.service\";\nimport { PrinterCache } from \"@/state/printer.cache\";\nimport { YamlService } from \"@/services/core/yaml.service\";\nimport { MulterService } from \"@/services/core/multer.service\";\nimport { LogDumpService } from \"@/services/core/logs-manager.service\";\nimport type { Request, Response } from \"express\";\nimport { demoUserNotAllowed } from \"@/middleware/demo.middleware\";\nimport { GithubService } from \"@/services/core/github.service\";\nimport type { IPrinterService } from \"@/services/interfaces/printer.service.interface\";\nimport { updateClientBundleSchema } from \"@/controllers/validation/server-private.validation\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\n\n@route(AppConstants.apiRoute + \"/server\")\n@before([authenticate(), authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\nexport class ServerPrivateController {\n private readonly logger;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly serverReleaseService: ServerReleaseService,\n private readonly printerCache: PrinterCache,\n private readonly printerService: IPrinterService,\n private readonly clientBundleService: ClientBundleService,\n private readonly githubService: GithubService,\n private readonly logDumpService: LogDumpService,\n private readonly yamlService: YamlService,\n private readonly multerService: MulterService,\n ) {\n this.logger = loggerFactory(ServerPrivateController.name);\n }\n\n @GET()\n @route(\"/\")\n async getReleaseStateInfo(req: Request, res: Response) {\n await this.serverReleaseService.syncLatestRelease();\n const updateState = this.serverReleaseService.getState();\n res.send(updateState);\n }\n\n @GET()\n @route(\"/client-releases\")\n async getClientReleases(_req: Request, res: Response) {\n const releaseSpec = await this.clientBundleService.getReleases();\n res.send(releaseSpec);\n }\n\n /**\n * It is not advised to downgrade beyond the default minimum version, any server restart will\n * update the bundle back to minimum version (if ENABLE_CLIENT_DIST_AUTO_UPDATE === 'true').\n */\n @POST()\n @route(\"/update-client-bundle-github\")\n async updateClientBundleGithub(req: Request, res: Response) {\n const updateDto = await validateMiddleware(req, updateClientBundleSchema);\n\n const willExecute = await this.clientBundleService.shouldUpdateWithReason(\n true,\n AppConstants.defaultClientMinimum,\n updateDto.downloadRelease,\n updateDto.allowDowngrade,\n );\n\n this.logger.log(`Will execute: ${willExecute?.shouldUpdate}, reason: ${willExecute?.reason}`);\n if (!willExecute?.shouldUpdate) {\n return res.send({\n executed: false,\n requestedVersion: willExecute.requestedVersion,\n currentVersion: willExecute.currentVersion,\n minimumVersion: willExecute.minimumVersion,\n shouldUpdate: willExecute.shouldUpdate,\n targetVersion: willExecute.targetVersion,\n reason: willExecute?.reason,\n });\n }\n\n if (willExecute.targetVersion) {\n await this.clientBundleService.downloadClientUpdate(willExecute.targetVersion);\n }\n\n return res.send({\n executed: true,\n requestedVersion: willExecute.requestedVersion,\n currentVersion: willExecute.currentVersion,\n minimumVersion: willExecute.minimumVersion,\n shouldUpdate: willExecute.shouldUpdate,\n targetVersion: willExecute.targetVersion,\n reason: willExecute?.reason,\n });\n }\n\n @GET()\n @route(\"/github-rate-limit\")\n async getGithubRateLimit(req: Request, res: Response) {\n const rateLimitResponse = await this.githubService.getRateLimit();\n res.send(rateLimitResponse.data);\n }\n\n @POST()\n @route(\"/yaml-import\")\n async importYaml(req: Request, res: Response) {\n const files = await this.multerService.multerLoadFileAsync(req, res, [\".yaml\", \".yml\"], false);\n const firstFile = files[0];\n const spec = await this.yamlService.importYaml(firstFile.buffer.toString());\n\n res.send({\n success: true,\n spec,\n });\n }\n\n @POST()\n @route(\"/yaml-export\")\n async exportYaml(req: Request, res: Response) {\n const yaml = await this.yamlService.exportYaml(req.body);\n const fileContents = Buffer.from(yaml);\n const readStream = new PassThrough();\n readStream.end(fileContents);\n\n const fileName = `export-${AppConstants.serverRepoName}-` + Date.now() + \".yaml\";\n res.set(\"Content-disposition\", \"attachment; filename=\" + fileName);\n res.set(\"Content-Type\", \"text/plain\");\n readStream.pipe(res);\n }\n\n @DELETE()\n @route(\"/delete-all-printers\")\n async deleteAllPrinters(req: Request, res: Response) {\n const printers = await this.printerCache.listCachedPrinters(true);\n const printerIds = printers.map((p) => p.id);\n await this.printerService.deleteMany(printerIds);\n res.send();\n }\n\n @DELETE()\n @route(\"/clear-outdated-fdm-monster-logs\")\n async clearLogs(req: Request, res: Response) {\n const counts = await this.logDumpService.deleteOlderThanWeekAndMismatchingLogFiles();\n res.send(counts);\n }\n\n @GET()\n @POST()\n @route(\"/dump-fdm-monster-logs\")\n async dumpLogZips(req: Request, res: Response) {\n const filePath = await this.logDumpService.dumpZip();\n res.sendFile(filePath);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBO,IAAA,0BAAA,2BAAA,MAAM,wBAAwB;CACnC;CAEA,YACE,eACA,sBACA,cACA,gBACA,qBACA,eACA,gBACA,aACA,eACA;
|
|
1
|
+
{"version":3,"file":"server-private.controller.js","names":[],"sources":["../../src/controllers/server-private.controller.ts"],"sourcesContent":["import { PassThrough } from \"node:stream\";\nimport { before, DELETE, GET, POST, route } from \"awilix-express\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport { AppConstants } from \"@/server.constants\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { validateMiddleware } from \"@/handlers/validators\";\nimport { ServerReleaseService } from \"@/services/core/server-release.service\";\nimport { ClientBundleService } from \"@/services/core/client-bundle.service\";\nimport { PrinterCache } from \"@/state/printer.cache\";\nimport { YamlService } from \"@/services/core/yaml.service\";\nimport { MulterService } from \"@/services/core/multer.service\";\nimport { LogDumpService } from \"@/services/core/logs-manager.service\";\nimport type { Request, Response } from \"express\";\nimport { demoUserNotAllowed } from \"@/middleware/demo.middleware\";\nimport { GithubService } from \"@/services/core/github.service\";\nimport type { IPrinterService } from \"@/services/interfaces/printer.service.interface\";\nimport { updateClientBundleSchema } from \"@/controllers/validation/server-private.validation\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\n\n@route(AppConstants.apiRoute + \"/server\")\n@before([authenticate(), authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\nexport class ServerPrivateController {\n private readonly logger;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly serverReleaseService: ServerReleaseService,\n private readonly printerCache: PrinterCache,\n private readonly printerService: IPrinterService,\n private readonly clientBundleService: ClientBundleService,\n private readonly githubService: GithubService,\n private readonly logDumpService: LogDumpService,\n private readonly yamlService: YamlService,\n private readonly multerService: MulterService,\n ) {\n this.logger = loggerFactory(ServerPrivateController.name);\n }\n\n @GET()\n @route(\"/\")\n async getReleaseStateInfo(req: Request, res: Response) {\n await this.serverReleaseService.syncLatestRelease();\n const updateState = this.serverReleaseService.getState();\n res.send(updateState);\n }\n\n @GET()\n @route(\"/client-releases\")\n async getClientReleases(_req: Request, res: Response) {\n const releaseSpec = await this.clientBundleService.getReleases();\n res.send(releaseSpec);\n }\n\n /**\n * It is not advised to downgrade beyond the default minimum version, any server restart will\n * update the bundle back to minimum version (if ENABLE_CLIENT_DIST_AUTO_UPDATE === 'true').\n */\n @POST()\n @route(\"/update-client-bundle-github\")\n async updateClientBundleGithub(req: Request, res: Response) {\n const updateDto = await validateMiddleware(req, updateClientBundleSchema);\n\n const willExecute = await this.clientBundleService.shouldUpdateWithReason(\n true,\n AppConstants.defaultClientMinimum,\n updateDto.downloadRelease,\n updateDto.allowDowngrade,\n );\n\n this.logger.log(`Will execute: ${willExecute?.shouldUpdate}, reason: ${willExecute?.reason}`);\n if (!willExecute?.shouldUpdate) {\n return res.send({\n executed: false,\n requestedVersion: willExecute.requestedVersion,\n currentVersion: willExecute.currentVersion,\n minimumVersion: willExecute.minimumVersion,\n shouldUpdate: willExecute.shouldUpdate,\n targetVersion: willExecute.targetVersion,\n reason: willExecute?.reason,\n });\n }\n\n if (willExecute.targetVersion) {\n await this.clientBundleService.downloadClientUpdate(willExecute.targetVersion);\n }\n\n return res.send({\n executed: true,\n requestedVersion: willExecute.requestedVersion,\n currentVersion: willExecute.currentVersion,\n minimumVersion: willExecute.minimumVersion,\n shouldUpdate: willExecute.shouldUpdate,\n targetVersion: willExecute.targetVersion,\n reason: willExecute?.reason,\n });\n }\n\n @GET()\n @route(\"/github-rate-limit\")\n async getGithubRateLimit(req: Request, res: Response) {\n const rateLimitResponse = await this.githubService.getRateLimit();\n res.send(rateLimitResponse.data);\n }\n\n @POST()\n @route(\"/yaml-import\")\n async importYaml(req: Request, res: Response) {\n const files = await this.multerService.multerLoadFileAsync(req, res, [\".yaml\", \".yml\"], false);\n const firstFile = files[0];\n const spec = await this.yamlService.importYaml(firstFile.buffer.toString());\n\n res.send({\n success: true,\n spec,\n });\n }\n\n @POST()\n @route(\"/yaml-export\")\n async exportYaml(req: Request, res: Response) {\n const yaml = await this.yamlService.exportYaml(req.body);\n const fileContents = Buffer.from(yaml);\n const readStream = new PassThrough();\n readStream.end(fileContents);\n\n const fileName = `export-${AppConstants.serverRepoName}-` + Date.now() + \".yaml\";\n res.set(\"Content-disposition\", \"attachment; filename=\" + fileName);\n res.set(\"Content-Type\", \"text/plain\");\n readStream.pipe(res);\n }\n\n @DELETE()\n @route(\"/delete-all-printers\")\n async deleteAllPrinters(req: Request, res: Response) {\n const printers = await this.printerCache.listCachedPrinters(true);\n const printerIds = printers.map((p) => p.id);\n await this.printerService.deleteMany(printerIds);\n res.send();\n }\n\n @DELETE()\n @route(\"/clear-outdated-fdm-monster-logs\")\n async clearLogs(req: Request, res: Response) {\n const counts = await this.logDumpService.deleteOlderThanWeekAndMismatchingLogFiles();\n res.send(counts);\n }\n\n @GET()\n @POST()\n @route(\"/dump-fdm-monster-logs\")\n async dumpLogZips(req: Request, res: Response) {\n const filePath = await this.logDumpService.dumpZip();\n res.sendFile(filePath);\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 { AppConstants } from "../server.constants.js";
|
|
5
5
|
import { isNode } from "../utils/env.utils.js";
|
|
6
6
|
import { SettingsStore } from "../state/settings.store.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-public.controller.js","names":[],"sources":["../../src/controllers/server-public.controller.ts"],"sourcesContent":["import { before, GET, route } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport { isNode } from \"@/utils/env.utils\";\nimport { authenticate, permission } from \"@/middleware/authenticate\";\nimport { PERMS } from \"@/constants/authorization.constants\";\nimport { SettingsStore } from \"@/state/settings.store\";\nimport { ServerReleaseService } from \"@/services/core/server-release.service\";\nimport { MonsterPiService } from \"@/services/core/monsterpi.service\";\nimport type { Request, Response } from \"express\";\n\n@route(AppConstants.apiRoute)\nexport class ServerPublicController {\n constructor(\n private readonly settingsStore: SettingsStore,\n private readonly serverVersion: string,\n private readonly serverReleaseService: ServerReleaseService,\n private readonly monsterPiService: MonsterPiService,\n ) {}\n\n @GET()\n @route(\"/\")\n @before([authenticate(), permission(PERMS.ServerInfo.Get)])\n async welcome(req: Request, res: Response) {\n this.settingsStore.getSettings();\n\n if (!(await this.settingsStore.getLoginRequired())) {\n return res.send({\n message: \"Login disabled. Please load the Vue app.\",\n apiDocs: \"http://localhost:4000/api-docs/\",\n swaggerJson: \"http://localhost:4000/api-docs/swagger.json\",\n });\n }\n\n return res.send({\n message: \"Login required. Please load the Vue app.\",\n apiDocs: \"http://localhost:4000/api-docs/\",\n swaggerJson: \"http://localhost:4000/api-docs/swagger.json\",\n });\n }\n\n @GET()\n @route(\"/features\")\n @before([authenticate()])\n getFeatures(req: Request, res: Response) {\n const serverSettings = this.settingsStore.getServerSettings();\n const moonrakerEnabled = serverSettings.experimentalMoonrakerSupport;\n const prusaLinkEnabled = serverSettings.experimentalPrusaLinkSupport;\n const bambuEnabled = serverSettings.experimentalBambuSupport;\n res.send({\n multiplePrinterServices: {\n available: true,\n version: 1,\n subFeatures: {\n types: [\n \"octoprint\",\n ...(moonrakerEnabled ? [\"klipper\"] : []),\n ...(prusaLinkEnabled ? [\"prusaLink\"] : []),\n ...(bambuEnabled ? [\"bambu\"] : []),\n ],\n },\n },\n });\n }\n\n @GET()\n @route(\"/version\")\n @before([authenticate(), permission(PERMS.ServerInfo.Get)])\n async getVersion(req: Request, res: Response) {\n const updateState = this.serverReleaseService.getState();\n const monsterPiVersion = this.monsterPiService.getMonsterPiVersionSafe();\n\n res.json({\n version: this.serverVersion,\n isNode: isNode(),\n os: process.env.OS,\n monsterPi: monsterPiVersion,\n update: {\n synced: updateState.synced,\n updateAvailable: updateState.updateAvailable,\n airGapped: updateState.airGapped,\n },\n });\n }\n\n @GET()\n @route(\"/test\")\n async test(req: Request, res: Response) {\n res.send({\n message: \"Test successful. Please load the Vue app.\",\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAWO,IAAA,yBAAA,MAAM,uBAAuB;CAClC,YACE,eACA,eACA,sBACA,kBACA;
|
|
1
|
+
{"version":3,"file":"server-public.controller.js","names":[],"sources":["../../src/controllers/server-public.controller.ts"],"sourcesContent":["import { before, GET, route } from \"awilix-express\";\nimport { AppConstants } from \"@/server.constants\";\nimport { isNode } from \"@/utils/env.utils\";\nimport { authenticate, permission } from \"@/middleware/authenticate\";\nimport { PERMS } from \"@/constants/authorization.constants\";\nimport { SettingsStore } from \"@/state/settings.store\";\nimport { ServerReleaseService } from \"@/services/core/server-release.service\";\nimport { MonsterPiService } from \"@/services/core/monsterpi.service\";\nimport type { Request, Response } from \"express\";\n\n@route(AppConstants.apiRoute)\nexport class ServerPublicController {\n constructor(\n private readonly settingsStore: SettingsStore,\n private readonly serverVersion: string,\n private readonly serverReleaseService: ServerReleaseService,\n private readonly monsterPiService: MonsterPiService,\n ) {}\n\n @GET()\n @route(\"/\")\n @before([authenticate(), permission(PERMS.ServerInfo.Get)])\n async welcome(req: Request, res: Response) {\n this.settingsStore.getSettings();\n\n if (!(await this.settingsStore.getLoginRequired())) {\n return res.send({\n message: \"Login disabled. Please load the Vue app.\",\n apiDocs: \"http://localhost:4000/api-docs/\",\n swaggerJson: \"http://localhost:4000/api-docs/swagger.json\",\n });\n }\n\n return res.send({\n message: \"Login required. Please load the Vue app.\",\n apiDocs: \"http://localhost:4000/api-docs/\",\n swaggerJson: \"http://localhost:4000/api-docs/swagger.json\",\n });\n }\n\n @GET()\n @route(\"/features\")\n @before([authenticate()])\n getFeatures(req: Request, res: Response) {\n const serverSettings = this.settingsStore.getServerSettings();\n const moonrakerEnabled = serverSettings.experimentalMoonrakerSupport;\n const prusaLinkEnabled = serverSettings.experimentalPrusaLinkSupport;\n const bambuEnabled = serverSettings.experimentalBambuSupport;\n res.send({\n multiplePrinterServices: {\n available: true,\n version: 1,\n subFeatures: {\n types: [\n \"octoprint\",\n ...(moonrakerEnabled ? [\"klipper\"] : []),\n ...(prusaLinkEnabled ? [\"prusaLink\"] : []),\n ...(bambuEnabled ? [\"bambu\"] : []),\n ],\n },\n },\n });\n }\n\n @GET()\n @route(\"/version\")\n @before([authenticate(), permission(PERMS.ServerInfo.Get)])\n async getVersion(req: Request, res: Response) {\n const updateState = this.serverReleaseService.getState();\n const monsterPiVersion = this.monsterPiService.getMonsterPiVersionSafe();\n\n res.json({\n version: this.serverVersion,\n isNode: isNode(),\n os: process.env.OS,\n monsterPi: monsterPiVersion,\n update: {\n synced: updateState.synced,\n updateAvailable: updateState.updateAvailable,\n airGapped: updateState.airGapped,\n },\n });\n }\n\n @GET()\n @route(\"/test\")\n async test(req: Request, res: Response) {\n res.send({\n message: \"Test successful. Please load the Vue app.\",\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAWO,IAAA,yBAAA,MAAM,uBAAuB;CAClC,YACE,eACA,eACA,sBACA,kBACA;EAJiB,KAAA,gBAAA;EACA,KAAA,gBAAA;EACA,KAAA,uBAAA;EACA,KAAA,mBAAA;;CAGnB,MAGM,QAAQ,KAAc,KAAe;EACzC,KAAK,cAAc,aAAa;EAEhC,IAAI,CAAE,MAAM,KAAK,cAAc,kBAAkB,EAC/C,OAAO,IAAI,KAAK;GACd,SAAS;GACT,SAAS;GACT,aAAa;GACd,CAAC;EAGJ,OAAO,IAAI,KAAK;GACd,SAAS;GACT,SAAS;GACT,aAAa;GACd,CAAC;;CAGJ,YAGY,KAAc,KAAe;EACvC,MAAM,iBAAiB,KAAK,cAAc,mBAAmB;EAC7D,MAAM,mBAAmB,eAAe;EACxC,MAAM,mBAAmB,eAAe;EACxC,MAAM,eAAe,eAAe;EACpC,IAAI,KAAK,EACP,yBAAyB;GACvB,WAAW;GACX,SAAS;GACT,aAAa,EACX,OAAO;IACL;IACA,GAAI,mBAAmB,CAAC,UAAU,GAAG,EAAE;IACvC,GAAI,mBAAmB,CAAC,YAAY,GAAG,EAAE;IACzC,GAAI,eAAe,CAAC,QAAQ,GAAG,EAAE;IAClC,EACF;GACF,EACF,CAAC;;CAGJ,MAGM,WAAW,KAAc,KAAe;EAC5C,MAAM,cAAc,KAAK,qBAAqB,UAAU;EACxD,MAAM,mBAAmB,KAAK,iBAAiB,yBAAyB;EAExE,IAAI,KAAK;GACP,SAAS,KAAK;GACd,QAAQ,QAAQ;GAChB,IAAI,QAAQ,IAAI;GAChB,WAAW;GACX,QAAQ;IACN,QAAQ,YAAY;IACpB,iBAAiB,YAAY;IAC7B,WAAW,YAAY;IACxB;GACF,CAAC;;CAGJ,MAEM,KAAK,KAAc,KAAe;EACtC,IAAI,KAAK,EACP,SAAS,6CACV,CAAC;;;;CAtEH,KAAK;CACL,MAAM,IAAI;CACV,OAAO,CAAC,cAAc,EAAE,WAAW,MAAM,WAAW,IAAI,CAAC,CAAC;;;;;;CAmB1D,KAAK;CACL,MAAM,YAAY;CAClB,OAAO,CAAC,cAAc,CAAC,CAAC;;;;;;CAsBxB,KAAK;CACL,MAAM,WAAW;CACjB,OAAO,CAAC,cAAc,EAAE,WAAW,MAAM,WAAW,IAAI,CAAC,CAAC;;;;;;CAkB1D,KAAK;CACL,MAAM,QAAQ;;;;;qCA3EhB,MAAM,aAAa,SAAS,EAAA,mBAAA,qBAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
-
import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.
|
|
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 { validateInput } from "../handlers/validators.js";
|
|
6
6
|
import { AppConstants } from "../server.constants.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.controller.js","names":[],"sources":["../../src/controllers/settings.controller.ts"],"sourcesContent":["import { DELETE, GET, PATCH, POST, PUT, route, before } from \"awilix-express\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport { AppConstants } from \"@/server.constants\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { validateInput } from \"@/handlers/validators\";\nimport {\n credentialCoreSettingUpdateSchema,\n frontendSettingsUpdateSchema,\n moonrakerSupportSchema,\n prusaLinkSupportSchema,\n sentryDiagnosticsEnabledSchema,\n timeoutSettingsUpdateSchema,\n bambuSupportSchema,\n} from \"@/services/validators/settings-service.validation\";\nimport { SettingsStore } from \"@/state/settings.store\";\nimport type { Request, Response } from \"express\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { demoUserNotAllowed } from \"@/middleware/demo.middleware\";\nimport { PrinterCache } from \"@/state/printer.cache\";\nimport { BambuType, PrusaLinkType, MoonrakerType } from \"@/services/printer-api.interface\";\nimport type { IPrinterService } from \"@/services/interfaces/printer.service.interface\";\nimport { PrinterThumbnailCache } from \"@/state/printer-thumbnail.cache\";\nimport { loginRequiredSchema, registrationEnabledSchema } from \"@/controllers/validation/setting.validation\";\n\n@route(AppConstants.apiRoute + \"/settings\")\n@before([authenticate()])\nexport class SettingsController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly serverVersion: string,\n private readonly printerCache: PrinterCache,\n private readonly printerService: IPrinterService,\n private readonly settingsStore: SettingsStore,\n private readonly printerThumbnailCache: PrinterThumbnailCache,\n ) {\n this.logger = loggerFactory(SettingsController.name);\n }\n\n @GET()\n @route(\"/\")\n async getSettings(req: Request, res: Response) {\n let connection;\n try {\n connection = {\n clientIp: req.socket?.remoteAddress,\n version: this.serverVersion,\n };\n } catch (e) {\n this.logger.warn(\"Could not fetch server IP address\");\n }\n const settings = this.settingsStore.getSettings();\n res.send({ ...settings, connection });\n }\n\n @GET()\n @route(\"/sensitive\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async getSettingsSensitive(req: Request, res: Response) {\n const settings = this.settingsStore.getSettingsSensitive();\n res.send(settings);\n }\n\n @PATCH()\n @route(\"/sentry-diagnostics\")\n @before([demoUserNotAllowed])\n async updateSentryDiagnosticsEnabled(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, sentryDiagnosticsEnabledSchema);\n const result = this.settingsStore.setSentryDiagnosticsEnabled(enabled);\n res.send(result);\n }\n\n @PUT()\n @route(\"/experimental-moonraker-support\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateMoonrakerSupport(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, moonrakerSupportSchema);\n const result = await this.settingsStore.setExperimentalMoonrakerSupport(enabled);\n\n if (!enabled) {\n const printers = await this.printerCache.listCachedPrinters(false);\n const klipperPrinters = printers.filter((p) => p.printerType === MoonrakerType);\n for (const printer of klipperPrinters) {\n await this.printerService.updateEnabled(printer.id, false);\n }\n }\n res.send(result);\n }\n\n @PUT()\n @route(\"/experimental-prusa-link-support\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updatePrusaLinkSupport(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, prusaLinkSupportSchema);\n const result = await this.settingsStore.setExperimentalPrusaLinkSupport(enabled);\n\n if (!enabled) {\n const printers = await this.printerCache.listCachedPrinters(false);\n const prusaLinkPrinters = printers.filter((p) => p.printerType === PrusaLinkType);\n for (const printer of prusaLinkPrinters) {\n await this.printerService.updateEnabled(printer.id, false);\n }\n }\n res.send(result);\n }\n\n @PUT()\n @route(\"/experimental-bambu-support\")\n async updateBambuSupport(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, bambuSupportSchema);\n const result = await this.settingsStore.setExperimentalBambuSupport(enabled);\n\n if (!enabled) {\n const printers = await this.printerCache.listCachedPrinters(false);\n const bambuPrinters = printers.filter((p) => p.printerType === BambuType);\n for (const printer of bambuPrinters) {\n await this.printerService.updateEnabled(printer.id, false);\n }\n }\n res.send(result);\n }\n\n @PUT()\n @route(\"/frontend\")\n @before([authorizeRoles([ROLES.ADMIN])])\n async updateFrontendSettings(req: Request, res: Response) {\n const validatedInput = await validateInput(req.body, frontendSettingsUpdateSchema);\n const result = await this.settingsStore.updateFrontendSettings(validatedInput);\n res.send(result);\n }\n\n @PUT()\n @route(\"/login-required\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateLoginRequiredSettings(req: Request, res: Response) {\n const { loginRequired } = await validateInput(req.body, loginRequiredSchema);\n const result = await this.settingsStore.setLoginRequired(loginRequired);\n res.send(result);\n }\n\n @PUT()\n @route(\"/registration-enabled\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateRegistrationEnabledSettings(req: Request, res: Response) {\n const { registrationEnabled } = await validateInput(req.body, registrationEnabledSchema);\n const result = await this.settingsStore.setRegistrationEnabled(registrationEnabled);\n res.send(result);\n }\n\n @PUT()\n @route(\"/credential\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateCredentialSettings(req: Request, res: Response) {\n const validatedInput = await validateInput(req.body, credentialCoreSettingUpdateSchema);\n await this.settingsStore.updateCoreCredentialSettings(validatedInput);\n res.send();\n }\n\n @PUT()\n @route(\"/timeout\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateTimeoutSettings(req: Request, res: Response) {\n const validatedInput = await validateInput(req.body, timeoutSettingsUpdateSchema);\n const result = await this.settingsStore.updateTimeoutSettings(validatedInput);\n res.send(result);\n }\n\n @GET()\n @route(\"/slicer-api-key\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async getSlicerApiKey(req: Request, res: Response) {\n const apiKey = this.settingsStore.getSlicerApiKey();\n res.send({ slicerApiKey: apiKey });\n }\n\n @POST()\n @route(\"/slicer-api-key/regenerate\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async regenerateSlicerApiKey(req: Request, res: Response) {\n const newApiKey = await this.settingsStore.generateSlicerApiKey();\n this.logger.log(\"Slicer API key regenerated\");\n res.send({ slicerApiKey: newApiKey });\n }\n\n @DELETE()\n @route(\"/slicer-api-key\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async deleteSlicerApiKey(req: Request, res: Response) {\n await this.settingsStore.deleteSlicerApiKey();\n this.logger.log(\"Slicer API key deleted\");\n res.send({ slicerApiKey: null });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"settings.controller.js","names":[],"sources":["../../src/controllers/settings.controller.ts"],"sourcesContent":["import { DELETE, GET, PATCH, POST, PUT, route, before } from \"awilix-express\";\nimport { authenticate, authorizeRoles } from \"@/middleware/authenticate\";\nimport { AppConstants } from \"@/server.constants\";\nimport { ROLES } from \"@/constants/authorization.constants\";\nimport { validateInput } from \"@/handlers/validators\";\nimport {\n credentialCoreSettingUpdateSchema,\n frontendSettingsUpdateSchema,\n moonrakerSupportSchema,\n prusaLinkSupportSchema,\n sentryDiagnosticsEnabledSchema,\n timeoutSettingsUpdateSchema,\n bambuSupportSchema,\n} from \"@/services/validators/settings-service.validation\";\nimport { SettingsStore } from \"@/state/settings.store\";\nimport type { Request, Response } from \"express\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { demoUserNotAllowed } from \"@/middleware/demo.middleware\";\nimport { PrinterCache } from \"@/state/printer.cache\";\nimport { BambuType, PrusaLinkType, MoonrakerType } from \"@/services/printer-api.interface\";\nimport type { IPrinterService } from \"@/services/interfaces/printer.service.interface\";\nimport { PrinterThumbnailCache } from \"@/state/printer-thumbnail.cache\";\nimport { loginRequiredSchema, registrationEnabledSchema } from \"@/controllers/validation/setting.validation\";\n\n@route(AppConstants.apiRoute + \"/settings\")\n@before([authenticate()])\nexport class SettingsController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly serverVersion: string,\n private readonly printerCache: PrinterCache,\n private readonly printerService: IPrinterService,\n private readonly settingsStore: SettingsStore,\n private readonly printerThumbnailCache: PrinterThumbnailCache,\n ) {\n this.logger = loggerFactory(SettingsController.name);\n }\n\n @GET()\n @route(\"/\")\n async getSettings(req: Request, res: Response) {\n let connection;\n try {\n connection = {\n clientIp: req.socket?.remoteAddress,\n version: this.serverVersion,\n };\n } catch (e) {\n this.logger.warn(\"Could not fetch server IP address\");\n }\n const settings = this.settingsStore.getSettings();\n res.send({ ...settings, connection });\n }\n\n @GET()\n @route(\"/sensitive\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async getSettingsSensitive(req: Request, res: Response) {\n const settings = this.settingsStore.getSettingsSensitive();\n res.send(settings);\n }\n\n @PATCH()\n @route(\"/sentry-diagnostics\")\n @before([demoUserNotAllowed])\n async updateSentryDiagnosticsEnabled(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, sentryDiagnosticsEnabledSchema);\n const result = this.settingsStore.setSentryDiagnosticsEnabled(enabled);\n res.send(result);\n }\n\n @PUT()\n @route(\"/experimental-moonraker-support\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateMoonrakerSupport(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, moonrakerSupportSchema);\n const result = await this.settingsStore.setExperimentalMoonrakerSupport(enabled);\n\n if (!enabled) {\n const printers = await this.printerCache.listCachedPrinters(false);\n const klipperPrinters = printers.filter((p) => p.printerType === MoonrakerType);\n for (const printer of klipperPrinters) {\n await this.printerService.updateEnabled(printer.id, false);\n }\n }\n res.send(result);\n }\n\n @PUT()\n @route(\"/experimental-prusa-link-support\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updatePrusaLinkSupport(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, prusaLinkSupportSchema);\n const result = await this.settingsStore.setExperimentalPrusaLinkSupport(enabled);\n\n if (!enabled) {\n const printers = await this.printerCache.listCachedPrinters(false);\n const prusaLinkPrinters = printers.filter((p) => p.printerType === PrusaLinkType);\n for (const printer of prusaLinkPrinters) {\n await this.printerService.updateEnabled(printer.id, false);\n }\n }\n res.send(result);\n }\n\n @PUT()\n @route(\"/experimental-bambu-support\")\n async updateBambuSupport(req: Request, res: Response) {\n const { enabled } = await validateInput(req.body, bambuSupportSchema);\n const result = await this.settingsStore.setExperimentalBambuSupport(enabled);\n\n if (!enabled) {\n const printers = await this.printerCache.listCachedPrinters(false);\n const bambuPrinters = printers.filter((p) => p.printerType === BambuType);\n for (const printer of bambuPrinters) {\n await this.printerService.updateEnabled(printer.id, false);\n }\n }\n res.send(result);\n }\n\n @PUT()\n @route(\"/frontend\")\n @before([authorizeRoles([ROLES.ADMIN])])\n async updateFrontendSettings(req: Request, res: Response) {\n const validatedInput = await validateInput(req.body, frontendSettingsUpdateSchema);\n const result = await this.settingsStore.updateFrontendSettings(validatedInput);\n res.send(result);\n }\n\n @PUT()\n @route(\"/login-required\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateLoginRequiredSettings(req: Request, res: Response) {\n const { loginRequired } = await validateInput(req.body, loginRequiredSchema);\n const result = await this.settingsStore.setLoginRequired(loginRequired);\n res.send(result);\n }\n\n @PUT()\n @route(\"/registration-enabled\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateRegistrationEnabledSettings(req: Request, res: Response) {\n const { registrationEnabled } = await validateInput(req.body, registrationEnabledSchema);\n const result = await this.settingsStore.setRegistrationEnabled(registrationEnabled);\n res.send(result);\n }\n\n @PUT()\n @route(\"/credential\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateCredentialSettings(req: Request, res: Response) {\n const validatedInput = await validateInput(req.body, credentialCoreSettingUpdateSchema);\n await this.settingsStore.updateCoreCredentialSettings(validatedInput);\n res.send();\n }\n\n @PUT()\n @route(\"/timeout\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async updateTimeoutSettings(req: Request, res: Response) {\n const validatedInput = await validateInput(req.body, timeoutSettingsUpdateSchema);\n const result = await this.settingsStore.updateTimeoutSettings(validatedInput);\n res.send(result);\n }\n\n @GET()\n @route(\"/slicer-api-key\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async getSlicerApiKey(req: Request, res: Response) {\n const apiKey = this.settingsStore.getSlicerApiKey();\n res.send({ slicerApiKey: apiKey });\n }\n\n @POST()\n @route(\"/slicer-api-key/regenerate\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async regenerateSlicerApiKey(req: Request, res: Response) {\n const newApiKey = await this.settingsStore.generateSlicerApiKey();\n this.logger.log(\"Slicer API key regenerated\");\n res.send({ slicerApiKey: newApiKey });\n }\n\n @DELETE()\n @route(\"/slicer-api-key\")\n @before([authorizeRoles([ROLES.ADMIN]), demoUserNotAllowed])\n async deleteSlicerApiKey(req: Request, res: Response) {\n await this.settingsStore.deleteSlicerApiKey();\n this.logger.log(\"Slicer API key deleted\");\n res.send({ slicerApiKey: null });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
-
import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.
|
|
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 { MulterService } from "../services/core/multer.service.js";
|
|
6
6
|
import { FileStorageService } from "../services/file-storage.service.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slicer-compat.controller.js","names":[],"sources":["../../src/controllers/slicer-compat.controller.ts"],"sourcesContent":["import { GET, POST, route, before } from \"awilix-express\";\nimport type { Request, Response } from \"express\";\nimport { FileStorageService } from \"@/services/file-storage.service\";\nimport { FileAnalysisService } from \"@/services/file-analysis.service\";\nimport { MulterService } from \"@/services/core/multer.service\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { AppConstants } from \"@/server.constants\";\nimport { slicerApiKeyAuth } from \"@/middleware/slicer-api-key.middleware\";\n\n/**\n * OctoPrint-compatible API for PrusaSlicer and other slicer integration\n * Implements minimal OctoPrint API surface for file upload\n *\n * File operations require authentication\n */\n@route(\"/api\")\n@before([slicerApiKeyAuth()])\nexport class SlicerCompatController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly fileStorageService: FileStorageService,\n private readonly fileAnalysisService: FileAnalysisService,\n private readonly multerService: MulterService,\n ) {\n this.logger = loggerFactory(SlicerCompatController.name);\n }\n\n /**\n * OctoPrint version endpoint\n * GET /api/version\n */\n @GET()\n @route(\"/version\")\n async getVersion(req: Request, res: Response) {\n res.send({\n api: \"0.1\",\n server: \"1.9.0\",\n text: \"OctoPrint 1.9.3\",\n });\n }\n\n /**\n * OctoPrint files endpoint - Upload file\n * POST /api/files/local\n *\n * This endpoint mimics OctoPrint's file upload API for slicer compatibility\n * PrusaSlicer uses: POST /api/files/local with multipart form data\n */\n @POST()\n @route(\"/files/local\")\n async uploadFile(req: Request, res: Response) {\n let files: Express.Multer.File[] | undefined;\n\n try {\n // Accept all common 3D printer file formats\n const acceptedExtensions = [\n ...AppConstants.defaultAcceptedGcodeExtensions,\n ...AppConstants.defaultAcceptedBambuExtensions,\n ];\n\n // Load uploaded file using multer\n files = await this.multerService.multerLoadFileAsync(req, res, acceptedExtensions, true);\n\n if (!files?.length) {\n res.status(400).send({\n error: \"No file uploaded\",\n });\n return;\n }\n\n const file = files[0];\n\n await this.fileStorageService.validateUniqueFilename(file.originalname);\n\n const fileHash = await this.fileStorageService.calculateFileHash(file.path);\n const fileStorageId = await this.fileStorageService.saveFile(file, fileHash);\n const filePath = this.fileStorageService.getFilePath(fileStorageId);\n\n let metadata: any = {};\n let thumbnails: any[] = [];\n\n try {\n const analysisResult = await this.fileAnalysisService.analyzeFile(filePath);\n metadata = analysisResult.metadata;\n thumbnails = analysisResult.thumbnails || [];\n\n const thumbnailMetadata =\n thumbnails.length > 0 ? await this.fileStorageService.saveThumbnails(fileStorageId, thumbnails) : [];\n\n await this.fileStorageService.saveMetadata(\n fileStorageId,\n metadata,\n fileHash,\n file.originalname,\n thumbnailMetadata,\n );\n } catch (analysisError) {\n this.logger.error(`Failed to analyze uploaded file: ${analysisError}`);\n }\n\n try {\n this.multerService.clearUploadedFile(file);\n } catch (e) {\n this.logger.error(`Could not remove uploaded file from temporary storage`);\n }\n\n // Return OctoPrint-compatible response\n res.status(201).send({\n files: {\n local: {\n name: file.originalname,\n origin: \"local\",\n refs: {\n resource: `/api/files/local/${fileStorageId}`,\n download: `/api/files/local/${fileStorageId}`,\n },\n },\n },\n done: true,\n // Additional FDM Monster metadata\n _fdmMonster: {\n fileStorageId,\n fileHash,\n analyzed: Object.keys(metadata).length > 0,\n thumbnailCount: thumbnails.length,\n printTime: metadata.gcodePrintTimeSeconds,\n filament: metadata.filamentUsedGrams,\n },\n });\n\n this.logger.log(`File uploaded to printer: ${file.originalname} -> ${fileStorageId}`);\n } catch (error) {\n // Clean up temp file if it exists\n if (files?.[0]?.path) {\n try {\n this.multerService.clearUploadedFile(files[0]);\n } catch (e) {\n this.logger.error(`Could not remove uploaded file from temporary storage`);\n }\n }\n\n // Re-throw to let exception filter handle it properly\n throw error;\n }\n }\n\n /**\n * Files list endpoint\n * GET /api/files\n */\n @GET()\n @route(\"/files\")\n async listFiles(req: Request, res: Response) {\n try {\n const files = await this.fileStorageService.listAllFiles();\n\n // Convert to known format\n const knownFiles = files.map((file) => ({\n name: file.metadata?._originalFileName || file.fileName,\n path: file.fileStorageId,\n type: \"machinecode\",\n typePath: [\"machinecode\", file.fileFormat],\n origin: \"local\",\n refs: {\n resource: `/api/files/local/${file.fileStorageId}`,\n download: `/api/files/local/${file.fileStorageId}`,\n },\n gcodeAnalysis: file.metadata\n ? {\n estimatedPrintTime: file.metadata.gcodePrintTimeSeconds,\n filament: {\n tool0: {\n length: file.metadata.filamentUsedMm,\n volume: file.metadata.filamentUsedCm3,\n },\n },\n }\n : undefined,\n date: Math.floor(file.createdAt.getTime() / 1000),\n size: file.fileSize,\n }));\n\n res.send({\n files: knownFiles,\n free: 0, // Not applicable\n total: 0, // Not applicable\n });\n } catch (error) {\n this.logger.error(`Failed to list files via printer API: ${error}`);\n throw error;\n }\n }\n\n /**\n * Server endpoint (for compatibility checks)\n * GET /api/server\n */\n @GET()\n @route(\"/server\")\n async getServer(req: Request, res: Response) {\n res.send({\n version: \"1.9.0\",\n safemode: null,\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;AAkBO,IAAA,yBAAA,0BAAA,MAAM,uBAAuB;CAClC;CAEA,YACE,eACA,oBACA,qBACA,eACA;
|
|
1
|
+
{"version":3,"file":"slicer-compat.controller.js","names":[],"sources":["../../src/controllers/slicer-compat.controller.ts"],"sourcesContent":["import { GET, POST, route, before } from \"awilix-express\";\nimport type { Request, Response } from \"express\";\nimport { FileStorageService } from \"@/services/file-storage.service\";\nimport { FileAnalysisService } from \"@/services/file-analysis.service\";\nimport { MulterService } from \"@/services/core/multer.service\";\nimport type { ILoggerFactory } from \"@/handlers/logger-factory\";\nimport { LoggerService } from \"@/handlers/logger\";\nimport { AppConstants } from \"@/server.constants\";\nimport { slicerApiKeyAuth } from \"@/middleware/slicer-api-key.middleware\";\n\n/**\n * OctoPrint-compatible API for PrusaSlicer and other slicer integration\n * Implements minimal OctoPrint API surface for file upload\n *\n * File operations require authentication\n */\n@route(\"/api\")\n@before([slicerApiKeyAuth()])\nexport class SlicerCompatController {\n private readonly logger: LoggerService;\n\n constructor(\n loggerFactory: ILoggerFactory,\n private readonly fileStorageService: FileStorageService,\n private readonly fileAnalysisService: FileAnalysisService,\n private readonly multerService: MulterService,\n ) {\n this.logger = loggerFactory(SlicerCompatController.name);\n }\n\n /**\n * OctoPrint version endpoint\n * GET /api/version\n */\n @GET()\n @route(\"/version\")\n async getVersion(req: Request, res: Response) {\n res.send({\n api: \"0.1\",\n server: \"1.9.0\",\n text: \"OctoPrint 1.9.3\",\n });\n }\n\n /**\n * OctoPrint files endpoint - Upload file\n * POST /api/files/local\n *\n * This endpoint mimics OctoPrint's file upload API for slicer compatibility\n * PrusaSlicer uses: POST /api/files/local with multipart form data\n */\n @POST()\n @route(\"/files/local\")\n async uploadFile(req: Request, res: Response) {\n let files: Express.Multer.File[] | undefined;\n\n try {\n // Accept all common 3D printer file formats\n const acceptedExtensions = [\n ...AppConstants.defaultAcceptedGcodeExtensions,\n ...AppConstants.defaultAcceptedBambuExtensions,\n ];\n\n // Load uploaded file using multer\n files = await this.multerService.multerLoadFileAsync(req, res, acceptedExtensions, true);\n\n if (!files?.length) {\n res.status(400).send({\n error: \"No file uploaded\",\n });\n return;\n }\n\n const file = files[0];\n\n await this.fileStorageService.validateUniqueFilename(file.originalname);\n\n const fileHash = await this.fileStorageService.calculateFileHash(file.path);\n const fileStorageId = await this.fileStorageService.saveFile(file, fileHash);\n const filePath = this.fileStorageService.getFilePath(fileStorageId);\n\n let metadata: any = {};\n let thumbnails: any[] = [];\n\n try {\n const analysisResult = await this.fileAnalysisService.analyzeFile(filePath);\n metadata = analysisResult.metadata;\n thumbnails = analysisResult.thumbnails || [];\n\n const thumbnailMetadata =\n thumbnails.length > 0 ? await this.fileStorageService.saveThumbnails(fileStorageId, thumbnails) : [];\n\n await this.fileStorageService.saveMetadata(\n fileStorageId,\n metadata,\n fileHash,\n file.originalname,\n thumbnailMetadata,\n );\n } catch (analysisError) {\n this.logger.error(`Failed to analyze uploaded file: ${analysisError}`);\n }\n\n try {\n this.multerService.clearUploadedFile(file);\n } catch (e) {\n this.logger.error(`Could not remove uploaded file from temporary storage`);\n }\n\n // Return OctoPrint-compatible response\n res.status(201).send({\n files: {\n local: {\n name: file.originalname,\n origin: \"local\",\n refs: {\n resource: `/api/files/local/${fileStorageId}`,\n download: `/api/files/local/${fileStorageId}`,\n },\n },\n },\n done: true,\n // Additional FDM Monster metadata\n _fdmMonster: {\n fileStorageId,\n fileHash,\n analyzed: Object.keys(metadata).length > 0,\n thumbnailCount: thumbnails.length,\n printTime: metadata.gcodePrintTimeSeconds,\n filament: metadata.filamentUsedGrams,\n },\n });\n\n this.logger.log(`File uploaded to printer: ${file.originalname} -> ${fileStorageId}`);\n } catch (error) {\n // Clean up temp file if it exists\n if (files?.[0]?.path) {\n try {\n this.multerService.clearUploadedFile(files[0]);\n } catch (e) {\n this.logger.error(`Could not remove uploaded file from temporary storage`);\n }\n }\n\n // Re-throw to let exception filter handle it properly\n throw error;\n }\n }\n\n /**\n * Files list endpoint\n * GET /api/files\n */\n @GET()\n @route(\"/files\")\n async listFiles(req: Request, res: Response) {\n try {\n const files = await this.fileStorageService.listAllFiles();\n\n // Convert to known format\n const knownFiles = files.map((file) => ({\n name: file.metadata?._originalFileName || file.fileName,\n path: file.fileStorageId,\n type: \"machinecode\",\n typePath: [\"machinecode\", file.fileFormat],\n origin: \"local\",\n refs: {\n resource: `/api/files/local/${file.fileStorageId}`,\n download: `/api/files/local/${file.fileStorageId}`,\n },\n gcodeAnalysis: file.metadata\n ? {\n estimatedPrintTime: file.metadata.gcodePrintTimeSeconds,\n filament: {\n tool0: {\n length: file.metadata.filamentUsedMm,\n volume: file.metadata.filamentUsedCm3,\n },\n },\n }\n : undefined,\n date: Math.floor(file.createdAt.getTime() / 1000),\n size: file.fileSize,\n }));\n\n res.send({\n files: knownFiles,\n free: 0, // Not applicable\n total: 0, // Not applicable\n });\n } catch (error) {\n this.logger.error(`Failed to list files via printer API: ${error}`);\n throw error;\n }\n }\n\n /**\n * Server endpoint (for compatibility checks)\n * GET /api/server\n */\n @GET()\n @route(\"/server\")\n async getServer(req: Request, res: Response) {\n res.send({\n version: \"1.9.0\",\n safemode: null,\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __exportAll } from "../_virtual/_rolldown/runtime.js";
|
|
2
|
-
import { __decorateMetadata } from "../_virtual/_@oxc-project_runtime@0.
|
|
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 { validateInput, validateMiddleware } from "../handlers/validators.js";
|
|
6
6
|
import { AppConstants } from "../server.constants.js";
|