@de-otio/trellis 0.4.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 (1150) hide show
  1. package/dist/db.d.ts +36 -0
  2. package/dist/db.d.ts.map +1 -0
  3. package/dist/db.js +39 -0
  4. package/dist/db.js.map +1 -0
  5. package/dist/env.d.ts +107 -0
  6. package/dist/env.d.ts.map +1 -0
  7. package/dist/env.js +268 -0
  8. package/dist/env.js.map +1 -0
  9. package/dist/extensions.d.ts +15 -0
  10. package/dist/extensions.d.ts.map +1 -0
  11. package/dist/extensions.js +35 -0
  12. package/dist/extensions.js.map +1 -0
  13. package/dist/index.d.ts +8 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +15 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/lambda/cleanup-cron.d.ts +2 -0
  18. package/dist/lambda/cleanup-cron.d.ts.map +1 -0
  19. package/dist/lambda/cleanup-cron.js +38 -0
  20. package/dist/lambda/cleanup-cron.js.map +1 -0
  21. package/dist/lambda/create-auth-challenge.d.ts +2 -0
  22. package/dist/lambda/create-auth-challenge.d.ts.map +1 -0
  23. package/dist/lambda/create-auth-challenge.js +108 -0
  24. package/dist/lambda/create-auth-challenge.js.map +1 -0
  25. package/dist/lambda/custom-message.d.ts +3 -0
  26. package/dist/lambda/custom-message.d.ts.map +1 -0
  27. package/dist/lambda/custom-message.js +29 -0
  28. package/dist/lambda/custom-message.js.map +1 -0
  29. package/dist/lambda/define-auth-challenge.d.ts +2 -0
  30. package/dist/lambda/define-auth-challenge.d.ts.map +1 -0
  31. package/dist/lambda/define-auth-challenge.js +27 -0
  32. package/dist/lambda/define-auth-challenge.js.map +1 -0
  33. package/dist/lambda/delete-account-worker.d.ts +3 -0
  34. package/dist/lambda/delete-account-worker.d.ts.map +1 -0
  35. package/dist/lambda/delete-account-worker.js +122 -0
  36. package/dist/lambda/delete-account-worker.js.map +1 -0
  37. package/dist/lambda/diagnostics-proxy.d.ts +6 -0
  38. package/dist/lambda/diagnostics-proxy.d.ts.map +1 -0
  39. package/dist/lambda/diagnostics-proxy.js +154 -0
  40. package/dist/lambda/diagnostics-proxy.js.map +1 -0
  41. package/dist/lambda/e2e-sweeper.d.ts +18 -0
  42. package/dist/lambda/e2e-sweeper.d.ts.map +1 -0
  43. package/dist/lambda/e2e-sweeper.js +127 -0
  44. package/dist/lambda/e2e-sweeper.js.map +1 -0
  45. package/dist/lambda/federation-outbox-worker.d.ts +3 -0
  46. package/dist/lambda/federation-outbox-worker.d.ts.map +1 -0
  47. package/dist/lambda/federation-outbox-worker.js +11 -0
  48. package/dist/lambda/federation-outbox-worker.js.map +1 -0
  49. package/dist/lambda/followers-events-worker.d.ts +3 -0
  50. package/dist/lambda/followers-events-worker.d.ts.map +1 -0
  51. package/dist/lambda/followers-events-worker.js +11 -0
  52. package/dist/lambda/followers-events-worker.js.map +1 -0
  53. package/dist/lambda/hourly-cron.d.ts +2 -0
  54. package/dist/lambda/hourly-cron.d.ts.map +1 -0
  55. package/dist/lambda/hourly-cron.js +101 -0
  56. package/dist/lambda/hourly-cron.js.map +1 -0
  57. package/dist/lambda/link-check-worker.d.ts +3 -0
  58. package/dist/lambda/link-check-worker.d.ts.map +1 -0
  59. package/dist/lambda/link-check-worker.js +11 -0
  60. package/dist/lambda/link-check-worker.js.map +1 -0
  61. package/dist/lambda/maintenance-cron.d.ts +2 -0
  62. package/dist/lambda/maintenance-cron.d.ts.map +1 -0
  63. package/dist/lambda/maintenance-cron.js +127 -0
  64. package/dist/lambda/maintenance-cron.js.map +1 -0
  65. package/dist/lambda/media-processing-worker.d.ts +3 -0
  66. package/dist/lambda/media-processing-worker.d.ts.map +1 -0
  67. package/dist/lambda/media-processing-worker.js +95 -0
  68. package/dist/lambda/media-processing-worker.js.map +1 -0
  69. package/dist/lambda/media-reconciliation-worker.d.ts +3 -0
  70. package/dist/lambda/media-reconciliation-worker.d.ts.map +1 -0
  71. package/dist/lambda/media-reconciliation-worker.js +11 -0
  72. package/dist/lambda/media-reconciliation-worker.js.map +1 -0
  73. package/dist/lambda/nightly-cron.d.ts +2 -0
  74. package/dist/lambda/nightly-cron.d.ts.map +1 -0
  75. package/dist/lambda/nightly-cron.js +348 -0
  76. package/dist/lambda/nightly-cron.js.map +1 -0
  77. package/dist/lambda/post-confirmation.d.ts +3 -0
  78. package/dist/lambda/post-confirmation.d.ts.map +1 -0
  79. package/dist/lambda/post-confirmation.js +79 -0
  80. package/dist/lambda/post-confirmation.js.map +1 -0
  81. package/dist/lambda/pre-signup.d.ts +3 -0
  82. package/dist/lambda/pre-signup.d.ts.map +1 -0
  83. package/dist/lambda/pre-signup.js +35 -0
  84. package/dist/lambda/pre-signup.js.map +1 -0
  85. package/dist/lambda/pre-token-generation.d.ts +3 -0
  86. package/dist/lambda/pre-token-generation.d.ts.map +1 -0
  87. package/dist/lambda/pre-token-generation.js +79 -0
  88. package/dist/lambda/pre-token-generation.js.map +1 -0
  89. package/dist/lambda/tools/check-health.d.ts +6 -0
  90. package/dist/lambda/tools/check-health.d.ts.map +1 -0
  91. package/dist/lambda/tools/check-health.js +24 -0
  92. package/dist/lambda/tools/check-health.js.map +1 -0
  93. package/dist/lambda/tools/describe-services.d.ts +20 -0
  94. package/dist/lambda/tools/describe-services.d.ts.map +1 -0
  95. package/dist/lambda/tools/describe-services.js +41 -0
  96. package/dist/lambda/tools/describe-services.js.map +1 -0
  97. package/dist/lambda/tools/get-cost-report.d.ts +16 -0
  98. package/dist/lambda/tools/get-cost-report.d.ts.map +1 -0
  99. package/dist/lambda/tools/get-cost-report.js +54 -0
  100. package/dist/lambda/tools/get-cost-report.js.map +1 -0
  101. package/dist/lambda/tools/get-errors.d.ts +11 -0
  102. package/dist/lambda/tools/get-errors.d.ts.map +1 -0
  103. package/dist/lambda/tools/get-errors.js +62 -0
  104. package/dist/lambda/tools/get-errors.js.map +1 -0
  105. package/dist/lambda/tools/get-feature-flags.d.ts +8 -0
  106. package/dist/lambda/tools/get-feature-flags.d.ts.map +1 -0
  107. package/dist/lambda/tools/get-feature-flags.js +23 -0
  108. package/dist/lambda/tools/get-feature-flags.js.map +1 -0
  109. package/dist/lambda/tools/get-queue-status.d.ts +9 -0
  110. package/dist/lambda/tools/get-queue-status.d.ts.map +1 -0
  111. package/dist/lambda/tools/get-queue-status.js +46 -0
  112. package/dist/lambda/tools/get-queue-status.js.map +1 -0
  113. package/dist/lambda/tools/search-logs.d.ts +19 -0
  114. package/dist/lambda/tools/search-logs.d.ts.map +1 -0
  115. package/dist/lambda/tools/search-logs.js +55 -0
  116. package/dist/lambda/tools/search-logs.js.map +1 -0
  117. package/dist/lambda/tools/send-alert.d.ts +8 -0
  118. package/dist/lambda/tools/send-alert.d.ts.map +1 -0
  119. package/dist/lambda/tools/send-alert.js +29 -0
  120. package/dist/lambda/tools/send-alert.js.map +1 -0
  121. package/dist/lambda/verify-auth-challenge.d.ts +2 -0
  122. package/dist/lambda/verify-auth-challenge.d.ts.map +1 -0
  123. package/dist/lambda/verify-auth-challenge.js +35 -0
  124. package/dist/lambda/verify-auth-challenge.js.map +1 -0
  125. package/dist/lib/abuse-metrics.d.ts +44 -0
  126. package/dist/lib/abuse-metrics.d.ts.map +1 -0
  127. package/dist/lib/abuse-metrics.js +322 -0
  128. package/dist/lib/abuse-metrics.js.map +1 -0
  129. package/dist/lib/activitypub/activity-processor.d.ts +89 -0
  130. package/dist/lib/activitypub/activity-processor.d.ts.map +1 -0
  131. package/dist/lib/activitypub/activity-processor.js +709 -0
  132. package/dist/lib/activitypub/activity-processor.js.map +1 -0
  133. package/dist/lib/activitypub/activity-service.d.ts +47 -0
  134. package/dist/lib/activitypub/activity-service.d.ts.map +1 -0
  135. package/dist/lib/activitypub/activity-service.js +165 -0
  136. package/dist/lib/activitypub/activity-service.js.map +1 -0
  137. package/dist/lib/activitypub/actor.d.ts +44 -0
  138. package/dist/lib/activitypub/actor.d.ts.map +1 -0
  139. package/dist/lib/activitypub/actor.js +116 -0
  140. package/dist/lib/activitypub/actor.js.map +1 -0
  141. package/dist/lib/activitypub/audience-service.d.ts +52 -0
  142. package/dist/lib/activitypub/audience-service.d.ts.map +1 -0
  143. package/dist/lib/activitypub/audience-service.js +245 -0
  144. package/dist/lib/activitypub/audience-service.js.map +1 -0
  145. package/dist/lib/activitypub/crypto.d.ts +42 -0
  146. package/dist/lib/activitypub/crypto.d.ts.map +1 -0
  147. package/dist/lib/activitypub/crypto.js +129 -0
  148. package/dist/lib/activitypub/crypto.js.map +1 -0
  149. package/dist/lib/activitypub/delivery-service.d.ts +44 -0
  150. package/dist/lib/activitypub/delivery-service.d.ts.map +1 -0
  151. package/dist/lib/activitypub/delivery-service.js +259 -0
  152. package/dist/lib/activitypub/delivery-service.js.map +1 -0
  153. package/dist/lib/activitypub/dispatchers/entity-actor.d.ts +50 -0
  154. package/dist/lib/activitypub/dispatchers/entity-actor.d.ts.map +1 -0
  155. package/dist/lib/activitypub/dispatchers/entity-actor.js +247 -0
  156. package/dist/lib/activitypub/dispatchers/entity-actor.js.map +1 -0
  157. package/dist/lib/activitypub/dispatchers/group-actor.d.ts +47 -0
  158. package/dist/lib/activitypub/dispatchers/group-actor.d.ts.map +1 -0
  159. package/dist/lib/activitypub/dispatchers/group-actor.js +202 -0
  160. package/dist/lib/activitypub/dispatchers/group-actor.js.map +1 -0
  161. package/dist/lib/activitypub/dispatchers/user-actor.d.ts +47 -0
  162. package/dist/lib/activitypub/dispatchers/user-actor.d.ts.map +1 -0
  163. package/dist/lib/activitypub/dispatchers/user-actor.js +207 -0
  164. package/dist/lib/activitypub/dispatchers/user-actor.js.map +1 -0
  165. package/dist/lib/activitypub/dm-service.d.ts +35 -0
  166. package/dist/lib/activitypub/dm-service.d.ts.map +1 -0
  167. package/dist/lib/activitypub/dm-service.js +73 -0
  168. package/dist/lib/activitypub/dm-service.js.map +1 -0
  169. package/dist/lib/activitypub/entity-profile-service.d.ts +43 -0
  170. package/dist/lib/activitypub/entity-profile-service.d.ts.map +1 -0
  171. package/dist/lib/activitypub/entity-profile-service.js +80 -0
  172. package/dist/lib/activitypub/entity-profile-service.js.map +1 -0
  173. package/dist/lib/activitypub/fedify/config.d.ts +15 -0
  174. package/dist/lib/activitypub/fedify/config.d.ts.map +1 -0
  175. package/dist/lib/activitypub/fedify/config.js +38 -0
  176. package/dist/lib/activitypub/fedify/config.js.map +1 -0
  177. package/dist/lib/activitypub/fedify/context.d.ts +21 -0
  178. package/dist/lib/activitypub/fedify/context.d.ts.map +1 -0
  179. package/dist/lib/activitypub/fedify/context.js +67 -0
  180. package/dist/lib/activitypub/fedify/context.js.map +1 -0
  181. package/dist/lib/activitypub/fedify/runtime.d.ts +18 -0
  182. package/dist/lib/activitypub/fedify/runtime.d.ts.map +1 -0
  183. package/dist/lib/activitypub/fedify/runtime.js +26 -0
  184. package/dist/lib/activitypub/fedify/runtime.js.map +1 -0
  185. package/dist/lib/activitypub/friendship-service.d.ts +15 -0
  186. package/dist/lib/activitypub/friendship-service.d.ts.map +1 -0
  187. package/dist/lib/activitypub/friendship-service.js +26 -0
  188. package/dist/lib/activitypub/friendship-service.js.map +1 -0
  189. package/dist/lib/activitypub/group-service.d.ts +83 -0
  190. package/dist/lib/activitypub/group-service.d.ts.map +1 -0
  191. package/dist/lib/activitypub/group-service.js +301 -0
  192. package/dist/lib/activitypub/group-service.js.map +1 -0
  193. package/dist/lib/activitypub/http-signatures.d.ts +41 -0
  194. package/dist/lib/activitypub/http-signatures.d.ts.map +1 -0
  195. package/dist/lib/activitypub/http-signatures.js +284 -0
  196. package/dist/lib/activitypub/http-signatures.js.map +1 -0
  197. package/dist/lib/activitypub/jsonld.d.ts +39 -0
  198. package/dist/lib/activitypub/jsonld.d.ts.map +1 -0
  199. package/dist/lib/activitypub/jsonld.js +97 -0
  200. package/dist/lib/activitypub/jsonld.js.map +1 -0
  201. package/dist/lib/activitypub/listeners/friends-collection.d.ts +20 -0
  202. package/dist/lib/activitypub/listeners/friends-collection.d.ts.map +1 -0
  203. package/dist/lib/activitypub/listeners/friends-collection.js +105 -0
  204. package/dist/lib/activitypub/listeners/friends-collection.js.map +1 -0
  205. package/dist/lib/activitypub/listeners/http-signatures.d.ts +29 -0
  206. package/dist/lib/activitypub/listeners/http-signatures.d.ts.map +1 -0
  207. package/dist/lib/activitypub/listeners/http-signatures.js +208 -0
  208. package/dist/lib/activitypub/listeners/http-signatures.js.map +1 -0
  209. package/dist/lib/activitypub/listeners/inbox.d.ts +34 -0
  210. package/dist/lib/activitypub/listeners/inbox.d.ts.map +1 -0
  211. package/dist/lib/activitypub/listeners/inbox.js +226 -0
  212. package/dist/lib/activitypub/listeners/inbox.js.map +1 -0
  213. package/dist/lib/activitypub/listeners/outbox.d.ts +20 -0
  214. package/dist/lib/activitypub/listeners/outbox.d.ts.map +1 -0
  215. package/dist/lib/activitypub/listeners/outbox.js +117 -0
  216. package/dist/lib/activitypub/listeners/outbox.js.map +1 -0
  217. package/dist/lib/activitypub/remote-fetch-service.d.ts +108 -0
  218. package/dist/lib/activitypub/remote-fetch-service.d.ts.map +1 -0
  219. package/dist/lib/activitypub/remote-fetch-service.js +364 -0
  220. package/dist/lib/activitypub/remote-fetch-service.js.map +1 -0
  221. package/dist/lib/activitypub/services/abuse-prevention.d.ts +52 -0
  222. package/dist/lib/activitypub/services/abuse-prevention.d.ts.map +1 -0
  223. package/dist/lib/activitypub/services/abuse-prevention.js +118 -0
  224. package/dist/lib/activitypub/services/abuse-prevention.js.map +1 -0
  225. package/dist/lib/activitypub/services/dm-service-fedify.d.ts +46 -0
  226. package/dist/lib/activitypub/services/dm-service-fedify.d.ts.map +1 -0
  227. package/dist/lib/activitypub/services/dm-service-fedify.js +168 -0
  228. package/dist/lib/activitypub/services/dm-service-fedify.js.map +1 -0
  229. package/dist/lib/activitypub/services/fedify-converters.d.ts +51 -0
  230. package/dist/lib/activitypub/services/fedify-converters.d.ts.map +1 -0
  231. package/dist/lib/activitypub/services/fedify-converters.js +109 -0
  232. package/dist/lib/activitypub/services/fedify-converters.js.map +1 -0
  233. package/dist/lib/activitypub/services/fedify-delivery.d.ts +41 -0
  234. package/dist/lib/activitypub/services/fedify-delivery.d.ts.map +1 -0
  235. package/dist/lib/activitypub/services/fedify-delivery.js +186 -0
  236. package/dist/lib/activitypub/services/fedify-delivery.js.map +1 -0
  237. package/dist/lib/activitypub/services/follow-activity-service.d.ts +34 -0
  238. package/dist/lib/activitypub/services/follow-activity-service.d.ts.map +1 -0
  239. package/dist/lib/activitypub/services/follow-activity-service.js +64 -0
  240. package/dist/lib/activitypub/services/follow-activity-service.js.map +1 -0
  241. package/dist/lib/activitypub/services/post-service-fedify.d.ts +49 -0
  242. package/dist/lib/activitypub/services/post-service-fedify.d.ts.map +1 -0
  243. package/dist/lib/activitypub/services/post-service-fedify.js +281 -0
  244. package/dist/lib/activitypub/services/post-service-fedify.js.map +1 -0
  245. package/dist/lib/activitypub/services/remote-activity-handler.d.ts +22 -0
  246. package/dist/lib/activitypub/services/remote-activity-handler.d.ts.map +1 -0
  247. package/dist/lib/activitypub/services/remote-activity-handler.js +136 -0
  248. package/dist/lib/activitypub/services/remote-activity-handler.js.map +1 -0
  249. package/dist/lib/activitypub/standalone-mode.d.ts +34 -0
  250. package/dist/lib/activitypub/standalone-mode.d.ts.map +1 -0
  251. package/dist/lib/activitypub/standalone-mode.js +127 -0
  252. package/dist/lib/activitypub/standalone-mode.js.map +1 -0
  253. package/dist/lib/activitypub/webfinger/server.d.ts +16 -0
  254. package/dist/lib/activitypub/webfinger/server.d.ts.map +1 -0
  255. package/dist/lib/activitypub/webfinger/server.js +221 -0
  256. package/dist/lib/activitypub/webfinger/server.js.map +1 -0
  257. package/dist/lib/age-gate-middleware.d.ts +19 -0
  258. package/dist/lib/age-gate-middleware.d.ts.map +1 -0
  259. package/dist/lib/age-gate-middleware.js +26 -0
  260. package/dist/lib/age-gate-middleware.js.map +1 -0
  261. package/dist/lib/age-gate.d.ts +37 -0
  262. package/dist/lib/age-gate.d.ts.map +1 -0
  263. package/dist/lib/age-gate.js +96 -0
  264. package/dist/lib/age-gate.js.map +1 -0
  265. package/dist/lib/age-tier-transition.d.ts +21 -0
  266. package/dist/lib/age-tier-transition.d.ts.map +1 -0
  267. package/dist/lib/age-tier-transition.js +190 -0
  268. package/dist/lib/age-tier-transition.js.map +1 -0
  269. package/dist/lib/audit-logger.d.ts +142 -0
  270. package/dist/lib/audit-logger.d.ts.map +1 -0
  271. package/dist/lib/audit-logger.js +326 -0
  272. package/dist/lib/audit-logger.js.map +1 -0
  273. package/dist/lib/auth/cognito-jwt.d.ts +20 -0
  274. package/dist/lib/auth/cognito-jwt.d.ts.map +1 -0
  275. package/dist/lib/auth/cognito-jwt.js +56 -0
  276. package/dist/lib/auth/cognito-jwt.js.map +1 -0
  277. package/dist/lib/auth-context-manager.d.ts +116 -0
  278. package/dist/lib/auth-context-manager.d.ts.map +1 -0
  279. package/dist/lib/auth-context-manager.js +130 -0
  280. package/dist/lib/auth-context-manager.js.map +1 -0
  281. package/dist/lib/auth-handler.d.ts +19 -0
  282. package/dist/lib/auth-handler.d.ts.map +1 -0
  283. package/dist/lib/auth-handler.js +76 -0
  284. package/dist/lib/auth-handler.js.map +1 -0
  285. package/dist/lib/badge-handler.d.ts +20 -0
  286. package/dist/lib/badge-handler.d.ts.map +1 -0
  287. package/dist/lib/badge-handler.js +142 -0
  288. package/dist/lib/badge-handler.js.map +1 -0
  289. package/dist/lib/circle-handler.d.ts +22 -0
  290. package/dist/lib/circle-handler.d.ts.map +1 -0
  291. package/dist/lib/circle-handler.js +224 -0
  292. package/dist/lib/circle-handler.js.map +1 -0
  293. package/dist/lib/circuit-breaker.d.ts +27 -0
  294. package/dist/lib/circuit-breaker.d.ts.map +1 -0
  295. package/dist/lib/circuit-breaker.js +63 -0
  296. package/dist/lib/circuit-breaker.js.map +1 -0
  297. package/dist/lib/comment-handler.d.ts +77 -0
  298. package/dist/lib/comment-handler.d.ts.map +1 -0
  299. package/dist/lib/comment-handler.js +953 -0
  300. package/dist/lib/comment-handler.js.map +1 -0
  301. package/dist/lib/connection-code-handler.d.ts +17 -0
  302. package/dist/lib/connection-code-handler.d.ts.map +1 -0
  303. package/dist/lib/connection-code-handler.js +293 -0
  304. package/dist/lib/connection-code-handler.js.map +1 -0
  305. package/dist/lib/content-discovery.d.ts +113 -0
  306. package/dist/lib/content-discovery.d.ts.map +1 -0
  307. package/dist/lib/content-discovery.js +519 -0
  308. package/dist/lib/content-discovery.js.map +1 -0
  309. package/dist/lib/context-aware-data-access.d.ts +89 -0
  310. package/dist/lib/context-aware-data-access.d.ts.map +1 -0
  311. package/dist/lib/context-aware-data-access.js +97 -0
  312. package/dist/lib/context-aware-data-access.js.map +1 -0
  313. package/dist/lib/cors-handler.d.ts +29 -0
  314. package/dist/lib/cors-handler.d.ts.map +1 -0
  315. package/dist/lib/cors-handler.js +225 -0
  316. package/dist/lib/cors-handler.js.map +1 -0
  317. package/dist/lib/cost-accumulator.d.ts +58 -0
  318. package/dist/lib/cost-accumulator.d.ts.map +1 -0
  319. package/dist/lib/cost-accumulator.js +173 -0
  320. package/dist/lib/cost-accumulator.js.map +1 -0
  321. package/dist/lib/crypto/encryption-service.d.ts +100 -0
  322. package/dist/lib/crypto/encryption-service.d.ts.map +1 -0
  323. package/dist/lib/crypto/encryption-service.js +293 -0
  324. package/dist/lib/crypto/encryption-service.js.map +1 -0
  325. package/dist/lib/crypto/index.d.ts +22 -0
  326. package/dist/lib/crypto/index.d.ts.map +1 -0
  327. package/dist/lib/crypto/index.js +28 -0
  328. package/dist/lib/crypto/index.js.map +1 -0
  329. package/dist/lib/crypto/types.d.ts +71 -0
  330. package/dist/lib/crypto/types.d.ts.map +1 -0
  331. package/dist/lib/crypto/types.js +3 -0
  332. package/dist/lib/crypto/types.js.map +1 -0
  333. package/dist/lib/crypto/versioning.d.ts +112 -0
  334. package/dist/lib/crypto/versioning.d.ts.map +1 -0
  335. package/dist/lib/crypto/versioning.js +148 -0
  336. package/dist/lib/crypto/versioning.js.map +1 -0
  337. package/dist/lib/crypto/voting/elgamal-encryption.d.ts +156 -0
  338. package/dist/lib/crypto/voting/elgamal-encryption.d.ts.map +1 -0
  339. package/dist/lib/crypto/voting/elgamal-encryption.js +172 -0
  340. package/dist/lib/crypto/voting/elgamal-encryption.js.map +1 -0
  341. package/dist/lib/crypto/voting/encryption-scheme.d.ts +138 -0
  342. package/dist/lib/crypto/voting/encryption-scheme.d.ts.map +1 -0
  343. package/dist/lib/crypto/voting/encryption-scheme.js +13 -0
  344. package/dist/lib/crypto/voting/encryption-scheme.js.map +1 -0
  345. package/dist/lib/crypto/voting/hash-utils.d.ts +58 -0
  346. package/dist/lib/crypto/voting/hash-utils.d.ts.map +1 -0
  347. package/dist/lib/crypto/voting/hash-utils.js +73 -0
  348. package/dist/lib/crypto/voting/hash-utils.js.map +1 -0
  349. package/dist/lib/crypto/voting/hybrid-encryption.d.ts +109 -0
  350. package/dist/lib/crypto/voting/hybrid-encryption.d.ts.map +1 -0
  351. package/dist/lib/crypto/voting/hybrid-encryption.js +134 -0
  352. package/dist/lib/crypto/voting/hybrid-encryption.js.map +1 -0
  353. package/dist/lib/crypto/voting/index.d.ts +18 -0
  354. package/dist/lib/crypto/voting/index.d.ts.map +1 -0
  355. package/dist/lib/crypto/voting/index.js +27 -0
  356. package/dist/lib/crypto/voting/index.js.map +1 -0
  357. package/dist/lib/crypto/voting/post-quantum-encryption.d.ts +107 -0
  358. package/dist/lib/crypto/voting/post-quantum-encryption.d.ts.map +1 -0
  359. package/dist/lib/crypto/voting/post-quantum-encryption.js +123 -0
  360. package/dist/lib/crypto/voting/post-quantum-encryption.js.map +1 -0
  361. package/dist/lib/csrf.d.ts +95 -0
  362. package/dist/lib/csrf.d.ts.map +1 -0
  363. package/dist/lib/csrf.js +174 -0
  364. package/dist/lib/csrf.js.map +1 -0
  365. package/dist/lib/data-router.d.ts +209 -0
  366. package/dist/lib/data-router.d.ts.map +1 -0
  367. package/dist/lib/data-router.js +792 -0
  368. package/dist/lib/data-router.js.map +1 -0
  369. package/dist/lib/database-circuit-breaker.d.ts +75 -0
  370. package/dist/lib/database-circuit-breaker.d.ts.map +1 -0
  371. package/dist/lib/database-circuit-breaker.js +155 -0
  372. package/dist/lib/database-circuit-breaker.js.map +1 -0
  373. package/dist/lib/database-config.d.ts +20 -0
  374. package/dist/lib/database-config.d.ts.map +1 -0
  375. package/dist/lib/database-config.js +46 -0
  376. package/dist/lib/database-config.js.map +1 -0
  377. package/dist/lib/database-connection-manager.d.ts +99 -0
  378. package/dist/lib/database-connection-manager.d.ts.map +1 -0
  379. package/dist/lib/database-connection-manager.js +495 -0
  380. package/dist/lib/database-connection-manager.js.map +1 -0
  381. package/dist/lib/database-monitor.d.ts +89 -0
  382. package/dist/lib/database-monitor.d.ts.map +1 -0
  383. package/dist/lib/database-monitor.js +199 -0
  384. package/dist/lib/database-monitor.js.map +1 -0
  385. package/dist/lib/database-rate-limiter.d.ts +41 -0
  386. package/dist/lib/database-rate-limiter.d.ts.map +1 -0
  387. package/dist/lib/database-rate-limiter.js +90 -0
  388. package/dist/lib/database-rate-limiter.js.map +1 -0
  389. package/dist/lib/database-wrapper-helper.d.ts +44 -0
  390. package/dist/lib/database-wrapper-helper.d.ts.map +1 -0
  391. package/dist/lib/database-wrapper-helper.js +104 -0
  392. package/dist/lib/database-wrapper-helper.js.map +1 -0
  393. package/dist/lib/database-wrapper.d.ts +51 -0
  394. package/dist/lib/database-wrapper.d.ts.map +1 -0
  395. package/dist/lib/database-wrapper.js +109 -0
  396. package/dist/lib/database-wrapper.js.map +1 -0
  397. package/dist/lib/db-query-helper.d.ts +130 -0
  398. package/dist/lib/db-query-helper.d.ts.map +1 -0
  399. package/dist/lib/db-query-helper.js +105 -0
  400. package/dist/lib/db-query-helper.js.map +1 -0
  401. package/dist/lib/discovery-handler.d.ts +19 -0
  402. package/dist/lib/discovery-handler.d.ts.map +1 -0
  403. package/dist/lib/discovery-handler.js +195 -0
  404. package/dist/lib/discovery-handler.js.map +1 -0
  405. package/dist/lib/domain-reputation-service.d.ts +112 -0
  406. package/dist/lib/domain-reputation-service.d.ts.map +1 -0
  407. package/dist/lib/domain-reputation-service.js +344 -0
  408. package/dist/lib/domain-reputation-service.js.map +1 -0
  409. package/dist/lib/email-privacy.d.ts +54 -0
  410. package/dist/lib/email-privacy.d.ts.map +1 -0
  411. package/dist/lib/email-privacy.js +72 -0
  412. package/dist/lib/email-privacy.js.map +1 -0
  413. package/dist/lib/email-provider.d.ts +133 -0
  414. package/dist/lib/email-provider.d.ts.map +1 -0
  415. package/dist/lib/email-provider.js +391 -0
  416. package/dist/lib/email-provider.js.map +1 -0
  417. package/dist/lib/encryption-key-service.d.ts +115 -0
  418. package/dist/lib/encryption-key-service.d.ts.map +1 -0
  419. package/dist/lib/encryption-key-service.js +272 -0
  420. package/dist/lib/encryption-key-service.js.map +1 -0
  421. package/dist/lib/entity-handler.d.ts +59 -0
  422. package/dist/lib/entity-handler.d.ts.map +1 -0
  423. package/dist/lib/entity-handler.js +866 -0
  424. package/dist/lib/entity-handler.js.map +1 -0
  425. package/dist/lib/entity-relationship-handler.d.ts +19 -0
  426. package/dist/lib/entity-relationship-handler.d.ts.map +1 -0
  427. package/dist/lib/entity-relationship-handler.js +242 -0
  428. package/dist/lib/entity-relationship-handler.js.map +1 -0
  429. package/dist/lib/entity-tagging-errors.d.ts +32 -0
  430. package/dist/lib/entity-tagging-errors.d.ts.map +1 -0
  431. package/dist/lib/entity-tagging-errors.js +53 -0
  432. package/dist/lib/entity-tagging-errors.js.map +1 -0
  433. package/dist/lib/entity-tagging-validator.d.ts +47 -0
  434. package/dist/lib/entity-tagging-validator.d.ts.map +1 -0
  435. package/dist/lib/entity-tagging-validator.js +84 -0
  436. package/dist/lib/entity-tagging-validator.js.map +1 -0
  437. package/dist/lib/exif-stripper.d.ts +37 -0
  438. package/dist/lib/exif-stripper.d.ts.map +1 -0
  439. package/dist/lib/exif-stripper.js +62 -0
  440. package/dist/lib/exif-stripper.js.map +1 -0
  441. package/dist/lib/extension-context.d.ts +19 -0
  442. package/dist/lib/extension-context.d.ts.map +1 -0
  443. package/dist/lib/extension-context.js +78 -0
  444. package/dist/lib/extension-context.js.map +1 -0
  445. package/dist/lib/extension-route-wrapper.d.ts +21 -0
  446. package/dist/lib/extension-route-wrapper.d.ts.map +1 -0
  447. package/dist/lib/extension-route-wrapper.js +113 -0
  448. package/dist/lib/extension-route-wrapper.js.map +1 -0
  449. package/dist/lib/extension-validator.d.ts +12 -0
  450. package/dist/lib/extension-validator.d.ts.map +1 -0
  451. package/dist/lib/extension-validator.js +60 -0
  452. package/dist/lib/extension-validator.js.map +1 -0
  453. package/dist/lib/feature-flags.d.ts +56 -0
  454. package/dist/lib/feature-flags.d.ts.map +1 -0
  455. package/dist/lib/feature-flags.js +140 -0
  456. package/dist/lib/feature-flags.js.map +1 -0
  457. package/dist/lib/feature-toggle-service.d.ts +48 -0
  458. package/dist/lib/feature-toggle-service.d.ts.map +1 -0
  459. package/dist/lib/feature-toggle-service.js +167 -0
  460. package/dist/lib/feature-toggle-service.js.map +1 -0
  461. package/dist/lib/feed-handler.d.ts +152 -0
  462. package/dist/lib/feed-handler.d.ts.map +1 -0
  463. package/dist/lib/feed-handler.js +784 -0
  464. package/dist/lib/feed-handler.js.map +1 -0
  465. package/dist/lib/feed-pagination.d.ts +42 -0
  466. package/dist/lib/feed-pagination.d.ts.map +1 -0
  467. package/dist/lib/feed-pagination.js +54 -0
  468. package/dist/lib/feed-pagination.js.map +1 -0
  469. package/dist/lib/feed-personalization.d.ts +52 -0
  470. package/dist/lib/feed-personalization.d.ts.map +1 -0
  471. package/dist/lib/feed-personalization.js +105 -0
  472. package/dist/lib/feed-personalization.js.map +1 -0
  473. package/dist/lib/followers-events.d.ts +37 -0
  474. package/dist/lib/followers-events.d.ts.map +1 -0
  475. package/dist/lib/followers-events.js +149 -0
  476. package/dist/lib/followers-events.js.map +1 -0
  477. package/dist/lib/followers-handler.d.ts +21 -0
  478. package/dist/lib/followers-handler.d.ts.map +1 -0
  479. package/dist/lib/followers-handler.js +35 -0
  480. package/dist/lib/followers-handler.js.map +1 -0
  481. package/dist/lib/friends-handler.d.ts +78 -0
  482. package/dist/lib/friends-handler.d.ts.map +1 -0
  483. package/dist/lib/friends-handler.js +390 -0
  484. package/dist/lib/friends-handler.js.map +1 -0
  485. package/dist/lib/graph/dual-write-service.d.ts +116 -0
  486. package/dist/lib/graph/dual-write-service.d.ts.map +1 -0
  487. package/dist/lib/graph/dual-write-service.js +332 -0
  488. package/dist/lib/graph/dual-write-service.js.map +1 -0
  489. package/dist/lib/graph/dual-write.d.ts +396 -0
  490. package/dist/lib/graph/dual-write.d.ts.map +1 -0
  491. package/dist/lib/graph/dual-write.js +53 -0
  492. package/dist/lib/graph/dual-write.js.map +1 -0
  493. package/dist/lib/graph/errors.d.ts +90 -0
  494. package/dist/lib/graph/errors.d.ts.map +1 -0
  495. package/dist/lib/graph/errors.js +131 -0
  496. package/dist/lib/graph/errors.js.map +1 -0
  497. package/dist/lib/graph/graph-factory.d.ts +64 -0
  498. package/dist/lib/graph/graph-factory.d.ts.map +1 -0
  499. package/dist/lib/graph/graph-factory.js +190 -0
  500. package/dist/lib/graph/graph-factory.js.map +1 -0
  501. package/dist/lib/graph/graph-schema-init.d.ts +31 -0
  502. package/dist/lib/graph/graph-schema-init.d.ts.map +1 -0
  503. package/dist/lib/graph/graph-schema-init.js +105 -0
  504. package/dist/lib/graph/graph-schema-init.js.map +1 -0
  505. package/dist/lib/graph/graph-service.d.ts +479 -0
  506. package/dist/lib/graph/graph-service.d.ts.map +1 -0
  507. package/dist/lib/graph/graph-service.js +21 -0
  508. package/dist/lib/graph/graph-service.js.map +1 -0
  509. package/dist/lib/graph/index.d.ts +40 -0
  510. package/dist/lib/graph/index.d.ts.map +1 -0
  511. package/dist/lib/graph/index.js +74 -0
  512. package/dist/lib/graph/index.js.map +1 -0
  513. package/dist/lib/graph/neo4j-graph-service.d.ts +186 -0
  514. package/dist/lib/graph/neo4j-graph-service.d.ts.map +1 -0
  515. package/dist/lib/graph/neo4j-graph-service.js +1625 -0
  516. package/dist/lib/graph/neo4j-graph-service.js.map +1 -0
  517. package/dist/lib/graph/reconciliation-service.d.ts +113 -0
  518. package/dist/lib/graph/reconciliation-service.d.ts.map +1 -0
  519. package/dist/lib/graph/reconciliation-service.js +533 -0
  520. package/dist/lib/graph/reconciliation-service.js.map +1 -0
  521. package/dist/lib/graph/scoring-engine.d.ts +154 -0
  522. package/dist/lib/graph/scoring-engine.d.ts.map +1 -0
  523. package/dist/lib/graph/scoring-engine.js +286 -0
  524. package/dist/lib/graph/scoring-engine.js.map +1 -0
  525. package/dist/lib/graph/types.d.ts +480 -0
  526. package/dist/lib/graph/types.d.ts.map +1 -0
  527. package/dist/lib/graph/types.js +10 -0
  528. package/dist/lib/graph/types.js.map +1 -0
  529. package/dist/lib/hook-dispatcher.d.ts +21 -0
  530. package/dist/lib/hook-dispatcher.d.ts.map +1 -0
  531. package/dist/lib/hook-dispatcher.js +62 -0
  532. package/dist/lib/hook-dispatcher.js.map +1 -0
  533. package/dist/lib/id-generator.d.ts +29 -0
  534. package/dist/lib/id-generator.d.ts.map +1 -0
  535. package/dist/lib/id-generator.js +51 -0
  536. package/dist/lib/id-generator.js.map +1 -0
  537. package/dist/lib/input-sanitizer.d.ts +55 -0
  538. package/dist/lib/input-sanitizer.d.ts.map +1 -0
  539. package/dist/lib/input-sanitizer.js +167 -0
  540. package/dist/lib/input-sanitizer.js.map +1 -0
  541. package/dist/lib/internal-docs-dashboard.json +112 -0
  542. package/dist/lib/internal-docs-handler.d.ts +60 -0
  543. package/dist/lib/internal-docs-handler.d.ts.map +1 -0
  544. package/dist/lib/internal-docs-handler.js +570 -0
  545. package/dist/lib/internal-docs-handler.js.map +1 -0
  546. package/dist/lib/internal-docs-navigation.d.ts +42 -0
  547. package/dist/lib/internal-docs-navigation.d.ts.map +1 -0
  548. package/dist/lib/internal-docs-navigation.js +73 -0
  549. package/dist/lib/internal-docs-navigation.js.map +1 -0
  550. package/dist/lib/internal-docs-navigation.json +169 -0
  551. package/dist/lib/invitation-handler.d.ts +133 -0
  552. package/dist/lib/invitation-handler.d.ts.map +1 -0
  553. package/dist/lib/invitation-handler.js +1335 -0
  554. package/dist/lib/invitation-handler.js.map +1 -0
  555. package/dist/lib/ip-scrubber.d.ts +59 -0
  556. package/dist/lib/ip-scrubber.d.ts.map +1 -0
  557. package/dist/lib/ip-scrubber.js +101 -0
  558. package/dist/lib/ip-scrubber.js.map +1 -0
  559. package/dist/lib/kv/dynamodb-kv.d.ts +39 -0
  560. package/dist/lib/kv/dynamodb-kv.d.ts.map +1 -0
  561. package/dist/lib/kv/dynamodb-kv.js +239 -0
  562. package/dist/lib/kv/dynamodb-kv.js.map +1 -0
  563. package/dist/lib/link-security-handler.d.ts +140 -0
  564. package/dist/lib/link-security-handler.d.ts.map +1 -0
  565. package/dist/lib/link-security-handler.js +460 -0
  566. package/dist/lib/link-security-handler.js.map +1 -0
  567. package/dist/lib/logger.d.ts +100 -0
  568. package/dist/lib/logger.d.ts.map +1 -0
  569. package/dist/lib/logger.js +201 -0
  570. package/dist/lib/logger.js.map +1 -0
  571. package/dist/lib/media-cleanup-handler.d.ts +46 -0
  572. package/dist/lib/media-cleanup-handler.d.ts.map +1 -0
  573. package/dist/lib/media-cleanup-handler.js +190 -0
  574. package/dist/lib/media-cleanup-handler.js.map +1 -0
  575. package/dist/lib/media-handler.d.ts +150 -0
  576. package/dist/lib/media-handler.d.ts.map +1 -0
  577. package/dist/lib/media-handler.js +1544 -0
  578. package/dist/lib/media-handler.js.map +1 -0
  579. package/dist/lib/media-metadata-extractor.d.ts +71 -0
  580. package/dist/lib/media-metadata-extractor.d.ts.map +1 -0
  581. package/dist/lib/media-metadata-extractor.js +278 -0
  582. package/dist/lib/media-metadata-extractor.js.map +1 -0
  583. package/dist/lib/media-metrics.d.ts +57 -0
  584. package/dist/lib/media-metrics.d.ts.map +1 -0
  585. package/dist/lib/media-metrics.js +202 -0
  586. package/dist/lib/media-metrics.js.map +1 -0
  587. package/dist/lib/metadata/index.d.ts +6 -0
  588. package/dist/lib/metadata/index.d.ts.map +1 -0
  589. package/dist/lib/metadata/index.js +22 -0
  590. package/dist/lib/metadata/index.js.map +1 -0
  591. package/dist/lib/metadata/metadata-config.d.ts +17 -0
  592. package/dist/lib/metadata/metadata-config.d.ts.map +1 -0
  593. package/dist/lib/metadata/metadata-config.js +23 -0
  594. package/dist/lib/metadata/metadata-config.js.map +1 -0
  595. package/dist/lib/metadata/metadata-errors.d.ts +18 -0
  596. package/dist/lib/metadata/metadata-errors.d.ts.map +1 -0
  597. package/dist/lib/metadata/metadata-errors.js +26 -0
  598. package/dist/lib/metadata/metadata-errors.js.map +1 -0
  599. package/dist/lib/metadata/metadata-extractor.d.ts +17 -0
  600. package/dist/lib/metadata/metadata-extractor.d.ts.map +1 -0
  601. package/dist/lib/metadata/metadata-extractor.js +264 -0
  602. package/dist/lib/metadata/metadata-extractor.js.map +1 -0
  603. package/dist/lib/metadata/metadata-sanitizer.d.ts +9 -0
  604. package/dist/lib/metadata/metadata-sanitizer.d.ts.map +1 -0
  605. package/dist/lib/metadata/metadata-sanitizer.js +100 -0
  606. package/dist/lib/metadata/metadata-sanitizer.js.map +1 -0
  607. package/dist/lib/metadata/metadata-schemas.d.ts +131 -0
  608. package/dist/lib/metadata/metadata-schemas.d.ts.map +1 -0
  609. package/dist/lib/metadata/metadata-schemas.js +71 -0
  610. package/dist/lib/metadata/metadata-schemas.js.map +1 -0
  611. package/dist/lib/mfa/mfa-handler.d.ts +60 -0
  612. package/dist/lib/mfa/mfa-handler.d.ts.map +1 -0
  613. package/dist/lib/mfa/mfa-handler.js +150 -0
  614. package/dist/lib/mfa/mfa-handler.js.map +1 -0
  615. package/dist/lib/mfa/totp-service.d.ts +41 -0
  616. package/dist/lib/mfa/totp-service.d.ts.map +1 -0
  617. package/dist/lib/mfa/totp-service.js +183 -0
  618. package/dist/lib/mfa/totp-service.js.map +1 -0
  619. package/dist/lib/middleware/comment-rate-limit.d.ts +19 -0
  620. package/dist/lib/middleware/comment-rate-limit.d.ts.map +1 -0
  621. package/dist/lib/middleware/comment-rate-limit.js +113 -0
  622. package/dist/lib/middleware/comment-rate-limit.js.map +1 -0
  623. package/dist/lib/middleware/feature-toggle-rate-limit.d.ts +53 -0
  624. package/dist/lib/middleware/feature-toggle-rate-limit.d.ts.map +1 -0
  625. package/dist/lib/middleware/feature-toggle-rate-limit.js +164 -0
  626. package/dist/lib/middleware/feature-toggle-rate-limit.js.map +1 -0
  627. package/dist/lib/middleware.d.ts +70 -0
  628. package/dist/lib/middleware.d.ts.map +1 -0
  629. package/dist/lib/middleware.js +375 -0
  630. package/dist/lib/middleware.js.map +1 -0
  631. package/dist/lib/moderation-handler.d.ts +55 -0
  632. package/dist/lib/moderation-handler.d.ts.map +1 -0
  633. package/dist/lib/moderation-handler.js +230 -0
  634. package/dist/lib/moderation-handler.js.map +1 -0
  635. package/dist/lib/notification-handler.d.ts +65 -0
  636. package/dist/lib/notification-handler.d.ts.map +1 -0
  637. package/dist/lib/notification-handler.js +236 -0
  638. package/dist/lib/notification-handler.js.map +1 -0
  639. package/dist/lib/notification-preferences-handler.d.ts +27 -0
  640. package/dist/lib/notification-preferences-handler.d.ts.map +1 -0
  641. package/dist/lib/notification-preferences-handler.js +119 -0
  642. package/dist/lib/notification-preferences-handler.js.map +1 -0
  643. package/dist/lib/openai-budget.d.ts +45 -0
  644. package/dist/lib/openai-budget.d.ts.map +1 -0
  645. package/dist/lib/openai-budget.js +175 -0
  646. package/dist/lib/openai-budget.js.map +1 -0
  647. package/dist/lib/orphaned-media-handler.d.ts +60 -0
  648. package/dist/lib/orphaned-media-handler.d.ts.map +1 -0
  649. package/dist/lib/orphaned-media-handler.js +487 -0
  650. package/dist/lib/orphaned-media-handler.js.map +1 -0
  651. package/dist/lib/parental-control-handler.d.ts +42 -0
  652. package/dist/lib/parental-control-handler.d.ts.map +1 -0
  653. package/dist/lib/parental-control-handler.js +327 -0
  654. package/dist/lib/parental-control-handler.js.map +1 -0
  655. package/dist/lib/parental-link-handler.d.ts +38 -0
  656. package/dist/lib/parental-link-handler.d.ts.map +1 -0
  657. package/dist/lib/parental-link-handler.js +217 -0
  658. package/dist/lib/parental-link-handler.js.map +1 -0
  659. package/dist/lib/performance-metrics.d.ts +125 -0
  660. package/dist/lib/performance-metrics.d.ts.map +1 -0
  661. package/dist/lib/performance-metrics.js +277 -0
  662. package/dist/lib/performance-metrics.js.map +1 -0
  663. package/dist/lib/post-handler.d.ts +94 -0
  664. package/dist/lib/post-handler.d.ts.map +1 -0
  665. package/dist/lib/post-handler.js +1346 -0
  666. package/dist/lib/post-handler.js.map +1 -0
  667. package/dist/lib/privacy-defaults.d.ts +32 -0
  668. package/dist/lib/privacy-defaults.d.ts.map +1 -0
  669. package/dist/lib/privacy-defaults.js +85 -0
  670. package/dist/lib/privacy-defaults.js.map +1 -0
  671. package/dist/lib/privacy-handler.d.ts +43 -0
  672. package/dist/lib/privacy-handler.d.ts.map +1 -0
  673. package/dist/lib/privacy-handler.js +124 -0
  674. package/dist/lib/privacy-handler.js.map +1 -0
  675. package/dist/lib/queue/sqs-queue.d.ts +16 -0
  676. package/dist/lib/queue/sqs-queue.d.ts.map +1 -0
  677. package/dist/lib/queue/sqs-queue.js +39 -0
  678. package/dist/lib/queue/sqs-queue.js.map +1 -0
  679. package/dist/lib/queue-consumers/media-reconciliation-consumer.d.ts +9 -0
  680. package/dist/lib/queue-consumers/media-reconciliation-consumer.d.ts.map +1 -0
  681. package/dist/lib/queue-consumers/media-reconciliation-consumer.js +37 -0
  682. package/dist/lib/queue-consumers/media-reconciliation-consumer.js.map +1 -0
  683. package/dist/lib/quiet-hours.d.ts +33 -0
  684. package/dist/lib/quiet-hours.d.ts.map +1 -0
  685. package/dist/lib/quiet-hours.js +51 -0
  686. package/dist/lib/quiet-hours.js.map +1 -0
  687. package/dist/lib/rate-limit.d.ts +95 -0
  688. package/dist/lib/rate-limit.d.ts.map +1 -0
  689. package/dist/lib/rate-limit.js +247 -0
  690. package/dist/lib/rate-limit.js.map +1 -0
  691. package/dist/lib/reaction-handler.d.ts +68 -0
  692. package/dist/lib/reaction-handler.d.ts.map +1 -0
  693. package/dist/lib/reaction-handler.js +858 -0
  694. package/dist/lib/reaction-handler.js.map +1 -0
  695. package/dist/lib/recaptcha.d.ts +16 -0
  696. package/dist/lib/recaptcha.d.ts.map +1 -0
  697. package/dist/lib/recaptcha.js +71 -0
  698. package/dist/lib/recaptcha.js.map +1 -0
  699. package/dist/lib/redirect-resolver.d.ts +78 -0
  700. package/dist/lib/redirect-resolver.d.ts.map +1 -0
  701. package/dist/lib/redirect-resolver.js +276 -0
  702. package/dist/lib/redirect-resolver.js.map +1 -0
  703. package/dist/lib/region-config.d.ts +179 -0
  704. package/dist/lib/region-config.d.ts.map +1 -0
  705. package/dist/lib/region-config.js +474 -0
  706. package/dist/lib/region-config.js.map +1 -0
  707. package/dist/lib/region-detection.d.ts +110 -0
  708. package/dist/lib/region-detection.d.ts.map +1 -0
  709. package/dist/lib/region-detection.js +408 -0
  710. package/dist/lib/region-detection.js.map +1 -0
  711. package/dist/lib/relationship-handler.d.ts +19 -0
  712. package/dist/lib/relationship-handler.d.ts.map +1 -0
  713. package/dist/lib/relationship-handler.js +233 -0
  714. package/dist/lib/relationship-handler.js.map +1 -0
  715. package/dist/lib/request-context.d.ts +103 -0
  716. package/dist/lib/request-context.d.ts.map +1 -0
  717. package/dist/lib/request-context.js +179 -0
  718. package/dist/lib/request-context.js.map +1 -0
  719. package/dist/lib/route-helpers.d.ts +74 -0
  720. package/dist/lib/route-helpers.d.ts.map +1 -0
  721. package/dist/lib/route-helpers.js +190 -0
  722. package/dist/lib/route-helpers.js.map +1 -0
  723. package/dist/lib/route-matcher.d.ts +24 -0
  724. package/dist/lib/route-matcher.d.ts.map +1 -0
  725. package/dist/lib/route-matcher.js +96 -0
  726. package/dist/lib/route-matcher.js.map +1 -0
  727. package/dist/lib/router.d.ts +26 -0
  728. package/dist/lib/router.d.ts.map +1 -0
  729. package/dist/lib/router.js +90 -0
  730. package/dist/lib/router.js.map +1 -0
  731. package/dist/lib/routes/activitypub/actor.d.ts +12 -0
  732. package/dist/lib/routes/activitypub/actor.d.ts.map +1 -0
  733. package/dist/lib/routes/activitypub/actor.js +141 -0
  734. package/dist/lib/routes/activitypub/actor.js.map +1 -0
  735. package/dist/lib/routes/activitypub/audiences.d.ts +12 -0
  736. package/dist/lib/routes/activitypub/audiences.d.ts.map +1 -0
  737. package/dist/lib/routes/activitypub/audiences.js +325 -0
  738. package/dist/lib/routes/activitypub/audiences.js.map +1 -0
  739. package/dist/lib/routes/activitypub/collections.d.ts +12 -0
  740. package/dist/lib/routes/activitypub/collections.d.ts.map +1 -0
  741. package/dist/lib/routes/activitypub/collections.js +127 -0
  742. package/dist/lib/routes/activitypub/collections.js.map +1 -0
  743. package/dist/lib/routes/activitypub/entity-profile.d.ts +9 -0
  744. package/dist/lib/routes/activitypub/entity-profile.d.ts.map +1 -0
  745. package/dist/lib/routes/activitypub/entity-profile.js +136 -0
  746. package/dist/lib/routes/activitypub/entity-profile.js.map +1 -0
  747. package/dist/lib/routes/activitypub/friends.d.ts +15 -0
  748. package/dist/lib/routes/activitypub/friends.d.ts.map +1 -0
  749. package/dist/lib/routes/activitypub/friends.js +33 -0
  750. package/dist/lib/routes/activitypub/friends.js.map +1 -0
  751. package/dist/lib/routes/activitypub/group.d.ts +8 -0
  752. package/dist/lib/routes/activitypub/group.d.ts.map +1 -0
  753. package/dist/lib/routes/activitypub/group.js +436 -0
  754. package/dist/lib/routes/activitypub/group.js.map +1 -0
  755. package/dist/lib/routes/activitypub/inbox.d.ts +15 -0
  756. package/dist/lib/routes/activitypub/inbox.d.ts.map +1 -0
  757. package/dist/lib/routes/activitypub/inbox.js +125 -0
  758. package/dist/lib/routes/activitypub/inbox.js.map +1 -0
  759. package/dist/lib/routes/activitypub/messages.d.ts +12 -0
  760. package/dist/lib/routes/activitypub/messages.d.ts.map +1 -0
  761. package/dist/lib/routes/activitypub/messages.js +374 -0
  762. package/dist/lib/routes/activitypub/messages.js.map +1 -0
  763. package/dist/lib/routes/activitypub/outbox.d.ts +15 -0
  764. package/dist/lib/routes/activitypub/outbox.d.ts.map +1 -0
  765. package/dist/lib/routes/activitypub/outbox.js +33 -0
  766. package/dist/lib/routes/activitypub/outbox.js.map +1 -0
  767. package/dist/lib/routes/activitypub/post.d.ts +12 -0
  768. package/dist/lib/routes/activitypub/post.d.ts.map +1 -0
  769. package/dist/lib/routes/activitypub/post.js +213 -0
  770. package/dist/lib/routes/activitypub/post.js.map +1 -0
  771. package/dist/lib/routes/activitypub/webfinger.d.ts +11 -0
  772. package/dist/lib/routes/activitypub/webfinger.d.ts.map +1 -0
  773. package/dist/lib/routes/activitypub/webfinger.js +27 -0
  774. package/dist/lib/routes/activitypub/webfinger.js.map +1 -0
  775. package/dist/lib/routes/admin-costs.d.ts +8 -0
  776. package/dist/lib/routes/admin-costs.d.ts.map +1 -0
  777. package/dist/lib/routes/admin-costs.js +89 -0
  778. package/dist/lib/routes/admin-costs.js.map +1 -0
  779. package/dist/lib/routes/admin.d.ts +6 -0
  780. package/dist/lib/routes/admin.d.ts.map +1 -0
  781. package/dist/lib/routes/admin.js +1450 -0
  782. package/dist/lib/routes/admin.js.map +1 -0
  783. package/dist/lib/routes/auth.d.ts +6 -0
  784. package/dist/lib/routes/auth.d.ts.map +1 -0
  785. package/dist/lib/routes/auth.js +49 -0
  786. package/dist/lib/routes/auth.js.map +1 -0
  787. package/dist/lib/routes/badges.d.ts +6 -0
  788. package/dist/lib/routes/badges.d.ts.map +1 -0
  789. package/dist/lib/routes/badges.js +66 -0
  790. package/dist/lib/routes/badges.js.map +1 -0
  791. package/dist/lib/routes/circles.d.ts +8 -0
  792. package/dist/lib/routes/circles.d.ts.map +1 -0
  793. package/dist/lib/routes/circles.js +135 -0
  794. package/dist/lib/routes/circles.js.map +1 -0
  795. package/dist/lib/routes/comments.d.ts +6 -0
  796. package/dist/lib/routes/comments.d.ts.map +1 -0
  797. package/dist/lib/routes/comments.js +228 -0
  798. package/dist/lib/routes/comments.js.map +1 -0
  799. package/dist/lib/routes/connection-codes.d.ts +8 -0
  800. package/dist/lib/routes/connection-codes.d.ts.map +1 -0
  801. package/dist/lib/routes/connection-codes.js +84 -0
  802. package/dist/lib/routes/connection-codes.js.map +1 -0
  803. package/dist/lib/routes/content-discovery.d.ts +11 -0
  804. package/dist/lib/routes/content-discovery.d.ts.map +1 -0
  805. package/dist/lib/routes/content-discovery.js +211 -0
  806. package/dist/lib/routes/content-discovery.js.map +1 -0
  807. package/dist/lib/routes/dashboard.d.ts +8 -0
  808. package/dist/lib/routes/dashboard.d.ts.map +1 -0
  809. package/dist/lib/routes/dashboard.js +1139 -0
  810. package/dist/lib/routes/dashboard.js.map +1 -0
  811. package/dist/lib/routes/deletion.d.ts +6 -0
  812. package/dist/lib/routes/deletion.d.ts.map +1 -0
  813. package/dist/lib/routes/deletion.js +213 -0
  814. package/dist/lib/routes/deletion.js.map +1 -0
  815. package/dist/lib/routes/discovery.d.ts +8 -0
  816. package/dist/lib/routes/discovery.d.ts.map +1 -0
  817. package/dist/lib/routes/discovery.js +67 -0
  818. package/dist/lib/routes/discovery.js.map +1 -0
  819. package/dist/lib/routes/employees.d.ts +6 -0
  820. package/dist/lib/routes/employees.d.ts.map +1 -0
  821. package/dist/lib/routes/employees.js +82 -0
  822. package/dist/lib/routes/employees.js.map +1 -0
  823. package/dist/lib/routes/entities.d.ts +8 -0
  824. package/dist/lib/routes/entities.d.ts.map +1 -0
  825. package/dist/lib/routes/entities.js +467 -0
  826. package/dist/lib/routes/entities.js.map +1 -0
  827. package/dist/lib/routes/entity-relationships.d.ts +8 -0
  828. package/dist/lib/routes/entity-relationships.d.ts.map +1 -0
  829. package/dist/lib/routes/entity-relationships.js +118 -0
  830. package/dist/lib/routes/entity-relationships.js.map +1 -0
  831. package/dist/lib/routes/export.d.ts +6 -0
  832. package/dist/lib/routes/export.d.ts.map +1 -0
  833. package/dist/lib/routes/export.js +118 -0
  834. package/dist/lib/routes/export.js.map +1 -0
  835. package/dist/lib/routes/feature-flags.d.ts +8 -0
  836. package/dist/lib/routes/feature-flags.d.ts.map +1 -0
  837. package/dist/lib/routes/feature-flags.js +75 -0
  838. package/dist/lib/routes/feature-flags.js.map +1 -0
  839. package/dist/lib/routes/feeds.d.ts +6 -0
  840. package/dist/lib/routes/feeds.d.ts.map +1 -0
  841. package/dist/lib/routes/feeds.js +131 -0
  842. package/dist/lib/routes/feeds.js.map +1 -0
  843. package/dist/lib/routes/followers.d.ts +6 -0
  844. package/dist/lib/routes/followers.d.ts.map +1 -0
  845. package/dist/lib/routes/followers.js +405 -0
  846. package/dist/lib/routes/followers.js.map +1 -0
  847. package/dist/lib/routes/friends.d.ts +6 -0
  848. package/dist/lib/routes/friends.d.ts.map +1 -0
  849. package/dist/lib/routes/friends.js +116 -0
  850. package/dist/lib/routes/friends.js.map +1 -0
  851. package/dist/lib/routes/health.d.ts +6 -0
  852. package/dist/lib/routes/health.d.ts.map +1 -0
  853. package/dist/lib/routes/health.js +129 -0
  854. package/dist/lib/routes/health.js.map +1 -0
  855. package/dist/lib/routes/index.d.ts +21 -0
  856. package/dist/lib/routes/index.d.ts.map +1 -0
  857. package/dist/lib/routes/index.js +212 -0
  858. package/dist/lib/routes/index.js.map +1 -0
  859. package/dist/lib/routes/internal-docs.d.ts +6 -0
  860. package/dist/lib/routes/internal-docs.d.ts.map +1 -0
  861. package/dist/lib/routes/internal-docs.js +44 -0
  862. package/dist/lib/routes/internal-docs.js.map +1 -0
  863. package/dist/lib/routes/invitations.d.ts +6 -0
  864. package/dist/lib/routes/invitations.d.ts.map +1 -0
  865. package/dist/lib/routes/invitations.js +67 -0
  866. package/dist/lib/routes/invitations.js.map +1 -0
  867. package/dist/lib/routes/link-reports.d.ts +11 -0
  868. package/dist/lib/routes/link-reports.d.ts.map +1 -0
  869. package/dist/lib/routes/link-reports.js +287 -0
  870. package/dist/lib/routes/link-reports.js.map +1 -0
  871. package/dist/lib/routes/map.d.ts +6 -0
  872. package/dist/lib/routes/map.d.ts.map +1 -0
  873. package/dist/lib/routes/map.js +21 -0
  874. package/dist/lib/routes/map.js.map +1 -0
  875. package/dist/lib/routes/media-metadata-visibility.d.ts +3 -0
  876. package/dist/lib/routes/media-metadata-visibility.d.ts.map +1 -0
  877. package/dist/lib/routes/media-metadata-visibility.js +184 -0
  878. package/dist/lib/routes/media-metadata-visibility.js.map +1 -0
  879. package/dist/lib/routes/media.d.ts +9 -0
  880. package/dist/lib/routes/media.d.ts.map +1 -0
  881. package/dist/lib/routes/media.js +1910 -0
  882. package/dist/lib/routes/media.js.map +1 -0
  883. package/dist/lib/routes/mfa.d.ts +8 -0
  884. package/dist/lib/routes/mfa.d.ts.map +1 -0
  885. package/dist/lib/routes/mfa.js +193 -0
  886. package/dist/lib/routes/mfa.js.map +1 -0
  887. package/dist/lib/routes/notifications.d.ts +9 -0
  888. package/dist/lib/routes/notifications.d.ts.map +1 -0
  889. package/dist/lib/routes/notifications.js +230 -0
  890. package/dist/lib/routes/notifications.js.map +1 -0
  891. package/dist/lib/routes/orphaned-media-health.d.ts +9 -0
  892. package/dist/lib/routes/orphaned-media-health.d.ts.map +1 -0
  893. package/dist/lib/routes/orphaned-media-health.js +121 -0
  894. package/dist/lib/routes/orphaned-media-health.js.map +1 -0
  895. package/dist/lib/routes/orphaned-media.d.ts +8 -0
  896. package/dist/lib/routes/orphaned-media.d.ts.map +1 -0
  897. package/dist/lib/routes/orphaned-media.js +111 -0
  898. package/dist/lib/routes/orphaned-media.js.map +1 -0
  899. package/dist/lib/routes/out.d.ts +17 -0
  900. package/dist/lib/routes/out.d.ts.map +1 -0
  901. package/dist/lib/routes/out.js +339 -0
  902. package/dist/lib/routes/out.js.map +1 -0
  903. package/dist/lib/routes/parental-controls.d.ts +8 -0
  904. package/dist/lib/routes/parental-controls.d.ts.map +1 -0
  905. package/dist/lib/routes/parental-controls.js +282 -0
  906. package/dist/lib/routes/parental-controls.js.map +1 -0
  907. package/dist/lib/routes/posts.d.ts +6 -0
  908. package/dist/lib/routes/posts.d.ts.map +1 -0
  909. package/dist/lib/routes/posts.js +518 -0
  910. package/dist/lib/routes/posts.js.map +1 -0
  911. package/dist/lib/routes/privacy.d.ts +6 -0
  912. package/dist/lib/routes/privacy.d.ts.map +1 -0
  913. package/dist/lib/routes/privacy.js +66 -0
  914. package/dist/lib/routes/privacy.js.map +1 -0
  915. package/dist/lib/routes/products.d.ts +9 -0
  916. package/dist/lib/routes/products.d.ts.map +1 -0
  917. package/dist/lib/routes/products.js +224 -0
  918. package/dist/lib/routes/products.js.map +1 -0
  919. package/dist/lib/routes/relationships.d.ts +8 -0
  920. package/dist/lib/routes/relationships.d.ts.map +1 -0
  921. package/dist/lib/routes/relationships.js +118 -0
  922. package/dist/lib/routes/relationships.js.map +1 -0
  923. package/dist/lib/routes/sentiments.d.ts +6 -0
  924. package/dist/lib/routes/sentiments.d.ts.map +1 -0
  925. package/dist/lib/routes/sentiments.js +285 -0
  926. package/dist/lib/routes/sentiments.js.map +1 -0
  927. package/dist/lib/routes/taxonomy-analytics.d.ts +8 -0
  928. package/dist/lib/routes/taxonomy-analytics.d.ts.map +1 -0
  929. package/dist/lib/routes/taxonomy-analytics.js +151 -0
  930. package/dist/lib/routes/taxonomy-analytics.js.map +1 -0
  931. package/dist/lib/routes/taxonomy.d.ts +15 -0
  932. package/dist/lib/routes/taxonomy.d.ts.map +1 -0
  933. package/dist/lib/routes/taxonomy.js +370 -0
  934. package/dist/lib/routes/taxonomy.js.map +1 -0
  935. package/dist/lib/routes/types.d.ts +46 -0
  936. package/dist/lib/routes/types.d.ts.map +1 -0
  937. package/dist/lib/routes/types.js +8 -0
  938. package/dist/lib/routes/types.js.map +1 -0
  939. package/dist/lib/routes/upload-sessions.d.ts +9 -0
  940. package/dist/lib/routes/upload-sessions.d.ts.map +1 -0
  941. package/dist/lib/routes/upload-sessions.js +268 -0
  942. package/dist/lib/routes/upload-sessions.js.map +1 -0
  943. package/dist/lib/routes/user.d.ts +8 -0
  944. package/dist/lib/routes/user.d.ts.map +1 -0
  945. package/dist/lib/routes/user.js +287 -0
  946. package/dist/lib/routes/user.js.map +1 -0
  947. package/dist/lib/routes-all.d.ts +9 -0
  948. package/dist/lib/routes-all.d.ts.map +1 -0
  949. package/dist/lib/routes-all.js +170 -0
  950. package/dist/lib/routes-all.js.map +1 -0
  951. package/dist/lib/routes.d.ts +10 -0
  952. package/dist/lib/routes.d.ts.map +1 -0
  953. package/dist/lib/routes.js +16 -0
  954. package/dist/lib/routes.js.map +1 -0
  955. package/dist/lib/scaling-health.d.ts +48 -0
  956. package/dist/lib/scaling-health.d.ts.map +1 -0
  957. package/dist/lib/scaling-health.js +363 -0
  958. package/dist/lib/scaling-health.js.map +1 -0
  959. package/dist/lib/scheduled/media-stale-cleanup.d.ts +11 -0
  960. package/dist/lib/scheduled/media-stale-cleanup.d.ts.map +1 -0
  961. package/dist/lib/scheduled/media-stale-cleanup.js +79 -0
  962. package/dist/lib/scheduled/media-stale-cleanup.js.map +1 -0
  963. package/dist/lib/scheduled/orphaned-media-monitor.d.ts +97 -0
  964. package/dist/lib/scheduled/orphaned-media-monitor.d.ts.map +1 -0
  965. package/dist/lib/scheduled/orphaned-media-monitor.js +399 -0
  966. package/dist/lib/scheduled/orphaned-media-monitor.js.map +1 -0
  967. package/dist/lib/schemas.d.ts +314 -0
  968. package/dist/lib/schemas.d.ts.map +1 -0
  969. package/dist/lib/schemas.js +235 -0
  970. package/dist/lib/schemas.js.map +1 -0
  971. package/dist/lib/secret-resolver.d.ts +88 -0
  972. package/dist/lib/secret-resolver.d.ts.map +1 -0
  973. package/dist/lib/secret-resolver.js +183 -0
  974. package/dist/lib/secret-resolver.js.map +1 -0
  975. package/dist/lib/security-event-cleaner.d.ts +61 -0
  976. package/dist/lib/security-event-cleaner.d.ts.map +1 -0
  977. package/dist/lib/security-event-cleaner.js +74 -0
  978. package/dist/lib/security-event-cleaner.js.map +1 -0
  979. package/dist/lib/security-headers.d.ts +36 -0
  980. package/dist/lib/security-headers.d.ts.map +1 -0
  981. package/dist/lib/security-headers.js +87 -0
  982. package/dist/lib/security-headers.js.map +1 -0
  983. package/dist/lib/security-monitor.d.ts +92 -0
  984. package/dist/lib/security-monitor.d.ts.map +1 -0
  985. package/dist/lib/security-monitor.js +287 -0
  986. package/dist/lib/security-monitor.js.map +1 -0
  987. package/dist/lib/sentiment-digest.d.ts +19 -0
  988. package/dist/lib/sentiment-digest.d.ts.map +1 -0
  989. package/dist/lib/sentiment-digest.js +99 -0
  990. package/dist/lib/sentiment-digest.js.map +1 -0
  991. package/dist/lib/sentiment-display.d.ts +20 -0
  992. package/dist/lib/sentiment-display.d.ts.map +1 -0
  993. package/dist/lib/sentiment-display.js +38 -0
  994. package/dist/lib/sentiment-display.js.map +1 -0
  995. package/dist/lib/services/image-normalizer.d.ts +15 -0
  996. package/dist/lib/services/image-normalizer.d.ts.map +1 -0
  997. package/dist/lib/services/image-normalizer.js +22 -0
  998. package/dist/lib/services/image-normalizer.js.map +1 -0
  999. package/dist/lib/services/media-reconciliation-service.d.ts +25 -0
  1000. package/dist/lib/services/media-reconciliation-service.d.ts.map +1 -0
  1001. package/dist/lib/services/media-reconciliation-service.js +191 -0
  1002. package/dist/lib/services/media-reconciliation-service.js.map +1 -0
  1003. package/dist/lib/services/media-upload-service.d.ts +25 -0
  1004. package/dist/lib/services/media-upload-service.d.ts.map +1 -0
  1005. package/dist/lib/services/media-upload-service.js +240 -0
  1006. package/dist/lib/services/media-upload-service.js.map +1 -0
  1007. package/dist/lib/services/user-data-deletion.d.ts +30 -0
  1008. package/dist/lib/services/user-data-deletion.d.ts.map +1 -0
  1009. package/dist/lib/services/user-data-deletion.js +118 -0
  1010. package/dist/lib/services/user-data-deletion.js.map +1 -0
  1011. package/dist/lib/session-awareness.d.ts +35 -0
  1012. package/dist/lib/session-awareness.d.ts.map +1 -0
  1013. package/dist/lib/session-awareness.js +79 -0
  1014. package/dist/lib/session-awareness.js.map +1 -0
  1015. package/dist/lib/session-config.d.ts +87 -0
  1016. package/dist/lib/session-config.d.ts.map +1 -0
  1017. package/dist/lib/session-config.js +165 -0
  1018. package/dist/lib/session-config.js.map +1 -0
  1019. package/dist/lib/session-manager.d.ts +103 -0
  1020. package/dist/lib/session-manager.d.ts.map +1 -0
  1021. package/dist/lib/session-manager.js +492 -0
  1022. package/dist/lib/session-manager.js.map +1 -0
  1023. package/dist/lib/sso-auth-handler.d.ts +12 -0
  1024. package/dist/lib/sso-auth-handler.d.ts.map +1 -0
  1025. package/dist/lib/sso-auth-handler.js +24 -0
  1026. package/dist/lib/sso-auth-handler.js.map +1 -0
  1027. package/dist/lib/storage/s3-storage.d.ts +29 -0
  1028. package/dist/lib/storage/s3-storage.d.ts.map +1 -0
  1029. package/dist/lib/storage/s3-storage.js +135 -0
  1030. package/dist/lib/storage/s3-storage.js.map +1 -0
  1031. package/dist/lib/tag-suggestions-handler.d.ts +52 -0
  1032. package/dist/lib/tag-suggestions-handler.d.ts.map +1 -0
  1033. package/dist/lib/tag-suggestions-handler.js +195 -0
  1034. package/dist/lib/tag-suggestions-handler.js.map +1 -0
  1035. package/dist/lib/taxonomy-handler-factory.d.ts +18 -0
  1036. package/dist/lib/taxonomy-handler-factory.d.ts.map +1 -0
  1037. package/dist/lib/taxonomy-handler-factory.js +29 -0
  1038. package/dist/lib/taxonomy-handler-factory.js.map +1 -0
  1039. package/dist/lib/taxonomy-handler.d.ts +142 -0
  1040. package/dist/lib/taxonomy-handler.d.ts.map +1 -0
  1041. package/dist/lib/taxonomy-handler.js +636 -0
  1042. package/dist/lib/taxonomy-handler.js.map +1 -0
  1043. package/dist/lib/taxonomy-metrics.d.ts +76 -0
  1044. package/dist/lib/taxonomy-metrics.d.ts.map +1 -0
  1045. package/dist/lib/taxonomy-metrics.js +201 -0
  1046. package/dist/lib/taxonomy-metrics.js.map +1 -0
  1047. package/dist/lib/taxonomy-search-metrics.d.ts +45 -0
  1048. package/dist/lib/taxonomy-search-metrics.d.ts.map +1 -0
  1049. package/dist/lib/taxonomy-search-metrics.js +75 -0
  1050. package/dist/lib/taxonomy-search-metrics.js.map +1 -0
  1051. package/dist/lib/tenant-context.d.ts +35 -0
  1052. package/dist/lib/tenant-context.d.ts.map +1 -0
  1053. package/dist/lib/tenant-context.js +54 -0
  1054. package/dist/lib/tenant-context.js.map +1 -0
  1055. package/dist/lib/terminology.d.ts +25 -0
  1056. package/dist/lib/terminology.d.ts.map +1 -0
  1057. package/dist/lib/terminology.js +44 -0
  1058. package/dist/lib/terminology.js.map +1 -0
  1059. package/dist/lib/theme.d.ts +29 -0
  1060. package/dist/lib/theme.d.ts.map +1 -0
  1061. package/dist/lib/theme.js +38 -0
  1062. package/dist/lib/theme.js.map +1 -0
  1063. package/dist/lib/threat-intel-service.d.ts +67 -0
  1064. package/dist/lib/threat-intel-service.d.ts.map +1 -0
  1065. package/dist/lib/threat-intel-service.js +193 -0
  1066. package/dist/lib/threat-intel-service.js.map +1 -0
  1067. package/dist/lib/types/media-reconciliation.d.ts +64 -0
  1068. package/dist/lib/types/media-reconciliation.d.ts.map +1 -0
  1069. package/dist/lib/types/media-reconciliation.js +8 -0
  1070. package/dist/lib/types/media-reconciliation.js.map +1 -0
  1071. package/dist/lib/upload-session-handler.d.ts +56 -0
  1072. package/dist/lib/upload-session-handler.d.ts.map +1 -0
  1073. package/dist/lib/upload-session-handler.js +312 -0
  1074. package/dist/lib/upload-session-handler.js.map +1 -0
  1075. package/dist/lib/user-badge.d.ts +56 -0
  1076. package/dist/lib/user-badge.d.ts.map +1 -0
  1077. package/dist/lib/user-badge.js +92 -0
  1078. package/dist/lib/user-badge.js.map +1 -0
  1079. package/dist/lib/user-deletion-handler-enhanced.d.ts +96 -0
  1080. package/dist/lib/user-deletion-handler-enhanced.d.ts.map +1 -0
  1081. package/dist/lib/user-deletion-handler-enhanced.js +401 -0
  1082. package/dist/lib/user-deletion-handler-enhanced.js.map +1 -0
  1083. package/dist/lib/user-deprovisioning.d.ts +43 -0
  1084. package/dist/lib/user-deprovisioning.d.ts.map +1 -0
  1085. package/dist/lib/user-deprovisioning.js +138 -0
  1086. package/dist/lib/user-deprovisioning.js.map +1 -0
  1087. package/dist/lib/user-export-handler.d.ts +172 -0
  1088. package/dist/lib/user-export-handler.d.ts.map +1 -0
  1089. package/dist/lib/user-export-handler.js +435 -0
  1090. package/dist/lib/user-export-handler.js.map +1 -0
  1091. package/dist/lib/validate-request.d.ts +46 -0
  1092. package/dist/lib/validate-request.d.ts.map +1 -0
  1093. package/dist/lib/validate-request.js +127 -0
  1094. package/dist/lib/validate-request.js.map +1 -0
  1095. package/dist/lib/validation/feature-toggle-schemas.d.ts +410 -0
  1096. package/dist/lib/validation/feature-toggle-schemas.d.ts.map +1 -0
  1097. package/dist/lib/validation/feature-toggle-schemas.js +274 -0
  1098. package/dist/lib/validation/feature-toggle-schemas.js.map +1 -0
  1099. package/dist/lib/validation/validate-request.d.ts +75 -0
  1100. package/dist/lib/validation/validate-request.d.ts.map +1 -0
  1101. package/dist/lib/validation/validate-request.js +183 -0
  1102. package/dist/lib/validation/validate-request.js.map +1 -0
  1103. package/dist/lib/validation.d.ts +50 -0
  1104. package/dist/lib/validation.d.ts.map +1 -0
  1105. package/dist/lib/validation.js +122 -0
  1106. package/dist/lib/validation.js.map +1 -0
  1107. package/dist/lib/version.d.ts +36 -0
  1108. package/dist/lib/version.d.ts.map +1 -0
  1109. package/dist/lib/version.js +44 -0
  1110. package/dist/lib/version.js.map +1 -0
  1111. package/dist/server.d.ts +13 -0
  1112. package/dist/server.d.ts.map +1 -0
  1113. package/dist/server.js +254 -0
  1114. package/dist/server.js.map +1 -0
  1115. package/dist/types/cloudflare-compat.d.ts +134 -0
  1116. package/dist/types/cloudflare-compat.d.ts.map +1 -0
  1117. package/dist/types/cloudflare-compat.js +7 -0
  1118. package/dist/types/cloudflare-compat.js.map +1 -0
  1119. package/dist/worker.d.ts +16 -0
  1120. package/dist/worker.d.ts.map +1 -0
  1121. package/dist/worker.js +21 -0
  1122. package/dist/worker.js.map +1 -0
  1123. package/package.json +91 -0
  1124. package/src/lambda/cleanup-cron.ts +37 -0
  1125. package/src/lambda/create-auth-challenge.ts +112 -0
  1126. package/src/lambda/custom-message.ts +30 -0
  1127. package/src/lambda/define-auth-challenge.ts +24 -0
  1128. package/src/lambda/delete-account-worker.ts +96 -0
  1129. package/src/lambda/diagnostics-proxy.ts +139 -0
  1130. package/src/lambda/e2e-sweeper.ts +140 -0
  1131. package/src/lambda/federation-outbox-worker.ts +8 -0
  1132. package/src/lambda/followers-events-worker.ts +8 -0
  1133. package/src/lambda/hourly-cron.ts +103 -0
  1134. package/src/lambda/link-check-worker.ts +8 -0
  1135. package/src/lambda/maintenance-cron.ts +95 -0
  1136. package/src/lambda/media-processing-worker.ts +68 -0
  1137. package/src/lambda/media-reconciliation-worker.ts +8 -0
  1138. package/src/lambda/nightly-cron.ts +338 -0
  1139. package/src/lambda/post-confirmation.ts +80 -0
  1140. package/src/lambda/pre-signup.ts +39 -0
  1141. package/src/lambda/pre-token-generation.ts +93 -0
  1142. package/src/lambda/tools/check-health.ts +22 -0
  1143. package/src/lambda/tools/describe-services.ts +45 -0
  1144. package/src/lambda/tools/get-cost-report.ts +64 -0
  1145. package/src/lambda/tools/get-errors.ts +78 -0
  1146. package/src/lambda/tools/get-feature-flags.ts +27 -0
  1147. package/src/lambda/tools/get-queue-status.ts +60 -0
  1148. package/src/lambda/tools/search-logs.ts +75 -0
  1149. package/src/lambda/tools/send-alert.ts +37 -0
  1150. package/src/lambda/verify-auth-challenge.ts +37 -0
@@ -0,0 +1,1910 @@
1
+ "use strict";
2
+ /**
3
+ * Media Routes
4
+ *
5
+ * Handles media file uploads (images, videos) for posts and profiles.
6
+ * Implements content-addressed storage (CAS) with SHA-256 hashing for deduplication.
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.mediaRoutes = void 0;
43
+ const cors_handler_1 = require("../cors-handler");
44
+ const database_connection_manager_1 = require("../database-connection-manager");
45
+ const db_query_helper_1 = require("../db-query-helper");
46
+ const logger_1 = require("../logger");
47
+ const media_handler_1 = require("../media-handler");
48
+ const middleware_1 = require("../middleware");
49
+ const rate_limit_1 = require("../rate-limit");
50
+ const secret_resolver_1 = require("../secret-resolver");
51
+ const security_headers_1 = require("../security-headers");
52
+ const session_manager_1 = require("../session-manager");
53
+ const image_normalizer_1 = require("../services/image-normalizer");
54
+ const media_upload_service_1 = require("../services/media-upload-service");
55
+ /**
56
+ * Generate SHA-256 content hash for content-addressed storage
57
+ */
58
+ async function generateContentHash(file) {
59
+ const hashBuffer = await crypto.subtle.digest("SHA-256", file);
60
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
61
+ return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
62
+ }
63
+ /**
64
+ * Get file extension from MIME type
65
+ */
66
+ function getExtensionFromMimeType(mimeType) {
67
+ const mimeMap = {
68
+ "image/jpeg": "jpg",
69
+ "image/jpg": "jpg",
70
+ "image/png": "png",
71
+ "image/gif": "gif",
72
+ "image/webp": "webp",
73
+ "video/mp4": "mp4",
74
+ "video/webm": "webm",
75
+ "video/quicktime": "mov",
76
+ };
77
+ return mimeMap[mimeType] || "bin";
78
+ }
79
+ /**
80
+ * Validate magic numbers (file signatures) to ensure file type matches declared MIME type
81
+ */
82
+ function validateMagicNumbers(bytes, declaredMimeType) {
83
+ // JPEG: FF D8 FF
84
+ if (declaredMimeType === "image/jpeg" || declaredMimeType === "image/jpg") {
85
+ if (bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {
86
+ return true;
87
+ }
88
+ }
89
+ // PNG: 89 50 4E 47 0D 0A 1A 0A
90
+ if (declaredMimeType === "image/png") {
91
+ if (bytes[0] === 0x89 &&
92
+ bytes[1] === 0x50 &&
93
+ bytes[2] === 0x4e &&
94
+ bytes[3] === 0x47 &&
95
+ bytes[4] === 0x0d &&
96
+ bytes[5] === 0x0a &&
97
+ bytes[6] === 0x1a &&
98
+ bytes[7] === 0x0a) {
99
+ return true;
100
+ }
101
+ }
102
+ // GIF: 47 49 46 38 (GIF8)
103
+ if (declaredMimeType === "image/gif") {
104
+ if (bytes[0] === 0x47 &&
105
+ bytes[1] === 0x49 &&
106
+ bytes[2] === 0x46 &&
107
+ bytes[3] === 0x38) {
108
+ return true;
109
+ }
110
+ }
111
+ // WebP: RIFF ... WEBP
112
+ if (declaredMimeType === "image/webp") {
113
+ if (bytes[0] === 0x52 &&
114
+ bytes[1] === 0x49 &&
115
+ bytes[2] === 0x46 &&
116
+ bytes[3] === 0x46 &&
117
+ bytes.length >= 12 &&
118
+ bytes[8] === 0x57 &&
119
+ bytes[9] === 0x45 &&
120
+ bytes[10] === 0x42 &&
121
+ bytes[11] === 0x50) {
122
+ return true;
123
+ }
124
+ }
125
+ // MP4: ftyp box at offset 4
126
+ if (declaredMimeType === "video/mp4") {
127
+ // MP4 files start with ftyp box: bytes 4-7 should be "ftyp"
128
+ if (bytes.length >= 8 &&
129
+ bytes[4] === 0x66 &&
130
+ bytes[5] === 0x74 &&
131
+ bytes[6] === 0x79 &&
132
+ bytes[7] === 0x70) {
133
+ return true;
134
+ }
135
+ }
136
+ // WebM: starts with 1A 45 DF A3
137
+ if (declaredMimeType === "video/webm") {
138
+ if (bytes[0] === 0x1a &&
139
+ bytes[1] === 0x45 &&
140
+ bytes[2] === 0xdf &&
141
+ bytes[3] === 0xa3) {
142
+ return true;
143
+ }
144
+ }
145
+ // QuickTime: ftyp box (similar to MP4)
146
+ if (declaredMimeType === "video/quicktime") {
147
+ if (bytes.length >= 8 &&
148
+ bytes[4] === 0x66 &&
149
+ bytes[5] === 0x74 &&
150
+ bytes[6] === 0x79 &&
151
+ bytes[7] === 0x70) {
152
+ return true;
153
+ }
154
+ }
155
+ // HEIC/HEIF: ISO Base Media File Format with ftyp box
156
+ if (declaredMimeType === "image/heic" || declaredMimeType === "image/heif") {
157
+ if (bytes.length >= 8 &&
158
+ bytes[0] === 0x00 &&
159
+ bytes[1] === 0x00 &&
160
+ bytes[2] === 0x00 &&
161
+ bytes[4] === 0x66 &&
162
+ bytes[5] === 0x74 &&
163
+ bytes[6] === 0x79 &&
164
+ bytes[7] === 0x70) {
165
+ return true;
166
+ }
167
+ }
168
+ return false;
169
+ }
170
+ /**
171
+ * Serve media file by content hash with variant support
172
+ * Shared function used by both /api/media/:mediaId and /api/media/:hash routes
173
+ */
174
+ async function serveMediaByHash(contentHash, variant, request, env, session) {
175
+ const logger = logger_1.Logger.getInstance(env);
176
+ logger.debug("SERVE MEDIA BY HASH: Starting", {
177
+ contentHash,
178
+ variant,
179
+ userId: session.userId,
180
+ });
181
+ const securityHeaders = new security_headers_1.SecurityHeaders(env);
182
+ try {
183
+ // Wrap entire function in try-catch to catch any unexpected errors
184
+ logger.debug("SERVE MEDIA: Inside try block");
185
+ // Find media file in database - using retry logic
186
+ let mediaFile = null;
187
+ try {
188
+ const region = "US"; // TODO: Get from session or request
189
+ // Using retry logic with exponential backoff for connection resilience
190
+ mediaFile = await (0, db_query_helper_1.withQueryTimeoutAndRetry)(database_connection_manager_1.sharedDatabaseConnectionManager, region, env, async (db) => {
191
+ const dbAny = db;
192
+ if (dbAny.mediaFile) {
193
+ return await dbAny.mediaFile.findUnique({
194
+ where: { contentHash },
195
+ });
196
+ }
197
+ return null;
198
+ }, {
199
+ ...db_query_helper_1.QueryTimeoutPresets.USER_FACING,
200
+ maxRetries: 3,
201
+ baseDelayMs: 100,
202
+ context: {
203
+ operation: "media_get",
204
+ contentHash,
205
+ },
206
+ });
207
+ if (!mediaFile) {
208
+ logger.debug("MediaFile not found in database, using fallback key lookup", {
209
+ contentHash,
210
+ variant,
211
+ });
212
+ }
213
+ else {
214
+ logger.debug("MediaFile found in database", {
215
+ contentHash,
216
+ variant,
217
+ originalKey: mediaFile.originalKey,
218
+ optimizedKey: mediaFile.optimizedKey,
219
+ thumbnailKey: mediaFile.thumbnailKey,
220
+ });
221
+ }
222
+ }
223
+ catch (error) {
224
+ logger.warn("Failed to query MediaFile, using fallback key lookup", {
225
+ error: error.message,
226
+ contentHash,
227
+ variant,
228
+ });
229
+ }
230
+ // Fetch from R2
231
+ const r2Bucket = env.MEDIA_BUCKET_R2 || env.R2_BUCKET;
232
+ if (!r2Bucket) {
233
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({ error: "Media storage not configured" }), { status: 503, headers: { "content-type": "application/json" } });
234
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
235
+ }
236
+ // Determine which R2 key to serve
237
+ let r2Key = null;
238
+ let contentType = "application/octet-stream";
239
+ if (mediaFile) {
240
+ logger.debug("SERVE MEDIA: Found database record", {
241
+ contentHash,
242
+ variant,
243
+ hasOriginalKey: !!mediaFile.originalKey,
244
+ hasOptimizedKey: !!mediaFile.optimizedKey,
245
+ hasThumbnailKey: !!mediaFile.thumbnailKey,
246
+ originalKey: mediaFile.originalKey,
247
+ optimizedKey: mediaFile.optimizedKey,
248
+ thumbnailKey: mediaFile.thumbnailKey,
249
+ });
250
+ switch (variant) {
251
+ case "thumbnail":
252
+ r2Key =
253
+ mediaFile.thumbnailKey ||
254
+ mediaFile.optimizedKey ||
255
+ mediaFile.originalKey;
256
+ contentType =
257
+ mediaFile.thumbnailKey || mediaFile.optimizedKey
258
+ ? "image/webp"
259
+ : mediaFile.mimeType || "application/octet-stream";
260
+ break;
261
+ case "optimized":
262
+ // For optimized variant, prefer optimized but ALWAYS fall back to original
263
+ r2Key = mediaFile.optimizedKey || mediaFile.originalKey;
264
+ // If still no key, this is a data integrity issue - log and continue to fallback
265
+ if (!r2Key) {
266
+ logger.error("SERVE MEDIA: Database record has no keys!", {
267
+ contentHash,
268
+ mediaFileId: mediaFile.id,
269
+ });
270
+ }
271
+ contentType = mediaFile.optimizedKey
272
+ ? "image/webp"
273
+ : mediaFile.mimeType || "application/octet-stream";
274
+ break;
275
+ case "original":
276
+ r2Key = mediaFile.originalKey;
277
+ contentType = mediaFile.mimeType || "application/octet-stream";
278
+ break;
279
+ default:
280
+ // Default to optimized with fallback to original
281
+ r2Key = mediaFile.optimizedKey || mediaFile.originalKey;
282
+ contentType = mediaFile.optimizedKey
283
+ ? "image/webp"
284
+ : mediaFile.mimeType || "application/octet-stream";
285
+ }
286
+ logger.debug("SERVE MEDIA: Using database record", {
287
+ contentHash,
288
+ variant,
289
+ r2Key,
290
+ contentType,
291
+ hasOptimized: !!mediaFile.optimizedKey,
292
+ hasOriginal: !!mediaFile.originalKey,
293
+ });
294
+ // CRITICAL FIX: If r2Key is still null after using database record,
295
+ // fall back to R2 key lookup
296
+ if (!r2Key) {
297
+ logger.debug("SERVE MEDIA: Database record has no keys, falling back to R2 lookup", {
298
+ contentHash,
299
+ variant,
300
+ });
301
+ // Set mediaFile to null to trigger fallback logic
302
+ mediaFile = null;
303
+ }
304
+ }
305
+ if (!mediaFile) {
306
+ // Fallback: construct key from hash and variant
307
+ logger.debug("SERVE MEDIA: Using R2 fallback key lookup", {
308
+ contentHash,
309
+ variant,
310
+ });
311
+ const commonExtensions = ["jpg", "jpeg", "png", "webp", "gif"];
312
+ // First, try to find the original file with any extension
313
+ let foundOriginalKey = null;
314
+ let foundContentType = "image/jpeg";
315
+ for (const ext of commonExtensions) {
316
+ const testKey = `media/${contentHash}.${ext}`;
317
+ logger.debug("SERVE MEDIA: Trying R2 key", { testKey });
318
+ try {
319
+ const testObject = await r2Bucket.head(testKey);
320
+ if (testObject) {
321
+ foundOriginalKey = testKey;
322
+ foundContentType = `image/${ext === "jpg" ? "jpeg" : ext}`;
323
+ logger.debug("SERVE MEDIA: Found media file in R2 fallback", {
324
+ contentHash,
325
+ key: testKey,
326
+ contentType: foundContentType,
327
+ });
328
+ break;
329
+ }
330
+ }
331
+ catch (error) {
332
+ // head() can throw errors, continue trying other extensions
333
+ logger.debug("SERVE MEDIA: R2 head() failed for key", {
334
+ key: testKey,
335
+ error: error.message,
336
+ });
337
+ }
338
+ }
339
+ logger.debug("SERVE MEDIA: Original file search complete", {
340
+ foundOriginalKey,
341
+ foundContentType,
342
+ });
343
+ // Now determine which key to use based on variant
344
+ if (variant === "thumbnail") {
345
+ // Try thumbnail first
346
+ let foundThumb = false;
347
+ for (const ext of ["webp", ...commonExtensions]) {
348
+ const testKey = `media/${contentHash}_thumb.${ext}`;
349
+ try {
350
+ const testObject = await r2Bucket.head(testKey);
351
+ if (testObject) {
352
+ r2Key = testKey;
353
+ contentType = "image/webp";
354
+ foundThumb = true;
355
+ break;
356
+ }
357
+ }
358
+ catch (error) {
359
+ // head() can throw errors, continue trying other extensions
360
+ logger.debug("R2 head() failed for thumbnail key", {
361
+ key: testKey,
362
+ error: error.message,
363
+ });
364
+ }
365
+ }
366
+ // Fall back to optimized if no thumbnail
367
+ if (!foundThumb) {
368
+ for (const ext of ["webp", ...commonExtensions]) {
369
+ const testKey = `media/${contentHash}_opt.${ext}`;
370
+ try {
371
+ const testObject = await r2Bucket.head(testKey);
372
+ if (testObject) {
373
+ r2Key = testKey;
374
+ contentType = "image/webp";
375
+ foundThumb = true;
376
+ break;
377
+ }
378
+ }
379
+ catch (error) {
380
+ // head() can throw errors, continue trying other extensions
381
+ logger.debug("R2 head() failed for optimized key", {
382
+ key: testKey,
383
+ error: error.message,
384
+ });
385
+ }
386
+ }
387
+ }
388
+ // Fall back to original if no thumbnail or optimized
389
+ if (!foundThumb && foundOriginalKey) {
390
+ r2Key = foundOriginalKey;
391
+ contentType = foundContentType;
392
+ }
393
+ }
394
+ else if (variant === "optimized") {
395
+ // Try optimized first
396
+ logger.debug("SERVE MEDIA: Looking for optimized variant", {
397
+ contentHash,
398
+ });
399
+ let foundOpt = false;
400
+ for (const ext of ["webp", ...commonExtensions]) {
401
+ const testKey = `media/${contentHash}_opt.${ext}`;
402
+ logger.debug("SERVE MEDIA: Trying optimized key", { testKey });
403
+ try {
404
+ const testObject = await r2Bucket.head(testKey);
405
+ if (testObject) {
406
+ r2Key = testKey;
407
+ contentType = "image/webp";
408
+ foundOpt = true;
409
+ logger.debug("SERVE MEDIA: Found optimized variant", { testKey });
410
+ break;
411
+ }
412
+ }
413
+ catch (error) {
414
+ // head() can throw errors, continue trying other extensions
415
+ logger.debug("SERVE MEDIA: R2 head() failed for optimized key", {
416
+ key: testKey,
417
+ error: error.message,
418
+ });
419
+ }
420
+ }
421
+ // Fall back to original if no optimized version
422
+ // ALWAYS fall back to original if we didn't find an optimized version
423
+ if (!foundOpt) {
424
+ if (foundOriginalKey) {
425
+ r2Key = foundOriginalKey;
426
+ contentType = foundContentType;
427
+ logger.debug("SERVE MEDIA: Falling back to original for optimized variant", {
428
+ r2Key,
429
+ contentType,
430
+ });
431
+ }
432
+ else {
433
+ // If we still haven't found the original, log it for debugging
434
+ logger.debug("SERVE MEDIA: No optimized version found and foundOriginalKey is null", {
435
+ contentHash,
436
+ variant,
437
+ });
438
+ }
439
+ }
440
+ }
441
+ else {
442
+ // Original variant or any other variant: use the found original key
443
+ if (foundOriginalKey) {
444
+ r2Key = foundOriginalKey;
445
+ contentType = foundContentType;
446
+ }
447
+ }
448
+ }
449
+ logger.debug("SERVE MEDIA: Final R2 key selection", {
450
+ r2Key,
451
+ contentType,
452
+ variant,
453
+ contentHash,
454
+ hasMediaFile: !!mediaFile,
455
+ });
456
+ // CRITICAL FIX: If r2Key is still null at this point, try one more fallback
457
+ // This handles edge cases where the database record exists but has null keys,
458
+ // or the fallback R2 lookup failed for some reason
459
+ if (!r2Key) {
460
+ logger.debug("SERVE MEDIA: r2Key is null, attempting final fallback", {
461
+ contentHash,
462
+ variant,
463
+ });
464
+ // Try to find the file with common extensions
465
+ const commonExtensions = ["png", "jpg", "jpeg", "webp", "gif"];
466
+ for (const ext of commonExtensions) {
467
+ const testKey = `media/${contentHash}.${ext}`;
468
+ logger.debug("SERVE MEDIA: Final fallback trying key", { testKey });
469
+ try {
470
+ const testObject = await r2Bucket.head(testKey);
471
+ if (testObject) {
472
+ r2Key = testKey;
473
+ contentType = `image/${ext === "jpg" ? "jpeg" : ext}`;
474
+ logger.debug("SERVE MEDIA: Final fallback found file", {
475
+ r2Key,
476
+ contentType,
477
+ });
478
+ break;
479
+ }
480
+ }
481
+ catch (error) {
482
+ logger.debug("SERVE MEDIA: Final fallback head() failed", {
483
+ key: testKey,
484
+ error: error.message,
485
+ });
486
+ }
487
+ }
488
+ }
489
+ if (!r2Key) {
490
+ logger.debug("SERVE MEDIA: No R2 key found, returning 404", {
491
+ contentHash,
492
+ variant,
493
+ hasMediaFile: !!mediaFile,
494
+ });
495
+ // In dev, return detailed debug info
496
+ const debugInfo = env.ENVIRONMENT === "dev"
497
+ ? {
498
+ contentHash,
499
+ variant,
500
+ hasMediaFile: !!mediaFile,
501
+ mediaFileKeys: mediaFile
502
+ ? {
503
+ original: mediaFile.originalKey,
504
+ optimized: mediaFile.optimizedKey,
505
+ thumbnail: mediaFile.thumbnailKey,
506
+ }
507
+ : null,
508
+ codeVersion: "v2-with-debug",
509
+ }
510
+ : undefined;
511
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
512
+ error: "Media not found",
513
+ source: "serveMediaByHash-noKey",
514
+ ...(debugInfo && { debug: debugInfo }),
515
+ }), { status: 404, headers: { "content-type": "application/json" } });
516
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
517
+ }
518
+ const object = await r2Bucket.get(r2Key);
519
+ if (!object) {
520
+ logger.debug("SERVE MEDIA: R2 object not found", {
521
+ r2Key,
522
+ contentHash,
523
+ variant,
524
+ });
525
+ // In dev, return detailed debug info
526
+ const debugInfo = env.ENVIRONMENT === "dev"
527
+ ? {
528
+ r2Key,
529
+ contentHash,
530
+ variant,
531
+ message: "R2 object not found at key",
532
+ codeVersion: "v2-with-debug",
533
+ }
534
+ : undefined;
535
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
536
+ error: "Media not found",
537
+ source: "serveMediaByHash",
538
+ ...(debugInfo && { debug: debugInfo }),
539
+ }), { status: 404, headers: { "content-type": "application/json" } });
540
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
541
+ }
542
+ // Get content type from object metadata or use determined type
543
+ const objectContentType = object.httpMetadata?.contentType || contentType;
544
+ // Return file with appropriate cache headers
545
+ const response = new Response(object.body, {
546
+ headers: {
547
+ "Content-Type": objectContentType,
548
+ "Cache-Control": `no-cache, no-store, must-revalidate`,
549
+ Pragma: "no-cache",
550
+ Expires: "0",
551
+ "Cache-Key": `media:${session.userId}:${contentHash}:${variant}`,
552
+ "X-Content-Type-Options": "nosniff",
553
+ "X-Debug-Variant": variant, // Simple debug header
554
+ "X-Debug-Timestamp": Date.now().toString(), // Unique per request
555
+ },
556
+ });
557
+ return cors_handler_1.CorsHandler.addCorsHeaders(response, request, env);
558
+ }
559
+ catch (unexpectedError) {
560
+ // Catch any unexpected errors in serveMediaByHash
561
+ logger.error("SERVE MEDIA BY HASH: Unexpected error", {
562
+ error: unexpectedError.message,
563
+ stack: unexpectedError.stack,
564
+ contentHash,
565
+ variant,
566
+ });
567
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
568
+ error: "Internal server error",
569
+ message: unexpectedError.message || "An unexpected error occurred",
570
+ source: "serveMediaByHash-unexpected",
571
+ contentHash,
572
+ variant,
573
+ }), { status: 500, headers: { "content-type": "application/json" } });
574
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
575
+ }
576
+ }
577
+ /**
578
+ * Check for suspicious patterns in file content
579
+ */
580
+ function checkSuspiciousContent(bytes, mimeType) {
581
+ const suspicious = [];
582
+ // Check for executable patterns (MZ header = Windows executable)
583
+ if (bytes[0] === 0x4d && bytes[1] === 0x5a) {
584
+ suspicious.push("Executable header detected");
585
+ }
586
+ // Check for script patterns in first 1KB
587
+ if (bytes.length > 1024) {
588
+ const text = new TextDecoder("utf-8", {
589
+ fatal: false,
590
+ ignoreBOM: true,
591
+ }).decode(bytes.slice(0, 1024));
592
+ if (text.includes("<?php") || text.includes("<script")) {
593
+ suspicious.push("Script content detected");
594
+ }
595
+ }
596
+ // Check for unusually large metadata sections in JPEG
597
+ if (mimeType === "image/jpeg" || mimeType === "image/jpg") {
598
+ let metadataSize = 0;
599
+ let offset = 2; // Skip FF D8
600
+ while (offset < bytes.length && bytes[offset] === 0xff) {
601
+ const marker = bytes[offset + 1];
602
+ if (marker >= 0xe0 && marker <= 0xef) {
603
+ // APP segment
604
+ if (offset + 3 < bytes.length) {
605
+ const segmentLength = (bytes[offset + 2] << 8) | bytes[offset + 3];
606
+ metadataSize += segmentLength;
607
+ offset += segmentLength + 2;
608
+ }
609
+ else {
610
+ break;
611
+ }
612
+ }
613
+ else {
614
+ break;
615
+ }
616
+ }
617
+ if (metadataSize > 64 * 1024) {
618
+ suspicious.push("Excessive metadata detected");
619
+ }
620
+ }
621
+ return suspicious;
622
+ }
623
+ exports.mediaRoutes = [
624
+ {
625
+ path: "/api/media/upload",
626
+ method: "POST",
627
+ handler: async (request, env) => {
628
+ const sessionManager = new session_manager_1.SessionManager();
629
+ const securityHeaders = new security_headers_1.SecurityHeaders(env);
630
+ const logger = logger_1.Logger.getInstance(env);
631
+ const rateLimiter = new rate_limit_1.RateLimiter();
632
+ // Check authentication
633
+ const authHeader = request.headers.get("Authorization");
634
+ logger.debug("[Media Upload] Attempting to get session", {
635
+ hasCookie: !!request.headers.get("Cookie"),
636
+ hasAuthHeader: !!authHeader,
637
+ authHeaderPreview: authHeader?.substring(0, 50) || "none",
638
+ });
639
+ const session = await sessionManager.getSession(request, secret_resolver_1.Secrets.getSessionSecret(env), env);
640
+ if (!session) {
641
+ logger.warn("[Media Upload] Unauthorized - no valid session", {
642
+ hasCookie: !!request.headers.get("Cookie"),
643
+ hasAuthHeader: !!authHeader,
644
+ });
645
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { "content-type": "application/json" } });
646
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
647
+ }
648
+ // Apply rate limiting: 10 uploads per 60s per user
649
+ const rateLimitResponse = await rateLimiter.applyRateLimitKV(env, request, "/api/media/upload", 10, 60, session.userId);
650
+ if (rateLimitResponse) {
651
+ return securityHeaders.addSecurityHeaders(rateLimitResponse);
652
+ }
653
+ try {
654
+ // Parse multipart form data
655
+ let formData;
656
+ try {
657
+ formData = await request.formData();
658
+ }
659
+ catch (error) {
660
+ logger.error("Media upload failed: Error parsing form data", {
661
+ userId: session.userId,
662
+ error: error.message,
663
+ });
664
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
665
+ error: "Invalid request format",
666
+ message: "Failed to parse multipart form data",
667
+ }), { status: 400, headers: { "content-type": "application/json" } });
668
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
669
+ }
670
+ const file = formData.get("file");
671
+ if (!file) {
672
+ logger.warn("Media upload failed: No file provided", {
673
+ userId: session.userId,
674
+ formDataKeys: Array.from(formData.keys()),
675
+ });
676
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
677
+ error: "No file provided",
678
+ message: "File field is required in multipart form data",
679
+ }), { status: 400, headers: { "content-type": "application/json" } });
680
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
681
+ }
682
+ // Check if file is empty
683
+ if (file.size === 0) {
684
+ logger.warn("Media upload failed: Empty file", {
685
+ userId: session.userId,
686
+ fileName: file.name,
687
+ });
688
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
689
+ error: "Empty file",
690
+ message: "File cannot be empty",
691
+ }), { status: 400, headers: { "content-type": "application/json" } });
692
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
693
+ }
694
+ // Validate file type
695
+ const allowedImageTypes = [
696
+ "image/jpeg",
697
+ "image/jpg",
698
+ "image/png",
699
+ "image/gif",
700
+ "image/webp",
701
+ "image/heic",
702
+ "image/heif",
703
+ ];
704
+ const allowedVideoTypes = [
705
+ "video/mp4",
706
+ "video/webm",
707
+ "video/quicktime",
708
+ ];
709
+ // Read file bytes first to detect MIME type if not provided
710
+ let fileBuffer;
711
+ try {
712
+ fileBuffer = await file.arrayBuffer();
713
+ }
714
+ catch (error) {
715
+ logger.error("Media upload failed: Error reading file", {
716
+ userId: session.userId,
717
+ fileName: file.name,
718
+ fileSize: file.size,
719
+ error: error.message,
720
+ });
721
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
722
+ error: "File read error",
723
+ message: "Failed to read file data",
724
+ }), { status: 400, headers: { "content-type": "application/json" } });
725
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
726
+ }
727
+ if (fileBuffer.byteLength === 0) {
728
+ logger.warn("Media upload failed: File buffer is empty", {
729
+ userId: session.userId,
730
+ fileName: file.name,
731
+ fileSize: file.size,
732
+ });
733
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
734
+ error: "Empty file",
735
+ message: "File data is empty",
736
+ }), { status: 400, headers: { "content-type": "application/json" } });
737
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
738
+ }
739
+ const bytes = new Uint8Array(fileBuffer);
740
+ // Always detect MIME type from magic numbers (trust the file, not the declared type)
741
+ // This handles cases where the frontend compresses/converts images
742
+ let detectedMimeType = "application/octet-stream";
743
+ if (bytes.length >= 3 &&
744
+ bytes[0] === 0xff &&
745
+ bytes[1] === 0xd8 &&
746
+ bytes[2] === 0xff) {
747
+ detectedMimeType = "image/jpeg";
748
+ }
749
+ else if (bytes.length >= 8 &&
750
+ bytes[0] === 0x89 &&
751
+ bytes[1] === 0x50 &&
752
+ bytes[2] === 0x4e &&
753
+ bytes[3] === 0x47) {
754
+ detectedMimeType = "image/png";
755
+ }
756
+ else if (bytes.length >= 4 &&
757
+ bytes[0] === 0x47 &&
758
+ bytes[1] === 0x49 &&
759
+ bytes[2] === 0x46 &&
760
+ bytes[3] === 0x38) {
761
+ detectedMimeType = "image/gif";
762
+ }
763
+ else if (bytes.length >= 12 &&
764
+ bytes[0] === 0x52 &&
765
+ bytes[1] === 0x49 &&
766
+ bytes[2] === 0x46 &&
767
+ bytes[3] === 0x46 &&
768
+ bytes[8] === 0x57 &&
769
+ bytes[9] === 0x45 &&
770
+ bytes[10] === 0x42 &&
771
+ bytes[11] === 0x50) {
772
+ detectedMimeType = "image/webp";
773
+ }
774
+ else if (bytes.length >= 8 &&
775
+ bytes[0] === 0x00 &&
776
+ bytes[1] === 0x00 &&
777
+ bytes[2] === 0x00 &&
778
+ bytes[4] === 0x66 &&
779
+ bytes[5] === 0x74 &&
780
+ bytes[6] === 0x79 &&
781
+ bytes[7] === 0x70) {
782
+ // HEIC/HEIF: ISO Base Media File Format with ftyp box
783
+ detectedMimeType = "image/heic";
784
+ }
785
+ // Use detected type if we found one, otherwise fall back to declared type
786
+ const declaredMimeType = file.type || "application/octet-stream";
787
+ let mimeType = detectedMimeType !== "application/octet-stream"
788
+ ? detectedMimeType
789
+ : declaredMimeType;
790
+ // Log if declared type doesn't match detected type (frontend may have converted the image)
791
+ if (declaredMimeType !== "application/octet-stream" &&
792
+ detectedMimeType !== "application/octet-stream" &&
793
+ declaredMimeType !== detectedMimeType) {
794
+ logger.info("Media upload: Declared MIME type differs from detected type", {
795
+ userId: session.userId,
796
+ fileName: file.name,
797
+ declaredMimeType,
798
+ detectedMimeType,
799
+ usingDetectedType: true,
800
+ });
801
+ }
802
+ const isImage = allowedImageTypes.includes(mimeType);
803
+ const isVideo = allowedVideoTypes.includes(mimeType);
804
+ if (!isImage && !isVideo) {
805
+ logger.warn("Media upload failed: Invalid file type", {
806
+ userId: session.userId,
807
+ fileName: file.name,
808
+ declaredMimeType: file.type,
809
+ detectedMimeType: mimeType,
810
+ fileSize: file.size,
811
+ firstBytes: bytes.length > 0
812
+ ? Array.from(bytes.slice(0, 8))
813
+ .map((b) => `0x${b.toString(16).padStart(2, "0")}`)
814
+ .join(" ")
815
+ : "empty",
816
+ });
817
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
818
+ error: "Invalid file type",
819
+ message: "Only JPEG, PNG, GIF, WebP, HEIC images and MP4, WebM, QuickTime videos are supported",
820
+ details: {
821
+ declaredType: file.type || "not provided",
822
+ detectedType: mimeType,
823
+ fileName: file.name,
824
+ },
825
+ }), { status: 400, headers: { "content-type": "application/json" } });
826
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
827
+ }
828
+ // Validate file size (per documentation: 10MB for images, 100MB for videos)
829
+ const maxImageSize = 10 * 1024 * 1024; // 10MB
830
+ const maxVideoSize = 100 * 1024 * 1024; // 100MB
831
+ const maxSize = isImage ? maxImageSize : maxVideoSize;
832
+ if (file.size > maxSize) {
833
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
834
+ error: "File too large",
835
+ message: isImage
836
+ ? "Image must be 10MB or less"
837
+ : "Video must be 100MB or less",
838
+ }), { status: 400, headers: { "content-type": "application/json" } });
839
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
840
+ }
841
+ // File buffer already read above for MIME type detection
842
+ // Reuse the bytes array
843
+ // Validate magic numbers (file signatures)
844
+ // Since we always detect from magic numbers and use the detected type,
845
+ // we should always validate to ensure the file is what we think it is
846
+ if (mimeType !== "application/octet-stream" &&
847
+ !validateMagicNumbers(bytes, mimeType)) {
848
+ logger.warn("Media upload failed: Invalid file signature", {
849
+ userId: session.userId,
850
+ fileName: file.name,
851
+ declaredMimeType: declaredMimeType,
852
+ detectedMimeType: detectedMimeType,
853
+ usingMimeType: mimeType,
854
+ fileSize: file.size,
855
+ firstBytes: bytes.length > 0
856
+ ? Array.from(bytes.slice(0, 12))
857
+ .map((b) => `0x${b.toString(16).padStart(2, "0")}`)
858
+ .join(" ")
859
+ : "empty",
860
+ });
861
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
862
+ error: "Invalid file signature",
863
+ message: "File signature does not match detected file type. File may be corrupted or malicious.",
864
+ }), { status: 400, headers: { "content-type": "application/json" } });
865
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
866
+ }
867
+ // Check for suspicious patterns
868
+ const suspicious = checkSuspiciousContent(bytes, mimeType);
869
+ if (suspicious.length > 0) {
870
+ logger.warn("Suspicious file detected", {
871
+ userId: session.userId,
872
+ fileName: file.name,
873
+ mimeType,
874
+ suspicious,
875
+ });
876
+ // For now, log but don't reject (can be made stricter later)
877
+ // In production, you might want to reject or quarantine
878
+ }
879
+ // Get extension from MIME type
880
+ const ext = getExtensionFromMimeType(mimeType);
881
+ // Extract metadata (best effort, non-fatal)
882
+ let extracted = {};
883
+ try {
884
+ const { MetadataExtractor } = await Promise.resolve().then(() => __importStar(require("../metadata/metadata-extractor")));
885
+ const extractor = new MetadataExtractor(env);
886
+ extracted = await extractor.extractAll(fileBuffer, mimeType);
887
+ }
888
+ catch (metaError) {
889
+ logger.warn("[Media Upload] Metadata extraction failed", {
890
+ userId: session.userId,
891
+ mimeType,
892
+ errorType: metaError?.name,
893
+ code: metaError?.code,
894
+ error: metaError?.message,
895
+ });
896
+ }
897
+ // Prepare metadata for upload service
898
+ const metadata = {
899
+ width: extracted?.exifData?.width || extracted?.videoMetadata?.width,
900
+ height: extracted?.exifData?.height || extracted?.videoMetadata?.height,
901
+ duration: extracted?.videoMetadata?.duration,
902
+ };
903
+ // Use MediaUploadService for eventual consistency upload
904
+ // Pass the already-read fileBuffer to avoid a second file.arrayBuffer() call.
905
+ // On Cloudflare Workers, File objects from FormData may not support
906
+ // reliable re-reads of arrayBuffer(), causing a different contentHash.
907
+ const uploadService = new media_upload_service_1.MediaUploadService(env);
908
+ const result = await uploadService.uploadSingle(file, session.userId, metadata, fileBuffer);
909
+ // Normalize images to sRGB (non-blocking, best effort)
910
+ let optimizedKey = null;
911
+ if (mimeType.startsWith("image/")) {
912
+ if (env.IMAGES && env.MEDIA_BUCKET_R2) {
913
+ const normalizer = new image_normalizer_1.ImageNormalizer(env.IMAGES, env.MEDIA_BUCKET_R2);
914
+ const startTime = Date.now();
915
+ logger.info("image_normalization.started", {
916
+ contentHash: result.contentHash,
917
+ mimeType,
918
+ });
919
+ optimizedKey = await normalizer.normalize(`media/${result.contentHash}.${getExtensionFromMimeType(mimeType)}`, result.contentHash);
920
+ const durationMs = Date.now() - startTime;
921
+ if (optimizedKey) {
922
+ logger.info("image_normalization.completed", {
923
+ contentHash: result.contentHash,
924
+ optimizedKey,
925
+ durationMs,
926
+ });
927
+ }
928
+ else {
929
+ logger.warn("image_normalization.failed", {
930
+ contentHash: result.contentHash,
931
+ durationMs,
932
+ });
933
+ }
934
+ }
935
+ else {
936
+ logger.info("image_normalization.skipped", {
937
+ contentHash: result.contentHash,
938
+ reason: "images_binding_not_available",
939
+ });
940
+ }
941
+ }
942
+ else {
943
+ logger.info("image_normalization.skipped", {
944
+ contentHash: result.contentHash,
945
+ reason: "not_image",
946
+ });
947
+ }
948
+ // Create MediaFile DB record synchronously so post creation can
949
+ // reference it immediately (reconciliation will enrich it later)
950
+ const uploadOriginalKey = `media/${result.contentHash}.${getExtensionFromMimeType(mimeType)}`;
951
+ const uploadRegion = "US"; // TODO: Get from session or request
952
+ try {
953
+ await (0, db_query_helper_1.withQueryTimeoutAndRetry)(database_connection_manager_1.sharedDatabaseConnectionManager, uploadRegion, env, async (db) => {
954
+ return await db.mediaFile.upsert({
955
+ where: { contentHash: result.contentHash },
956
+ create: {
957
+ contentHash: result.contentHash,
958
+ mimeType: mimeType,
959
+ size: file.size,
960
+ originalKey: uploadOriginalKey,
961
+ optimizedKey: optimizedKey ?? undefined,
962
+ uploadStatus: "COMPLETE",
963
+ uploadedBy: session.userId,
964
+ width: metadata?.width,
965
+ height: metadata?.height,
966
+ duration: metadata?.duration,
967
+ },
968
+ update: {
969
+ // If record already exists (e.g. re-upload), update status and ownership
970
+ // Clear deletedAt so previously-deleted media can be reused
971
+ uploadStatus: "COMPLETE",
972
+ uploadedBy: session.userId,
973
+ optimizedKey: optimizedKey ?? undefined,
974
+ deletedAt: null,
975
+ },
976
+ });
977
+ }, {
978
+ ...db_query_helper_1.QueryTimeoutPresets.USER_FACING,
979
+ maxRetries: 1,
980
+ context: {
981
+ operation: "mediaUpload_createRecord",
982
+ userId: session.userId,
983
+ },
984
+ });
985
+ }
986
+ catch (dbError) {
987
+ // DB record is required for post creation to validate media ownership.
988
+ // If this fails, the upload must fail so the frontend can retry.
989
+ logger.error("[Media Upload] Synchronous DB record creation failed", {
990
+ contentHash: result.contentHash,
991
+ error: dbError.message,
992
+ });
993
+ const dbErrorResponse = securityHeaders.createSecureResponse(JSON.stringify({
994
+ error: "Database error",
995
+ message: "Failed to register uploaded media. Please try again.",
996
+ }), {
997
+ status: 500,
998
+ headers: { "content-type": "application/json" },
999
+ });
1000
+ return cors_handler_1.CorsHandler.addCorsHeaders(dbErrorResponse, request, env);
1001
+ }
1002
+ logger.debug("[Media Upload] DB record created successfully", {
1003
+ contentHash: result.contentHash,
1004
+ uploadedBy: session.userId,
1005
+ originalKey: uploadOriginalKey,
1006
+ uploadRegion,
1007
+ });
1008
+ logger.info("Media upload successful", {
1009
+ userId: session.userId,
1010
+ fileName: file.name,
1011
+ fileSize: file.size,
1012
+ mimeType,
1013
+ contentHash: result.contentHash,
1014
+ status: result.status,
1015
+ });
1016
+ const response = securityHeaders.createSecureResponse(JSON.stringify({
1017
+ url: result.url,
1018
+ mediaKey: result.contentHash,
1019
+ contentHash: result.contentHash,
1020
+ status: result.status,
1021
+ }), { status: 200, headers: { "content-type": "application/json" } });
1022
+ return cors_handler_1.CorsHandler.addCorsHeaders(response, request, env);
1023
+ }
1024
+ catch (error) {
1025
+ logger.error("Error handling media upload:", error);
1026
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1027
+ error: "Failed to upload media",
1028
+ message: error.message || "An unexpected error occurred",
1029
+ }), { status: 500, headers: { "content-type": "application/json" } });
1030
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1031
+ }
1032
+ },
1033
+ middleware: [(0, middleware_1.corsMiddleware)(), (0, middleware_1.csrfMiddleware)()],
1034
+ description: "Upload media file (image or video) with content-addressed storage",
1035
+ },
1036
+ {
1037
+ path: "/api/media/upload/batch",
1038
+ method: "POST",
1039
+ handler: async (request, env) => {
1040
+ const sessionManager = new session_manager_1.SessionManager();
1041
+ const securityHeaders = new security_headers_1.SecurityHeaders(env);
1042
+ const logger = logger_1.Logger.getInstance(env);
1043
+ const rateLimiter = new rate_limit_1.RateLimiter();
1044
+ // Check authentication
1045
+ const session = await sessionManager.getSession(request, secret_resolver_1.Secrets.getSessionSecret(env), env);
1046
+ if (!session) {
1047
+ logger.warn("[Media Batch Upload] Unauthorized");
1048
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { "content-type": "application/json" } });
1049
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1050
+ }
1051
+ // Apply rate limiting: 5 batch uploads per 60s per user (stricter than single)
1052
+ const rateLimitResponse = await rateLimiter.applyRateLimitKV(env, request, "/api/media/upload/batch", 5, 60, session.userId);
1053
+ if (rateLimitResponse) {
1054
+ return securityHeaders.addSecurityHeaders(rateLimitResponse);
1055
+ }
1056
+ try {
1057
+ // Parse multipart form data
1058
+ const formData = await request.formData();
1059
+ const files = [];
1060
+ // Collect all files from form data
1061
+ for (const [key, value] of formData.entries()) {
1062
+ if (key.startsWith("files[") &&
1063
+ value &&
1064
+ typeof value === "object" &&
1065
+ "name" in value) {
1066
+ files.push(value);
1067
+ }
1068
+ else if (key === "file" &&
1069
+ value &&
1070
+ typeof value === "object" &&
1071
+ "name" in value) {
1072
+ // Also support single 'file' field for compatibility
1073
+ files.push(value);
1074
+ }
1075
+ }
1076
+ if (files.length === 0) {
1077
+ logger.warn("[Media Batch Upload] No files provided", {
1078
+ userId: session.userId,
1079
+ formDataKeys: Array.from(formData.keys()),
1080
+ });
1081
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1082
+ error: "No files provided",
1083
+ message: "At least one file is required",
1084
+ }), { status: 400, headers: { "content-type": "application/json" } });
1085
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1086
+ }
1087
+ if (files.length > 20) {
1088
+ logger.warn("[Media Batch Upload] Too many files", {
1089
+ userId: session.userId,
1090
+ fileCount: files.length,
1091
+ });
1092
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1093
+ error: "Too many files",
1094
+ message: "Maximum 20 files per batch",
1095
+ }), { status: 400, headers: { "content-type": "application/json" } });
1096
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1097
+ }
1098
+ logger.info("[Media Batch Upload] Processing batch", {
1099
+ userId: session.userId,
1100
+ fileCount: files.length,
1101
+ });
1102
+ // Use MediaUploadService for batch upload
1103
+ const uploadService = new media_upload_service_1.MediaUploadService(env);
1104
+ const results = await uploadService.uploadBatch(files, session.userId);
1105
+ const successCount = results.filter((r) => r.success).length;
1106
+ const failureCount = results.filter((r) => !r.success).length;
1107
+ logger.info("[Media Batch Upload] Batch complete", {
1108
+ userId: session.userId,
1109
+ total: files.length,
1110
+ successful: successCount,
1111
+ failed: failureCount,
1112
+ });
1113
+ const response = securityHeaders.createSecureResponse(JSON.stringify({
1114
+ results,
1115
+ summary: {
1116
+ total: files.length,
1117
+ successful: successCount,
1118
+ failed: failureCount,
1119
+ },
1120
+ }), { status: 200, headers: { "content-type": "application/json" } });
1121
+ return cors_handler_1.CorsHandler.addCorsHeaders(response, request, env);
1122
+ }
1123
+ catch (error) {
1124
+ logger.error("[Media Batch Upload] Error:", error);
1125
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1126
+ error: "Failed to upload media batch",
1127
+ message: error.message || "An unexpected error occurred",
1128
+ }), { status: 500, headers: { "content-type": "application/json" } });
1129
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1130
+ }
1131
+ },
1132
+ middleware: [(0, middleware_1.corsMiddleware)(), (0, middleware_1.csrfMiddleware)()],
1133
+ description: "Upload multiple media files in a single batch request",
1134
+ },
1135
+ {
1136
+ path: "/api/media/grouped",
1137
+ method: "GET",
1138
+ handler: async (request, env) => {
1139
+ const startTime = Date.now();
1140
+ const sessionManager = new session_manager_1.SessionManager();
1141
+ const securityHeaders = new security_headers_1.SecurityHeaders(env);
1142
+ const logger = logger_1.Logger.getInstance(env);
1143
+ const rateLimiter = new rate_limit_1.RateLimiter();
1144
+ const mediaHandler = media_handler_1.MediaHandler.create(env);
1145
+ const { MediaMetrics } = await Promise.resolve().then(() => __importStar(require("../media-metrics")));
1146
+ const { RegionDetector } = await Promise.resolve().then(() => __importStar(require("../region-detection")));
1147
+ const metrics = new MediaMetrics(env);
1148
+ // Check authentication
1149
+ const session = await sessionManager.getSession(request, secret_resolver_1.Secrets.getSessionSecret(env), env);
1150
+ if (!session) {
1151
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { "content-type": "application/json" } });
1152
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1153
+ }
1154
+ // Apply rate limiting: 60 requests per minute per user
1155
+ const rateLimitResponse = await rateLimiter.applyRateLimitKV(env, request, "/api/media/grouped", 60, 60, session.userId);
1156
+ if (rateLimitResponse) {
1157
+ return securityHeaders.addSecurityHeaders(rateLimitResponse);
1158
+ }
1159
+ try {
1160
+ const url = new URL(request.url);
1161
+ const groupBy = (url.searchParams.get("groupBy") ||
1162
+ url.searchParams.get("groupby") ||
1163
+ "month");
1164
+ if (!["month", "year"].includes(groupBy)) {
1165
+ const duration = Date.now() - startTime;
1166
+ const regionDetector = new RegionDetector(env);
1167
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1168
+ metrics.trackOperation({
1169
+ operation: "grouped",
1170
+ endpoint: "/api/media/grouped",
1171
+ duration,
1172
+ statusCode: 400,
1173
+ errorType: "ValidationError",
1174
+ userId: session.userId,
1175
+ region,
1176
+ });
1177
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1178
+ error: "Invalid groupBy",
1179
+ message: 'groupBy must be "month" or "year"',
1180
+ }), { status: 400, headers: { "content-type": "application/json" } });
1181
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1182
+ }
1183
+ const includeHidden = url.searchParams.get("includeHidden") === "true";
1184
+ const type = url.searchParams.get("type") || "all";
1185
+ const limit = url.searchParams.get("limit")
1186
+ ? parseInt(url.searchParams.get("limit"), 10)
1187
+ : undefined;
1188
+ // Validate limit if provided
1189
+ if (limit !== undefined && (limit < 1 || limit > 10000)) {
1190
+ const duration = Date.now() - startTime;
1191
+ const regionDetector = new RegionDetector(env);
1192
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1193
+ metrics.trackOperation({
1194
+ operation: "grouped",
1195
+ endpoint: "/api/media/grouped",
1196
+ duration,
1197
+ statusCode: 400,
1198
+ errorType: "ValidationError",
1199
+ userId: session.userId,
1200
+ region,
1201
+ });
1202
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1203
+ error: "Invalid limit",
1204
+ message: "Limit must be between 1 and 10000",
1205
+ }), { status: 400, headers: { "content-type": "application/json" } });
1206
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1207
+ }
1208
+ const result = await mediaHandler.listUserMediaGrouped(session.userId, groupBy, {
1209
+ includeHidden,
1210
+ type,
1211
+ limit,
1212
+ }, env, request);
1213
+ const duration = Date.now() - startTime;
1214
+ const regionDetector = new RegionDetector(env);
1215
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1216
+ // Calculate total items across all groups
1217
+ const totalItems = result.groups.reduce((sum, group) => sum + group.media.length, 0);
1218
+ // Track metrics
1219
+ metrics.trackGrouped("/api/media/grouped", duration, result.groups.length, totalItems, 200, region, session.userId);
1220
+ const response = securityHeaders.createSecureResponse(JSON.stringify(result), { status: 200, headers: { "content-type": "application/json" } });
1221
+ return cors_handler_1.CorsHandler.addCorsHeaders(response, request, env);
1222
+ }
1223
+ catch (error) {
1224
+ const duration = Date.now() - startTime;
1225
+ const regionDetector = new RegionDetector(env);
1226
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1227
+ const statusCode = error.message === "Media not found" ? 404 : 500;
1228
+ // Track error metrics
1229
+ metrics.trackOperation({
1230
+ operation: "grouped",
1231
+ endpoint: "/api/media/grouped",
1232
+ duration,
1233
+ statusCode,
1234
+ errorType: error?.name || "UnknownError",
1235
+ userId: session?.userId,
1236
+ region,
1237
+ });
1238
+ logger.error("Error grouping user media:", error);
1239
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1240
+ error: "Failed to group media",
1241
+ message: error.message || "An unexpected error occurred",
1242
+ }), {
1243
+ status: statusCode,
1244
+ headers: { "content-type": "application/json" },
1245
+ });
1246
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1247
+ }
1248
+ },
1249
+ middleware: [(0, middleware_1.corsMiddleware)()],
1250
+ description: "List user media grouped by month or year",
1251
+ },
1252
+ {
1253
+ path: "/api/media/stats",
1254
+ method: "GET",
1255
+ handler: async (request, env) => {
1256
+ const startTime = Date.now();
1257
+ const sessionManager = new session_manager_1.SessionManager();
1258
+ const securityHeaders = new security_headers_1.SecurityHeaders(env);
1259
+ const logger = logger_1.Logger.getInstance(env);
1260
+ const rateLimiter = new rate_limit_1.RateLimiter();
1261
+ const mediaHandler = media_handler_1.MediaHandler.create(env);
1262
+ const { MediaMetrics } = await Promise.resolve().then(() => __importStar(require("../media-metrics")));
1263
+ const { RegionDetector } = await Promise.resolve().then(() => __importStar(require("../region-detection")));
1264
+ const metrics = new MediaMetrics(env);
1265
+ // Check authentication
1266
+ const session = await sessionManager.getSession(request, secret_resolver_1.Secrets.getSessionSecret(env), env);
1267
+ if (!session) {
1268
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { "content-type": "application/json" } });
1269
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1270
+ }
1271
+ // Apply rate limiting: 60 requests per minute per user
1272
+ const rateLimitResponse = await rateLimiter.applyRateLimitKV(env, request, "/api/media/stats", 60, 60, session.userId);
1273
+ if (rateLimitResponse) {
1274
+ return securityHeaders.addSecurityHeaders(rateLimitResponse);
1275
+ }
1276
+ try {
1277
+ const url = new URL(request.url);
1278
+ const includeHidden = url.searchParams.get("includeHidden") === "true";
1279
+ const type = url.searchParams.get("type") || "all";
1280
+ const result = await mediaHandler.getUserMediaStats(session.userId, { includeHidden, type }, env, request);
1281
+ const duration = Date.now() - startTime;
1282
+ const regionDetector = new RegionDetector(env);
1283
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1284
+ // Track metrics
1285
+ metrics.trackStats("/api/media/stats", duration, result.totalCount, 200, region, session.userId);
1286
+ const response = securityHeaders.createSecureResponse(JSON.stringify(result), { status: 200, headers: { "content-type": "application/json" } });
1287
+ return cors_handler_1.CorsHandler.addCorsHeaders(response, request, env);
1288
+ }
1289
+ catch (error) {
1290
+ const duration = Date.now() - startTime;
1291
+ const regionDetector = new RegionDetector(env);
1292
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1293
+ const statusCode = error.message === "Media not found" ? 404 : 500;
1294
+ // Track error metrics
1295
+ metrics.trackOperation({
1296
+ operation: "stats",
1297
+ endpoint: "/api/media/stats",
1298
+ duration,
1299
+ statusCode,
1300
+ errorType: error?.name || "UnknownError",
1301
+ userId: session?.userId,
1302
+ region,
1303
+ });
1304
+ logger.error("Error getting media stats:", error);
1305
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1306
+ error: "Failed to get media stats",
1307
+ message: error.message || "An unexpected error occurred",
1308
+ }), {
1309
+ status: statusCode,
1310
+ headers: { "content-type": "application/json" },
1311
+ });
1312
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1313
+ }
1314
+ },
1315
+ middleware: [(0, middleware_1.corsMiddleware)()],
1316
+ description: "Get media statistics",
1317
+ },
1318
+ {
1319
+ path: "/api/media/:mediaId",
1320
+ method: "GET",
1321
+ handler: async (request, env, context) => {
1322
+ const startTime = Date.now();
1323
+ const sessionManager = new session_manager_1.SessionManager();
1324
+ const securityHeaders = new security_headers_1.SecurityHeaders(env);
1325
+ const logger = logger_1.Logger.getInstance(env);
1326
+ logger.debug("MEDIA ROUTE: /api/media/:mediaId GET handler called", {
1327
+ url: request.url,
1328
+ mediaId: context.params?.mediaId,
1329
+ });
1330
+ const rateLimiter = new rate_limit_1.RateLimiter();
1331
+ const mediaHandler = media_handler_1.MediaHandler.create(env);
1332
+ const { MediaMetrics } = await Promise.resolve().then(() => __importStar(require("../media-metrics")));
1333
+ const { RegionDetector } = await Promise.resolve().then(() => __importStar(require("../region-detection")));
1334
+ const metrics = new MediaMetrics(env);
1335
+ // Check authentication
1336
+ const session = await sessionManager.getSession(request, secret_resolver_1.Secrets.getSessionSecret(env), env);
1337
+ if (!session) {
1338
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { "content-type": "application/json" } });
1339
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1340
+ }
1341
+ // Apply rate limiting: 120 requests per minute per user
1342
+ const rateLimitResponse = await rateLimiter.applyRateLimitKV(env, request, "/api/media/:mediaId", 120, 60, session.userId);
1343
+ if (rateLimitResponse) {
1344
+ return securityHeaders.addSecurityHeaders(rateLimitResponse);
1345
+ }
1346
+ try {
1347
+ const mediaId = context.params?.mediaId;
1348
+ if (!mediaId) {
1349
+ const duration = Date.now() - startTime;
1350
+ const regionDetector = new RegionDetector(env);
1351
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1352
+ metrics.trackOperation({
1353
+ operation: "details",
1354
+ endpoint: "/api/media/:mediaId",
1355
+ duration,
1356
+ statusCode: 400,
1357
+ errorType: "ValidationError",
1358
+ userId: session.userId,
1359
+ region,
1360
+ });
1361
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1362
+ error: "Invalid request",
1363
+ message: "Media ID is required",
1364
+ }), { status: 400, headers: { "content-type": "application/json" } });
1365
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1366
+ }
1367
+ // Check if this is actually a content hash request (64-char hex)
1368
+ // Content hashes are hex strings and typically 64 characters
1369
+ // If it looks like a content hash, delegate to shared hash handler
1370
+ const url = new URL(request.url);
1371
+ const variant = url.searchParams.get("variant");
1372
+ logger.debug("MEDIA DEBUG: Checking content hash", {
1373
+ mediaId,
1374
+ mediaIdLength: mediaId.length,
1375
+ isHex: /^[0-9a-f]+$/i.test(mediaId),
1376
+ variant,
1377
+ url: request.url,
1378
+ });
1379
+ if (mediaId.length === 64 && /^[0-9a-f]+$/i.test(mediaId)) {
1380
+ logger.debug("MEDIA DEBUG: Detected content hash, delegating to serveMediaByHash", {
1381
+ mediaId,
1382
+ variant: variant || "original", // Changed default from 'optimized' to 'original'
1383
+ });
1384
+ // This is a content hash request - use shared hash serving function
1385
+ const duration = Date.now() - startTime;
1386
+ const regionDetector = new RegionDetector(env);
1387
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1388
+ metrics.trackOperation({
1389
+ operation: "details",
1390
+ endpoint: "/api/media/:mediaId",
1391
+ duration,
1392
+ statusCode: 200,
1393
+ errorType: undefined,
1394
+ userId: session.userId,
1395
+ region,
1396
+ });
1397
+ // CRITICAL FIX: Default to 'original' variant instead of 'optimized'
1398
+ // This ensures media is always accessible even if optimized versions don't exist yet
1399
+ return serveMediaByHash(mediaId, variant || "original", request, env, session);
1400
+ }
1401
+ logger.debug("MEDIA DEBUG: Not a content hash, proceeding with regular media details", {
1402
+ mediaId,
1403
+ });
1404
+ // Get media details
1405
+ const result = await mediaHandler.getMediaDetails(mediaId, session.userId, env, request);
1406
+ const duration = Date.now() - startTime;
1407
+ const regionDetector = new RegionDetector(env);
1408
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1409
+ // Track metrics
1410
+ metrics.trackMediaAction("details", "/api/media/:mediaId", duration, 200, mediaId, region, session.userId);
1411
+ const response = securityHeaders.createSecureResponse(JSON.stringify(result), {
1412
+ status: 200,
1413
+ headers: {
1414
+ "content-type": "application/json",
1415
+ "cache-control": "private, max-age=300", // Cache for 5 minutes, private to this user
1416
+ pragma: "no-cache",
1417
+ expires: new Date(Date.now() + 5 * 60 * 1000).toUTCString(),
1418
+ },
1419
+ });
1420
+ return cors_handler_1.CorsHandler.addCorsHeaders(response, request, env);
1421
+ }
1422
+ catch (error) {
1423
+ const duration = Date.now() - startTime;
1424
+ const regionDetector = new RegionDetector(env);
1425
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1426
+ let status = 500;
1427
+ let message = "Failed to get media details";
1428
+ let errorType = error?.name || "UnknownError";
1429
+ if (error.message === "Media not found") {
1430
+ status = 404;
1431
+ message = "Media not found";
1432
+ errorType = "NotFoundError";
1433
+ }
1434
+ else if (error.message.includes("permission")) {
1435
+ status = 403;
1436
+ message = "Forbidden";
1437
+ errorType = "ForbiddenError";
1438
+ }
1439
+ // Track error metrics
1440
+ metrics.trackMediaAction("details", "/api/media/:mediaId", duration, status, context.params?.mediaId || "unknown", region, session?.userId, errorType);
1441
+ logger.error("Error getting media details:", error);
1442
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1443
+ error: message,
1444
+ message: error.message || "An unexpected error occurred",
1445
+ source: "mediaId-route-catch",
1446
+ }), { status, headers: { "content-type": "application/json" } });
1447
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1448
+ }
1449
+ },
1450
+ middleware: [(0, middleware_1.corsMiddleware)()],
1451
+ description: "Get detailed information about a media file",
1452
+ },
1453
+ {
1454
+ path: "/api/media/:hash",
1455
+ method: "GET",
1456
+ handler: async (request, env, { params }) => {
1457
+ const sessionManager = new session_manager_1.SessionManager();
1458
+ const securityHeaders = new security_headers_1.SecurityHeaders(env);
1459
+ const logger = logger_1.Logger.getInstance(env);
1460
+ // Check authentication
1461
+ const session = await sessionManager.getSession(request, secret_resolver_1.Secrets.getSessionSecret(env), env);
1462
+ if (!session) {
1463
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { "content-type": "application/json" } });
1464
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1465
+ }
1466
+ try {
1467
+ const contentHash = params.hash;
1468
+ if (!contentHash) {
1469
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1470
+ error: "Missing content hash",
1471
+ source: "hash-route",
1472
+ }), { status: 400, headers: { "content-type": "application/json" } });
1473
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1474
+ }
1475
+ // Parse variant from query params (thumbnail, optimized, original)
1476
+ const url = new URL(request.url);
1477
+ const variant = url.searchParams.get("variant") || "original"; // Changed default from 'optimized' to 'original'
1478
+ logger.debug("HASH ROUTE: Serving media", {
1479
+ contentHash,
1480
+ variant,
1481
+ hasVariantParam: url.searchParams.has("variant"),
1482
+ });
1483
+ // Use shared function to serve media by hash
1484
+ return serveMediaByHash(contentHash, variant, request, env, session);
1485
+ }
1486
+ catch (error) {
1487
+ logger.error("Error serving media:", error);
1488
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1489
+ error: "Failed to serve media",
1490
+ message: error.message || "An unexpected error occurred",
1491
+ source: "hash-route-catch",
1492
+ }), { status: 500, headers: { "content-type": "application/json" } });
1493
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1494
+ }
1495
+ },
1496
+ middleware: [(0, middleware_1.corsMiddleware)()],
1497
+ description: "Serve media file by content hash with variant support",
1498
+ },
1499
+ {
1500
+ path: "/api/media",
1501
+ method: "GET",
1502
+ handler: async (request, env) => {
1503
+ const sessionManager = new session_manager_1.SessionManager();
1504
+ const securityHeaders = new security_headers_1.SecurityHeaders(env);
1505
+ const logger = logger_1.Logger.getInstance(env);
1506
+ const rateLimiter = new rate_limit_1.RateLimiter();
1507
+ const mediaHandler = media_handler_1.MediaHandler.create(env);
1508
+ const { MediaMetrics } = await Promise.resolve().then(() => __importStar(require("../media-metrics")));
1509
+ const { RegionDetector } = await Promise.resolve().then(() => __importStar(require("../region-detection")));
1510
+ const metrics = new MediaMetrics(env);
1511
+ const startTime = Date.now();
1512
+ // Check authentication
1513
+ const session = await sessionManager.getSession(request, secret_resolver_1.Secrets.getSessionSecret(env), env);
1514
+ if (!session) {
1515
+ const duration = Date.now() - startTime;
1516
+ metrics.trackOperation({
1517
+ operation: "list",
1518
+ endpoint: "/api/media",
1519
+ duration,
1520
+ statusCode: 401,
1521
+ errorType: "unauthorized",
1522
+ });
1523
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { "content-type": "application/json" } });
1524
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1525
+ }
1526
+ // Apply rate limiting: 60 requests per minute per user
1527
+ const rateLimitResponse = await rateLimiter.applyRateLimitKV(env, request, "/api/media", 60, 60, session.userId);
1528
+ if (rateLimitResponse) {
1529
+ const duration = Date.now() - startTime;
1530
+ metrics.trackRateLimit("/api/media", session.userId, undefined, 60, 60);
1531
+ return securityHeaders.addSecurityHeaders(rateLimitResponse);
1532
+ }
1533
+ try {
1534
+ // Parse query parameters
1535
+ const url = new URL(request.url);
1536
+ const limit = url.searchParams.get("limit")
1537
+ ? parseInt(url.searchParams.get("limit"), 10)
1538
+ : 50;
1539
+ const cursor = url.searchParams.get("cursor") || undefined;
1540
+ const sort = url.searchParams.get("sort") || "newest";
1541
+ const includeHidden = url.searchParams.get("includeHidden") === "true";
1542
+ const type = url.searchParams.get("type") || "all";
1543
+ const includeTotalCount = url.searchParams.get("includeTotalCount") === "true";
1544
+ // Validate limit
1545
+ if (limit < 1 || limit > 100) {
1546
+ const duration = Date.now() - startTime;
1547
+ metrics.trackOperation({
1548
+ operation: "list",
1549
+ endpoint: "/api/media",
1550
+ duration,
1551
+ statusCode: 400,
1552
+ errorType: "invalid_request",
1553
+ userId: session.userId,
1554
+ });
1555
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1556
+ error: "Invalid limit",
1557
+ message: "Limit must be between 1 and 100",
1558
+ }), { status: 400, headers: { "content-type": "application/json" } });
1559
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1560
+ }
1561
+ // Get user media
1562
+ const result = await mediaHandler.listUserMedia(session.userId, {
1563
+ limit,
1564
+ cursor,
1565
+ sort,
1566
+ includeHidden,
1567
+ type,
1568
+ includeTotalCount,
1569
+ }, env, request);
1570
+ const duration = Date.now() - startTime;
1571
+ const regionDetector = new RegionDetector(env);
1572
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1573
+ // Track metrics
1574
+ metrics.trackList("/api/media", duration, result.media.length, 200, region, session.userId);
1575
+ const response = securityHeaders.createSecureResponse(JSON.stringify(result), { status: 200, headers: { "content-type": "application/json" } });
1576
+ return cors_handler_1.CorsHandler.addCorsHeaders(response, request, env);
1577
+ }
1578
+ catch (error) {
1579
+ const duration = Date.now() - startTime;
1580
+ const regionDetector = new RegionDetector(env);
1581
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1582
+ const statusCode = error.message === "Media not found" ? 404 : 500;
1583
+ // Track error metrics
1584
+ metrics.trackOperation({
1585
+ operation: "list",
1586
+ endpoint: "/api/media",
1587
+ duration,
1588
+ statusCode,
1589
+ errorType: error?.name || "UnknownError",
1590
+ userId: session?.userId,
1591
+ region,
1592
+ });
1593
+ logger.error("Error listing user media:", error);
1594
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1595
+ error: "Failed to list media",
1596
+ message: error.message || "An unexpected error occurred",
1597
+ }), {
1598
+ status: statusCode,
1599
+ headers: { "content-type": "application/json" },
1600
+ });
1601
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1602
+ }
1603
+ },
1604
+ middleware: [(0, middleware_1.corsMiddleware)()],
1605
+ description: "List user media with pagination, sorting, and filtering",
1606
+ },
1607
+ {
1608
+ path: "/api/media/:mediaId/hide",
1609
+ method: "POST",
1610
+ handler: async (request, env, context) => {
1611
+ const startTime = Date.now();
1612
+ const sessionManager = new session_manager_1.SessionManager();
1613
+ const securityHeaders = new security_headers_1.SecurityHeaders(env);
1614
+ const logger = logger_1.Logger.getInstance(env);
1615
+ const rateLimiter = new rate_limit_1.RateLimiter();
1616
+ const mediaHandler = media_handler_1.MediaHandler.create(env);
1617
+ const { MediaMetrics } = await Promise.resolve().then(() => __importStar(require("../media-metrics")));
1618
+ const { RegionDetector } = await Promise.resolve().then(() => __importStar(require("../region-detection")));
1619
+ const metrics = new MediaMetrics(env);
1620
+ // Check authentication
1621
+ const session = await sessionManager.getSession(request, secret_resolver_1.Secrets.getSessionSecret(env), env);
1622
+ if (!session) {
1623
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { "content-type": "application/json" } });
1624
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1625
+ }
1626
+ // Apply rate limiting: 10 requests per minute per user
1627
+ const rateLimitResponse = await rateLimiter.applyRateLimitKV(env, request, "/api/media/:mediaId/hide", 10, 60, session.userId);
1628
+ if (rateLimitResponse) {
1629
+ return securityHeaders.addSecurityHeaders(rateLimitResponse);
1630
+ }
1631
+ try {
1632
+ const mediaId = context.params?.mediaId;
1633
+ if (!mediaId) {
1634
+ const duration = Date.now() - startTime;
1635
+ const regionDetector = new RegionDetector(env);
1636
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1637
+ metrics.trackOperation({
1638
+ operation: "hide",
1639
+ endpoint: "/api/media/:mediaId/hide",
1640
+ duration,
1641
+ statusCode: 400,
1642
+ errorType: "ValidationError",
1643
+ userId: session.userId,
1644
+ region,
1645
+ });
1646
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1647
+ error: "Invalid request",
1648
+ message: "Media ID is required",
1649
+ }), { status: 400, headers: { "content-type": "application/json" } });
1650
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1651
+ }
1652
+ // Hide media
1653
+ const result = await mediaHandler.hideMedia(mediaId, session.userId, env, request);
1654
+ const duration = Date.now() - startTime;
1655
+ const regionDetector = new RegionDetector(env);
1656
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1657
+ // Track metrics
1658
+ metrics.trackMediaAction("hide", "/api/media/:mediaId/hide", duration, 200, mediaId, region, session.userId);
1659
+ const response = securityHeaders.createSecureResponse(JSON.stringify({
1660
+ success: true,
1661
+ media: result,
1662
+ }), { status: 200, headers: { "content-type": "application/json" } });
1663
+ return cors_handler_1.CorsHandler.addCorsHeaders(response, request, env);
1664
+ }
1665
+ catch (error) {
1666
+ const duration = Date.now() - startTime;
1667
+ const regionDetector = new RegionDetector(env);
1668
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1669
+ let status = 500;
1670
+ let message = "Failed to hide media";
1671
+ let errorType = error?.name || "UnknownError";
1672
+ if (error.message === "Media not found") {
1673
+ status = 404;
1674
+ message = "Media not found";
1675
+ errorType = "NotFoundError";
1676
+ }
1677
+ else if (error.message.includes("permission")) {
1678
+ status = 403;
1679
+ message = "Forbidden";
1680
+ errorType = "ForbiddenError";
1681
+ }
1682
+ else if (error.message.includes("already hidden") ||
1683
+ error.message.includes("deleted")) {
1684
+ status = 400;
1685
+ message = error.message;
1686
+ errorType = "ValidationError";
1687
+ }
1688
+ // Track error metrics
1689
+ metrics.trackMediaAction("hide", "/api/media/:mediaId/hide", duration, status, context.params?.mediaId || "unknown", region, session?.userId, errorType);
1690
+ logger.error("Error hiding media:", error);
1691
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1692
+ error: message,
1693
+ message: error.message || "An unexpected error occurred",
1694
+ }), { status, headers: { "content-type": "application/json" } });
1695
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1696
+ }
1697
+ },
1698
+ middleware: [(0, middleware_1.corsMiddleware)(), (0, middleware_1.csrfMiddleware)()],
1699
+ description: "Hide a media file from all posts",
1700
+ },
1701
+ {
1702
+ path: "/api/media/:mediaId/unhide",
1703
+ method: "POST",
1704
+ handler: async (request, env, context) => {
1705
+ const startTime = Date.now();
1706
+ const sessionManager = new session_manager_1.SessionManager();
1707
+ const securityHeaders = new security_headers_1.SecurityHeaders(env);
1708
+ const logger = logger_1.Logger.getInstance(env);
1709
+ const rateLimiter = new rate_limit_1.RateLimiter();
1710
+ const mediaHandler = media_handler_1.MediaHandler.create(env);
1711
+ const { MediaMetrics } = await Promise.resolve().then(() => __importStar(require("../media-metrics")));
1712
+ const { RegionDetector } = await Promise.resolve().then(() => __importStar(require("../region-detection")));
1713
+ const metrics = new MediaMetrics(env);
1714
+ // Check authentication
1715
+ const session = await sessionManager.getSession(request, secret_resolver_1.Secrets.getSessionSecret(env), env);
1716
+ if (!session) {
1717
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { "content-type": "application/json" } });
1718
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1719
+ }
1720
+ // Apply rate limiting: 10 requests per minute per user
1721
+ const rateLimitResponse = await rateLimiter.applyRateLimitKV(env, request, "/api/media/:mediaId/unhide", 10, 60, session.userId);
1722
+ if (rateLimitResponse) {
1723
+ return securityHeaders.addSecurityHeaders(rateLimitResponse);
1724
+ }
1725
+ try {
1726
+ const mediaId = context.params?.mediaId;
1727
+ if (!mediaId) {
1728
+ const duration = Date.now() - startTime;
1729
+ const regionDetector = new RegionDetector(env);
1730
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1731
+ metrics.trackOperation({
1732
+ operation: "unhide",
1733
+ endpoint: "/api/media/:mediaId/unhide",
1734
+ duration,
1735
+ statusCode: 400,
1736
+ errorType: "ValidationError",
1737
+ userId: session.userId,
1738
+ region,
1739
+ });
1740
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1741
+ error: "Invalid request",
1742
+ message: "Media ID is required",
1743
+ }), { status: 400, headers: { "content-type": "application/json" } });
1744
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1745
+ }
1746
+ // Unhide media
1747
+ const result = await mediaHandler.unhideMedia(mediaId, session.userId, env, request);
1748
+ const duration = Date.now() - startTime;
1749
+ const regionDetector = new RegionDetector(env);
1750
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1751
+ // Track metrics
1752
+ metrics.trackMediaAction("unhide", "/api/media/:mediaId/unhide", duration, 200, mediaId, region, session.userId);
1753
+ const response = securityHeaders.createSecureResponse(JSON.stringify({
1754
+ success: true,
1755
+ media: result,
1756
+ }), { status: 200, headers: { "content-type": "application/json" } });
1757
+ return cors_handler_1.CorsHandler.addCorsHeaders(response, request, env);
1758
+ }
1759
+ catch (error) {
1760
+ const duration = Date.now() - startTime;
1761
+ const regionDetector = new RegionDetector(env);
1762
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1763
+ let status = 500;
1764
+ let message = "Failed to unhide media";
1765
+ let errorType = error?.name || "UnknownError";
1766
+ if (error.message === "Media not found") {
1767
+ status = 404;
1768
+ message = "Media not found";
1769
+ errorType = "NotFoundError";
1770
+ }
1771
+ else if (error.message.includes("permission")) {
1772
+ status = 403;
1773
+ message = "Forbidden";
1774
+ errorType = "ForbiddenError";
1775
+ }
1776
+ else if (error.message.includes("not hidden") ||
1777
+ error.message.includes("deleted")) {
1778
+ status = 400;
1779
+ message = error.message;
1780
+ errorType = "ValidationError";
1781
+ }
1782
+ // Track error metrics
1783
+ metrics.trackMediaAction("unhide", "/api/media/:mediaId/unhide", duration, status, context.params?.mediaId || "unknown", region, session?.userId, errorType);
1784
+ logger.error("Error unhiding media:", error);
1785
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1786
+ error: message,
1787
+ message: error.message || "An unexpected error occurred",
1788
+ }), { status, headers: { "content-type": "application/json" } });
1789
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1790
+ }
1791
+ },
1792
+ middleware: [(0, middleware_1.corsMiddleware)(), (0, middleware_1.csrfMiddleware)()],
1793
+ description: "Unhide a media file (make it visible again)",
1794
+ },
1795
+ {
1796
+ path: "/api/media/:mediaId",
1797
+ method: "DELETE",
1798
+ handler: async (request, env, context) => {
1799
+ const startTime = Date.now();
1800
+ const sessionManager = new session_manager_1.SessionManager();
1801
+ const securityHeaders = new security_headers_1.SecurityHeaders(env);
1802
+ const logger = logger_1.Logger.getInstance(env);
1803
+ const rateLimiter = new rate_limit_1.RateLimiter();
1804
+ const mediaHandler = media_handler_1.MediaHandler.create(env);
1805
+ const { MediaMetrics } = await Promise.resolve().then(() => __importStar(require("../media-metrics")));
1806
+ const { RegionDetector } = await Promise.resolve().then(() => __importStar(require("../region-detection")));
1807
+ const metrics = new MediaMetrics(env);
1808
+ // Check authentication
1809
+ const session = await sessionManager.getSession(request, secret_resolver_1.Secrets.getSessionSecret(env), env);
1810
+ if (!session) {
1811
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { "content-type": "application/json" } });
1812
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1813
+ }
1814
+ // Apply rate limiting: 10 requests per minute per user
1815
+ const rateLimitResponse = await rateLimiter.applyRateLimitKV(env, request, "/api/media/:mediaId", 10, 60, session.userId);
1816
+ if (rateLimitResponse) {
1817
+ return securityHeaders.addSecurityHeaders(rateLimitResponse);
1818
+ }
1819
+ try {
1820
+ const mediaId = context.params?.mediaId;
1821
+ if (!mediaId) {
1822
+ const duration = Date.now() - startTime;
1823
+ const regionDetector = new RegionDetector(env);
1824
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1825
+ metrics.trackOperation({
1826
+ operation: "delete",
1827
+ endpoint: "/api/media/:mediaId",
1828
+ duration,
1829
+ statusCode: 400,
1830
+ errorType: "ValidationError",
1831
+ userId: session.userId,
1832
+ region,
1833
+ });
1834
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1835
+ error: "Invalid request",
1836
+ message: "Media ID is required",
1837
+ }), { status: 400, headers: { "content-type": "application/json" } });
1838
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1839
+ }
1840
+ // Delete media
1841
+ try {
1842
+ await mediaHandler.deleteMedia(mediaId, session.userId, env, request);
1843
+ const duration = Date.now() - startTime;
1844
+ const regionDetector = new RegionDetector(env);
1845
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1846
+ // Track metrics
1847
+ metrics.trackMediaAction("delete", "/api/media/:mediaId", duration, 200, mediaId, region, session.userId);
1848
+ const response = securityHeaders.createSecureResponse(JSON.stringify({
1849
+ success: true,
1850
+ message: "Media deleted successfully",
1851
+ }), { status: 200, headers: { "content-type": "application/json" } });
1852
+ return cors_handler_1.CorsHandler.addCorsHeaders(response, request, env);
1853
+ }
1854
+ catch (deleteError) {
1855
+ const duration = Date.now() - startTime;
1856
+ const regionDetector = new RegionDetector(env);
1857
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1858
+ // Check if it's a "shared media" error (should hide instead)
1859
+ if (deleteError.message.includes("used by other users") ||
1860
+ deleteError.message.includes("hidden instead")) {
1861
+ // Track as conflict (media was hidden instead)
1862
+ metrics.trackMediaAction("delete", "/api/media/:mediaId", duration, 409, mediaId, region, session.userId, "ConflictError");
1863
+ const response = securityHeaders.createSecureResponse(JSON.stringify({
1864
+ success: false,
1865
+ error: "Media is shared with other users",
1866
+ message: deleteError.message,
1867
+ action: "hidden", // Media was hidden instead of deleted
1868
+ }), { status: 409, headers: { "content-type": "application/json" } });
1869
+ return cors_handler_1.CorsHandler.addCorsHeaders(response, request, env);
1870
+ }
1871
+ throw deleteError;
1872
+ }
1873
+ }
1874
+ catch (error) {
1875
+ const duration = Date.now() - startTime;
1876
+ const regionDetector = new RegionDetector(env);
1877
+ const region = await regionDetector.detectRegion(request, undefined, undefined);
1878
+ let status = 500;
1879
+ let message = "Failed to delete media";
1880
+ let errorType = error?.name || "UnknownError";
1881
+ if (error.message === "Media not found") {
1882
+ status = 404;
1883
+ message = "Media not found";
1884
+ errorType = "NotFoundError";
1885
+ }
1886
+ else if (error.message.includes("permission")) {
1887
+ status = 403;
1888
+ message = "Forbidden";
1889
+ errorType = "ForbiddenError";
1890
+ }
1891
+ else if (error.message.includes("already deleted")) {
1892
+ status = 400;
1893
+ message = error.message;
1894
+ errorType = "ValidationError";
1895
+ }
1896
+ // Track error metrics
1897
+ metrics.trackMediaAction("delete", "/api/media/:mediaId", duration, status, context.params?.mediaId || "unknown", region, session?.userId, errorType);
1898
+ logger.error("Error deleting media:", error);
1899
+ const errorResponse = securityHeaders.createSecureResponse(JSON.stringify({
1900
+ error: message,
1901
+ message: error.message || "An unexpected error occurred",
1902
+ }), { status, headers: { "content-type": "application/json" } });
1903
+ return cors_handler_1.CorsHandler.addCorsHeaders(errorResponse, request, env);
1904
+ }
1905
+ },
1906
+ middleware: [(0, middleware_1.corsMiddleware)(), (0, middleware_1.csrfMiddleware)()],
1907
+ description: "Delete a media file (soft delete)",
1908
+ },
1909
+ ];
1910
+ //# sourceMappingURL=media.js.map