arkos 2.0.0-next.18 → 2.0.0-next.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/cli.js +8 -1
  2. package/dist/esm/app.js +1 -1
  3. package/dist/esm/app.js.map +1 -1
  4. package/dist/esm/components/arkos-gateway/arkos-gateway.js +5 -4
  5. package/dist/esm/components/arkos-gateway/arkos-gateway.js.map +1 -1
  6. package/dist/esm/components/arkos-gateway/socket-extensions.js +7 -0
  7. package/dist/esm/components/arkos-gateway/socket-extensions.js.map +1 -1
  8. package/dist/esm/components/arkos-gateway/utils/memory-gateway-store.js +2 -4
  9. package/dist/esm/components/arkos-gateway/utils/memory-gateway-store.js.map +1 -1
  10. package/dist/esm/components/arkos-gateway/utils/multi-tier-arkos-gateway-store.js +1 -0
  11. package/dist/esm/components/arkos-gateway/utils/multi-tier-arkos-gateway-store.js.map +1 -1
  12. package/dist/esm/components/arkos-loadable-registry/index.js +1 -3
  13. package/dist/esm/components/arkos-loadable-registry/index.js.map +1 -1
  14. package/dist/esm/components/arkos-route-hook/reader.js.map +1 -1
  15. package/dist/esm/components/arkos-route-hook/types.js.map +1 -1
  16. package/dist/esm/exports/index.js +1 -1
  17. package/dist/esm/exports/index.js.map +1 -1
  18. package/dist/esm/exports/middlewares/index.js +1 -1
  19. package/dist/esm/exports/middlewares/index.js.map +1 -1
  20. package/dist/esm/modules/auth/auth.controller.js +213 -221
  21. package/dist/esm/modules/auth/auth.controller.js.map +1 -1
  22. package/dist/esm/modules/auth/auth.service.js +11 -58
  23. package/dist/esm/modules/auth/auth.service.js.map +1 -1
  24. package/dist/esm/modules/auth/utils/auth-prisma-json-schema-generator.js +1 -0
  25. package/dist/esm/modules/auth/utils/auth-prisma-json-schema-generator.js.map +1 -1
  26. package/dist/esm/modules/auth/utils/services/auth-action.service.js +10 -12
  27. package/dist/esm/modules/auth/utils/services/auth-action.service.js.map +1 -1
  28. package/dist/esm/modules/base/base.controller.js +179 -177
  29. package/dist/esm/modules/base/base.controller.js.map +1 -1
  30. package/dist/esm/modules/base/base.middlewares.js +6 -21
  31. package/dist/esm/modules/base/base.middlewares.js.map +1 -1
  32. package/dist/esm/modules/base/base.service.js +28 -25
  33. package/dist/esm/modules/base/base.service.js.map +1 -1
  34. package/dist/esm/modules/base/utils/error-prettifier.js +26 -30
  35. package/dist/esm/modules/base/utils/error-prettifier.js.map +1 -1
  36. package/dist/esm/modules/email/email.service.js +2 -2
  37. package/dist/esm/modules/email/email.service.js.map +1 -1
  38. package/dist/esm/modules/error-handler/utils/app-error.js +5 -1
  39. package/dist/esm/modules/error-handler/utils/app-error.js.map +1 -1
  40. package/dist/esm/modules/file-upload/file-upload.controller.js +203 -205
  41. package/dist/esm/modules/file-upload/file-upload.controller.js.map +1 -1
  42. package/dist/esm/modules/file-upload/file-upload.router.js +3 -3
  43. package/dist/esm/modules/file-upload/file-upload.router.js.map +1 -1
  44. package/dist/esm/modules/file-upload/file-upload.service.js +12 -7
  45. package/dist/esm/modules/file-upload/file-upload.service.js.map +1 -1
  46. package/dist/esm/modules/file-upload/utils/file-upload-json-schema-generator.js +1 -1
  47. package/dist/esm/modules/file-upload/utils/file-upload-json-schema-generator.js.map +1 -1
  48. package/dist/esm/modules/swagger/swagger.router.js.map +1 -1
  49. package/dist/esm/modules/swagger/utils/helpers/openapi-schema-converter.js +1 -0
  50. package/dist/esm/modules/swagger/utils/helpers/openapi-schema-converter.js.map +1 -1
  51. package/dist/esm/types/index.js.map +1 -1
  52. package/dist/esm/types/new-arkos-config.js.map +1 -1
  53. package/dist/esm/types/router-config.js.map +1 -1
  54. package/dist/esm/types/validation/validation-manager.js +21 -22
  55. package/dist/esm/types/validation/validation-manager.js.map +1 -1
  56. package/dist/esm/utils/arkos-router/index.js +1 -6
  57. package/dist/esm/utils/arkos-router/index.js.map +1 -1
  58. package/dist/esm/utils/arkos-router/route-config-registry.js +2 -3
  59. package/dist/esm/utils/arkos-router/route-config-registry.js.map +1 -1
  60. package/dist/esm/utils/arkos-router/types/index.js.map +1 -1
  61. package/dist/esm/utils/arkos-router/utils/helpers/index.js +86 -43
  62. package/dist/esm/utils/arkos-router/utils/helpers/index.js.map +1 -1
  63. package/dist/esm/utils/arkos-router/utils/helpers/upload-manager.js +12 -14
  64. package/dist/esm/utils/arkos-router/utils/helpers/upload-manager.js.map +1 -1
  65. package/dist/esm/utils/bundler.js +6 -6
  66. package/dist/esm/utils/bundler.js.map +1 -1
  67. package/dist/esm/utils/cli/dev.js +4 -17
  68. package/dist/esm/utils/cli/dev.js.map +1 -1
  69. package/dist/esm/utils/cli/prisma-generate.js +8 -37
  70. package/dist/esm/utils/cli/prisma-generate.js.map +1 -1
  71. package/dist/esm/utils/cli/utils/cli.helpers.js +1 -1
  72. package/dist/esm/utils/cli/utils/smart-fs-watcher.js +3 -0
  73. package/dist/esm/utils/cli/utils/smart-fs-watcher.js.map +1 -1
  74. package/dist/esm/utils/cli/utils/template-generator/templates/router-template.js +1 -1
  75. package/dist/esm/utils/cli/utils/template-generator/templates/router-template.js.map +1 -1
  76. package/dist/esm/utils/dynamic-loader.js +2 -1
  77. package/dist/esm/utils/dynamic-loader.js.map +1 -1
  78. package/dist/esm/utils/features/api.features.js +24 -20
  79. package/dist/esm/utils/features/api.features.js.map +1 -1
  80. package/dist/esm/utils/features/port-and-host-allocator.js +4 -3
  81. package/dist/esm/utils/features/port-and-host-allocator.js.map +1 -1
  82. package/dist/esm/utils/helpers/arkos-config.helpers.js.map +1 -1
  83. package/dist/esm/utils/helpers/query-parser.helpers.js +7 -22
  84. package/dist/esm/utils/helpers/query-parser.helpers.js.map +1 -1
  85. package/dist/esm/utils/initialize-app.js +1 -1
  86. package/dist/esm/utils/initialize-app.js.map +1 -1
  87. package/dist/esm/utils/prisma/prisma-json-schema-generator.js +1 -3
  88. package/dist/esm/utils/prisma/prisma-json-schema-generator.js.map +1 -1
  89. package/dist/esm/utils/prisma/prisma-schema-parser.js +14 -8
  90. package/dist/esm/utils/prisma/prisma-schema-parser.js.map +1 -1
  91. package/dist/esm/utils/validate-schema.js +23 -21
  92. package/dist/esm/utils/validate-schema.js.map +1 -1
  93. package/dist/types/app.d.ts +1 -1
  94. package/dist/types/components/arkos-route-hook/reader.d.ts +2 -5
  95. package/dist/types/components/arkos-route-hook/types.d.ts +4 -4
  96. package/dist/types/exports/index.d.ts +3 -4
  97. package/dist/types/exports/middlewares/index.d.ts +1 -1
  98. package/dist/types/modules/auth/auth.service.d.ts +1 -40
  99. package/dist/types/modules/base/base.middlewares.d.ts +1 -10
  100. package/dist/types/modules/swagger/swagger.router.d.ts +1 -2
  101. package/dist/types/types/index.d.ts +3 -3
  102. package/dist/types/types/new-arkos-config.d.ts +0 -14
  103. package/dist/types/types/router-config.d.ts +0 -111
  104. package/dist/types/utils/arkos-router/types/index.d.ts +3 -3
  105. package/dist/types/utils/arkos-router/utils/helpers/index.d.ts +2 -6
  106. package/dist/types/utils/dynamic-loader.d.ts +2 -2
  107. package/dist/types/utils/helpers/query-parser.helpers.d.ts +1 -1
  108. package/dist/types/utils/prisma/prisma-schema-parser.d.ts +1 -0
  109. package/package.json +41 -41
  110. package/dist/esm/components/arkos-loadable-translator/index.js +0 -138
  111. package/dist/esm/components/arkos-loadable-translator/index.js.map +0 -1
  112. package/dist/types/components/arkos-loadable-translator/index.d.ts +0 -53
@@ -1 +1 @@
1
- {"version":3,"file":"email.service.js","sourceRoot":"","sources":["../../../../src/modules/email/email.service.ts"],"names":[],"mappings":"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","sourcesContent":["import nodemailer, { SendMailOptions, Transporter } from \"nodemailer\";\nimport { convert } from \"html-to-text\";\nimport { getArkosConfig } from \"../../server\";\nimport AppError from \"../error-handler/utils/app-error\";\n\n/**\n * Defines the options for sending an email.\n */\nexport type EmailOptions = {\n subject: string;\n} & SendMailOptions;\n\n/**\n * Defines the authentication options for SMTP.\n */\nexport type SMTPAuthOptions = {\n user: string;\n pass: string;\n};\n\n/**\n * Defines the connection options for SMTP server.\n */\nexport type SMTPConnectionOptions = {\n host?: string;\n port?: number;\n secure?: boolean;\n auth?: SMTPAuthOptions;\n name?: string;\n};\n\n/**\n * A service class to handle email-related tasks, including sending emails.\n *\n * See the api reference [www.arkosjs.com/docs/reference/the-email-service-class](https://www.arkosjs.com/docs/reference/the-email-service-class)\n */\nexport class EmailService {\n transporter: Transporter | null = null;\n private customConfig: SMTPConnectionOptions | null = null;\n\n /**\n * Creates an instance of the EmailService class.\n *\n * @param {SMTPConnectionOptions} [config] - Optional custom SMTP configuration.\n * If provided, these settings will be used instead of the Arkos config.\n */\n constructor(config?: SMTPConnectionOptions) {\n if (config) {\n this.customConfig = config;\n }\n }\n\n /**\n * Gets the email configuration from multiple sources with priority:\n * 1. Constructor customConfig\n * 2. ArkosConfig\n * 3. Environment variables\n * @returns Configuration object with host, port, and auth details\n * @throws AppError if required email configuration is not set\n */\n private getEmailConfig(): SMTPConnectionOptions {\n if (this.customConfig) {\n return this.customConfig;\n }\n\n const { email: emailConfigs } = getArkosConfig();\n const host = emailConfigs?.host || process.env.EMAIL_HOST;\n const port =\n emailConfigs?.port ||\n (process.env.EMAIL_PORT ? parseInt(process.env.EMAIL_PORT) : undefined);\n const secure =\n emailConfigs?.secure !== undefined\n ? emailConfigs.secure\n : process.env.EMAIL_SECURE\n ? process.env.EMAIL_SECURE === \"true\"\n : undefined;\n const user = emailConfigs?.auth?.user || process.env.EMAIL_USER;\n const pass = emailConfigs?.auth?.pass || process.env.EMAIL_PASSWORD;\n const name = emailConfigs?.name || process.env.EMAIL_NAME;\n\n if (!host) {\n throw new AppError(\n \"You are trying to use emailService without setting email configurations. \" +\n \"Please configure either arkosConfig.email or environment variables (EMAIL_HOST)\",\n 500,\n {\n docs: \"Read more about emailService at https://www.arkosjs.com/docs/guides/email-service\",\n }\n );\n }\n\n return {\n ...emailConfigs,\n host,\n port: port || 465,\n secure: secure !== undefined ? secure : true,\n auth:\n user && pass\n ? {\n user,\n pass,\n }\n : undefined,\n name,\n };\n }\n\n /**\n * Gets or creates a transporter using the email configuration\n * @param customConfig Optional override connection settings (takes full priority if provided)\n * @returns A configured nodemailer transporter\n */\n private getTransporter(customConfig?: SMTPConnectionOptions): Transporter {\n if (customConfig) {\n const { name, ...config } = customConfig;\n return nodemailer.createTransport(config);\n }\n\n if (!this.transporter) {\n const { name, ...config } = this.getEmailConfig() || {};\n this.transporter = nodemailer.createTransport(config);\n }\n return this.transporter;\n }\n\n /**\n * Sends an email with the provided options.\n * Can use either the default configuration or custom connection options.\n *\n * @param {EmailOptions} options - The options for the email to be sent.\n * @param {SMTPConnectionOptions} [connectionOptions] - Optional custom connection settings.\n * @param {boolean} [skipVerification=false] - Whether to skip connection verification.\n * @returns {Promise<{ success: boolean; messageId?: string } & Record<string, any>>} Result with message ID on success.\n */\n public async send(\n options: EmailOptions & SendMailOptions,\n connectionOptions?: SMTPConnectionOptions,\n skipVerification: boolean = true\n ): Promise<{ success: boolean; messageId?: string } & Record<string, any>> {\n const config = this.getEmailConfig();\n const transporter = connectionOptions\n ? this.getTransporter(connectionOptions)\n : this.getTransporter();\n\n const fromAddress =\n options.from || connectionOptions?.auth?.user || config.auth?.user;\n\n if (connectionOptions || !skipVerification) {\n const isConnected = await this.verifyConnection(transporter);\n if (!isConnected) throw new Error(\"Failed to connect to email server\");\n }\n\n const info = await transporter.sendMail({\n ...options,\n from: fromAddress\n ? config.name\n ? `${config.name}<${fromAddress}>`\n : fromAddress\n : undefined,\n text:\n options?.text ||\n (typeof options.html === \"string\" && options.html\n ? convert(options.html as string)\n : undefined),\n });\n\n return { success: true, ...info };\n }\n\n /**\n * Verifies the connection to the email server.\n * @param {Transporter} [transporterToVerify] - Optional transporter to verify.\n * @returns {Promise<boolean>} A promise that resolves to true if connection is valid.\n */\n public async verifyConnection(\n transporterToVerify?: Transporter\n ): Promise<boolean> {\n try {\n const transporter = transporterToVerify || this.getTransporter();\n await transporter.verify();\n return true;\n } catch (error) {\n console.error(\"Email Server Connection Failed\", error);\n return false;\n }\n }\n\n /**\n * Updates the custom configuration for this email service instance.\n * @param {SMTPConnectionOptions} config - The new connection options.\n */\n public updateConfig(config: SMTPConnectionOptions): void {\n this.customConfig = config;\n this.transporter = null; // Reset transporter so it will be recreated with new config\n }\n\n /**\n * Creates a new instance of EmailService with custom configuration.\n * @param {SMTPConnectionOptions} config - The connection options for the new instance.\n * @returns {EmailService} A new EmailService instance.\n */\n public static create(config: SMTPConnectionOptions): EmailService {\n return new EmailService(config);\n }\n}\n\nconst emailService = new EmailService();\n\nexport default emailService;\n"]}
1
+ {"version":3,"file":"email.service.js","sourceRoot":"","sources":["../../../../src/modules/email/email.service.ts"],"names":[],"mappings":"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","sourcesContent":["import nodemailer, { SendMailOptions, Transporter } from \"nodemailer\";\nimport { convert } from \"html-to-text\";\nimport { getArkosConfig } from \"../../server\";\nimport AppError from \"../error-handler/utils/app-error\";\n\n/**\n * Defines the options for sending an email.\n */\nexport type EmailOptions = {\n subject: string;\n} & SendMailOptions;\n\n/**\n * Defines the authentication options for SMTP.\n */\nexport type SMTPAuthOptions = {\n user: string;\n pass: string;\n};\n\n/**\n * Defines the connection options for SMTP server.\n */\nexport type SMTPConnectionOptions = {\n host?: string;\n port?: number;\n secure?: boolean;\n auth?: SMTPAuthOptions;\n name?: string;\n};\n\n/**\n * A service class to handle email-related tasks, including sending emails.\n *\n * See the api reference [www.arkosjs.com/docs/reference/the-email-service-class](https://www.arkosjs.com/docs/reference/the-email-service-class)\n */\nexport class EmailService {\n transporter: Transporter | null = null;\n private customConfig: SMTPConnectionOptions | null = null;\n\n /**\n * Creates an instance of the EmailService class.\n *\n * @param {SMTPConnectionOptions} [config] - Optional custom SMTP configuration.\n * If provided, these settings will be used instead of the Arkos config.\n */\n constructor(config?: SMTPConnectionOptions) {\n if (config) {\n this.customConfig = config;\n }\n }\n\n /**\n * Gets the email configuration from multiple sources with priority:\n * 1. Constructor customConfig\n * 2. ArkosConfig\n * 3. Environment variables\n * @returns Configuration object with host, port, and auth details\n * @throws AppError if required email configuration is not set\n */\n private getEmailConfig(): SMTPConnectionOptions {\n if (this.customConfig) {\n return this.customConfig;\n }\n\n const { email: emailConfigs } = getArkosConfig();\n const host = emailConfigs?.host || process.env.EMAIL_HOST;\n const port =\n emailConfigs?.port ||\n (process.env.EMAIL_PORT ? parseInt(process.env.EMAIL_PORT) : undefined);\n const secure =\n emailConfigs?.secure !== undefined\n ? emailConfigs.secure\n : process.env.EMAIL_SECURE\n ? process.env.EMAIL_SECURE === \"true\"\n : undefined;\n const user = emailConfigs?.auth?.user || process.env.EMAIL_USER;\n const pass = emailConfigs?.auth?.pass || process.env.EMAIL_PASSWORD;\n const name = emailConfigs?.name || process.env.EMAIL_NAME;\n\n if (!host) {\n throw new AppError(\n \"You are trying to use emailService without setting email configurations. \" +\n \"Please configure either arkosConfig.email or environment variables (EMAIL_HOST)\",\n 500,\n {\n docs: \"Read more about emailService at https://www.arkosjs.com/docs/guides/email-service\",\n }\n );\n }\n\n return {\n ...emailConfigs,\n host,\n port: port || 465,\n secure: secure !== undefined ? secure : true,\n auth:\n user && pass\n ? {\n user,\n pass,\n }\n : undefined,\n name,\n };\n }\n\n /**\n * Gets or creates a transporter using the email configuration\n * @param customConfig Optional override connection settings (takes full priority if provided)\n * @returns A configured nodemailer transporter\n */\n private getTransporter(customConfig?: SMTPConnectionOptions): Transporter {\n if (customConfig) {\n const { name, ...config } = customConfig;\n return nodemailer.createTransport(config);\n }\n\n if (!this.transporter) {\n const { name, ...config } = this.getEmailConfig() || {};\n this.transporter = nodemailer.createTransport(config);\n }\n return this.transporter;\n }\n\n /**\n * Sends an email with the provided options.\n * Can use either the default configuration or custom connection options.\n *\n * @param {EmailOptions} options - The options for the email to be sent.\n * @param {SMTPConnectionOptions} [connectionOptions] - Optional custom connection settings.\n * @param {boolean} [skipVerification=false] - Whether to skip connection verification.\n * @returns {Promise<{ success: boolean; messageId?: string } & Record<string, any>>} Result with message ID on success.\n */\n public async send(\n options: EmailOptions & SendMailOptions,\n connectionOptions?: SMTPConnectionOptions,\n skipVerification: boolean = true\n ): Promise<{ success: boolean; messageId?: string } & Record<string, any>> {\n const config = this.getEmailConfig();\n const transporter = connectionOptions\n ? this.getTransporter(connectionOptions)\n : this.getTransporter();\n\n const fromAddress =\n options.from || connectionOptions?.auth?.user || config.auth?.user;\n\n if (connectionOptions || !skipVerification) {\n const isConnected = await this.verifyConnection(transporter);\n if (!isConnected) throw new Error(\"Failed to connect to email server\");\n }\n\n const info = await transporter.sendMail({\n ...options,\n from: fromAddress\n ? config.name\n ? `${config.name}<${fromAddress}>`\n : fromAddress\n : undefined,\n text:\n options?.text ||\n (typeof options.html === \"string\" && options.html\n ? convert(options.html as string)\n : undefined),\n });\n\n return { success: true, ...info };\n }\n\n /**\n * Verifies the connection to the email server.\n * @param {Transporter} [transporterToVerify] - Optional transporter to verify.\n * @returns {Promise<boolean>} A promise that resolves to true if connection is valid.\n */\n public async verifyConnection(\n transporterToVerify?: Transporter\n ): Promise<boolean> {\n try {\n const transporter = transporterToVerify || this.getTransporter();\n await transporter.verify();\n return true;\n } catch (error) {\n console.error(\"Email Server Connection Failed\", error);\n return false;\n }\n }\n\n /**\n * Updates the custom configuration for this email service instance.\n * @param {SMTPConnectionOptions} config - The new connection options.\n */\n public updateConfig(config: SMTPConnectionOptions): void {\n this.customConfig = config;\n this.transporter = null; // Reset transporter so it will be recreated with new config\n }\n\n /**\n * Creates a new instance of EmailService with custom configuration.\n * @param {SMTPConnectionOptions} config - The connection options for the new instance.\n * @returns {EmailService} A new EmailService instance.\n */\n public static create(config: SMTPConnectionOptions): EmailService {\n return new EmailService(config);\n }\n}\n\nconst emailService = new EmailService();\n\nexport default emailService;\n"]}
@@ -1,7 +1,11 @@
1
1
  class AppError extends Error {
2
+ statusCode;
3
+ status;
4
+ isOperational;
5
+ code = "Unknown";
6
+ meta;
2
7
  constructor(message, statusCode, code, meta) {
3
8
  super(message);
4
- this.code = "Unknown";
5
9
  this.message = message || "An error occurred, try again!";
6
10
  this.statusCode = statusCode;
7
11
  this.status = `${statusCode}`.startsWith("4") ? "fail" : "error";
@@ -1 +1 @@
1
- {"version":3,"file":"app-error.js","sourceRoot":"","sources":["../../../../../src/modules/error-handler/utils/app-error.ts"],"names":[],"mappings":"AA+BA,MAAM,QAAS,SAAQ,KAAK;IAe1B,YACE,OAAe,EACf,UAAkB,EAClB,IAAmC,EACnC,IAAmC;QAEnC,KAAK,CAAC,OAAO,CAAC,CAAC;QAjBjB,SAAI,GAAY,SAAS,CAAC;QAmBxB,IAAI,CAAC,OAAO,GAAG,OAAO,IAAI,+BAA+B,CAAC;QAC1D,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QACjE,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAE1B,IAAI,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,OAAO,IAAI;YAC7C,MAAM,IAAI,QAAQ,CAChB,kCAAkC,OAAO,IAAI,+DAA+D,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,EAC5I,GAAG,EACH,gBAAgB,EAChB,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAC;QAEJ,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,SAAS,CAAC;QAC5D,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAC/C,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,SAAS,CAAC;QAC5D,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAC/C,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;QAEjC,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAClD,CAAC;CACF;AAED,eAAe,QAAQ,CAAC","sourcesContent":["/**\n * Custom error class for handling application errors.\n *\n * @extends {Error}\n *\n * @property {number} statusCode - HTTP status code of the error.\n * @property {string} status - Status message derived from the status code (`fail` for 4xx, `error` for 5xx).\n * @property {boolean} isOperational - Indicates if the error is operational (intended for client visibility).\n * @property {string} [code] - Optional error code for categorization.\n * @property {Record<string, any>} [meta] - Additional metadata related to the error.\n *\n * @example\n * ```typescript\n *\n * function getUser(id: string) {\n * if (!id) {\n * throw new AppError('User ID is required', 400, 'UserIDMissing', { field: 'id' });\n * }\n * // Simulate a user not found scenario\n * throw new AppError('User not found', 404, 'UserNotFound', { userId: id });\n * }\n *\n * try {\n * getUser('');\n * } catch (error) {\n * if (error instanceof AppError) {\n * console.error(`Error: ${error.message}, Code: ${error.code}, Status: ${error.status}`);\n * }\n * }\n * ```\n */\nclass AppError extends Error {\n statusCode: number;\n status: string;\n public isOperational: boolean;\n code?: string = \"Unknown\";\n meta?: Record<string, any>;\n\n /**\n * Creates an instance of AppError.\n *\n * @param {string} message - The error message.\n * @param {number} statusCode - The HTTP status code.\n * @param {Record<string, any>} [meta] - Additional metadata for debugging or client feedback.\n * @param {string} [code] - A custom error code for categorization.\n */\n constructor(\n message: string,\n statusCode: number,\n code?: string | Record<string, any>,\n meta?: Record<string, any> | string\n ) {\n super(message);\n\n this.message = message || \"An error occurred, try again!\";\n this.statusCode = statusCode;\n this.status = `${statusCode}`.startsWith(\"4\") ? \"fail\" : \"error\";\n this.isOperational = true;\n\n if (code && meta && typeof code === typeof meta)\n throw new AppError(\n `meta and code must not both be ${typeof code}, one must be of type object and other string. but received ${JSON.stringify({ meta, code })}`,\n 500,\n \"AppErrorMisuse\",\n { meta, code }\n );\n\n if (typeof code === \"string\") this.code = code || \"Unknown\";\n if (typeof code === \"object\") this.meta = code;\n if (typeof meta === \"string\") this.code = meta || \"Unknown\";\n if (typeof meta === \"object\") this.meta = meta;\n if (!code) this.code = \"Unknown\";\n\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\nexport default AppError;\n"]}
1
+ {"version":3,"file":"app-error.js","sourceRoot":"","sources":["../../../../../src/modules/error-handler/utils/app-error.ts"],"names":[],"mappings":"AA+BA,MAAM,QAAS,SAAQ,KAAK;IAC1B,UAAU,CAAS;IACnB,MAAM,CAAS;IACR,aAAa,CAAU;IAC9B,IAAI,GAAY,SAAS,CAAC;IAC1B,IAAI,CAAuB;IAU3B,YACE,OAAe,EACf,UAAkB,EAClB,IAAmC,EACnC,IAAmC;QAEnC,KAAK,CAAC,OAAO,CAAC,CAAC;QAEf,IAAI,CAAC,OAAO,GAAG,OAAO,IAAI,+BAA+B,CAAC;QAC1D,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QACjE,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAE1B,IAAI,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,OAAO,IAAI;YAC7C,MAAM,IAAI,QAAQ,CAChB,kCAAkC,OAAO,IAAI,+DAA+D,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,EAC5I,GAAG,EACH,gBAAgB,EAChB,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAC;QAEJ,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,SAAS,CAAC;QAC5D,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAC/C,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,SAAS,CAAC;QAC5D,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAC/C,IAAI,CAAC,IAAI;YAAE,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;QAEjC,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAClD,CAAC;CACF;AAED,eAAe,QAAQ,CAAC","sourcesContent":["/**\n * Custom error class for handling application errors.\n *\n * @extends {Error}\n *\n * @property {number} statusCode - HTTP status code of the error.\n * @property {string} status - Status message derived from the status code (`fail` for 4xx, `error` for 5xx).\n * @property {boolean} isOperational - Indicates if the error is operational (intended for client visibility).\n * @property {string} [code] - Optional error code for categorization.\n * @property {Record<string, any>} [meta] - Additional metadata related to the error.\n *\n * @example\n * ```typescript\n *\n * function getUser(id: string) {\n * if (!id) {\n * throw new AppError('User ID is required', 400, 'UserIDMissing', { field: 'id' });\n * }\n * // Simulate a user not found scenario\n * throw new AppError('User not found', 404, 'UserNotFound', { userId: id });\n * }\n *\n * try {\n * getUser('');\n * } catch (error) {\n * if (error instanceof AppError) {\n * console.error(`Error: ${error.message}, Code: ${error.code}, Status: ${error.status}`);\n * }\n * }\n * ```\n */\nclass AppError extends Error {\n statusCode: number;\n status: string;\n public isOperational: boolean;\n code?: string = \"Unknown\";\n meta?: Record<string, any>;\n\n /**\n * Creates an instance of AppError.\n *\n * @param {string} message - The error message.\n * @param {number} statusCode - The HTTP status code.\n * @param {Record<string, any>} [meta] - Additional metadata for debugging or client feedback.\n * @param {string} [code] - A custom error code for categorization.\n */\n constructor(\n message: string,\n statusCode: number,\n code?: string | Record<string, any>,\n meta?: Record<string, any> | string\n ) {\n super(message);\n\n this.message = message || \"An error occurred, try again!\";\n this.statusCode = statusCode;\n this.status = `${statusCode}`.startsWith(\"4\") ? \"fail\" : \"error\";\n this.isOperational = true;\n\n if (code && meta && typeof code === typeof meta)\n throw new AppError(\n `meta and code must not both be ${typeof code}, one must be of type object and other string. but received ${JSON.stringify({ meta, code })}`,\n 500,\n \"AppErrorMisuse\",\n { meta, code }\n );\n\n if (typeof code === \"string\") this.code = code || \"Unknown\";\n if (typeof code === \"object\") this.meta = code;\n if (typeof meta === \"string\") this.code = meta || \"Unknown\";\n if (typeof meta === \"object\") this.meta = meta;\n if (!code) this.code = \"Unknown\";\n\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\nexport default AppError;\n"]}
@@ -13,232 +13,230 @@ function matchesUploadUrl(originalUrl, baseUploadRoute, fileType, fileName) {
13
13
  new RegExp(`${baseUploadRoute}/${fileType}/${fileName}`).test(originalUrl));
14
14
  }
15
15
  export class FileUploadController {
16
- constructor() {
17
- this.uploadFile = catchAsync(async (req, res, next) => {
18
- const { fileType } = req.params;
19
- const { format, width, height, resizeTo } = req.query;
20
- const options = { format, width, height, resizeTo };
21
- const { documentUploadService, fileUploadService, imageUploadService, videoUploadService, } = getFileUploadServices();
22
- const { fileUpload } = getArkosConfig();
23
- const baseUploadDir = fileUpload?.baseUploadDir || "/uploads";
24
- const uploadPath = path.resolve(path.join(process.cwd(), baseUploadDir, fileType));
25
- try {
26
- await fs.promises.access(uploadPath);
27
- }
28
- catch {
29
- await fs.promises.mkdir(uploadPath, { recursive: true });
30
- }
31
- let uploader;
32
- switch (fileType) {
33
- case "images":
34
- uploader = imageUploadService;
35
- break;
36
- case "videos":
37
- uploader = videoUploadService;
38
- break;
39
- case "documents":
40
- uploader = documentUploadService;
41
- break;
42
- case "files":
43
- uploader = fileUploadService;
44
- break;
45
- default:
46
- return next(new AppError("Invalid file type", 400, "InvalidFileType"));
47
- }
48
- uploader.handleMultipleUpload()(req, res, async (err) => {
49
- if (err)
50
- throw err;
51
- let data;
52
- if (req.files && Array.isArray(req.files) && req.files.length > 0) {
53
- if (fileType === "images") {
54
- data = await Promise.all(req.files.map((file) => processImage(req, next, file.path, options)));
55
- }
56
- else {
57
- data = req.files.map((file) => processFile(req, file.path));
58
- }
59
- data = data.filter((url) => url !== null);
60
- }
61
- else if (req.file) {
62
- if (fileType === "images") {
63
- data = await processImage(req, next, req.file.path, options);
64
- }
65
- else {
66
- data = processFile(req, req.file.path);
67
- }
16
+ getRouteHook() {
17
+ return loadableRegistry.getItem("ArkosRouteHook", "file-upload");
18
+ }
19
+ getAfterHook(operation) {
20
+ const hook = this.getRouteHook();
21
+ if (!hook)
22
+ return null;
23
+ return (routeHookReader.getHooks("file-upload", operation)?.after ?? null);
24
+ }
25
+ uploadFile = catchAsync(async (req, res, next) => {
26
+ const { fileType } = req.params;
27
+ const { format, width, height, resizeTo } = req.query;
28
+ const options = { format, width, height, resizeTo };
29
+ const { documentUploadService, fileUploadService, imageUploadService, videoUploadService, } = getFileUploadServices();
30
+ const { fileUpload } = getArkosConfig();
31
+ const baseUploadDir = fileUpload?.baseUploadDir || "/uploads";
32
+ const uploadPath = path.resolve(path.join(process.cwd(), baseUploadDir, fileType));
33
+ try {
34
+ await fs.promises.access(uploadPath);
35
+ }
36
+ catch {
37
+ await fs.promises.mkdir(uploadPath, { recursive: true });
38
+ }
39
+ let uploader;
40
+ switch (fileType) {
41
+ case "images":
42
+ uploader = imageUploadService;
43
+ break;
44
+ case "videos":
45
+ uploader = videoUploadService;
46
+ break;
47
+ case "documents":
48
+ uploader = documentUploadService;
49
+ break;
50
+ case "files":
51
+ uploader = fileUploadService;
52
+ break;
53
+ default:
54
+ return next(new AppError("Invalid file type", 400, "InvalidFileType"));
55
+ }
56
+ uploader.handleMultipleUpload()(req, res, async (err) => {
57
+ if (err)
58
+ throw err;
59
+ let data;
60
+ if (req.files && Array.isArray(req.files) && req.files.length > 0) {
61
+ if (fileType === "images") {
62
+ data = await Promise.all(req.files.map((file) => processImage(req, next, file.path, options)));
68
63
  }
69
64
  else {
70
- return next(new AppError(`No file or files were attached on field ${fileType} on the request body as form data.`, 400, "NoFileOrFilesAttached"));
65
+ data = req.files.map((file) => processFile(req, file.path));
71
66
  }
72
- const jsonContent = {
73
- success: true,
74
- data,
75
- message: Array.isArray(data)
76
- ? `${data.length} files uploaded successfully`
77
- : "File uploaded successfully",
78
- };
79
- const afterHook = this.getAfterHook("uploadFile");
80
- if (afterHook) {
81
- res.originalData = jsonContent;
82
- req.responseData = jsonContent;
83
- res.locals.data = jsonContent;
84
- res.originalStatus = 200;
85
- req.responseStatus = 200;
86
- res.locals.status = 200;
87
- return next();
88
- }
89
- res.status(200).json(jsonContent);
90
- });
91
- });
92
- this.deleteFile = catchAsync(async (req, res, next) => {
93
- const { fileType, fileName } = req.params;
94
- const { documentUploadService, fileUploadService, imageUploadService, videoUploadService, } = getFileUploadServices();
95
- let uploader;
96
- switch (fileType) {
97
- case "images":
98
- uploader = imageUploadService;
99
- break;
100
- case "videos":
101
- uploader = videoUploadService;
102
- break;
103
- case "documents":
104
- uploader = documentUploadService;
105
- break;
106
- case "files":
107
- uploader = fileUploadService;
108
- break;
109
- default:
110
- return next(new AppError("Invalid file type", 400, "InvalidFileType"));
67
+ data = data.filter((url) => url !== null);
111
68
  }
112
- const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
113
- try {
114
- const { fileUpload } = getArkosConfig();
115
- const baseUploadRoute = fileUpload?.baseRoute || "/api/uploads";
116
- const urlPattern = new RegExp(`${escapeRegExp(baseUploadRoute)}/${escapeRegExp(fileType)}/${escapeRegExp(fileName)}`);
117
- const isExpectedUrlPattern = urlPattern.test(req.originalUrl);
118
- if (isExpectedUrlPattern) {
119
- const fullUrl = `${req.protocol}://${req.get("host")}${req.originalUrl}`;
120
- await uploader.deleteFileByUrl(fullUrl);
69
+ else if (req.file) {
70
+ if (fileType === "images") {
71
+ data = await processImage(req, next, req.file.path, options);
121
72
  }
122
73
  else {
123
- await uploader.deleteFileByName(fileName, fileType);
74
+ data = processFile(req, req.file.path);
124
75
  }
125
- const afterHook = this.getAfterHook("deleteFile");
126
- if (afterHook) {
127
- req.responseStatus = 204;
128
- return next();
129
- }
130
- res.status(204).json();
131
76
  }
132
- catch (error) {
133
- if (error instanceof AppError)
134
- return next(error);
135
- return next(new AppError("File not found", 404, "FileNotFound"));
77
+ else {
78
+ return next(new AppError(`No file or files were attached on field ${fileType} on the request body as form data.`, 400, "NoFileOrFilesAttached"));
79
+ }
80
+ const jsonContent = {
81
+ success: true,
82
+ data,
83
+ message: Array.isArray(data)
84
+ ? `${data.length} files uploaded successfully`
85
+ : "File uploaded successfully",
86
+ };
87
+ const afterHook = this.getAfterHook("uploadFile");
88
+ if (afterHook) {
89
+ res.originalData = jsonContent;
90
+ req.responseData = jsonContent;
91
+ res.locals.data = jsonContent;
92
+ res.originalStatus = 200;
93
+ req.responseStatus = 200;
94
+ res.locals.status = 200;
95
+ return next();
136
96
  }
97
+ res.status(200).json(jsonContent);
137
98
  });
138
- this.updateFile = catchAsync(async (req, res, next) => {
139
- const { fileType, fileName } = req.params;
140
- const { format, width, height, resizeTo } = req.query;
141
- const options = { format, width, height, resizeTo };
142
- const { documentUploadService, fileUploadService, imageUploadService, videoUploadService, } = getFileUploadServices();
99
+ });
100
+ deleteFile = catchAsync(async (req, res, next) => {
101
+ const { fileType, fileName } = req.params;
102
+ const { documentUploadService, fileUploadService, imageUploadService, videoUploadService, } = getFileUploadServices();
103
+ let uploader;
104
+ switch (fileType) {
105
+ case "images":
106
+ uploader = imageUploadService;
107
+ break;
108
+ case "videos":
109
+ uploader = videoUploadService;
110
+ break;
111
+ case "documents":
112
+ uploader = documentUploadService;
113
+ break;
114
+ case "files":
115
+ uploader = fileUploadService;
116
+ break;
117
+ default:
118
+ return next(new AppError("Invalid file type", 400, "InvalidFileType"));
119
+ }
120
+ const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
121
+ try {
143
122
  const { fileUpload } = getArkosConfig();
144
- const baseUploadDir = fileUpload?.baseUploadDir || "/uploads";
145
- const uploadPath = path.resolve(path.join(process.cwd(), baseUploadDir, fileType));
146
- try {
147
- await fs.promises.access(uploadPath);
123
+ const baseUploadRoute = fileUpload?.baseRoute || "/api/uploads";
124
+ const urlPattern = new RegExp(`${escapeRegExp(baseUploadRoute)}/${escapeRegExp(fileType)}/${escapeRegExp(fileName)}`);
125
+ const isExpectedUrlPattern = urlPattern.test(req.originalUrl);
126
+ if (isExpectedUrlPattern) {
127
+ const fullUrl = `${req.protocol}://${req.get("host")}${req.originalUrl}`;
128
+ await uploader.deleteFileByUrl(fullUrl);
148
129
  }
149
- catch {
150
- await fs.promises.mkdir(uploadPath, { recursive: true });
130
+ else {
131
+ await uploader.deleteFileByName(fileName, fileType);
151
132
  }
152
- let uploader;
153
- switch (fileType) {
154
- case "images":
155
- uploader = imageUploadService;
156
- break;
157
- case "videos":
158
- uploader = videoUploadService;
159
- break;
160
- case "documents":
161
- uploader = documentUploadService;
162
- break;
163
- case "files":
164
- uploader = fileUploadService;
165
- break;
166
- default:
167
- return next(new AppError("Invalid file type", 400, "InvalidFileType"));
133
+ const afterHook = this.getAfterHook("deleteFile");
134
+ if (afterHook) {
135
+ req.responseStatus = 204;
136
+ return next();
168
137
  }
169
- uploader.handleMultipleUpload()(req, res, async (err) => {
170
- if (err)
171
- throw err;
172
- if (!req.file &&
173
- (!req.files || !Array.isArray(req.files) || req.files.length === 0))
174
- return next(new AppError("No new file uploaded", 400, "MissingNewFile"));
175
- if (fileName && fileName.trim() !== "") {
176
- try {
177
- const isExpectedUrlPattern = matchesUploadUrl(req.originalUrl, fileUpload?.baseRoute || "/api/uploads", fileType, fileName);
178
- if (isExpectedUrlPattern) {
179
- const oldFileUrl = `${req.protocol}://${req.get("host")}${req.originalUrl}`;
180
- await uploader.deleteFileByUrl(oldFileUrl);
181
- }
182
- else {
183
- await uploader.deleteFileByName(fileName, fileType);
184
- }
185
- }
186
- catch (error) {
187
- console.warn(`Could not delete old file: ${fileName}`, error);
188
- }
189
- }
190
- let data;
191
- if (req.files && Array.isArray(req.files) && req.files.length > 0) {
192
- if (fileType === "images") {
193
- data = await Promise.all(req.files.map((file) => processImage(req, next, file.path, options)));
138
+ res.status(204).json();
139
+ }
140
+ catch (error) {
141
+ if (error instanceof AppError)
142
+ return next(error);
143
+ return next(new AppError("File not found", 404, "FileNotFound"));
144
+ }
145
+ });
146
+ updateFile = catchAsync(async (req, res, next) => {
147
+ const { fileType, fileName } = req.params;
148
+ const { format, width, height, resizeTo } = req.query;
149
+ const options = { format, width, height, resizeTo };
150
+ const { documentUploadService, fileUploadService, imageUploadService, videoUploadService, } = getFileUploadServices();
151
+ const { fileUpload } = getArkosConfig();
152
+ const baseUploadDir = fileUpload?.baseUploadDir || "/uploads";
153
+ const uploadPath = path.resolve(path.join(process.cwd(), baseUploadDir, fileType));
154
+ try {
155
+ await fs.promises.access(uploadPath);
156
+ }
157
+ catch {
158
+ await fs.promises.mkdir(uploadPath, { recursive: true });
159
+ }
160
+ let uploader;
161
+ switch (fileType) {
162
+ case "images":
163
+ uploader = imageUploadService;
164
+ break;
165
+ case "videos":
166
+ uploader = videoUploadService;
167
+ break;
168
+ case "documents":
169
+ uploader = documentUploadService;
170
+ break;
171
+ case "files":
172
+ uploader = fileUploadService;
173
+ break;
174
+ default:
175
+ return next(new AppError("Invalid file type", 400, "InvalidFileType"));
176
+ }
177
+ uploader.handleMultipleUpload()(req, res, async (err) => {
178
+ if (err)
179
+ throw err;
180
+ if (!req.file &&
181
+ (!req.files || !Array.isArray(req.files) || req.files.length === 0))
182
+ return next(new AppError("No new file uploaded", 400, "MissingNewFile"));
183
+ if (fileName && fileName.trim() !== "") {
184
+ try {
185
+ const isExpectedUrlPattern = matchesUploadUrl(req.originalUrl, fileUpload?.baseRoute || "/api/uploads", fileType, fileName);
186
+ if (isExpectedUrlPattern) {
187
+ const oldFileUrl = `${req.protocol}://${req.get("host")}${req.originalUrl}`;
188
+ await uploader.deleteFileByUrl(oldFileUrl);
194
189
  }
195
190
  else {
196
- data = req.files.map((file) => processFile(req, file.path));
191
+ await uploader.deleteFileByName(fileName, fileType);
197
192
  }
198
- data = data.filter((url) => url !== null);
199
193
  }
200
- else if (req.file) {
201
- if (fileType === "images") {
202
- data = await processImage(req, next, req.file.path, options);
203
- }
204
- else {
205
- data = processFile(req, req.file.path);
206
- }
194
+ catch (error) {
195
+ console.warn(`Could not delete old file: ${fileName}`, error);
207
196
  }
208
- const jsonContent = {
209
- success: true,
210
- data,
211
- message: Array.isArray(data)
212
- ? fileName && fileName.trim() !== ""
213
- ? `File updated successfully. ${data.length} new files uploaded`
214
- : `${data.length} files uploaded successfully`
215
- : fileName && fileName.trim() !== ""
216
- ? "File updated successfully"
217
- : "File uploaded successfully",
218
- };
219
- const afterHook = this.getAfterHook("updateFile");
220
- if (afterHook) {
221
- res.originalData = jsonContent;
222
- req.responseData = jsonContent;
223
- res.locals.data = jsonContent;
224
- res.originalStatus = 200;
225
- req.responseStatus = 200;
226
- res.locals.status = 200;
227
- return next();
197
+ }
198
+ let data;
199
+ if (req.files && Array.isArray(req.files) && req.files.length > 0) {
200
+ if (fileType === "images") {
201
+ data = await Promise.all(req.files.map((file) => processImage(req, next, file.path, options)));
228
202
  }
229
- res.status(200).json(jsonContent);
230
- });
203
+ else {
204
+ data = req.files.map((file) => processFile(req, file.path));
205
+ }
206
+ data = data.filter((url) => url !== null);
207
+ }
208
+ else if (req.file) {
209
+ if (fileType === "images") {
210
+ data = await processImage(req, next, req.file.path, options);
211
+ }
212
+ else {
213
+ data = processFile(req, req.file.path);
214
+ }
215
+ }
216
+ const jsonContent = {
217
+ success: true,
218
+ data,
219
+ message: Array.isArray(data)
220
+ ? fileName && fileName.trim() !== ""
221
+ ? `File updated successfully. ${data.length} new files uploaded`
222
+ : `${data.length} files uploaded successfully`
223
+ : fileName && fileName.trim() !== ""
224
+ ? "File updated successfully"
225
+ : "File uploaded successfully",
226
+ };
227
+ const afterHook = this.getAfterHook("updateFile");
228
+ if (afterHook) {
229
+ res.originalData = jsonContent;
230
+ req.responseData = jsonContent;
231
+ res.locals.data = jsonContent;
232
+ res.originalStatus = 200;
233
+ req.responseStatus = 200;
234
+ res.locals.status = 200;
235
+ return next();
236
+ }
237
+ res.status(200).json(jsonContent);
231
238
  });
232
- }
233
- getRouteHook() {
234
- return loadableRegistry.getItem("ArkosRouteHook", "file-upload");
235
- }
236
- getAfterHook(operation) {
237
- const hook = this.getRouteHook();
238
- if (!hook)
239
- return null;
240
- return (routeHookReader.getHooks("file-upload", operation)?.after ?? null);
241
- }
239
+ });
242
240
  }
243
241
  const fileUploadController = new FileUploadController();
244
242
  export default fileUploadController;