create-pardx-scaffold 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (555) hide show
  1. package/README.md +45 -0
  2. package/cli.js +104 -0
  3. package/package.json +15 -0
  4. package/template/.cursorrules +479 -0
  5. package/template/.prettierignore +29 -0
  6. package/template/.prettierrc +11 -0
  7. package/template/.vscode/extensions.json +8 -0
  8. package/template/.vscode/settings.json +122 -0
  9. package/template/CLAUDE.md +762 -0
  10. package/template/README.md +125 -0
  11. package/template/apps/api/.env.example +11 -0
  12. package/template/apps/api/.eslintrc.js +222 -0
  13. package/template/apps/api/config.local.yaml +397 -0
  14. package/template/apps/api/libs/domain/auth/package.json +11 -0
  15. package/template/apps/api/libs/domain/auth/src/README.md +189 -0
  16. package/template/apps/api/libs/domain/auth/src/auth-validation.service.ts +37 -0
  17. package/template/apps/api/libs/domain/auth/src/auth.guard.ts +173 -0
  18. package/template/apps/api/libs/domain/auth/src/auth.module.ts +23 -0
  19. package/template/apps/api/libs/domain/auth/src/auth.service.ts +198 -0
  20. package/template/apps/api/libs/domain/auth/src/auth.ts +66 -0
  21. package/template/apps/api/libs/domain/auth/src/decorators/presets.decorator.ts +50 -0
  22. package/template/apps/api/libs/domain/auth/src/decorators/rbac.decorator.ts +67 -0
  23. package/template/apps/api/libs/domain/auth/src/decorators/resource-owner.decorator.ts +67 -0
  24. package/template/apps/api/libs/domain/auth/src/dto/auth.dto.ts +10 -0
  25. package/template/apps/api/libs/domain/auth/src/guards/streaming-asr-session.guard.ts +179 -0
  26. package/template/apps/api/libs/domain/auth/src/index.ts +12 -0
  27. package/template/apps/api/libs/domain/auth/src/types/auth.interface.ts +52 -0
  28. package/template/apps/api/libs/domain/auth/tsconfig.lib.json +9 -0
  29. package/template/apps/api/libs/domain/db/package.json +11 -0
  30. package/template/apps/api/libs/domain/db/src/index.ts +14 -0
  31. package/template/apps/api/libs/domain/db/src/modules/country-code/country-code.module.ts +12 -0
  32. package/template/apps/api/libs/domain/db/src/modules/country-code/country-code.service.ts +140 -0
  33. package/template/apps/api/libs/domain/db/src/modules/country-code/index.ts +2 -0
  34. package/template/apps/api/libs/domain/db/src/modules/discord-auth/discord-auth.module.ts +12 -0
  35. package/template/apps/api/libs/domain/db/src/modules/discord-auth/discord-auth.service.ts +101 -0
  36. package/template/apps/api/libs/domain/db/src/modules/discord-auth/index.ts +2 -0
  37. package/template/apps/api/libs/domain/db/src/modules/email-auth/email-auth.module.ts +12 -0
  38. package/template/apps/api/libs/domain/db/src/modules/email-auth/email-auth.service.ts +101 -0
  39. package/template/apps/api/libs/domain/db/src/modules/email-auth/index.ts +2 -0
  40. package/template/apps/api/libs/domain/db/src/modules/file-source/file-source.module.ts +12 -0
  41. package/template/apps/api/libs/domain/db/src/modules/file-source/file-source.service.ts +109 -0
  42. package/template/apps/api/libs/domain/db/src/modules/file-source/index.ts +2 -0
  43. package/template/apps/api/libs/domain/db/src/modules/google-auth/google-auth.module.ts +12 -0
  44. package/template/apps/api/libs/domain/db/src/modules/google-auth/google-auth.service.ts +101 -0
  45. package/template/apps/api/libs/domain/db/src/modules/google-auth/index.ts +2 -0
  46. package/template/apps/api/libs/domain/db/src/modules/message/index.ts +2 -0
  47. package/template/apps/api/libs/domain/db/src/modules/message/message.module.ts +10 -0
  48. package/template/apps/api/libs/domain/db/src/modules/message/message.service.ts +314 -0
  49. package/template/apps/api/libs/domain/db/src/modules/mobile-auth/index.ts +2 -0
  50. package/template/apps/api/libs/domain/db/src/modules/mobile-auth/mobile-auth.module.ts +12 -0
  51. package/template/apps/api/libs/domain/db/src/modules/mobile-auth/mobile-auth.service.ts +101 -0
  52. package/template/apps/api/libs/domain/db/src/modules/risk-detection-record/index.ts +2 -0
  53. package/template/apps/api/libs/domain/db/src/modules/risk-detection-record/risk-detection-record.module.ts +12 -0
  54. package/template/apps/api/libs/domain/db/src/modules/risk-detection-record/risk-detection-record.service.ts +101 -0
  55. package/template/apps/api/libs/domain/db/src/modules/system-task-queue/index.ts +2 -0
  56. package/template/apps/api/libs/domain/db/src/modules/system-task-queue/system-task-queue.module.ts +12 -0
  57. package/template/apps/api/libs/domain/db/src/modules/system-task-queue/system-task-queue.service.ts +101 -0
  58. package/template/apps/api/libs/domain/db/src/modules/user-info/index.ts +2 -0
  59. package/template/apps/api/libs/domain/db/src/modules/user-info/user-info.module.ts +12 -0
  60. package/template/apps/api/libs/domain/db/src/modules/user-info/user-info.service.ts +139 -0
  61. package/template/apps/api/libs/domain/db/src/modules/wechat-auth/index.ts +2 -0
  62. package/template/apps/api/libs/domain/db/src/modules/wechat-auth/wechat-auth.module.ts +12 -0
  63. package/template/apps/api/libs/domain/db/src/modules/wechat-auth/wechat-auth.service.ts +101 -0
  64. package/template/apps/api/libs/domain/db/tsconfig.lib.json +9 -0
  65. package/template/apps/api/libs/infra/clients/internal/ai/index.ts +2 -0
  66. package/template/apps/api/libs/infra/clients/internal/ai/risk-detection.client.ts +301 -0
  67. package/template/apps/api/libs/infra/clients/internal/ai/risk-detection.module.ts +22 -0
  68. package/template/apps/api/libs/infra/clients/internal/crypt/crypt-client.service.spec.ts +18 -0
  69. package/template/apps/api/libs/infra/clients/internal/crypt/crypt.client.ts +37 -0
  70. package/template/apps/api/libs/infra/clients/internal/crypt/crypt.module.ts +10 -0
  71. package/template/apps/api/libs/infra/clients/internal/crypt/index.ts +2 -0
  72. package/template/apps/api/libs/infra/clients/internal/email/dto/email.dto.ts +75 -0
  73. package/template/apps/api/libs/infra/clients/internal/email/index.ts +11 -0
  74. package/template/apps/api/libs/infra/clients/internal/email/sendcloud.client.ts +400 -0
  75. package/template/apps/api/libs/infra/clients/internal/file-cdn/README.md +255 -0
  76. package/template/apps/api/libs/infra/clients/internal/file-cdn/dto/file-cdn.dto.ts +96 -0
  77. package/template/apps/api/libs/infra/clients/internal/file-cdn/file-cdn-client.service.spec.ts +18 -0
  78. package/template/apps/api/libs/infra/clients/internal/file-cdn/file-cdn.client.ts +620 -0
  79. package/template/apps/api/libs/infra/clients/internal/file-cdn/file-cdn.module.ts +19 -0
  80. package/template/apps/api/libs/infra/clients/internal/file-cdn/index.ts +40 -0
  81. package/template/apps/api/libs/infra/clients/internal/file-storage/config/file.config.ts +14 -0
  82. package/template/apps/api/libs/infra/clients/internal/file-storage/dto/file.dto.ts +127 -0
  83. package/template/apps/api/libs/infra/clients/internal/file-storage/file-gcs.client.ts +154 -0
  84. package/template/apps/api/libs/infra/clients/internal/file-storage/file-qiniu.client.ts +729 -0
  85. package/template/apps/api/libs/infra/clients/internal/file-storage/file-s3.client.ts +1097 -0
  86. package/template/apps/api/libs/infra/clients/internal/file-storage/file-storage.interface.ts +114 -0
  87. package/template/apps/api/libs/infra/clients/internal/file-storage/file-tos.client.ts +767 -0
  88. package/template/apps/api/libs/infra/clients/internal/file-storage/file-us3.client.ts +176 -0
  89. package/template/apps/api/libs/infra/clients/internal/file-storage/index.ts +16 -0
  90. package/template/apps/api/libs/infra/clients/internal/ocr/dto/ocr.dto.ts +61 -0
  91. package/template/apps/api/libs/infra/clients/internal/ocr/index.ts +3 -0
  92. package/template/apps/api/libs/infra/clients/internal/ocr/ocr.client.ts +123 -0
  93. package/template/apps/api/libs/infra/clients/internal/ocr/ocr.module.ts +15 -0
  94. package/template/apps/api/libs/infra/clients/internal/openai/index.ts +2 -0
  95. package/template/apps/api/libs/infra/clients/internal/openai/openai.client.ts +135 -0
  96. package/template/apps/api/libs/infra/clients/internal/openai/openai.module.ts +17 -0
  97. package/template/apps/api/libs/infra/clients/internal/openspeech/README.md +508 -0
  98. package/template/apps/api/libs/infra/clients/internal/openspeech/index.ts +44 -0
  99. package/template/apps/api/libs/infra/clients/internal/openspeech/openspeech.client.ts +441 -0
  100. package/template/apps/api/libs/infra/clients/internal/openspeech/openspeech.factory.ts +450 -0
  101. package/template/apps/api/libs/infra/clients/internal/openspeech/openspeech.module.ts +56 -0
  102. package/template/apps/api/libs/infra/clients/internal/openspeech/providers/aliyun.provider.ts +308 -0
  103. package/template/apps/api/libs/infra/clients/internal/openspeech/providers/base.provider.ts +114 -0
  104. package/template/apps/api/libs/infra/clients/internal/openspeech/providers/index.ts +10 -0
  105. package/template/apps/api/libs/infra/clients/internal/openspeech/providers/volcengine-streaming.provider.ts +1689 -0
  106. package/template/apps/api/libs/infra/clients/internal/openspeech/providers/volcengine.provider.ts +387 -0
  107. package/template/apps/api/libs/infra/clients/internal/openspeech/types.ts +467 -0
  108. package/template/apps/api/libs/infra/clients/internal/sms/dto/sms.dto.ts +97 -0
  109. package/template/apps/api/libs/infra/clients/internal/sms/index.ts +15 -0
  110. package/template/apps/api/libs/infra/clients/internal/sms/sms-aliyun.client.ts +52 -0
  111. package/template/apps/api/libs/infra/clients/internal/sms/sms-http.client.ts +111 -0
  112. package/template/apps/api/libs/infra/clients/internal/sms/sms-tencent.client.ts +54 -0
  113. package/template/apps/api/libs/infra/clients/internal/sms/sms-volcengine.client.ts +165 -0
  114. package/template/apps/api/libs/infra/clients/internal/sms/sms-zxjc.client.ts +47 -0
  115. package/template/apps/api/libs/infra/clients/internal/sse/index.ts +2 -0
  116. package/template/apps/api/libs/infra/clients/internal/sse/sse-client.service.spec.ts +18 -0
  117. package/template/apps/api/libs/infra/clients/internal/sse/sse.client.ts +360 -0
  118. package/template/apps/api/libs/infra/clients/internal/sse/sse.module.ts +17 -0
  119. package/template/apps/api/libs/infra/clients/internal/third-party-sse/index.ts +2 -0
  120. package/template/apps/api/libs/infra/clients/internal/third-party-sse/third-party-sse.client.ts +51 -0
  121. package/template/apps/api/libs/infra/clients/internal/third-party-sse/third-party-sse.module.ts +10 -0
  122. package/template/apps/api/libs/infra/clients/internal/third-party-sse/third-party-sse.service.spec.ts +18 -0
  123. package/template/apps/api/libs/infra/clients/internal/verify/index.ts +2 -0
  124. package/template/apps/api/libs/infra/clients/internal/verify/verify.client.ts +42 -0
  125. package/template/apps/api/libs/infra/clients/internal/verify/verify.module.ts +10 -0
  126. package/template/apps/api/libs/infra/clients/internal/volcengine-tts/dto/tts.dto.ts +64 -0
  127. package/template/apps/api/libs/infra/clients/internal/volcengine-tts/index.ts +3 -0
  128. package/template/apps/api/libs/infra/clients/internal/volcengine-tts/volcengine-tts.client.ts +846 -0
  129. package/template/apps/api/libs/infra/clients/internal/volcengine-tts/volcengine-tts.module.ts +21 -0
  130. package/template/apps/api/libs/infra/clients/internal/wechat/index.ts +2 -0
  131. package/template/apps/api/libs/infra/clients/internal/wechat/wechat-client.service.spec.ts +18 -0
  132. package/template/apps/api/libs/infra/clients/internal/wechat/wechat.client.ts +4 -0
  133. package/template/apps/api/libs/infra/clients/internal/wechat/wechat.module.ts +8 -0
  134. package/template/apps/api/libs/infra/clients/plugin/decorators/inject-client.decorator.ts +60 -0
  135. package/template/apps/api/libs/infra/clients/plugin/index.ts +21 -0
  136. package/template/apps/api/libs/infra/clients/plugin/interceptors/http-logging.interceptor.ts +130 -0
  137. package/template/apps/api/libs/infra/clients/plugin/interfaces/client.interface.ts +86 -0
  138. package/template/apps/api/libs/infra/clients/plugin/utils/retry.util.ts +157 -0
  139. package/template/apps/api/libs/infra/common/adapters/base.adapter.ts +94 -0
  140. package/template/apps/api/libs/infra/common/adapters/index.ts +38 -0
  141. package/template/apps/api/libs/infra/common/config/README.md +254 -0
  142. package/template/apps/api/libs/infra/common/config/agentx.config.ts +91 -0
  143. package/template/apps/api/libs/infra/common/config/configuration.ts +289 -0
  144. package/template/apps/api/libs/infra/common/config/constant/config.constants.ts +92 -0
  145. package/template/apps/api/libs/infra/common/config/dto/config.dto.ts +282 -0
  146. package/template/apps/api/libs/infra/common/config/package.json +11 -0
  147. package/template/apps/api/libs/infra/common/config/validation/env.validation.ts +161 -0
  148. package/template/apps/api/libs/infra/common/config/validation/index.ts +188 -0
  149. package/template/apps/api/libs/infra/common/config/validation/keys.validation.ts +564 -0
  150. package/template/apps/api/libs/infra/common/config/validation/yaml.validation.ts +582 -0
  151. package/template/apps/api/libs/infra/common/decorators/app-version/app-version.controller.ts +135 -0
  152. package/template/apps/api/libs/infra/common/decorators/app-version/app-version.interceptor.ts +36 -0
  153. package/template/apps/api/libs/infra/common/decorators/app-version/app-version.module.ts +27 -0
  154. package/template/apps/api/libs/infra/common/decorators/app-version/app-version.service.ts +252 -0
  155. package/template/apps/api/libs/infra/common/decorators/app-version/index.ts +13 -0
  156. package/template/apps/api/libs/infra/common/decorators/cache/cache.decorator.ts +437 -0
  157. package/template/apps/api/libs/infra/common/decorators/cache/cache.interceptor.ts +268 -0
  158. package/template/apps/api/libs/infra/common/decorators/cache/cache.module.ts +24 -0
  159. package/template/apps/api/libs/infra/common/decorators/cache/index.ts +33 -0
  160. package/template/apps/api/libs/infra/common/decorators/event/event.decorator.ts +229 -0
  161. package/template/apps/api/libs/infra/common/decorators/event/event.interceptor.ts +155 -0
  162. package/template/apps/api/libs/infra/common/decorators/event/event.module.ts +47 -0
  163. package/template/apps/api/libs/infra/common/decorators/event/handlers/cache-event.handler.ts +159 -0
  164. package/template/apps/api/libs/infra/common/decorators/event/index.ts +29 -0
  165. package/template/apps/api/libs/infra/common/decorators/feature-flag/feature-flag.decorator.ts +221 -0
  166. package/template/apps/api/libs/infra/common/decorators/feature-flag/feature-flag.interceptor.ts +150 -0
  167. package/template/apps/api/libs/infra/common/decorators/feature-flag/feature-flag.module.ts +27 -0
  168. package/template/apps/api/libs/infra/common/decorators/feature-flag/feature-flag.service.spec.ts +330 -0
  169. package/template/apps/api/libs/infra/common/decorators/feature-flag/feature-flag.service.ts +423 -0
  170. package/template/apps/api/libs/infra/common/decorators/feature-flag/index.ts +28 -0
  171. package/template/apps/api/libs/infra/common/decorators/rate-limit/dto/rate-limit.dto.ts +201 -0
  172. package/template/apps/api/libs/infra/common/decorators/rate-limit/index.ts +54 -0
  173. package/template/apps/api/libs/infra/common/decorators/rate-limit/rate-limit.decorator.ts +216 -0
  174. package/template/apps/api/libs/infra/common/decorators/rate-limit/rate-limit.exception.ts +74 -0
  175. package/template/apps/api/libs/infra/common/decorators/rate-limit/rate-limit.module.ts +37 -0
  176. package/template/apps/api/libs/infra/common/decorators/rate-limit/rate-limit.service.ts +430 -0
  177. package/template/apps/api/libs/infra/common/decorators/response.decorator.ts +67 -0
  178. package/template/apps/api/libs/infra/common/decorators/skip-version-check.decorator.ts +27 -0
  179. package/template/apps/api/libs/infra/common/decorators/transaction/index.ts +12 -0
  180. package/template/apps/api/libs/infra/common/decorators/transaction/transactional.decorator.ts +677 -0
  181. package/template/apps/api/libs/infra/common/decorators/ts-rest-controller.decorator.ts +63 -0
  182. package/template/apps/api/libs/infra/common/decorators/validation.decorator.ts +120 -0
  183. package/template/apps/api/libs/infra/common/decorators/version/index.ts +24 -0
  184. package/template/apps/api/libs/infra/common/decorators/version/version.decorator.ts +168 -0
  185. package/template/apps/api/libs/infra/common/decorators/version/version.interceptor.ts +97 -0
  186. package/template/apps/api/libs/infra/common/decorators/version/version.module.ts +21 -0
  187. package/template/apps/api/libs/infra/common/enums/action.enum.ts +7 -0
  188. package/template/apps/api/libs/infra/common/enums/error-codes.ts +71 -0
  189. package/template/apps/api/libs/infra/common/enums/role.enum.ts +4 -0
  190. package/template/apps/api/libs/infra/common/filter/exception/api.exception.ts +168 -0
  191. package/template/apps/api/libs/infra/common/filter/exception/exception.ts +47 -0
  192. package/template/apps/api/libs/infra/common/filter/exception/http.exception.ts +126 -0
  193. package/template/apps/api/libs/infra/common/guards/index.ts +1 -0
  194. package/template/apps/api/libs/infra/common/guards/version.guard.ts +312 -0
  195. package/template/apps/api/libs/infra/common/interceptor/mask/index.ts +1 -0
  196. package/template/apps/api/libs/infra/common/interceptor/mask/mask.interceptor.ts +242 -0
  197. package/template/apps/api/libs/infra/common/interceptor/rate-limit/no-rate-limit.interceptor.ts +14 -0
  198. package/template/apps/api/libs/infra/common/interceptor/rate-limit/rate-limit.interceptor.ts +230 -0
  199. package/template/apps/api/libs/infra/common/interceptor/transform/transform.interceptor.spec.ts +7 -0
  200. package/template/apps/api/libs/infra/common/interceptor/transform/transform.interceptor.ts +75 -0
  201. package/template/apps/api/libs/infra/common/interceptor/version/index.ts +1 -0
  202. package/template/apps/api/libs/infra/common/interceptor/version/version-header.interceptor.ts +62 -0
  203. package/template/apps/api/libs/infra/common/middleware/request.middleware.ts +109 -0
  204. package/template/apps/api/libs/infra/common/package.json +11 -0
  205. package/template/apps/api/libs/infra/common/pipes/transform-root.pipe.ts +12 -0
  206. package/template/apps/api/libs/infra/common/ts-rest/index.ts +26 -0
  207. package/template/apps/api/libs/infra/common/ts-rest/response.helper.ts +233 -0
  208. package/template/apps/api/libs/infra/i18n/en/errors.json +77 -0
  209. package/template/apps/api/libs/infra/i18n/en/events.json +1 -0
  210. package/template/apps/api/libs/infra/i18n/package.json +11 -0
  211. package/template/apps/api/libs/infra/i18n/zh-CN/errors.json +77 -0
  212. package/template/apps/api/libs/infra/i18n/zh-CN/events.json +1 -0
  213. package/template/apps/api/libs/infra/jwt/dto/jwt.dto.ts +1 -0
  214. package/template/apps/api/libs/infra/jwt/jwt.module.ts +26 -0
  215. package/template/apps/api/libs/infra/jwt/package.json +11 -0
  216. package/template/apps/api/libs/infra/prisma/db-metrics/package.json +11 -0
  217. package/template/apps/api/libs/infra/prisma/db-metrics/src/db-metrics.module.ts +141 -0
  218. package/template/apps/api/libs/infra/prisma/db-metrics/src/db-metrics.service.ts +456 -0
  219. package/template/apps/api/libs/infra/prisma/db-metrics/src/index.ts +2 -0
  220. package/template/apps/api/libs/infra/prisma/db-metrics/tsconfig.lib.json +9 -0
  221. package/template/apps/api/libs/infra/prisma/middleware/soft-delete.middleware.ts +179 -0
  222. package/template/apps/api/libs/infra/prisma/package.json +11 -0
  223. package/template/apps/api/libs/infra/prisma/prisma/index.ts +3 -0
  224. package/template/apps/api/libs/infra/prisma/prisma/prisma.module.ts +12 -0
  225. package/template/apps/api/libs/infra/prisma/prisma/prisma.service.ts +18 -0
  226. package/template/apps/api/libs/infra/prisma/prisma/types.ts +6 -0
  227. package/template/apps/api/libs/infra/prisma/prisma-read/prisma-read.module.ts +11 -0
  228. package/template/apps/api/libs/infra/prisma/prisma-read/prisma-read.service.ts +280 -0
  229. package/template/apps/api/libs/infra/prisma/prisma-write/prisma-write.module.ts +11 -0
  230. package/template/apps/api/libs/infra/prisma/prisma-write/prisma-write.service.ts +278 -0
  231. package/template/apps/api/libs/infra/prisma/prometheus/index.ts +1 -0
  232. package/template/apps/api/libs/infra/prisma/prometheus/prometheus.module.ts +231 -0
  233. package/template/apps/api/libs/infra/rabbitmq/package.json +11 -0
  234. package/template/apps/api/libs/infra/rabbitmq/src/dto/rabbitmq.dto.ts +13 -0
  235. package/template/apps/api/libs/infra/rabbitmq/src/index.ts +5 -0
  236. package/template/apps/api/libs/infra/rabbitmq/src/rabbitmq-events.module.ts +132 -0
  237. package/template/apps/api/libs/infra/rabbitmq/src/rabbitmq-events.service.ts +199 -0
  238. package/template/apps/api/libs/infra/rabbitmq/src/rabbitmq.module.ts +101 -0
  239. package/template/apps/api/libs/infra/rabbitmq/src/rabbitmq.service.spec.ts +18 -0
  240. package/template/apps/api/libs/infra/rabbitmq/src/rabbitmq.service.ts +543 -0
  241. package/template/apps/api/libs/infra/rabbitmq/tsconfig.lib.json +9 -0
  242. package/template/apps/api/libs/infra/redis/dto/redis.dto.ts +3 -0
  243. package/template/apps/api/libs/infra/redis/package.json +11 -0
  244. package/template/apps/api/libs/infra/redis/src/index.ts +2 -0
  245. package/template/apps/api/libs/infra/redis/src/redis.module.ts +63 -0
  246. package/template/apps/api/libs/infra/redis/src/redis.service.spec.ts +18 -0
  247. package/template/apps/api/libs/infra/redis/src/redis.service.ts +730 -0
  248. package/template/apps/api/libs/infra/redis/tsconfig.lib.json +9 -0
  249. package/template/apps/api/libs/infra/shared-db/index.ts +14 -0
  250. package/template/apps/api/libs/infra/shared-db/transaction-context.ts +51 -0
  251. package/template/apps/api/libs/infra/shared-db/transaction.module.ts +15 -0
  252. package/template/apps/api/libs/infra/shared-db/transaction.perf.spec.ts +226 -0
  253. package/template/apps/api/libs/infra/shared-db/transactional-service.base.ts +102 -0
  254. package/template/apps/api/libs/infra/shared-db/unit-of-work.service.ts +142 -0
  255. package/template/apps/api/libs/infra/shared-services/email/dto/email.dto.ts +87 -0
  256. package/template/apps/api/libs/infra/shared-services/email/email.module.ts +27 -0
  257. package/template/apps/api/libs/infra/shared-services/email/email.service.ts +258 -0
  258. package/template/apps/api/libs/infra/shared-services/email/index.ts +5 -0
  259. package/template/apps/api/libs/infra/shared-services/file-storage/README.md +376 -0
  260. package/template/apps/api/libs/infra/shared-services/file-storage/bucket-resolver.ts +306 -0
  261. package/template/apps/api/libs/infra/shared-services/file-storage/file-storage.factory.ts +347 -0
  262. package/template/apps/api/libs/infra/shared-services/file-storage/file-storage.module.ts +62 -0
  263. package/template/apps/api/libs/infra/shared-services/file-storage/file-storage.service.ts +849 -0
  264. package/template/apps/api/libs/infra/shared-services/file-storage/index.ts +57 -0
  265. package/template/apps/api/libs/infra/shared-services/file-storage/types.ts +210 -0
  266. package/template/apps/api/libs/infra/shared-services/ip-info/index.ts +2 -0
  267. package/template/apps/api/libs/infra/shared-services/ip-info/ip-info.module.ts +18 -0
  268. package/template/apps/api/libs/infra/shared-services/ip-info/ip-info.service.ts +118 -0
  269. package/template/apps/api/libs/infra/shared-services/sms/index.ts +11 -0
  270. package/template/apps/api/libs/infra/shared-services/sms/sms.factory.ts +367 -0
  271. package/template/apps/api/libs/infra/shared-services/sms/sms.module.ts +27 -0
  272. package/template/apps/api/libs/infra/shared-services/sms/sms.service.ts +315 -0
  273. package/template/apps/api/libs/infra/shared-services/sms/types.ts +297 -0
  274. package/template/apps/api/libs/infra/shared-services/streaming-asr/index.ts +50 -0
  275. package/template/apps/api/libs/infra/shared-services/streaming-asr/streaming-asr.module.ts +47 -0
  276. package/template/apps/api/libs/infra/shared-services/streaming-asr/streaming-asr.service.ts +1336 -0
  277. package/template/apps/api/libs/infra/shared-services/streaming-asr/types.ts +208 -0
  278. package/template/apps/api/libs/infra/shared-services/system-health/index.ts +3 -0
  279. package/template/apps/api/libs/infra/shared-services/system-health/system-health.controller.ts +61 -0
  280. package/template/apps/api/libs/infra/shared-services/system-health/system-health.module.ts +16 -0
  281. package/template/apps/api/libs/infra/shared-services/system-health/system-health.service.ts +69 -0
  282. package/template/apps/api/libs/infra/shared-services/uploader/index.ts +2 -0
  283. package/template/apps/api/libs/infra/shared-services/uploader/uploader.module.ts +11 -0
  284. package/template/apps/api/libs/infra/shared-services/uploader/uploader.service.ts +265 -0
  285. package/template/apps/api/libs/infra/utils/array-buffer.util.ts +8 -0
  286. package/template/apps/api/libs/infra/utils/array.util.ts +3 -0
  287. package/template/apps/api/libs/infra/utils/bcrypt.util.ts +3 -0
  288. package/template/apps/api/libs/infra/utils/bigint.util.ts +3 -0
  289. package/template/apps/api/libs/infra/utils/bytes.convert.util.ts +13 -0
  290. package/template/apps/api/libs/infra/utils/crypto.util.ts +206 -0
  291. package/template/apps/api/libs/infra/utils/download.ts +21 -0
  292. package/template/apps/api/libs/infra/utils/enviroment.util.ts +130 -0
  293. package/template/apps/api/libs/infra/utils/ffmpeg.util.ts +29 -0
  294. package/template/apps/api/libs/infra/utils/file.util.ts +448 -0
  295. package/template/apps/api/libs/infra/utils/folder.util.ts +11 -0
  296. package/template/apps/api/libs/infra/utils/frame.util.ts +24 -0
  297. package/template/apps/api/libs/infra/utils/http-client.ts +133 -0
  298. package/template/apps/api/libs/infra/utils/ip.util.ts +22 -0
  299. package/template/apps/api/libs/infra/utils/json.util.ts +3 -0
  300. package/template/apps/api/libs/infra/utils/load-env.util.ts +53 -0
  301. package/template/apps/api/libs/infra/utils/logger.util.ts +121 -0
  302. package/template/apps/api/libs/infra/utils/object.util.ts +3 -0
  303. package/template/apps/api/libs/infra/utils/package.json +11 -0
  304. package/template/apps/api/libs/infra/utils/prisma-error.util.ts +397 -0
  305. package/template/apps/api/libs/infra/utils/response.ts +23 -0
  306. package/template/apps/api/libs/infra/utils/serialize.util.ts +3 -0
  307. package/template/apps/api/libs/infra/utils/string.util.ts +3 -0
  308. package/template/apps/api/libs/infra/utils/timer.util.ts +3 -0
  309. package/template/apps/api/libs/infra/utils/urlencode.util.ts +3 -0
  310. package/template/apps/api/libs/infra/utils/validate.util.ts +3 -0
  311. package/template/apps/api/nest-cli.json +25 -0
  312. package/template/apps/api/package.json +174 -0
  313. package/template/apps/api/prisma/schema.prisma +352 -0
  314. package/template/apps/api/prisma/seed.ts +30 -0
  315. package/template/apps/api/scripts/generate-db-crud.js +344 -0
  316. package/template/apps/api/scripts/insert-country-codes.ts +325 -0
  317. package/template/apps/api/scripts/link-prisma.js +44 -0
  318. package/template/apps/api/scripts/validate-api-versions.ts +273 -0
  319. package/template/apps/api/src/app.module.ts +208 -0
  320. package/template/apps/api/src/main.ts +298 -0
  321. package/template/apps/api/src/modules/health/health.controller.ts +13 -0
  322. package/template/apps/api/src/modules/health/health.module.ts +7 -0
  323. package/template/apps/api/tsconfig.build.json +4 -0
  324. package/template/apps/api/tsconfig.json +123 -0
  325. package/template/apps/web/.env.example +5 -0
  326. package/template/apps/web/app/globals.css +27 -0
  327. package/template/apps/web/app/layout.tsx +19 -0
  328. package/template/apps/web/app/page.tsx +42 -0
  329. package/template/apps/web/hooks/useAspectRatioSize.ts +187 -0
  330. package/template/apps/web/hooks/useDebouncedValue.ts +25 -0
  331. package/template/apps/web/hooks/useErrorHandler.ts +113 -0
  332. package/template/apps/web/hooks/useHotkeys.ts +251 -0
  333. package/template/apps/web/hooks/useI18nToast.ts +240 -0
  334. package/template/apps/web/hooks/useI18nValidation.ts +262 -0
  335. package/template/apps/web/hooks/useNotificationSSE.ts +270 -0
  336. package/template/apps/web/hooks/useOperationFeedback.ts +108 -0
  337. package/template/apps/web/hooks/usePerformanceMonitor.ts +105 -0
  338. package/template/apps/web/hooks/usePermissions.ts +17 -0
  339. package/template/apps/web/hooks/useTask.ts +489 -0
  340. package/template/apps/web/hooks/useVersionCheck.ts +329 -0
  341. package/template/apps/web/i18n/config.ts +50 -0
  342. package/template/apps/web/i18n/index.ts +30 -0
  343. package/template/apps/web/i18n/navigation.ts +26 -0
  344. package/template/apps/web/i18n/request.ts +50 -0
  345. package/template/apps/web/i18n/routing.ts +21 -0
  346. package/template/apps/web/i18n/types.ts +57 -0
  347. package/template/apps/web/lib/actions/auth.ts +81 -0
  348. package/template/apps/web/lib/actions/chat.ts +129 -0
  349. package/template/apps/web/lib/actions/common.ts +13 -0
  350. package/template/apps/web/lib/actions/task.ts +20 -0
  351. package/template/apps/web/lib/agent/chat-client.ts +42 -0
  352. package/template/apps/web/lib/agent/prompts.ts +43 -0
  353. package/template/apps/web/lib/analytics/components/PageTracker.tsx +137 -0
  354. package/template/apps/web/lib/analytics/hooks/usePageTracking.ts +137 -0
  355. package/template/apps/web/lib/analytics/index.ts +180 -0
  356. package/template/apps/web/lib/api/agents.ts +7 -0
  357. package/template/apps/web/lib/api/agno-chat.ts +263 -0
  358. package/template/apps/web/lib/api/auth-server.ts +244 -0
  359. package/template/apps/web/lib/api/avatar-upload.ts +96 -0
  360. package/template/apps/web/lib/api/cache-config.ts +236 -0
  361. package/template/apps/web/lib/api/client.ts +649 -0
  362. package/template/apps/web/lib/api/contracts/client.ts +336 -0
  363. package/template/apps/web/lib/api/contracts/hooks/index.ts +25 -0
  364. package/template/apps/web/lib/api/contracts/hooks/notification.ts +180 -0
  365. package/template/apps/web/lib/api/contracts/hooks/setting.ts +33 -0
  366. package/template/apps/web/lib/api/contracts/index.ts +18 -0
  367. package/template/apps/web/lib/api/contracts/server-client.ts +145 -0
  368. package/template/apps/web/lib/api/hooks/use-python-task.ts +154 -0
  369. package/template/apps/web/lib/api/queries/analytics.ts +51 -0
  370. package/template/apps/web/lib/api/queries/message.ts +75 -0
  371. package/template/apps/web/lib/api.ts +179 -0
  372. package/template/apps/web/lib/aspect-ratio.ts +10 -0
  373. package/template/apps/web/lib/audio-buffer-queue.ts +273 -0
  374. package/template/apps/web/lib/config.ts +163 -0
  375. package/template/apps/web/lib/data/industry.json +369 -0
  376. package/template/apps/web/lib/data/region.json +501 -0
  377. package/template/apps/web/lib/errors/error-handler.ts +194 -0
  378. package/template/apps/web/lib/errors/index.ts +16 -0
  379. package/template/apps/web/lib/errors/streaming-asr-errors.ts +434 -0
  380. package/template/apps/web/lib/form/index.ts +23 -0
  381. package/template/apps/web/lib/form/use-form.ts +143 -0
  382. package/template/apps/web/lib/icons-usage.md +99 -0
  383. package/template/apps/web/lib/icons.tsx +395 -0
  384. package/template/apps/web/lib/performance/monitor.ts +225 -0
  385. package/template/apps/web/lib/requests.ts +177 -0
  386. package/template/apps/web/lib/storage/index.ts +158 -0
  387. package/template/apps/web/lib/upload/api.ts +260 -0
  388. package/template/apps/web/lib/upload/batch-uploader.ts +286 -0
  389. package/template/apps/web/lib/upload/errors.ts +44 -0
  390. package/template/apps/web/lib/upload/folder-utils.ts +295 -0
  391. package/template/apps/web/lib/upload/uploader.ts +439 -0
  392. package/template/apps/web/lib/utils/reconnect.ts +223 -0
  393. package/template/apps/web/lib/utils/transcript-export.ts +321 -0
  394. package/template/apps/web/lib/version-mismatch.ts +147 -0
  395. package/template/apps/web/lib/version.ts +60 -0
  396. package/template/apps/web/next-env.d.ts +6 -0
  397. package/template/apps/web/next.config.ts +97 -0
  398. package/template/apps/web/package.json +89 -0
  399. package/template/apps/web/providers/app-provider.tsx +45 -0
  400. package/template/apps/web/providers/index.tsx +45 -0
  401. package/template/apps/web/providers/query-provider.tsx +181 -0
  402. package/template/apps/web/providers/theme-provider.tsx +26 -0
  403. package/template/apps/web/tsconfig.json +30 -0
  404. package/template/package.json +91 -0
  405. package/template/packages/config/eslint/base.js +32 -0
  406. package/template/packages/config/eslint/next.js +134 -0
  407. package/template/packages/config/eslint/react-internal.js +41 -0
  408. package/template/packages/config/eslint.config.mjs +26 -0
  409. package/template/packages/config/eslint.nestjs.config.mjs +62 -0
  410. package/template/packages/config/index.ts +2 -0
  411. package/template/packages/config/package.json +44 -0
  412. package/template/packages/config/postcss.config.mjs +8 -0
  413. package/template/packages/config/prettier.config.mjs +14 -0
  414. package/template/packages/config/tsconfig.json +19 -0
  415. package/template/packages/config/typescript/base.json +20 -0
  416. package/template/packages/config/typescript/nextjs.json +12 -0
  417. package/template/packages/config/typescript/react-library.json +8 -0
  418. package/template/packages/constants/README.md +111 -0
  419. package/template/packages/constants/package.json +25 -0
  420. package/template/packages/constants/src/index.ts +243 -0
  421. package/template/packages/constants/tsconfig.build.json +13 -0
  422. package/template/packages/constants/tsconfig.json +12 -0
  423. package/template/packages/contracts/ERROR-MIGRATION.md +179 -0
  424. package/template/packages/contracts/README.md +203 -0
  425. package/template/packages/contracts/jest.config.js +11 -0
  426. package/template/packages/contracts/package.json +60 -0
  427. package/template/packages/contracts/src/api/analytics.contract.ts +45 -0
  428. package/template/packages/contracts/src/api/download.contract.ts +66 -0
  429. package/template/packages/contracts/src/api/index.ts +12 -0
  430. package/template/packages/contracts/src/api/message.contract.ts +70 -0
  431. package/template/packages/contracts/src/api/risk-words.contract.ts +44 -0
  432. package/template/packages/contracts/src/api/setting.contract.ts +127 -0
  433. package/template/packages/contracts/src/api/sign.contract.ts +269 -0
  434. package/template/packages/contracts/src/api/sms.contract.ts +95 -0
  435. package/template/packages/contracts/src/api/system.contract.ts +52 -0
  436. package/template/packages/contracts/src/api/task.contract.ts +58 -0
  437. package/template/packages/contracts/src/api/uploader.contract.ts +93 -0
  438. package/template/packages/contracts/src/api/user.contract.ts +60 -0
  439. package/template/packages/contracts/src/api/webhook.contract.ts +73 -0
  440. package/template/packages/contracts/src/base.ts +319 -0
  441. package/template/packages/contracts/src/errors/codes.ts +55 -0
  442. package/template/packages/contracts/src/errors/domains/common.errors.ts +212 -0
  443. package/template/packages/contracts/src/errors/domains/index.ts +7 -0
  444. package/template/packages/contracts/src/errors/domains/user.errors.ts +51 -0
  445. package/template/packages/contracts/src/errors/error-response.ts +145 -0
  446. package/template/packages/contracts/src/errors/index.ts +16 -0
  447. package/template/packages/contracts/src/errors/messages.ts +240 -0
  448. package/template/packages/contracts/src/index.ts +16 -0
  449. package/template/packages/contracts/src/schemas/analytics.schema.ts +81 -0
  450. package/template/packages/contracts/src/schemas/download.schema.ts +59 -0
  451. package/template/packages/contracts/src/schemas/index.ts +18 -0
  452. package/template/packages/contracts/src/schemas/message.schema.ts +83 -0
  453. package/template/packages/contracts/src/schemas/risk-words.schema.ts +25 -0
  454. package/template/packages/contracts/src/schemas/setting.schema.ts +84 -0
  455. package/template/packages/contracts/src/schemas/sign.schema.ts +171 -0
  456. package/template/packages/contracts/src/schemas/sms.schema.ts +53 -0
  457. package/template/packages/contracts/src/schemas/sse.schema.ts +30 -0
  458. package/template/packages/contracts/src/schemas/system.schema.ts +26 -0
  459. package/template/packages/contracts/src/schemas/tag.schema.ts +65 -0
  460. package/template/packages/contracts/src/schemas/task.schema.ts +47 -0
  461. package/template/packages/contracts/src/schemas/uploader.schema.ts +121 -0
  462. package/template/packages/contracts/src/schemas/user.schema.ts +75 -0
  463. package/template/packages/contracts/src/schemas/webhook.schema.ts +72 -0
  464. package/template/packages/contracts/tsconfig.build.json +20 -0
  465. package/template/packages/contracts/tsconfig.json +12 -0
  466. package/template/packages/types/README.md +143 -0
  467. package/template/packages/types/ai.ts +30 -0
  468. package/template/packages/types/auth.ts +99 -0
  469. package/template/packages/types/common.ts +13 -0
  470. package/template/packages/types/creative.ts +68 -0
  471. package/template/packages/types/image-factory.ts +122 -0
  472. package/template/packages/types/index.ts +8 -0
  473. package/template/packages/types/package.json +21 -0
  474. package/template/packages/types/task.ts +27 -0
  475. package/template/packages/types/tsconfig.json +11 -0
  476. package/template/packages/ui/README.md +30 -0
  477. package/template/packages/ui/components.json +22 -0
  478. package/template/packages/ui/eslint.config.js +4 -0
  479. package/template/packages/ui/package.json +58 -0
  480. package/template/packages/ui/postcss.config.mjs +6 -0
  481. package/template/packages/ui/src/components/accordion.tsx +66 -0
  482. package/template/packages/ui/src/components/alert.tsx +61 -0
  483. package/template/packages/ui/src/components/avatar.tsx +57 -0
  484. package/template/packages/ui/src/components/badge.tsx +38 -0
  485. package/template/packages/ui/src/components/button.tsx +60 -0
  486. package/template/packages/ui/src/components/calendar.tsx +71 -0
  487. package/template/packages/ui/src/components/card.tsx +92 -0
  488. package/template/packages/ui/src/components/carousel.tsx +241 -0
  489. package/template/packages/ui/src/components/checkbox.tsx +32 -0
  490. package/template/packages/ui/src/components/command.tsx +184 -0
  491. package/template/packages/ui/src/components/dialog.tsx +134 -0
  492. package/template/packages/ui/src/components/dropdown-menu.tsx +257 -0
  493. package/template/packages/ui/src/components/empty.tsx +104 -0
  494. package/template/packages/ui/src/components/field.tsx +248 -0
  495. package/template/packages/ui/src/components/form.tsx +172 -0
  496. package/template/packages/ui/src/components/input-group.tsx +170 -0
  497. package/template/packages/ui/src/components/input.tsx +21 -0
  498. package/template/packages/ui/src/components/item.tsx +193 -0
  499. package/template/packages/ui/src/components/label.tsx +24 -0
  500. package/template/packages/ui/src/components/password-strength.tsx +248 -0
  501. package/template/packages/ui/src/components/popover.tsx +48 -0
  502. package/template/packages/ui/src/components/progress.tsx +35 -0
  503. package/template/packages/ui/src/components/scroll-area.tsx +48 -0
  504. package/template/packages/ui/src/components/select.tsx +190 -0
  505. package/template/packages/ui/src/components/separator.tsx +28 -0
  506. package/template/packages/ui/src/components/sheet.tsx +139 -0
  507. package/template/packages/ui/src/components/sidebar.tsx +729 -0
  508. package/template/packages/ui/src/components/skeleton.tsx +13 -0
  509. package/template/packages/ui/src/components/slider.tsx +87 -0
  510. package/template/packages/ui/src/components/sonner.tsx +40 -0
  511. package/template/packages/ui/src/components/switch.tsx +31 -0
  512. package/template/packages/ui/src/components/tabs.tsx +66 -0
  513. package/template/packages/ui/src/components/textarea.tsx +18 -0
  514. package/template/packages/ui/src/components/tooltip.tsx +61 -0
  515. package/template/packages/ui/src/hooks/use-mobile.ts +21 -0
  516. package/template/packages/ui/src/index.ts +38 -0
  517. package/template/packages/ui/src/lib/utils.ts +6 -0
  518. package/template/packages/ui/src/styles/globals.css +134 -0
  519. package/template/packages/ui/tsconfig.json +11 -0
  520. package/template/packages/ui/tsconfig.lint.json +8 -0
  521. package/template/packages/utils/README.md +173 -0
  522. package/template/packages/utils/array.util.ts +335 -0
  523. package/template/packages/utils/bcrypt.util.ts +10 -0
  524. package/template/packages/utils/bigint.util.ts +111 -0
  525. package/template/packages/utils/cn.ts +6 -0
  526. package/template/packages/utils/encrypt.ts +104 -0
  527. package/template/packages/utils/fetch.ts +170 -0
  528. package/template/packages/utils/file.ts +275 -0
  529. package/template/packages/utils/headers.ts +116 -0
  530. package/template/packages/utils/index.ts +22 -0
  531. package/template/packages/utils/jest.config.js +28 -0
  532. package/template/packages/utils/json.util.ts +9 -0
  533. package/template/packages/utils/mask.util.ts +348 -0
  534. package/template/packages/utils/object.util.ts +149 -0
  535. package/template/packages/utils/package.json +112 -0
  536. package/template/packages/utils/serialize.util.ts +17 -0
  537. package/template/packages/utils/string.util.ts +159 -0
  538. package/template/packages/utils/timer.util.ts +210 -0
  539. package/template/packages/utils/tsconfig.build.json +17 -0
  540. package/template/packages/utils/tsconfig.json +13 -0
  541. package/template/packages/utils/urlencode.util.ts +18 -0
  542. package/template/packages/utils/validate.util.ts +25 -0
  543. package/template/packages/validators/README.md +149 -0
  544. package/template/packages/validators/jest.config.js +20 -0
  545. package/template/packages/validators/package.json +32 -0
  546. package/template/packages/validators/src/index.ts +178 -0
  547. package/template/packages/validators/tsconfig.build.json +19 -0
  548. package/template/packages/validators/tsconfig.json +12 -0
  549. package/template/pnpm-lock.yaml +21574 -0
  550. package/template/pnpm-workspace.yaml +4 -0
  551. package/template/scripts/generate-i18n-errors.ts +371 -0
  552. package/template/scripts/generate-prisma-enums.js +170 -0
  553. package/template/scripts/generate-prisma-enums.ts +172 -0
  554. package/template/scripts/init-project.js +232 -0
  555. package/template/turbo.json +55 -0
@@ -0,0 +1,767 @@
1
+ import {
2
+ Injectable,
3
+ OnModuleInit,
4
+ OnModuleDestroy,
5
+ Inject,
6
+ } from '@nestjs/common';
7
+ import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
8
+ import { Logger } from 'winston';
9
+ import { HttpService } from '@nestjs/axios';
10
+
11
+ import {
12
+ PardxUploader,
13
+ GetObjectOptions,
14
+ PresignedPutUrlObject,
15
+ PutObjectOptions,
16
+ } from './dto/file.dto';
17
+
18
+ import { PardxApp } from '@/config/dto/config.dto';
19
+ import { StorageCredentialsConfig, AppConfig } from '@/config/validation';
20
+ import { FileS3Client } from './file-s3.client';
21
+ import { RedisService } from '@app/redis';
22
+ import { TosClient } from '@volcengine/tos-sdk';
23
+ import enviromentUtil from '@/utils/enviroment.util';
24
+ import { TRANSCODE_CONSTANTS } from '@/config/constant/config.constants';
25
+ import enviroment from '@/utils/enviroment.util';
26
+
27
+ /**
28
+ * Volcengine TOS (Tinder Object Storage) Client
29
+ *
30
+ * 职责:仅负责与火山引擎 TOS API 通信
31
+ * - 不访问数据库
32
+ * - 不包含业务逻辑
33
+ */
34
+ export class FileTosClient extends FileS3Client {
35
+ protected urlRedisKey = 'privateDownloadUrl';
36
+ private tosClient: TosClient;
37
+ private tosInternalClient: TosClient;
38
+
39
+ constructor(
40
+ config: PardxUploader.Config,
41
+ storageConfig: StorageCredentialsConfig,
42
+ appConfig: AppConfig,
43
+ redis: RedisService,
44
+ httpService: HttpService,
45
+ logger: Logger,
46
+ ) {
47
+ super(config, storageConfig, appConfig, redis, httpService, logger);
48
+ this.setTosClient();
49
+ }
50
+
51
+ /**
52
+ * 初始化火山引擎 TOS 客户端
53
+ * 参考:https://www.volcengine.com/docs/6349/113484?lang=zh
54
+ */
55
+ setTosClient() {
56
+ try {
57
+ // 从 endpoint 中提取域名(去掉协议前缀)
58
+ const extractEndpoint = (endpoint: string): string => {
59
+ if (!endpoint) return '';
60
+ return endpoint.replace(/^https?:\/\//, '').replace(/\/$/, '');
61
+ };
62
+
63
+ // 创建外部 TOS 客户端
64
+ this.tosClient = new TosClient({
65
+ accessKeyId: this.storageConfig.accessKey,
66
+ accessKeySecret: this.storageConfig.secretKey,
67
+ region: this.config.region,
68
+ endpoint: extractEndpoint(this.config.tosEndpoint || ''),
69
+ });
70
+ // 创建内部 TOS 客户端(如果配置了内部端点)
71
+ if (enviromentUtil.isProduction()) {
72
+ this.tosInternalClient = new TosClient({
73
+ accessKeyId: this.storageConfig.accessKey,
74
+ accessKeySecret: this.storageConfig.secretKey,
75
+ region: this.config.region,
76
+ endpoint: extractEndpoint(this.config.tosInternalEndpoint),
77
+ });
78
+
79
+ this.logger.info('TOS clients initialized with internal endpoint', {
80
+ externalEndpoint: this.config.tosEndpoint,
81
+ internalEndpoint: this.config.tosInternalEndpoint,
82
+ bucket: this.config.bucket,
83
+ region: this.config.region,
84
+ });
85
+ } else {
86
+ this.tosInternalClient = this.tosClient;
87
+
88
+ if (enviroment.isProduction()) {
89
+ this.logger.info('TOS client initialized (single endpoint)', {
90
+ endpoint: this.config.tosEndpoint,
91
+ bucket: this.config.bucket,
92
+ region: this.config.region,
93
+ });
94
+ }
95
+ }
96
+ } catch (error) {
97
+ this.logger.error('Failed to initialize TOS clients', {
98
+ error: error.message,
99
+ config: {
100
+ bucket: this.config.bucket,
101
+ region: this.config.region,
102
+ endpoint: this.config.tosEndpoint,
103
+ },
104
+ });
105
+ throw error;
106
+ }
107
+ }
108
+
109
+ /**
110
+ * 保持与父类的兼容性,同时初始化 S3 客户端(用于其他操作)
111
+ */
112
+ setClient() {
113
+ // 调用父类方法初始化 S3 客户端(用于兼容其他操作)
114
+ super.setClient();
115
+ // 同时初始化 TOS 客户端(用于预签名 URL)
116
+ this.setTosClient();
117
+ }
118
+
119
+ /**
120
+ * 获取视频信息,并组合成 VideoInfo 结构
121
+ *
122
+ * @param fileKey 视频文件键名
123
+ * @param internal 是否使用内部客户端,默认为false
124
+ * @param bucket 存储桶名称(可选),如果未提供则使用配置中的默认存储桶
125
+ * @returns 返回组合后的 VideoInfo 对象
126
+ */
127
+ async getVideoInfo(
128
+ fileKey: string,
129
+ internal: boolean = false,
130
+ bucket?: string,
131
+ ): Promise<any> {
132
+ const finalBucket = bucket || this.getBucketString();
133
+ const tosClient = internal ? this.tosInternalClient : this.tosClient;
134
+
135
+ try {
136
+ this.logger.info('Getting video info', {
137
+ fileKey,
138
+ bucket: finalBucket,
139
+ internal,
140
+ });
141
+
142
+ // 使用 TOS SDK 的 getObjectV2 方法获取视频信息
143
+ const result = await tosClient.getObjectV2({
144
+ bucket: finalBucket,
145
+ key: fileKey,
146
+ process: 'video/info',
147
+ dataType: 'buffer',
148
+ });
149
+
150
+ if (result.data && result.data.content) {
151
+ const videoInfoJson = result.data.content.toString();
152
+ let ffprobeInfo: any;
153
+ try {
154
+ ffprobeInfo = JSON.parse(videoInfoJson);
155
+ } catch (parseError) {
156
+ this.logger.warn('Failed to parse video info as JSON', {
157
+ fileKey,
158
+ content: videoInfoJson,
159
+ });
160
+ throw new Error('Failed to parse video info as JSON');
161
+ }
162
+
163
+ this.logger.info('Video info retrieved successfully', {
164
+ fileKey,
165
+ bucket: finalBucket,
166
+ requestId: result.requestId,
167
+ });
168
+
169
+ // 组合成 VideoInfo 结构
170
+ // VideoInfo @ prisma/schema.prisma:
171
+ // id, duration, streamDuration, height, width, sar, dar, rFrameRate, ffmpegInfo, spriteCount, ...
172
+ // 按 IMM、ffmpeg标准推算
173
+ const format = ffprobeInfo.format || {};
174
+ const streams = ffprobeInfo.streams || [];
175
+ const videoStream = streams.find((s: any) => s.codec_type === 'video');
176
+ // 若有多个视频流,默认取第一个
177
+ const audioStream = streams.find((s: any) => s.codec_type === 'audio');
178
+
179
+ const duration = ffprobeInfo.duration
180
+ ? parseFloat(ffprobeInfo.duration)
181
+ : format.duration
182
+ ? parseFloat(format.duration)
183
+ : videoStream && videoStream.duration
184
+ ? parseFloat(videoStream.duration)
185
+ : 0;
186
+ const streamDuration = ffprobeInfo.duration
187
+ ? parseFloat(ffprobeInfo.duration)
188
+ : videoStream && videoStream.duration
189
+ ? parseFloat(videoStream.duration)
190
+ : duration;
191
+
192
+ const width = videoStream?.width ?? null;
193
+ const height = videoStream?.height ?? null;
194
+ const sar = videoStream?.sample_aspect_ratio ?? '1:1';
195
+ const dar =
196
+ videoStream?.display_aspect_ratio ?? videoStream?.dar ?? null;
197
+ const rFrameRate = videoStream?.r_frame_rate ?? null;
198
+
199
+ // 返回 VideoInfo 主体和原始 ffmpeg info
200
+ // 这些字段与 schema 里 VideoInfo 字段保持同步
201
+ const videoInfo = {
202
+ duration: duration || 0,
203
+ streamDuration: streamDuration || 0,
204
+ height: width != null && height != null ? height : null,
205
+ width: width != null && height != null ? width : null,
206
+ sar,
207
+ dar,
208
+ rFrameRate,
209
+ ffmpegInfo: ffprobeInfo,
210
+ audioDuration: audioStream?.duration
211
+ ? parseFloat(audioStream.duration)
212
+ : 0,
213
+ // 其它结构字段,需用到可补充
214
+ // id, fileKeyId, ... 由上层数据库生成
215
+ };
216
+
217
+ return videoInfo;
218
+ } else {
219
+ throw new Error('Failed to get video info: missing data in response');
220
+ }
221
+ } catch (error) {
222
+ this.logger.error('Failed to get video info', {
223
+ fileKey,
224
+ bucket: finalBucket,
225
+ error: error.message,
226
+ stack: error.stack,
227
+ internal,
228
+ });
229
+ throw error;
230
+ }
231
+ }
232
+
233
+ /**
234
+ * 获取图片信息
235
+ * 参考:https://www.volcengine.com/docs/6349/1179568?lang=zh
236
+ *
237
+ * 使用 TOS SDK 的图片信息获取功能,返回图片的基本信息(格式、宽度、高度、大小等)
238
+ * 如果图片包含 Exif 信息,将按照 JSON 格式返回内容
239
+ *
240
+ * @param fileKey 图片文件键名
241
+ * @param internal 是否使用内部客户端,默认为false
242
+ * @param bucket 存储桶名称(可选),如果未提供则使用配置中的默认存储桶
243
+ * @returns 返回图片信息的 JSON 字符串
244
+ */
245
+ async getImageInfo(
246
+ fileKey: string,
247
+ internal: boolean = false,
248
+ bucket?: string,
249
+ ): Promise<any> {
250
+ const finalBucket = bucket || this.getBucketString();
251
+ const tosClient = internal ? this.tosInternalClient : this.tosClient;
252
+
253
+ try {
254
+ this.logger.info('Getting image info', {
255
+ fileKey,
256
+ bucket: finalBucket,
257
+ internal,
258
+ });
259
+
260
+ // 使用 TOS SDK 的 getObjectV2 方法获取图片信息
261
+ // process 参数:image/info 表示获取图片信息
262
+ // 参考文档:https://www.volcengine.com/docs/6349/1179568?lang=zh
263
+ const result = await tosClient.getObjectV2({
264
+ bucket: finalBucket,
265
+ key: fileKey,
266
+ process: 'image/info', // 图片信息处理参数
267
+ dataType: 'buffer', // 返回 buffer 类型数据
268
+ });
269
+
270
+ // 解析返回的图片信息
271
+ if (result.data && result.data.content) {
272
+ const imageInfoJson = result.data.content.toString();
273
+
274
+ // 尝试解析 JSON 以验证格式
275
+ try {
276
+ const rawImageInfo: any = JSON.parse(imageInfoJson);
277
+
278
+ // 提取宽高值(TOS 返回的是字符串格式)
279
+ const widthStr = rawImageInfo.ImageWidth?.value;
280
+ const heightStr = rawImageInfo.ImageHeight?.value;
281
+
282
+ // 转换为数字
283
+ const width = widthStr ? parseInt(widthStr, 10) : undefined;
284
+ const height = heightStr ? parseInt(heightStr, 10) : undefined;
285
+
286
+ // 计算宽高比(SAR 和 DAR)
287
+ // SAR (Sample Aspect Ratio): 像素宽高比,默认 1:1
288
+ // DAR (Display Aspect Ratio): 显示宽高比,默认与 SAR 相同
289
+ let sar: string = '1:1'; // 默认值
290
+ let dar: string | undefined = undefined;
291
+
292
+ if (width && height) {
293
+ // 计算最大公约数以简化比例
294
+ const gcd = (a: number, b: number): number => {
295
+ return b === 0 ? a : gcd(b, a % b);
296
+ };
297
+ const divisor = gcd(width, height);
298
+ sar = `${width / divisor}:${height / divisor}`;
299
+ dar = sar; // 默认 DAR 与 SAR 相同
300
+ }
301
+
302
+ // 重组为 ImageInfo 格式
303
+ const imageInfo: Partial<{
304
+ width: number;
305
+ height: number;
306
+ sar: string;
307
+ dar: string | undefined;
308
+ ffmpegInfo: any;
309
+ }> = {
310
+ width,
311
+ height,
312
+ sar,
313
+ dar,
314
+ ffmpegInfo: rawImageInfo, // 保存完整的原始数据
315
+ };
316
+
317
+ this.logger.info('Image info retrieved successfully', {
318
+ fileKey,
319
+ bucket: finalBucket,
320
+ requestId: result.requestId,
321
+ format: rawImageInfo.Format?.value,
322
+ width: imageInfo.width,
323
+ height: imageInfo.height,
324
+ sar: imageInfo.sar,
325
+ dar: imageInfo.dar,
326
+ fileSize: rawImageInfo.FileSize?.value,
327
+ });
328
+
329
+ return imageInfo;
330
+ } catch (parseError) {
331
+ // 如果不是有效的 JSON,记录警告但继续返回原始内容
332
+ this.logger.warn('Failed to parse image info as JSON', {
333
+ fileKey,
334
+ content: imageInfoJson,
335
+ });
336
+ throw new Error('Failed to parse image info as JSON');
337
+ }
338
+ } else {
339
+ throw new Error('Failed to get image info: missing data in response');
340
+ }
341
+ } catch (error) {
342
+ this.logger.error('Failed to get image info', {
343
+ fileKey,
344
+ bucket: finalBucket,
345
+ error: error.message,
346
+ stack: error.stack,
347
+ internal,
348
+ });
349
+ throw error;
350
+ }
351
+ }
352
+
353
+ /**
354
+ * 获取音频信息
355
+ * 参考:火山引擎 TOS 媒体处理文档
356
+ *
357
+ * 使用 TOS SDK 的音频信息获取功能,返回音频的详细信息(时长、采样率、声道数、比特率等)
358
+ *
359
+ * @param fileKey 音频文件键名
360
+ * @param internal 是否使用内部客户端,默认为false
361
+ * @param bucket 存储桶名称(可选),如果未提供则使用配置中的默认存储桶
362
+ * @returns 返回音频信息的对象
363
+ */
364
+ /**
365
+ * 获取音频信息,并组合成 AudioInfo 结构
366
+ *
367
+ * @param fileKey 音频文件键名
368
+ * @param internal 是否使用内部客户端,默认为false
369
+ * @param bucket 存储桶名称(可选),如果未提供则使用配置中的默认存储桶
370
+ * @returns 返回组合后的 AudioInfo 对象
371
+ */
372
+ async getAudioInfo(
373
+ fileKey: string,
374
+ internal: boolean = false,
375
+ bucket?: string,
376
+ ): Promise<any> {
377
+ const finalBucket = bucket || this.getBucketString();
378
+ const tosClient = internal ? this.tosInternalClient : this.tosClient;
379
+
380
+ try {
381
+ this.logger.info('Getting audio info', {
382
+ fileKey,
383
+ bucket: finalBucket,
384
+ internal,
385
+ });
386
+
387
+ // 使用 TOS SDK 的 getObjectV2 方法获取音频信息
388
+ const result = await tosClient.getObjectV2({
389
+ bucket: finalBucket,
390
+ key: fileKey,
391
+ process: 'video/info',
392
+ dataType: 'buffer',
393
+ });
394
+
395
+ if (result.data && result.data.content) {
396
+ const audioInfoJson = result.data.content.toString();
397
+ let ffprobeInfo: any;
398
+
399
+ try {
400
+ ffprobeInfo = JSON.parse(audioInfoJson);
401
+ } catch (parseError) {
402
+ this.logger.warn('Failed to parse audio info as JSON', {
403
+ fileKey,
404
+ content: audioInfoJson,
405
+ });
406
+ console.log('techwu parseError', fileKey, audioInfoJson, parseError);
407
+ throw new Error('Failed to parse audio info as JSON');
408
+ }
409
+
410
+ const format = ffprobeInfo.format || {};
411
+ const streams = ffprobeInfo.streams || [];
412
+
413
+ // 查找音频流(可能有多个,取第一个)
414
+ const audioStream = streams.find((s: any) => s.codec_type === 'audio');
415
+
416
+ // 提取时长信息
417
+ const duration = ffprobeInfo.duration
418
+ ? parseFloat(ffprobeInfo.duration.toString())
419
+ : ffprobeInfo.duration
420
+ ? parseFloat(ffprobeInfo.duration.toString())
421
+ : format.duration
422
+ ? parseFloat(format.duration.toString())
423
+ : audioStream?.duration
424
+ ? parseFloat(audioStream.duration.toString())
425
+ : 0;
426
+
427
+ const streamDuration = ffprobeInfo.streamDuration
428
+ ? parseFloat(ffprobeInfo.streamDuration.toString())
429
+ : audioStream?.duration
430
+ ? parseFloat(audioStream.duration.toString())
431
+ : duration;
432
+
433
+ // 提取音频流信息
434
+ const channels = audioStream?.channels ?? undefined;
435
+ const channelLayout = audioStream?.channel_layout ?? undefined;
436
+ const sampleRate = audioStream?.sample_rate
437
+ ? audioStream.sample_rate.toString()
438
+ : undefined;
439
+
440
+ // 提取比特率(优先使用 format.bit_rate,其次使用 stream.bit_rate)
441
+ const bitRate = format.bit_rate
442
+ ? format.bit_rate.toString()
443
+ : audioStream?.bit_rate
444
+ ? audioStream.bit_rate.toString()
445
+ : undefined;
446
+
447
+ // 组合成 AudioInfo 结构
448
+ // AudioInfo @ prisma/schema.prisma:
449
+ // id, duration, streamDuration, channels, channelLayout, sampleRate, bitRate, ffmpegInfo, fileKeyId
450
+ const audioInfo: Partial<{
451
+ duration: number;
452
+ streamDuration: number;
453
+ channels: number | undefined;
454
+ channelLayout: string | undefined;
455
+ sampleRate: string | undefined;
456
+ bitRate: string | undefined;
457
+ ffmpegInfo: any;
458
+ }> = {
459
+ duration: duration || 0,
460
+ streamDuration: streamDuration || 0,
461
+ channels,
462
+ channelLayout,
463
+ sampleRate,
464
+ bitRate,
465
+ ffmpegInfo: ffprobeInfo, // 保存完整的原始数据
466
+ };
467
+
468
+ this.logger.info('Audio info retrieved successfully', {
469
+ fileKey,
470
+ bucket: finalBucket,
471
+ requestId: result.requestId,
472
+ duration: audioInfo.duration,
473
+ streamDuration: audioInfo.streamDuration,
474
+ channels: audioInfo.channels,
475
+ sampleRate: audioInfo.sampleRate,
476
+ bitRate: audioInfo.bitRate,
477
+ });
478
+
479
+ return audioInfo;
480
+ } else {
481
+ throw new Error('Failed to get audio info: missing data in response');
482
+ }
483
+ } catch (error) {
484
+ this.logger.error('Failed to get audio info', {
485
+ fileKey,
486
+ bucket: finalBucket,
487
+ error: error.message,
488
+ stack: error.stack,
489
+ internal,
490
+ });
491
+ throw error;
492
+ }
493
+ }
494
+
495
+ /**
496
+ * 视频第一帧截帧并持久化存储
497
+ * 参考:https://www.volcengine.com/docs/6349/1179565?lang=zh
498
+ *
499
+ * 使用 TOS SDK 的视频截帧功能,截取视频第一帧并保存到指定位置
500
+ *
501
+ * @param fileKey 视频文件键名
502
+ * @param internal 是否使用内部客户端,默认为false
503
+ * @param bucket 存储桶名称(可选),如果未提供则使用配置中的默认存储桶
504
+ * @returns 返回保存的截图文件键名
505
+ */
506
+ async getSnapshot(
507
+ fileKey: string,
508
+ internal: boolean = false,
509
+ bucket?: string,
510
+ time: number = 0,
511
+ width: number = 0,
512
+ height: number = 0,
513
+ format: string = 'jpg',
514
+ ): Promise<string> {
515
+ const finalBucket = bucket || this.getBucketString();
516
+ const tosClient = internal ? this.tosInternalClient : this.tosClient;
517
+
518
+ try {
519
+ // 构建目标文件路径:将 fileKey 的后缀改为 _snapshot.jpg
520
+ // 例如:path/to/video.mp4 -> path/to/video_snapshot.jpg
521
+ const pathParts = fileKey.split('/');
522
+ const fileName = pathParts.pop() || '';
523
+ const basePath = pathParts.join('/');
524
+
525
+ // 移除原文件扩展名,添加 _snapshot.jpg 后缀
526
+ const nameWithoutExt = fileName.replace(/\.[^/.]+$/, '');
527
+ const snapshotFileName = `${nameWithoutExt}${TRANSCODE_CONSTANTS.SUFFIXES.SNAPSHOT}${TRANSCODE_CONSTANTS.EXTENSIONS.JPG}`;
528
+ const snapshotFileKey = basePath
529
+ ? `${basePath}/${snapshotFileName}`
530
+ : snapshotFileName;
531
+
532
+ this.logger.info('Generating video snapshot', {
533
+ fileKey,
534
+ snapshotFileKey,
535
+ bucket: finalBucket,
536
+ internal,
537
+ });
538
+
539
+ // 使用 TOS SDK 的 getObjectV2 方法进行视频截帧并持久化存储
540
+ // process 参数:video/snapshot,t_0 表示截取第0秒(第一帧)
541
+ // saveBucket 和 saveObject 需要使用 base64url 编码
542
+ // 构建 process 参数,width 或 height 为 0 时不包含
543
+ let process = `video/snapshot,t_${time}`;
544
+ if (width > 0) {
545
+ process += `,w_${width}`;
546
+ }
547
+ if (height > 0) {
548
+ process += `,h_${height}`;
549
+ }
550
+ if (format) {
551
+ process += `,f_${format}`;
552
+ }
553
+ const saveBucket = Buffer.from(finalBucket).toString('base64url');
554
+ const saveObject = Buffer.from(snapshotFileKey).toString('base64url');
555
+
556
+ const result = await tosClient.getObjectV2({
557
+ bucket: finalBucket,
558
+ key: fileKey,
559
+ process: process,
560
+ dataType: 'buffer',
561
+ saveBucket: saveBucket,
562
+ saveObject: saveObject,
563
+ });
564
+
565
+ // 解析返回结果
566
+ // 根据文档,持久化存储成功后,返回的 data.content 包含保存结果信息
567
+ if (result.data) {
568
+ let saveResult;
569
+ if (result.data.content) {
570
+ try {
571
+ saveResult = JSON.parse(result.data.content.toString());
572
+ } catch (parseError) {
573
+ // 如果不是 JSON,可能是其他格式,记录原始内容
574
+ this.logger.warn('Failed to parse snapshot result as JSON', {
575
+ content: result.data.content.toString(),
576
+ });
577
+ }
578
+ }
579
+
580
+ this.logger.info('Video snapshot generated and saved successfully', {
581
+ fileKey,
582
+ snapshotFileKey,
583
+ bucket: finalBucket,
584
+ requestId: result.requestId,
585
+ saveResult: saveResult,
586
+ });
587
+
588
+ // 返回保存的截图文件键名
589
+ return snapshotFileKey;
590
+ } else {
591
+ throw new Error(
592
+ 'Failed to get snapshot result from TOS response: missing data',
593
+ );
594
+ }
595
+ } catch (error) {
596
+ this.logger.error('Failed to generate video snapshot', {
597
+ fileKey,
598
+ bucket: finalBucket,
599
+ error: error.message,
600
+ stack: error.stack,
601
+ internal,
602
+ });
603
+ throw error;
604
+ }
605
+ }
606
+
607
+ /**
608
+ * 获取私有文件的下载链接
609
+ * 参考:https://www.volcengine.com/docs/6349/113484?lang=zh
610
+ *
611
+ * 使用火山引擎官方 TOS SDK 生成预签名 URL
612
+ *
613
+ * @param fileKey 文件键名
614
+ * @param expire 链接过期时间,单位为秒,默认为30秒
615
+ * @param internal 是否使用内部客户端,默认为false
616
+ * @param bucket 存储桶名称(可选),如果未提供则使用配置中的默认存储桶
617
+ * @returns 返回一个Promise,解析后得到私有文件的下载链接
618
+ */
619
+ async getPrivateDownloadUrl(
620
+ fileKey: string,
621
+ expire: number = 3600,
622
+ internal: boolean = false,
623
+ bucket?: string,
624
+ ): Promise<string> {
625
+ // 如果是公开存储桶,直接返回公开 URL
626
+ if (this.config.isPublic) {
627
+ return `${this.config.domain}/${fileKey}`;
628
+ }
629
+ console.log('techwu bucket', bucket, fileKey);
630
+
631
+ const finalBucket = bucket || this.getBucketString();
632
+ const cacheKey = `${finalBucket}:${fileKey}`;
633
+
634
+ // 检查 Redis 缓存
635
+ // const redisUrl = await this.redis.getData(this.urlRedisKey, cacheKey);
636
+ // if (redisUrl) {
637
+ // this.logger.debug('Using cached presigned URL', { fileKey, bucket: finalBucket });
638
+ // return redisUrl;
639
+ // }
640
+
641
+ // 使用火山引擎 TOS SDK 生成预签名 URL
642
+ const tosClient = internal ? this.tosInternalClient : this.tosClient;
643
+
644
+ try {
645
+ // 使用 TOS SDK 的 getPreSignedUrl 方法生成预签名 URL
646
+ // 参考文档:https://www.volcengine.com/docs/6349/113484?lang=zh
647
+ const signedUrl = tosClient.getPreSignedUrl({
648
+ method: 'GET',
649
+ bucket: finalBucket,
650
+ key: fileKey,
651
+ expires: expire, // 预签名 URL 的有效期,单位是秒
652
+ });
653
+
654
+ this.logger.info('Generated presigned URL for TOS using TOS SDK', {
655
+ fileKey,
656
+ bucket: finalBucket,
657
+ expiresIn: expire,
658
+ internal,
659
+ });
660
+
661
+ // 缓存 URL(缓存时间略短于过期时间,确保不会返回已过期的 URL)
662
+ const cacheExpire = Math.max(expire - 5, 1); // 至少缓存1秒
663
+ await this.redis.saveData(
664
+ this.urlRedisKey,
665
+ cacheKey,
666
+ signedUrl,
667
+ cacheExpire,
668
+ );
669
+
670
+ // 如果需要替换为自定义域名,使用 replaceUrlToOwnDoamin
671
+ return this.replaceUrlToOwnDoamin(signedUrl);
672
+ } catch (error) {
673
+ this.logger.error('Failed to generate presigned URL for TOS', {
674
+ fileKey,
675
+ bucket: finalBucket,
676
+ error: error.message,
677
+ internal,
678
+ });
679
+ throw error;
680
+ }
681
+ }
682
+
683
+ /**
684
+ * 获取私有文件的下载链接(不进行 CDN 加密)
685
+ * 参考:https://www.volcengine.com/docs/6349/113484?lang=zh
686
+ *
687
+ * 使用火山引擎官方 TOS SDK 生成预签名 URL
688
+ *
689
+ * @param fileKey 文件键名
690
+ * @param expiresIn 链接过期时间,单位为秒,默认为30秒
691
+ * @param internal 是否使用内部客户端,默认为false
692
+ * @param bucket 存储桶名称(可选),如果未提供则使用配置中的默认存储桶
693
+ * @returns 返回一个Promise,解析后得到私有文件的下载链接
694
+ */
695
+ async getPrivateDownloadUrlWithoutCdnEncrypt(
696
+ fileKey: string,
697
+ expiresIn: number = 30,
698
+ internal: boolean = false,
699
+ bucket?: string,
700
+ ): Promise<string> {
701
+ // 如果是公开存储桶,直接返回公开 URL
702
+ if (this.config.isPublic) {
703
+ return `${this.config.domain}/${fileKey}`;
704
+ }
705
+
706
+ const finalBucket = bucket || this.getBucketString();
707
+ const cacheKey = `${finalBucket}:${fileKey}`;
708
+
709
+ // 检查 Redis 缓存
710
+ const redisUrl = await this.redis.getData(this.urlRedisKey, cacheKey);
711
+ if (redisUrl) {
712
+ this.logger.debug('Using cached presigned URL', {
713
+ fileKey,
714
+ bucket: finalBucket,
715
+ });
716
+ return redisUrl;
717
+ }
718
+
719
+ // 使用火山引擎 TOS SDK 生成预签名 URL
720
+ const tosClient = internal ? this.tosInternalClient : this.tosClient;
721
+
722
+ try {
723
+ // 使用 TOS SDK 的 getPreSignedUrl 方法生成预签名 URL
724
+ // 参考文档:https://www.volcengine.com/docs/6349/113484?lang=zh
725
+ const signedUrl = tosClient.getPreSignedUrl({
726
+ method: 'GET',
727
+ bucket: finalBucket,
728
+ key: fileKey,
729
+ expires: expiresIn, // 预签名 URL 的有效期,单位是秒
730
+ });
731
+
732
+ this.logger.info(
733
+ 'Generated presigned URL for TOS using TOS SDK (without CDN encrypt)',
734
+ {
735
+ fileKey,
736
+ bucket: finalBucket,
737
+ expiresIn,
738
+ internal,
739
+ },
740
+ );
741
+
742
+ // 缓存 URL
743
+ const cacheExpire = Math.max(expiresIn - 5, 1);
744
+ await this.redis.saveData(
745
+ this.urlRedisKey,
746
+ cacheKey,
747
+ signedUrl,
748
+ cacheExpire,
749
+ );
750
+
751
+ // 如果需要替换为自定义域名
752
+ if (internal) {
753
+ return this.replaceUrlToOwnDoamin(signedUrl);
754
+ }
755
+
756
+ return signedUrl;
757
+ } catch (error) {
758
+ this.logger.error('Failed to generate presigned URL for TOS', {
759
+ fileKey,
760
+ bucket: finalBucket,
761
+ error: error.message,
762
+ internal,
763
+ });
764
+ throw error;
765
+ }
766
+ }
767
+ }