@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.
- package/dist/db.d.ts +36 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +39 -0
- package/dist/db.js.map +1 -0
- package/dist/env.d.ts +107 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +268 -0
- package/dist/env.js.map +1 -0
- package/dist/extensions.d.ts +15 -0
- package/dist/extensions.d.ts.map +1 -0
- package/dist/extensions.js +35 -0
- package/dist/extensions.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/lambda/cleanup-cron.d.ts +2 -0
- package/dist/lambda/cleanup-cron.d.ts.map +1 -0
- package/dist/lambda/cleanup-cron.js +38 -0
- package/dist/lambda/cleanup-cron.js.map +1 -0
- package/dist/lambda/create-auth-challenge.d.ts +2 -0
- package/dist/lambda/create-auth-challenge.d.ts.map +1 -0
- package/dist/lambda/create-auth-challenge.js +108 -0
- package/dist/lambda/create-auth-challenge.js.map +1 -0
- package/dist/lambda/custom-message.d.ts +3 -0
- package/dist/lambda/custom-message.d.ts.map +1 -0
- package/dist/lambda/custom-message.js +29 -0
- package/dist/lambda/custom-message.js.map +1 -0
- package/dist/lambda/define-auth-challenge.d.ts +2 -0
- package/dist/lambda/define-auth-challenge.d.ts.map +1 -0
- package/dist/lambda/define-auth-challenge.js +27 -0
- package/dist/lambda/define-auth-challenge.js.map +1 -0
- package/dist/lambda/delete-account-worker.d.ts +3 -0
- package/dist/lambda/delete-account-worker.d.ts.map +1 -0
- package/dist/lambda/delete-account-worker.js +122 -0
- package/dist/lambda/delete-account-worker.js.map +1 -0
- package/dist/lambda/diagnostics-proxy.d.ts +6 -0
- package/dist/lambda/diagnostics-proxy.d.ts.map +1 -0
- package/dist/lambda/diagnostics-proxy.js +154 -0
- package/dist/lambda/diagnostics-proxy.js.map +1 -0
- package/dist/lambda/e2e-sweeper.d.ts +18 -0
- package/dist/lambda/e2e-sweeper.d.ts.map +1 -0
- package/dist/lambda/e2e-sweeper.js +127 -0
- package/dist/lambda/e2e-sweeper.js.map +1 -0
- package/dist/lambda/federation-outbox-worker.d.ts +3 -0
- package/dist/lambda/federation-outbox-worker.d.ts.map +1 -0
- package/dist/lambda/federation-outbox-worker.js +11 -0
- package/dist/lambda/federation-outbox-worker.js.map +1 -0
- package/dist/lambda/followers-events-worker.d.ts +3 -0
- package/dist/lambda/followers-events-worker.d.ts.map +1 -0
- package/dist/lambda/followers-events-worker.js +11 -0
- package/dist/lambda/followers-events-worker.js.map +1 -0
- package/dist/lambda/hourly-cron.d.ts +2 -0
- package/dist/lambda/hourly-cron.d.ts.map +1 -0
- package/dist/lambda/hourly-cron.js +101 -0
- package/dist/lambda/hourly-cron.js.map +1 -0
- package/dist/lambda/link-check-worker.d.ts +3 -0
- package/dist/lambda/link-check-worker.d.ts.map +1 -0
- package/dist/lambda/link-check-worker.js +11 -0
- package/dist/lambda/link-check-worker.js.map +1 -0
- package/dist/lambda/maintenance-cron.d.ts +2 -0
- package/dist/lambda/maintenance-cron.d.ts.map +1 -0
- package/dist/lambda/maintenance-cron.js +127 -0
- package/dist/lambda/maintenance-cron.js.map +1 -0
- package/dist/lambda/media-processing-worker.d.ts +3 -0
- package/dist/lambda/media-processing-worker.d.ts.map +1 -0
- package/dist/lambda/media-processing-worker.js +95 -0
- package/dist/lambda/media-processing-worker.js.map +1 -0
- package/dist/lambda/media-reconciliation-worker.d.ts +3 -0
- package/dist/lambda/media-reconciliation-worker.d.ts.map +1 -0
- package/dist/lambda/media-reconciliation-worker.js +11 -0
- package/dist/lambda/media-reconciliation-worker.js.map +1 -0
- package/dist/lambda/nightly-cron.d.ts +2 -0
- package/dist/lambda/nightly-cron.d.ts.map +1 -0
- package/dist/lambda/nightly-cron.js +348 -0
- package/dist/lambda/nightly-cron.js.map +1 -0
- package/dist/lambda/post-confirmation.d.ts +3 -0
- package/dist/lambda/post-confirmation.d.ts.map +1 -0
- package/dist/lambda/post-confirmation.js +79 -0
- package/dist/lambda/post-confirmation.js.map +1 -0
- package/dist/lambda/pre-signup.d.ts +3 -0
- package/dist/lambda/pre-signup.d.ts.map +1 -0
- package/dist/lambda/pre-signup.js +35 -0
- package/dist/lambda/pre-signup.js.map +1 -0
- package/dist/lambda/pre-token-generation.d.ts +3 -0
- package/dist/lambda/pre-token-generation.d.ts.map +1 -0
- package/dist/lambda/pre-token-generation.js +79 -0
- package/dist/lambda/pre-token-generation.js.map +1 -0
- package/dist/lambda/tools/check-health.d.ts +6 -0
- package/dist/lambda/tools/check-health.d.ts.map +1 -0
- package/dist/lambda/tools/check-health.js +24 -0
- package/dist/lambda/tools/check-health.js.map +1 -0
- package/dist/lambda/tools/describe-services.d.ts +20 -0
- package/dist/lambda/tools/describe-services.d.ts.map +1 -0
- package/dist/lambda/tools/describe-services.js +41 -0
- package/dist/lambda/tools/describe-services.js.map +1 -0
- package/dist/lambda/tools/get-cost-report.d.ts +16 -0
- package/dist/lambda/tools/get-cost-report.d.ts.map +1 -0
- package/dist/lambda/tools/get-cost-report.js +54 -0
- package/dist/lambda/tools/get-cost-report.js.map +1 -0
- package/dist/lambda/tools/get-errors.d.ts +11 -0
- package/dist/lambda/tools/get-errors.d.ts.map +1 -0
- package/dist/lambda/tools/get-errors.js +62 -0
- package/dist/lambda/tools/get-errors.js.map +1 -0
- package/dist/lambda/tools/get-feature-flags.d.ts +8 -0
- package/dist/lambda/tools/get-feature-flags.d.ts.map +1 -0
- package/dist/lambda/tools/get-feature-flags.js +23 -0
- package/dist/lambda/tools/get-feature-flags.js.map +1 -0
- package/dist/lambda/tools/get-queue-status.d.ts +9 -0
- package/dist/lambda/tools/get-queue-status.d.ts.map +1 -0
- package/dist/lambda/tools/get-queue-status.js +46 -0
- package/dist/lambda/tools/get-queue-status.js.map +1 -0
- package/dist/lambda/tools/search-logs.d.ts +19 -0
- package/dist/lambda/tools/search-logs.d.ts.map +1 -0
- package/dist/lambda/tools/search-logs.js +55 -0
- package/dist/lambda/tools/search-logs.js.map +1 -0
- package/dist/lambda/tools/send-alert.d.ts +8 -0
- package/dist/lambda/tools/send-alert.d.ts.map +1 -0
- package/dist/lambda/tools/send-alert.js +29 -0
- package/dist/lambda/tools/send-alert.js.map +1 -0
- package/dist/lambda/verify-auth-challenge.d.ts +2 -0
- package/dist/lambda/verify-auth-challenge.d.ts.map +1 -0
- package/dist/lambda/verify-auth-challenge.js +35 -0
- package/dist/lambda/verify-auth-challenge.js.map +1 -0
- package/dist/lib/abuse-metrics.d.ts +44 -0
- package/dist/lib/abuse-metrics.d.ts.map +1 -0
- package/dist/lib/abuse-metrics.js +322 -0
- package/dist/lib/abuse-metrics.js.map +1 -0
- package/dist/lib/activitypub/activity-processor.d.ts +89 -0
- package/dist/lib/activitypub/activity-processor.d.ts.map +1 -0
- package/dist/lib/activitypub/activity-processor.js +709 -0
- package/dist/lib/activitypub/activity-processor.js.map +1 -0
- package/dist/lib/activitypub/activity-service.d.ts +47 -0
- package/dist/lib/activitypub/activity-service.d.ts.map +1 -0
- package/dist/lib/activitypub/activity-service.js +165 -0
- package/dist/lib/activitypub/activity-service.js.map +1 -0
- package/dist/lib/activitypub/actor.d.ts +44 -0
- package/dist/lib/activitypub/actor.d.ts.map +1 -0
- package/dist/lib/activitypub/actor.js +116 -0
- package/dist/lib/activitypub/actor.js.map +1 -0
- package/dist/lib/activitypub/audience-service.d.ts +52 -0
- package/dist/lib/activitypub/audience-service.d.ts.map +1 -0
- package/dist/lib/activitypub/audience-service.js +245 -0
- package/dist/lib/activitypub/audience-service.js.map +1 -0
- package/dist/lib/activitypub/crypto.d.ts +42 -0
- package/dist/lib/activitypub/crypto.d.ts.map +1 -0
- package/dist/lib/activitypub/crypto.js +129 -0
- package/dist/lib/activitypub/crypto.js.map +1 -0
- package/dist/lib/activitypub/delivery-service.d.ts +44 -0
- package/dist/lib/activitypub/delivery-service.d.ts.map +1 -0
- package/dist/lib/activitypub/delivery-service.js +259 -0
- package/dist/lib/activitypub/delivery-service.js.map +1 -0
- package/dist/lib/activitypub/dispatchers/entity-actor.d.ts +50 -0
- package/dist/lib/activitypub/dispatchers/entity-actor.d.ts.map +1 -0
- package/dist/lib/activitypub/dispatchers/entity-actor.js +247 -0
- package/dist/lib/activitypub/dispatchers/entity-actor.js.map +1 -0
- package/dist/lib/activitypub/dispatchers/group-actor.d.ts +47 -0
- package/dist/lib/activitypub/dispatchers/group-actor.d.ts.map +1 -0
- package/dist/lib/activitypub/dispatchers/group-actor.js +202 -0
- package/dist/lib/activitypub/dispatchers/group-actor.js.map +1 -0
- package/dist/lib/activitypub/dispatchers/user-actor.d.ts +47 -0
- package/dist/lib/activitypub/dispatchers/user-actor.d.ts.map +1 -0
- package/dist/lib/activitypub/dispatchers/user-actor.js +207 -0
- package/dist/lib/activitypub/dispatchers/user-actor.js.map +1 -0
- package/dist/lib/activitypub/dm-service.d.ts +35 -0
- package/dist/lib/activitypub/dm-service.d.ts.map +1 -0
- package/dist/lib/activitypub/dm-service.js +73 -0
- package/dist/lib/activitypub/dm-service.js.map +1 -0
- package/dist/lib/activitypub/entity-profile-service.d.ts +43 -0
- package/dist/lib/activitypub/entity-profile-service.d.ts.map +1 -0
- package/dist/lib/activitypub/entity-profile-service.js +80 -0
- package/dist/lib/activitypub/entity-profile-service.js.map +1 -0
- package/dist/lib/activitypub/fedify/config.d.ts +15 -0
- package/dist/lib/activitypub/fedify/config.d.ts.map +1 -0
- package/dist/lib/activitypub/fedify/config.js +38 -0
- package/dist/lib/activitypub/fedify/config.js.map +1 -0
- package/dist/lib/activitypub/fedify/context.d.ts +21 -0
- package/dist/lib/activitypub/fedify/context.d.ts.map +1 -0
- package/dist/lib/activitypub/fedify/context.js +67 -0
- package/dist/lib/activitypub/fedify/context.js.map +1 -0
- package/dist/lib/activitypub/fedify/runtime.d.ts +18 -0
- package/dist/lib/activitypub/fedify/runtime.d.ts.map +1 -0
- package/dist/lib/activitypub/fedify/runtime.js +26 -0
- package/dist/lib/activitypub/fedify/runtime.js.map +1 -0
- package/dist/lib/activitypub/friendship-service.d.ts +15 -0
- package/dist/lib/activitypub/friendship-service.d.ts.map +1 -0
- package/dist/lib/activitypub/friendship-service.js +26 -0
- package/dist/lib/activitypub/friendship-service.js.map +1 -0
- package/dist/lib/activitypub/group-service.d.ts +83 -0
- package/dist/lib/activitypub/group-service.d.ts.map +1 -0
- package/dist/lib/activitypub/group-service.js +301 -0
- package/dist/lib/activitypub/group-service.js.map +1 -0
- package/dist/lib/activitypub/http-signatures.d.ts +41 -0
- package/dist/lib/activitypub/http-signatures.d.ts.map +1 -0
- package/dist/lib/activitypub/http-signatures.js +284 -0
- package/dist/lib/activitypub/http-signatures.js.map +1 -0
- package/dist/lib/activitypub/jsonld.d.ts +39 -0
- package/dist/lib/activitypub/jsonld.d.ts.map +1 -0
- package/dist/lib/activitypub/jsonld.js +97 -0
- package/dist/lib/activitypub/jsonld.js.map +1 -0
- package/dist/lib/activitypub/listeners/friends-collection.d.ts +20 -0
- package/dist/lib/activitypub/listeners/friends-collection.d.ts.map +1 -0
- package/dist/lib/activitypub/listeners/friends-collection.js +105 -0
- package/dist/lib/activitypub/listeners/friends-collection.js.map +1 -0
- package/dist/lib/activitypub/listeners/http-signatures.d.ts +29 -0
- package/dist/lib/activitypub/listeners/http-signatures.d.ts.map +1 -0
- package/dist/lib/activitypub/listeners/http-signatures.js +208 -0
- package/dist/lib/activitypub/listeners/http-signatures.js.map +1 -0
- package/dist/lib/activitypub/listeners/inbox.d.ts +34 -0
- package/dist/lib/activitypub/listeners/inbox.d.ts.map +1 -0
- package/dist/lib/activitypub/listeners/inbox.js +226 -0
- package/dist/lib/activitypub/listeners/inbox.js.map +1 -0
- package/dist/lib/activitypub/listeners/outbox.d.ts +20 -0
- package/dist/lib/activitypub/listeners/outbox.d.ts.map +1 -0
- package/dist/lib/activitypub/listeners/outbox.js +117 -0
- package/dist/lib/activitypub/listeners/outbox.js.map +1 -0
- package/dist/lib/activitypub/remote-fetch-service.d.ts +108 -0
- package/dist/lib/activitypub/remote-fetch-service.d.ts.map +1 -0
- package/dist/lib/activitypub/remote-fetch-service.js +364 -0
- package/dist/lib/activitypub/remote-fetch-service.js.map +1 -0
- package/dist/lib/activitypub/services/abuse-prevention.d.ts +52 -0
- package/dist/lib/activitypub/services/abuse-prevention.d.ts.map +1 -0
- package/dist/lib/activitypub/services/abuse-prevention.js +118 -0
- package/dist/lib/activitypub/services/abuse-prevention.js.map +1 -0
- package/dist/lib/activitypub/services/dm-service-fedify.d.ts +46 -0
- package/dist/lib/activitypub/services/dm-service-fedify.d.ts.map +1 -0
- package/dist/lib/activitypub/services/dm-service-fedify.js +168 -0
- package/dist/lib/activitypub/services/dm-service-fedify.js.map +1 -0
- package/dist/lib/activitypub/services/fedify-converters.d.ts +51 -0
- package/dist/lib/activitypub/services/fedify-converters.d.ts.map +1 -0
- package/dist/lib/activitypub/services/fedify-converters.js +109 -0
- package/dist/lib/activitypub/services/fedify-converters.js.map +1 -0
- package/dist/lib/activitypub/services/fedify-delivery.d.ts +41 -0
- package/dist/lib/activitypub/services/fedify-delivery.d.ts.map +1 -0
- package/dist/lib/activitypub/services/fedify-delivery.js +186 -0
- package/dist/lib/activitypub/services/fedify-delivery.js.map +1 -0
- package/dist/lib/activitypub/services/follow-activity-service.d.ts +34 -0
- package/dist/lib/activitypub/services/follow-activity-service.d.ts.map +1 -0
- package/dist/lib/activitypub/services/follow-activity-service.js +64 -0
- package/dist/lib/activitypub/services/follow-activity-service.js.map +1 -0
- package/dist/lib/activitypub/services/post-service-fedify.d.ts +49 -0
- package/dist/lib/activitypub/services/post-service-fedify.d.ts.map +1 -0
- package/dist/lib/activitypub/services/post-service-fedify.js +281 -0
- package/dist/lib/activitypub/services/post-service-fedify.js.map +1 -0
- package/dist/lib/activitypub/services/remote-activity-handler.d.ts +22 -0
- package/dist/lib/activitypub/services/remote-activity-handler.d.ts.map +1 -0
- package/dist/lib/activitypub/services/remote-activity-handler.js +136 -0
- package/dist/lib/activitypub/services/remote-activity-handler.js.map +1 -0
- package/dist/lib/activitypub/standalone-mode.d.ts +34 -0
- package/dist/lib/activitypub/standalone-mode.d.ts.map +1 -0
- package/dist/lib/activitypub/standalone-mode.js +127 -0
- package/dist/lib/activitypub/standalone-mode.js.map +1 -0
- package/dist/lib/activitypub/webfinger/server.d.ts +16 -0
- package/dist/lib/activitypub/webfinger/server.d.ts.map +1 -0
- package/dist/lib/activitypub/webfinger/server.js +221 -0
- package/dist/lib/activitypub/webfinger/server.js.map +1 -0
- package/dist/lib/age-gate-middleware.d.ts +19 -0
- package/dist/lib/age-gate-middleware.d.ts.map +1 -0
- package/dist/lib/age-gate-middleware.js +26 -0
- package/dist/lib/age-gate-middleware.js.map +1 -0
- package/dist/lib/age-gate.d.ts +37 -0
- package/dist/lib/age-gate.d.ts.map +1 -0
- package/dist/lib/age-gate.js +96 -0
- package/dist/lib/age-gate.js.map +1 -0
- package/dist/lib/age-tier-transition.d.ts +21 -0
- package/dist/lib/age-tier-transition.d.ts.map +1 -0
- package/dist/lib/age-tier-transition.js +190 -0
- package/dist/lib/age-tier-transition.js.map +1 -0
- package/dist/lib/audit-logger.d.ts +142 -0
- package/dist/lib/audit-logger.d.ts.map +1 -0
- package/dist/lib/audit-logger.js +326 -0
- package/dist/lib/audit-logger.js.map +1 -0
- package/dist/lib/auth/cognito-jwt.d.ts +20 -0
- package/dist/lib/auth/cognito-jwt.d.ts.map +1 -0
- package/dist/lib/auth/cognito-jwt.js +56 -0
- package/dist/lib/auth/cognito-jwt.js.map +1 -0
- package/dist/lib/auth-context-manager.d.ts +116 -0
- package/dist/lib/auth-context-manager.d.ts.map +1 -0
- package/dist/lib/auth-context-manager.js +130 -0
- package/dist/lib/auth-context-manager.js.map +1 -0
- package/dist/lib/auth-handler.d.ts +19 -0
- package/dist/lib/auth-handler.d.ts.map +1 -0
- package/dist/lib/auth-handler.js +76 -0
- package/dist/lib/auth-handler.js.map +1 -0
- package/dist/lib/badge-handler.d.ts +20 -0
- package/dist/lib/badge-handler.d.ts.map +1 -0
- package/dist/lib/badge-handler.js +142 -0
- package/dist/lib/badge-handler.js.map +1 -0
- package/dist/lib/circle-handler.d.ts +22 -0
- package/dist/lib/circle-handler.d.ts.map +1 -0
- package/dist/lib/circle-handler.js +224 -0
- package/dist/lib/circle-handler.js.map +1 -0
- package/dist/lib/circuit-breaker.d.ts +27 -0
- package/dist/lib/circuit-breaker.d.ts.map +1 -0
- package/dist/lib/circuit-breaker.js +63 -0
- package/dist/lib/circuit-breaker.js.map +1 -0
- package/dist/lib/comment-handler.d.ts +77 -0
- package/dist/lib/comment-handler.d.ts.map +1 -0
- package/dist/lib/comment-handler.js +953 -0
- package/dist/lib/comment-handler.js.map +1 -0
- package/dist/lib/connection-code-handler.d.ts +17 -0
- package/dist/lib/connection-code-handler.d.ts.map +1 -0
- package/dist/lib/connection-code-handler.js +293 -0
- package/dist/lib/connection-code-handler.js.map +1 -0
- package/dist/lib/content-discovery.d.ts +113 -0
- package/dist/lib/content-discovery.d.ts.map +1 -0
- package/dist/lib/content-discovery.js +519 -0
- package/dist/lib/content-discovery.js.map +1 -0
- package/dist/lib/context-aware-data-access.d.ts +89 -0
- package/dist/lib/context-aware-data-access.d.ts.map +1 -0
- package/dist/lib/context-aware-data-access.js +97 -0
- package/dist/lib/context-aware-data-access.js.map +1 -0
- package/dist/lib/cors-handler.d.ts +29 -0
- package/dist/lib/cors-handler.d.ts.map +1 -0
- package/dist/lib/cors-handler.js +225 -0
- package/dist/lib/cors-handler.js.map +1 -0
- package/dist/lib/cost-accumulator.d.ts +58 -0
- package/dist/lib/cost-accumulator.d.ts.map +1 -0
- package/dist/lib/cost-accumulator.js +173 -0
- package/dist/lib/cost-accumulator.js.map +1 -0
- package/dist/lib/crypto/encryption-service.d.ts +100 -0
- package/dist/lib/crypto/encryption-service.d.ts.map +1 -0
- package/dist/lib/crypto/encryption-service.js +293 -0
- package/dist/lib/crypto/encryption-service.js.map +1 -0
- package/dist/lib/crypto/index.d.ts +22 -0
- package/dist/lib/crypto/index.d.ts.map +1 -0
- package/dist/lib/crypto/index.js +28 -0
- package/dist/lib/crypto/index.js.map +1 -0
- package/dist/lib/crypto/types.d.ts +71 -0
- package/dist/lib/crypto/types.d.ts.map +1 -0
- package/dist/lib/crypto/types.js +3 -0
- package/dist/lib/crypto/types.js.map +1 -0
- package/dist/lib/crypto/versioning.d.ts +112 -0
- package/dist/lib/crypto/versioning.d.ts.map +1 -0
- package/dist/lib/crypto/versioning.js +148 -0
- package/dist/lib/crypto/versioning.js.map +1 -0
- package/dist/lib/crypto/voting/elgamal-encryption.d.ts +156 -0
- package/dist/lib/crypto/voting/elgamal-encryption.d.ts.map +1 -0
- package/dist/lib/crypto/voting/elgamal-encryption.js +172 -0
- package/dist/lib/crypto/voting/elgamal-encryption.js.map +1 -0
- package/dist/lib/crypto/voting/encryption-scheme.d.ts +138 -0
- package/dist/lib/crypto/voting/encryption-scheme.d.ts.map +1 -0
- package/dist/lib/crypto/voting/encryption-scheme.js +13 -0
- package/dist/lib/crypto/voting/encryption-scheme.js.map +1 -0
- package/dist/lib/crypto/voting/hash-utils.d.ts +58 -0
- package/dist/lib/crypto/voting/hash-utils.d.ts.map +1 -0
- package/dist/lib/crypto/voting/hash-utils.js +73 -0
- package/dist/lib/crypto/voting/hash-utils.js.map +1 -0
- package/dist/lib/crypto/voting/hybrid-encryption.d.ts +109 -0
- package/dist/lib/crypto/voting/hybrid-encryption.d.ts.map +1 -0
- package/dist/lib/crypto/voting/hybrid-encryption.js +134 -0
- package/dist/lib/crypto/voting/hybrid-encryption.js.map +1 -0
- package/dist/lib/crypto/voting/index.d.ts +18 -0
- package/dist/lib/crypto/voting/index.d.ts.map +1 -0
- package/dist/lib/crypto/voting/index.js +27 -0
- package/dist/lib/crypto/voting/index.js.map +1 -0
- package/dist/lib/crypto/voting/post-quantum-encryption.d.ts +107 -0
- package/dist/lib/crypto/voting/post-quantum-encryption.d.ts.map +1 -0
- package/dist/lib/crypto/voting/post-quantum-encryption.js +123 -0
- package/dist/lib/crypto/voting/post-quantum-encryption.js.map +1 -0
- package/dist/lib/csrf.d.ts +95 -0
- package/dist/lib/csrf.d.ts.map +1 -0
- package/dist/lib/csrf.js +174 -0
- package/dist/lib/csrf.js.map +1 -0
- package/dist/lib/data-router.d.ts +209 -0
- package/dist/lib/data-router.d.ts.map +1 -0
- package/dist/lib/data-router.js +792 -0
- package/dist/lib/data-router.js.map +1 -0
- package/dist/lib/database-circuit-breaker.d.ts +75 -0
- package/dist/lib/database-circuit-breaker.d.ts.map +1 -0
- package/dist/lib/database-circuit-breaker.js +155 -0
- package/dist/lib/database-circuit-breaker.js.map +1 -0
- package/dist/lib/database-config.d.ts +20 -0
- package/dist/lib/database-config.d.ts.map +1 -0
- package/dist/lib/database-config.js +46 -0
- package/dist/lib/database-config.js.map +1 -0
- package/dist/lib/database-connection-manager.d.ts +99 -0
- package/dist/lib/database-connection-manager.d.ts.map +1 -0
- package/dist/lib/database-connection-manager.js +495 -0
- package/dist/lib/database-connection-manager.js.map +1 -0
- package/dist/lib/database-monitor.d.ts +89 -0
- package/dist/lib/database-monitor.d.ts.map +1 -0
- package/dist/lib/database-monitor.js +199 -0
- package/dist/lib/database-monitor.js.map +1 -0
- package/dist/lib/database-rate-limiter.d.ts +41 -0
- package/dist/lib/database-rate-limiter.d.ts.map +1 -0
- package/dist/lib/database-rate-limiter.js +90 -0
- package/dist/lib/database-rate-limiter.js.map +1 -0
- package/dist/lib/database-wrapper-helper.d.ts +44 -0
- package/dist/lib/database-wrapper-helper.d.ts.map +1 -0
- package/dist/lib/database-wrapper-helper.js +104 -0
- package/dist/lib/database-wrapper-helper.js.map +1 -0
- package/dist/lib/database-wrapper.d.ts +51 -0
- package/dist/lib/database-wrapper.d.ts.map +1 -0
- package/dist/lib/database-wrapper.js +109 -0
- package/dist/lib/database-wrapper.js.map +1 -0
- package/dist/lib/db-query-helper.d.ts +130 -0
- package/dist/lib/db-query-helper.d.ts.map +1 -0
- package/dist/lib/db-query-helper.js +105 -0
- package/dist/lib/db-query-helper.js.map +1 -0
- package/dist/lib/discovery-handler.d.ts +19 -0
- package/dist/lib/discovery-handler.d.ts.map +1 -0
- package/dist/lib/discovery-handler.js +195 -0
- package/dist/lib/discovery-handler.js.map +1 -0
- package/dist/lib/domain-reputation-service.d.ts +112 -0
- package/dist/lib/domain-reputation-service.d.ts.map +1 -0
- package/dist/lib/domain-reputation-service.js +344 -0
- package/dist/lib/domain-reputation-service.js.map +1 -0
- package/dist/lib/email-privacy.d.ts +54 -0
- package/dist/lib/email-privacy.d.ts.map +1 -0
- package/dist/lib/email-privacy.js +72 -0
- package/dist/lib/email-privacy.js.map +1 -0
- package/dist/lib/email-provider.d.ts +133 -0
- package/dist/lib/email-provider.d.ts.map +1 -0
- package/dist/lib/email-provider.js +391 -0
- package/dist/lib/email-provider.js.map +1 -0
- package/dist/lib/encryption-key-service.d.ts +115 -0
- package/dist/lib/encryption-key-service.d.ts.map +1 -0
- package/dist/lib/encryption-key-service.js +272 -0
- package/dist/lib/encryption-key-service.js.map +1 -0
- package/dist/lib/entity-handler.d.ts +59 -0
- package/dist/lib/entity-handler.d.ts.map +1 -0
- package/dist/lib/entity-handler.js +866 -0
- package/dist/lib/entity-handler.js.map +1 -0
- package/dist/lib/entity-relationship-handler.d.ts +19 -0
- package/dist/lib/entity-relationship-handler.d.ts.map +1 -0
- package/dist/lib/entity-relationship-handler.js +242 -0
- package/dist/lib/entity-relationship-handler.js.map +1 -0
- package/dist/lib/entity-tagging-errors.d.ts +32 -0
- package/dist/lib/entity-tagging-errors.d.ts.map +1 -0
- package/dist/lib/entity-tagging-errors.js +53 -0
- package/dist/lib/entity-tagging-errors.js.map +1 -0
- package/dist/lib/entity-tagging-validator.d.ts +47 -0
- package/dist/lib/entity-tagging-validator.d.ts.map +1 -0
- package/dist/lib/entity-tagging-validator.js +84 -0
- package/dist/lib/entity-tagging-validator.js.map +1 -0
- package/dist/lib/exif-stripper.d.ts +37 -0
- package/dist/lib/exif-stripper.d.ts.map +1 -0
- package/dist/lib/exif-stripper.js +62 -0
- package/dist/lib/exif-stripper.js.map +1 -0
- package/dist/lib/extension-context.d.ts +19 -0
- package/dist/lib/extension-context.d.ts.map +1 -0
- package/dist/lib/extension-context.js +78 -0
- package/dist/lib/extension-context.js.map +1 -0
- package/dist/lib/extension-route-wrapper.d.ts +21 -0
- package/dist/lib/extension-route-wrapper.d.ts.map +1 -0
- package/dist/lib/extension-route-wrapper.js +113 -0
- package/dist/lib/extension-route-wrapper.js.map +1 -0
- package/dist/lib/extension-validator.d.ts +12 -0
- package/dist/lib/extension-validator.d.ts.map +1 -0
- package/dist/lib/extension-validator.js +60 -0
- package/dist/lib/extension-validator.js.map +1 -0
- package/dist/lib/feature-flags.d.ts +56 -0
- package/dist/lib/feature-flags.d.ts.map +1 -0
- package/dist/lib/feature-flags.js +140 -0
- package/dist/lib/feature-flags.js.map +1 -0
- package/dist/lib/feature-toggle-service.d.ts +48 -0
- package/dist/lib/feature-toggle-service.d.ts.map +1 -0
- package/dist/lib/feature-toggle-service.js +167 -0
- package/dist/lib/feature-toggle-service.js.map +1 -0
- package/dist/lib/feed-handler.d.ts +152 -0
- package/dist/lib/feed-handler.d.ts.map +1 -0
- package/dist/lib/feed-handler.js +784 -0
- package/dist/lib/feed-handler.js.map +1 -0
- package/dist/lib/feed-pagination.d.ts +42 -0
- package/dist/lib/feed-pagination.d.ts.map +1 -0
- package/dist/lib/feed-pagination.js +54 -0
- package/dist/lib/feed-pagination.js.map +1 -0
- package/dist/lib/feed-personalization.d.ts +52 -0
- package/dist/lib/feed-personalization.d.ts.map +1 -0
- package/dist/lib/feed-personalization.js +105 -0
- package/dist/lib/feed-personalization.js.map +1 -0
- package/dist/lib/followers-events.d.ts +37 -0
- package/dist/lib/followers-events.d.ts.map +1 -0
- package/dist/lib/followers-events.js +149 -0
- package/dist/lib/followers-events.js.map +1 -0
- package/dist/lib/followers-handler.d.ts +21 -0
- package/dist/lib/followers-handler.d.ts.map +1 -0
- package/dist/lib/followers-handler.js +35 -0
- package/dist/lib/followers-handler.js.map +1 -0
- package/dist/lib/friends-handler.d.ts +78 -0
- package/dist/lib/friends-handler.d.ts.map +1 -0
- package/dist/lib/friends-handler.js +390 -0
- package/dist/lib/friends-handler.js.map +1 -0
- package/dist/lib/graph/dual-write-service.d.ts +116 -0
- package/dist/lib/graph/dual-write-service.d.ts.map +1 -0
- package/dist/lib/graph/dual-write-service.js +332 -0
- package/dist/lib/graph/dual-write-service.js.map +1 -0
- package/dist/lib/graph/dual-write.d.ts +396 -0
- package/dist/lib/graph/dual-write.d.ts.map +1 -0
- package/dist/lib/graph/dual-write.js +53 -0
- package/dist/lib/graph/dual-write.js.map +1 -0
- package/dist/lib/graph/errors.d.ts +90 -0
- package/dist/lib/graph/errors.d.ts.map +1 -0
- package/dist/lib/graph/errors.js +131 -0
- package/dist/lib/graph/errors.js.map +1 -0
- package/dist/lib/graph/graph-factory.d.ts +64 -0
- package/dist/lib/graph/graph-factory.d.ts.map +1 -0
- package/dist/lib/graph/graph-factory.js +190 -0
- package/dist/lib/graph/graph-factory.js.map +1 -0
- package/dist/lib/graph/graph-schema-init.d.ts +31 -0
- package/dist/lib/graph/graph-schema-init.d.ts.map +1 -0
- package/dist/lib/graph/graph-schema-init.js +105 -0
- package/dist/lib/graph/graph-schema-init.js.map +1 -0
- package/dist/lib/graph/graph-service.d.ts +479 -0
- package/dist/lib/graph/graph-service.d.ts.map +1 -0
- package/dist/lib/graph/graph-service.js +21 -0
- package/dist/lib/graph/graph-service.js.map +1 -0
- package/dist/lib/graph/index.d.ts +40 -0
- package/dist/lib/graph/index.d.ts.map +1 -0
- package/dist/lib/graph/index.js +74 -0
- package/dist/lib/graph/index.js.map +1 -0
- package/dist/lib/graph/neo4j-graph-service.d.ts +186 -0
- package/dist/lib/graph/neo4j-graph-service.d.ts.map +1 -0
- package/dist/lib/graph/neo4j-graph-service.js +1625 -0
- package/dist/lib/graph/neo4j-graph-service.js.map +1 -0
- package/dist/lib/graph/reconciliation-service.d.ts +113 -0
- package/dist/lib/graph/reconciliation-service.d.ts.map +1 -0
- package/dist/lib/graph/reconciliation-service.js +533 -0
- package/dist/lib/graph/reconciliation-service.js.map +1 -0
- package/dist/lib/graph/scoring-engine.d.ts +154 -0
- package/dist/lib/graph/scoring-engine.d.ts.map +1 -0
- package/dist/lib/graph/scoring-engine.js +286 -0
- package/dist/lib/graph/scoring-engine.js.map +1 -0
- package/dist/lib/graph/types.d.ts +480 -0
- package/dist/lib/graph/types.d.ts.map +1 -0
- package/dist/lib/graph/types.js +10 -0
- package/dist/lib/graph/types.js.map +1 -0
- package/dist/lib/hook-dispatcher.d.ts +21 -0
- package/dist/lib/hook-dispatcher.d.ts.map +1 -0
- package/dist/lib/hook-dispatcher.js +62 -0
- package/dist/lib/hook-dispatcher.js.map +1 -0
- package/dist/lib/id-generator.d.ts +29 -0
- package/dist/lib/id-generator.d.ts.map +1 -0
- package/dist/lib/id-generator.js +51 -0
- package/dist/lib/id-generator.js.map +1 -0
- package/dist/lib/input-sanitizer.d.ts +55 -0
- package/dist/lib/input-sanitizer.d.ts.map +1 -0
- package/dist/lib/input-sanitizer.js +167 -0
- package/dist/lib/input-sanitizer.js.map +1 -0
- package/dist/lib/internal-docs-dashboard.json +112 -0
- package/dist/lib/internal-docs-handler.d.ts +60 -0
- package/dist/lib/internal-docs-handler.d.ts.map +1 -0
- package/dist/lib/internal-docs-handler.js +570 -0
- package/dist/lib/internal-docs-handler.js.map +1 -0
- package/dist/lib/internal-docs-navigation.d.ts +42 -0
- package/dist/lib/internal-docs-navigation.d.ts.map +1 -0
- package/dist/lib/internal-docs-navigation.js +73 -0
- package/dist/lib/internal-docs-navigation.js.map +1 -0
- package/dist/lib/internal-docs-navigation.json +169 -0
- package/dist/lib/invitation-handler.d.ts +133 -0
- package/dist/lib/invitation-handler.d.ts.map +1 -0
- package/dist/lib/invitation-handler.js +1335 -0
- package/dist/lib/invitation-handler.js.map +1 -0
- package/dist/lib/ip-scrubber.d.ts +59 -0
- package/dist/lib/ip-scrubber.d.ts.map +1 -0
- package/dist/lib/ip-scrubber.js +101 -0
- package/dist/lib/ip-scrubber.js.map +1 -0
- package/dist/lib/kv/dynamodb-kv.d.ts +39 -0
- package/dist/lib/kv/dynamodb-kv.d.ts.map +1 -0
- package/dist/lib/kv/dynamodb-kv.js +239 -0
- package/dist/lib/kv/dynamodb-kv.js.map +1 -0
- package/dist/lib/link-security-handler.d.ts +140 -0
- package/dist/lib/link-security-handler.d.ts.map +1 -0
- package/dist/lib/link-security-handler.js +460 -0
- package/dist/lib/link-security-handler.js.map +1 -0
- package/dist/lib/logger.d.ts +100 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +201 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/media-cleanup-handler.d.ts +46 -0
- package/dist/lib/media-cleanup-handler.d.ts.map +1 -0
- package/dist/lib/media-cleanup-handler.js +190 -0
- package/dist/lib/media-cleanup-handler.js.map +1 -0
- package/dist/lib/media-handler.d.ts +150 -0
- package/dist/lib/media-handler.d.ts.map +1 -0
- package/dist/lib/media-handler.js +1544 -0
- package/dist/lib/media-handler.js.map +1 -0
- package/dist/lib/media-metadata-extractor.d.ts +71 -0
- package/dist/lib/media-metadata-extractor.d.ts.map +1 -0
- package/dist/lib/media-metadata-extractor.js +278 -0
- package/dist/lib/media-metadata-extractor.js.map +1 -0
- package/dist/lib/media-metrics.d.ts +57 -0
- package/dist/lib/media-metrics.d.ts.map +1 -0
- package/dist/lib/media-metrics.js +202 -0
- package/dist/lib/media-metrics.js.map +1 -0
- package/dist/lib/metadata/index.d.ts +6 -0
- package/dist/lib/metadata/index.d.ts.map +1 -0
- package/dist/lib/metadata/index.js +22 -0
- package/dist/lib/metadata/index.js.map +1 -0
- package/dist/lib/metadata/metadata-config.d.ts +17 -0
- package/dist/lib/metadata/metadata-config.d.ts.map +1 -0
- package/dist/lib/metadata/metadata-config.js +23 -0
- package/dist/lib/metadata/metadata-config.js.map +1 -0
- package/dist/lib/metadata/metadata-errors.d.ts +18 -0
- package/dist/lib/metadata/metadata-errors.d.ts.map +1 -0
- package/dist/lib/metadata/metadata-errors.js +26 -0
- package/dist/lib/metadata/metadata-errors.js.map +1 -0
- package/dist/lib/metadata/metadata-extractor.d.ts +17 -0
- package/dist/lib/metadata/metadata-extractor.d.ts.map +1 -0
- package/dist/lib/metadata/metadata-extractor.js +264 -0
- package/dist/lib/metadata/metadata-extractor.js.map +1 -0
- package/dist/lib/metadata/metadata-sanitizer.d.ts +9 -0
- package/dist/lib/metadata/metadata-sanitizer.d.ts.map +1 -0
- package/dist/lib/metadata/metadata-sanitizer.js +100 -0
- package/dist/lib/metadata/metadata-sanitizer.js.map +1 -0
- package/dist/lib/metadata/metadata-schemas.d.ts +131 -0
- package/dist/lib/metadata/metadata-schemas.d.ts.map +1 -0
- package/dist/lib/metadata/metadata-schemas.js +71 -0
- package/dist/lib/metadata/metadata-schemas.js.map +1 -0
- package/dist/lib/mfa/mfa-handler.d.ts +60 -0
- package/dist/lib/mfa/mfa-handler.d.ts.map +1 -0
- package/dist/lib/mfa/mfa-handler.js +150 -0
- package/dist/lib/mfa/mfa-handler.js.map +1 -0
- package/dist/lib/mfa/totp-service.d.ts +41 -0
- package/dist/lib/mfa/totp-service.d.ts.map +1 -0
- package/dist/lib/mfa/totp-service.js +183 -0
- package/dist/lib/mfa/totp-service.js.map +1 -0
- package/dist/lib/middleware/comment-rate-limit.d.ts +19 -0
- package/dist/lib/middleware/comment-rate-limit.d.ts.map +1 -0
- package/dist/lib/middleware/comment-rate-limit.js +113 -0
- package/dist/lib/middleware/comment-rate-limit.js.map +1 -0
- package/dist/lib/middleware/feature-toggle-rate-limit.d.ts +53 -0
- package/dist/lib/middleware/feature-toggle-rate-limit.d.ts.map +1 -0
- package/dist/lib/middleware/feature-toggle-rate-limit.js +164 -0
- package/dist/lib/middleware/feature-toggle-rate-limit.js.map +1 -0
- package/dist/lib/middleware.d.ts +70 -0
- package/dist/lib/middleware.d.ts.map +1 -0
- package/dist/lib/middleware.js +375 -0
- package/dist/lib/middleware.js.map +1 -0
- package/dist/lib/moderation-handler.d.ts +55 -0
- package/dist/lib/moderation-handler.d.ts.map +1 -0
- package/dist/lib/moderation-handler.js +230 -0
- package/dist/lib/moderation-handler.js.map +1 -0
- package/dist/lib/notification-handler.d.ts +65 -0
- package/dist/lib/notification-handler.d.ts.map +1 -0
- package/dist/lib/notification-handler.js +236 -0
- package/dist/lib/notification-handler.js.map +1 -0
- package/dist/lib/notification-preferences-handler.d.ts +27 -0
- package/dist/lib/notification-preferences-handler.d.ts.map +1 -0
- package/dist/lib/notification-preferences-handler.js +119 -0
- package/dist/lib/notification-preferences-handler.js.map +1 -0
- package/dist/lib/openai-budget.d.ts +45 -0
- package/dist/lib/openai-budget.d.ts.map +1 -0
- package/dist/lib/openai-budget.js +175 -0
- package/dist/lib/openai-budget.js.map +1 -0
- package/dist/lib/orphaned-media-handler.d.ts +60 -0
- package/dist/lib/orphaned-media-handler.d.ts.map +1 -0
- package/dist/lib/orphaned-media-handler.js +487 -0
- package/dist/lib/orphaned-media-handler.js.map +1 -0
- package/dist/lib/parental-control-handler.d.ts +42 -0
- package/dist/lib/parental-control-handler.d.ts.map +1 -0
- package/dist/lib/parental-control-handler.js +327 -0
- package/dist/lib/parental-control-handler.js.map +1 -0
- package/dist/lib/parental-link-handler.d.ts +38 -0
- package/dist/lib/parental-link-handler.d.ts.map +1 -0
- package/dist/lib/parental-link-handler.js +217 -0
- package/dist/lib/parental-link-handler.js.map +1 -0
- package/dist/lib/performance-metrics.d.ts +125 -0
- package/dist/lib/performance-metrics.d.ts.map +1 -0
- package/dist/lib/performance-metrics.js +277 -0
- package/dist/lib/performance-metrics.js.map +1 -0
- package/dist/lib/post-handler.d.ts +94 -0
- package/dist/lib/post-handler.d.ts.map +1 -0
- package/dist/lib/post-handler.js +1346 -0
- package/dist/lib/post-handler.js.map +1 -0
- package/dist/lib/privacy-defaults.d.ts +32 -0
- package/dist/lib/privacy-defaults.d.ts.map +1 -0
- package/dist/lib/privacy-defaults.js +85 -0
- package/dist/lib/privacy-defaults.js.map +1 -0
- package/dist/lib/privacy-handler.d.ts +43 -0
- package/dist/lib/privacy-handler.d.ts.map +1 -0
- package/dist/lib/privacy-handler.js +124 -0
- package/dist/lib/privacy-handler.js.map +1 -0
- package/dist/lib/queue/sqs-queue.d.ts +16 -0
- package/dist/lib/queue/sqs-queue.d.ts.map +1 -0
- package/dist/lib/queue/sqs-queue.js +39 -0
- package/dist/lib/queue/sqs-queue.js.map +1 -0
- package/dist/lib/queue-consumers/media-reconciliation-consumer.d.ts +9 -0
- package/dist/lib/queue-consumers/media-reconciliation-consumer.d.ts.map +1 -0
- package/dist/lib/queue-consumers/media-reconciliation-consumer.js +37 -0
- package/dist/lib/queue-consumers/media-reconciliation-consumer.js.map +1 -0
- package/dist/lib/quiet-hours.d.ts +33 -0
- package/dist/lib/quiet-hours.d.ts.map +1 -0
- package/dist/lib/quiet-hours.js +51 -0
- package/dist/lib/quiet-hours.js.map +1 -0
- package/dist/lib/rate-limit.d.ts +95 -0
- package/dist/lib/rate-limit.d.ts.map +1 -0
- package/dist/lib/rate-limit.js +247 -0
- package/dist/lib/rate-limit.js.map +1 -0
- package/dist/lib/reaction-handler.d.ts +68 -0
- package/dist/lib/reaction-handler.d.ts.map +1 -0
- package/dist/lib/reaction-handler.js +858 -0
- package/dist/lib/reaction-handler.js.map +1 -0
- package/dist/lib/recaptcha.d.ts +16 -0
- package/dist/lib/recaptcha.d.ts.map +1 -0
- package/dist/lib/recaptcha.js +71 -0
- package/dist/lib/recaptcha.js.map +1 -0
- package/dist/lib/redirect-resolver.d.ts +78 -0
- package/dist/lib/redirect-resolver.d.ts.map +1 -0
- package/dist/lib/redirect-resolver.js +276 -0
- package/dist/lib/redirect-resolver.js.map +1 -0
- package/dist/lib/region-config.d.ts +179 -0
- package/dist/lib/region-config.d.ts.map +1 -0
- package/dist/lib/region-config.js +474 -0
- package/dist/lib/region-config.js.map +1 -0
- package/dist/lib/region-detection.d.ts +110 -0
- package/dist/lib/region-detection.d.ts.map +1 -0
- package/dist/lib/region-detection.js +408 -0
- package/dist/lib/region-detection.js.map +1 -0
- package/dist/lib/relationship-handler.d.ts +19 -0
- package/dist/lib/relationship-handler.d.ts.map +1 -0
- package/dist/lib/relationship-handler.js +233 -0
- package/dist/lib/relationship-handler.js.map +1 -0
- package/dist/lib/request-context.d.ts +103 -0
- package/dist/lib/request-context.d.ts.map +1 -0
- package/dist/lib/request-context.js +179 -0
- package/dist/lib/request-context.js.map +1 -0
- package/dist/lib/route-helpers.d.ts +74 -0
- package/dist/lib/route-helpers.d.ts.map +1 -0
- package/dist/lib/route-helpers.js +190 -0
- package/dist/lib/route-helpers.js.map +1 -0
- package/dist/lib/route-matcher.d.ts +24 -0
- package/dist/lib/route-matcher.d.ts.map +1 -0
- package/dist/lib/route-matcher.js +96 -0
- package/dist/lib/route-matcher.js.map +1 -0
- package/dist/lib/router.d.ts +26 -0
- package/dist/lib/router.d.ts.map +1 -0
- package/dist/lib/router.js +90 -0
- package/dist/lib/router.js.map +1 -0
- package/dist/lib/routes/activitypub/actor.d.ts +12 -0
- package/dist/lib/routes/activitypub/actor.d.ts.map +1 -0
- package/dist/lib/routes/activitypub/actor.js +141 -0
- package/dist/lib/routes/activitypub/actor.js.map +1 -0
- package/dist/lib/routes/activitypub/audiences.d.ts +12 -0
- package/dist/lib/routes/activitypub/audiences.d.ts.map +1 -0
- package/dist/lib/routes/activitypub/audiences.js +325 -0
- package/dist/lib/routes/activitypub/audiences.js.map +1 -0
- package/dist/lib/routes/activitypub/collections.d.ts +12 -0
- package/dist/lib/routes/activitypub/collections.d.ts.map +1 -0
- package/dist/lib/routes/activitypub/collections.js +127 -0
- package/dist/lib/routes/activitypub/collections.js.map +1 -0
- package/dist/lib/routes/activitypub/entity-profile.d.ts +9 -0
- package/dist/lib/routes/activitypub/entity-profile.d.ts.map +1 -0
- package/dist/lib/routes/activitypub/entity-profile.js +136 -0
- package/dist/lib/routes/activitypub/entity-profile.js.map +1 -0
- package/dist/lib/routes/activitypub/friends.d.ts +15 -0
- package/dist/lib/routes/activitypub/friends.d.ts.map +1 -0
- package/dist/lib/routes/activitypub/friends.js +33 -0
- package/dist/lib/routes/activitypub/friends.js.map +1 -0
- package/dist/lib/routes/activitypub/group.d.ts +8 -0
- package/dist/lib/routes/activitypub/group.d.ts.map +1 -0
- package/dist/lib/routes/activitypub/group.js +436 -0
- package/dist/lib/routes/activitypub/group.js.map +1 -0
- package/dist/lib/routes/activitypub/inbox.d.ts +15 -0
- package/dist/lib/routes/activitypub/inbox.d.ts.map +1 -0
- package/dist/lib/routes/activitypub/inbox.js +125 -0
- package/dist/lib/routes/activitypub/inbox.js.map +1 -0
- package/dist/lib/routes/activitypub/messages.d.ts +12 -0
- package/dist/lib/routes/activitypub/messages.d.ts.map +1 -0
- package/dist/lib/routes/activitypub/messages.js +374 -0
- package/dist/lib/routes/activitypub/messages.js.map +1 -0
- package/dist/lib/routes/activitypub/outbox.d.ts +15 -0
- package/dist/lib/routes/activitypub/outbox.d.ts.map +1 -0
- package/dist/lib/routes/activitypub/outbox.js +33 -0
- package/dist/lib/routes/activitypub/outbox.js.map +1 -0
- package/dist/lib/routes/activitypub/post.d.ts +12 -0
- package/dist/lib/routes/activitypub/post.d.ts.map +1 -0
- package/dist/lib/routes/activitypub/post.js +213 -0
- package/dist/lib/routes/activitypub/post.js.map +1 -0
- package/dist/lib/routes/activitypub/webfinger.d.ts +11 -0
- package/dist/lib/routes/activitypub/webfinger.d.ts.map +1 -0
- package/dist/lib/routes/activitypub/webfinger.js +27 -0
- package/dist/lib/routes/activitypub/webfinger.js.map +1 -0
- package/dist/lib/routes/admin-costs.d.ts +8 -0
- package/dist/lib/routes/admin-costs.d.ts.map +1 -0
- package/dist/lib/routes/admin-costs.js +89 -0
- package/dist/lib/routes/admin-costs.js.map +1 -0
- package/dist/lib/routes/admin.d.ts +6 -0
- package/dist/lib/routes/admin.d.ts.map +1 -0
- package/dist/lib/routes/admin.js +1450 -0
- package/dist/lib/routes/admin.js.map +1 -0
- package/dist/lib/routes/auth.d.ts +6 -0
- package/dist/lib/routes/auth.d.ts.map +1 -0
- package/dist/lib/routes/auth.js +49 -0
- package/dist/lib/routes/auth.js.map +1 -0
- package/dist/lib/routes/badges.d.ts +6 -0
- package/dist/lib/routes/badges.d.ts.map +1 -0
- package/dist/lib/routes/badges.js +66 -0
- package/dist/lib/routes/badges.js.map +1 -0
- package/dist/lib/routes/circles.d.ts +8 -0
- package/dist/lib/routes/circles.d.ts.map +1 -0
- package/dist/lib/routes/circles.js +135 -0
- package/dist/lib/routes/circles.js.map +1 -0
- package/dist/lib/routes/comments.d.ts +6 -0
- package/dist/lib/routes/comments.d.ts.map +1 -0
- package/dist/lib/routes/comments.js +228 -0
- package/dist/lib/routes/comments.js.map +1 -0
- package/dist/lib/routes/connection-codes.d.ts +8 -0
- package/dist/lib/routes/connection-codes.d.ts.map +1 -0
- package/dist/lib/routes/connection-codes.js +84 -0
- package/dist/lib/routes/connection-codes.js.map +1 -0
- package/dist/lib/routes/content-discovery.d.ts +11 -0
- package/dist/lib/routes/content-discovery.d.ts.map +1 -0
- package/dist/lib/routes/content-discovery.js +211 -0
- package/dist/lib/routes/content-discovery.js.map +1 -0
- package/dist/lib/routes/dashboard.d.ts +8 -0
- package/dist/lib/routes/dashboard.d.ts.map +1 -0
- package/dist/lib/routes/dashboard.js +1139 -0
- package/dist/lib/routes/dashboard.js.map +1 -0
- package/dist/lib/routes/deletion.d.ts +6 -0
- package/dist/lib/routes/deletion.d.ts.map +1 -0
- package/dist/lib/routes/deletion.js +213 -0
- package/dist/lib/routes/deletion.js.map +1 -0
- package/dist/lib/routes/discovery.d.ts +8 -0
- package/dist/lib/routes/discovery.d.ts.map +1 -0
- package/dist/lib/routes/discovery.js +67 -0
- package/dist/lib/routes/discovery.js.map +1 -0
- package/dist/lib/routes/employees.d.ts +6 -0
- package/dist/lib/routes/employees.d.ts.map +1 -0
- package/dist/lib/routes/employees.js +82 -0
- package/dist/lib/routes/employees.js.map +1 -0
- package/dist/lib/routes/entities.d.ts +8 -0
- package/dist/lib/routes/entities.d.ts.map +1 -0
- package/dist/lib/routes/entities.js +467 -0
- package/dist/lib/routes/entities.js.map +1 -0
- package/dist/lib/routes/entity-relationships.d.ts +8 -0
- package/dist/lib/routes/entity-relationships.d.ts.map +1 -0
- package/dist/lib/routes/entity-relationships.js +118 -0
- package/dist/lib/routes/entity-relationships.js.map +1 -0
- package/dist/lib/routes/export.d.ts +6 -0
- package/dist/lib/routes/export.d.ts.map +1 -0
- package/dist/lib/routes/export.js +118 -0
- package/dist/lib/routes/export.js.map +1 -0
- package/dist/lib/routes/feature-flags.d.ts +8 -0
- package/dist/lib/routes/feature-flags.d.ts.map +1 -0
- package/dist/lib/routes/feature-flags.js +75 -0
- package/dist/lib/routes/feature-flags.js.map +1 -0
- package/dist/lib/routes/feeds.d.ts +6 -0
- package/dist/lib/routes/feeds.d.ts.map +1 -0
- package/dist/lib/routes/feeds.js +131 -0
- package/dist/lib/routes/feeds.js.map +1 -0
- package/dist/lib/routes/followers.d.ts +6 -0
- package/dist/lib/routes/followers.d.ts.map +1 -0
- package/dist/lib/routes/followers.js +405 -0
- package/dist/lib/routes/followers.js.map +1 -0
- package/dist/lib/routes/friends.d.ts +6 -0
- package/dist/lib/routes/friends.d.ts.map +1 -0
- package/dist/lib/routes/friends.js +116 -0
- package/dist/lib/routes/friends.js.map +1 -0
- package/dist/lib/routes/health.d.ts +6 -0
- package/dist/lib/routes/health.d.ts.map +1 -0
- package/dist/lib/routes/health.js +129 -0
- package/dist/lib/routes/health.js.map +1 -0
- package/dist/lib/routes/index.d.ts +21 -0
- package/dist/lib/routes/index.d.ts.map +1 -0
- package/dist/lib/routes/index.js +212 -0
- package/dist/lib/routes/index.js.map +1 -0
- package/dist/lib/routes/internal-docs.d.ts +6 -0
- package/dist/lib/routes/internal-docs.d.ts.map +1 -0
- package/dist/lib/routes/internal-docs.js +44 -0
- package/dist/lib/routes/internal-docs.js.map +1 -0
- package/dist/lib/routes/invitations.d.ts +6 -0
- package/dist/lib/routes/invitations.d.ts.map +1 -0
- package/dist/lib/routes/invitations.js +67 -0
- package/dist/lib/routes/invitations.js.map +1 -0
- package/dist/lib/routes/link-reports.d.ts +11 -0
- package/dist/lib/routes/link-reports.d.ts.map +1 -0
- package/dist/lib/routes/link-reports.js +287 -0
- package/dist/lib/routes/link-reports.js.map +1 -0
- package/dist/lib/routes/map.d.ts +6 -0
- package/dist/lib/routes/map.d.ts.map +1 -0
- package/dist/lib/routes/map.js +21 -0
- package/dist/lib/routes/map.js.map +1 -0
- package/dist/lib/routes/media-metadata-visibility.d.ts +3 -0
- package/dist/lib/routes/media-metadata-visibility.d.ts.map +1 -0
- package/dist/lib/routes/media-metadata-visibility.js +184 -0
- package/dist/lib/routes/media-metadata-visibility.js.map +1 -0
- package/dist/lib/routes/media.d.ts +9 -0
- package/dist/lib/routes/media.d.ts.map +1 -0
- package/dist/lib/routes/media.js +1910 -0
- package/dist/lib/routes/media.js.map +1 -0
- package/dist/lib/routes/mfa.d.ts +8 -0
- package/dist/lib/routes/mfa.d.ts.map +1 -0
- package/dist/lib/routes/mfa.js +193 -0
- package/dist/lib/routes/mfa.js.map +1 -0
- package/dist/lib/routes/notifications.d.ts +9 -0
- package/dist/lib/routes/notifications.d.ts.map +1 -0
- package/dist/lib/routes/notifications.js +230 -0
- package/dist/lib/routes/notifications.js.map +1 -0
- package/dist/lib/routes/orphaned-media-health.d.ts +9 -0
- package/dist/lib/routes/orphaned-media-health.d.ts.map +1 -0
- package/dist/lib/routes/orphaned-media-health.js +121 -0
- package/dist/lib/routes/orphaned-media-health.js.map +1 -0
- package/dist/lib/routes/orphaned-media.d.ts +8 -0
- package/dist/lib/routes/orphaned-media.d.ts.map +1 -0
- package/dist/lib/routes/orphaned-media.js +111 -0
- package/dist/lib/routes/orphaned-media.js.map +1 -0
- package/dist/lib/routes/out.d.ts +17 -0
- package/dist/lib/routes/out.d.ts.map +1 -0
- package/dist/lib/routes/out.js +339 -0
- package/dist/lib/routes/out.js.map +1 -0
- package/dist/lib/routes/parental-controls.d.ts +8 -0
- package/dist/lib/routes/parental-controls.d.ts.map +1 -0
- package/dist/lib/routes/parental-controls.js +282 -0
- package/dist/lib/routes/parental-controls.js.map +1 -0
- package/dist/lib/routes/posts.d.ts +6 -0
- package/dist/lib/routes/posts.d.ts.map +1 -0
- package/dist/lib/routes/posts.js +518 -0
- package/dist/lib/routes/posts.js.map +1 -0
- package/dist/lib/routes/privacy.d.ts +6 -0
- package/dist/lib/routes/privacy.d.ts.map +1 -0
- package/dist/lib/routes/privacy.js +66 -0
- package/dist/lib/routes/privacy.js.map +1 -0
- package/dist/lib/routes/products.d.ts +9 -0
- package/dist/lib/routes/products.d.ts.map +1 -0
- package/dist/lib/routes/products.js +224 -0
- package/dist/lib/routes/products.js.map +1 -0
- package/dist/lib/routes/relationships.d.ts +8 -0
- package/dist/lib/routes/relationships.d.ts.map +1 -0
- package/dist/lib/routes/relationships.js +118 -0
- package/dist/lib/routes/relationships.js.map +1 -0
- package/dist/lib/routes/sentiments.d.ts +6 -0
- package/dist/lib/routes/sentiments.d.ts.map +1 -0
- package/dist/lib/routes/sentiments.js +285 -0
- package/dist/lib/routes/sentiments.js.map +1 -0
- package/dist/lib/routes/taxonomy-analytics.d.ts +8 -0
- package/dist/lib/routes/taxonomy-analytics.d.ts.map +1 -0
- package/dist/lib/routes/taxonomy-analytics.js +151 -0
- package/dist/lib/routes/taxonomy-analytics.js.map +1 -0
- package/dist/lib/routes/taxonomy.d.ts +15 -0
- package/dist/lib/routes/taxonomy.d.ts.map +1 -0
- package/dist/lib/routes/taxonomy.js +370 -0
- package/dist/lib/routes/taxonomy.js.map +1 -0
- package/dist/lib/routes/types.d.ts +46 -0
- package/dist/lib/routes/types.d.ts.map +1 -0
- package/dist/lib/routes/types.js +8 -0
- package/dist/lib/routes/types.js.map +1 -0
- package/dist/lib/routes/upload-sessions.d.ts +9 -0
- package/dist/lib/routes/upload-sessions.d.ts.map +1 -0
- package/dist/lib/routes/upload-sessions.js +268 -0
- package/dist/lib/routes/upload-sessions.js.map +1 -0
- package/dist/lib/routes/user.d.ts +8 -0
- package/dist/lib/routes/user.d.ts.map +1 -0
- package/dist/lib/routes/user.js +287 -0
- package/dist/lib/routes/user.js.map +1 -0
- package/dist/lib/routes-all.d.ts +9 -0
- package/dist/lib/routes-all.d.ts.map +1 -0
- package/dist/lib/routes-all.js +170 -0
- package/dist/lib/routes-all.js.map +1 -0
- package/dist/lib/routes.d.ts +10 -0
- package/dist/lib/routes.d.ts.map +1 -0
- package/dist/lib/routes.js +16 -0
- package/dist/lib/routes.js.map +1 -0
- package/dist/lib/scaling-health.d.ts +48 -0
- package/dist/lib/scaling-health.d.ts.map +1 -0
- package/dist/lib/scaling-health.js +363 -0
- package/dist/lib/scaling-health.js.map +1 -0
- package/dist/lib/scheduled/media-stale-cleanup.d.ts +11 -0
- package/dist/lib/scheduled/media-stale-cleanup.d.ts.map +1 -0
- package/dist/lib/scheduled/media-stale-cleanup.js +79 -0
- package/dist/lib/scheduled/media-stale-cleanup.js.map +1 -0
- package/dist/lib/scheduled/orphaned-media-monitor.d.ts +97 -0
- package/dist/lib/scheduled/orphaned-media-monitor.d.ts.map +1 -0
- package/dist/lib/scheduled/orphaned-media-monitor.js +399 -0
- package/dist/lib/scheduled/orphaned-media-monitor.js.map +1 -0
- package/dist/lib/schemas.d.ts +314 -0
- package/dist/lib/schemas.d.ts.map +1 -0
- package/dist/lib/schemas.js +235 -0
- package/dist/lib/schemas.js.map +1 -0
- package/dist/lib/secret-resolver.d.ts +88 -0
- package/dist/lib/secret-resolver.d.ts.map +1 -0
- package/dist/lib/secret-resolver.js +183 -0
- package/dist/lib/secret-resolver.js.map +1 -0
- package/dist/lib/security-event-cleaner.d.ts +61 -0
- package/dist/lib/security-event-cleaner.d.ts.map +1 -0
- package/dist/lib/security-event-cleaner.js +74 -0
- package/dist/lib/security-event-cleaner.js.map +1 -0
- package/dist/lib/security-headers.d.ts +36 -0
- package/dist/lib/security-headers.d.ts.map +1 -0
- package/dist/lib/security-headers.js +87 -0
- package/dist/lib/security-headers.js.map +1 -0
- package/dist/lib/security-monitor.d.ts +92 -0
- package/dist/lib/security-monitor.d.ts.map +1 -0
- package/dist/lib/security-monitor.js +287 -0
- package/dist/lib/security-monitor.js.map +1 -0
- package/dist/lib/sentiment-digest.d.ts +19 -0
- package/dist/lib/sentiment-digest.d.ts.map +1 -0
- package/dist/lib/sentiment-digest.js +99 -0
- package/dist/lib/sentiment-digest.js.map +1 -0
- package/dist/lib/sentiment-display.d.ts +20 -0
- package/dist/lib/sentiment-display.d.ts.map +1 -0
- package/dist/lib/sentiment-display.js +38 -0
- package/dist/lib/sentiment-display.js.map +1 -0
- package/dist/lib/services/image-normalizer.d.ts +15 -0
- package/dist/lib/services/image-normalizer.d.ts.map +1 -0
- package/dist/lib/services/image-normalizer.js +22 -0
- package/dist/lib/services/image-normalizer.js.map +1 -0
- package/dist/lib/services/media-reconciliation-service.d.ts +25 -0
- package/dist/lib/services/media-reconciliation-service.d.ts.map +1 -0
- package/dist/lib/services/media-reconciliation-service.js +191 -0
- package/dist/lib/services/media-reconciliation-service.js.map +1 -0
- package/dist/lib/services/media-upload-service.d.ts +25 -0
- package/dist/lib/services/media-upload-service.d.ts.map +1 -0
- package/dist/lib/services/media-upload-service.js +240 -0
- package/dist/lib/services/media-upload-service.js.map +1 -0
- package/dist/lib/services/user-data-deletion.d.ts +30 -0
- package/dist/lib/services/user-data-deletion.d.ts.map +1 -0
- package/dist/lib/services/user-data-deletion.js +118 -0
- package/dist/lib/services/user-data-deletion.js.map +1 -0
- package/dist/lib/session-awareness.d.ts +35 -0
- package/dist/lib/session-awareness.d.ts.map +1 -0
- package/dist/lib/session-awareness.js +79 -0
- package/dist/lib/session-awareness.js.map +1 -0
- package/dist/lib/session-config.d.ts +87 -0
- package/dist/lib/session-config.d.ts.map +1 -0
- package/dist/lib/session-config.js +165 -0
- package/dist/lib/session-config.js.map +1 -0
- package/dist/lib/session-manager.d.ts +103 -0
- package/dist/lib/session-manager.d.ts.map +1 -0
- package/dist/lib/session-manager.js +492 -0
- package/dist/lib/session-manager.js.map +1 -0
- package/dist/lib/sso-auth-handler.d.ts +12 -0
- package/dist/lib/sso-auth-handler.d.ts.map +1 -0
- package/dist/lib/sso-auth-handler.js +24 -0
- package/dist/lib/sso-auth-handler.js.map +1 -0
- package/dist/lib/storage/s3-storage.d.ts +29 -0
- package/dist/lib/storage/s3-storage.d.ts.map +1 -0
- package/dist/lib/storage/s3-storage.js +135 -0
- package/dist/lib/storage/s3-storage.js.map +1 -0
- package/dist/lib/tag-suggestions-handler.d.ts +52 -0
- package/dist/lib/tag-suggestions-handler.d.ts.map +1 -0
- package/dist/lib/tag-suggestions-handler.js +195 -0
- package/dist/lib/tag-suggestions-handler.js.map +1 -0
- package/dist/lib/taxonomy-handler-factory.d.ts +18 -0
- package/dist/lib/taxonomy-handler-factory.d.ts.map +1 -0
- package/dist/lib/taxonomy-handler-factory.js +29 -0
- package/dist/lib/taxonomy-handler-factory.js.map +1 -0
- package/dist/lib/taxonomy-handler.d.ts +142 -0
- package/dist/lib/taxonomy-handler.d.ts.map +1 -0
- package/dist/lib/taxonomy-handler.js +636 -0
- package/dist/lib/taxonomy-handler.js.map +1 -0
- package/dist/lib/taxonomy-metrics.d.ts +76 -0
- package/dist/lib/taxonomy-metrics.d.ts.map +1 -0
- package/dist/lib/taxonomy-metrics.js +201 -0
- package/dist/lib/taxonomy-metrics.js.map +1 -0
- package/dist/lib/taxonomy-search-metrics.d.ts +45 -0
- package/dist/lib/taxonomy-search-metrics.d.ts.map +1 -0
- package/dist/lib/taxonomy-search-metrics.js +75 -0
- package/dist/lib/taxonomy-search-metrics.js.map +1 -0
- package/dist/lib/tenant-context.d.ts +35 -0
- package/dist/lib/tenant-context.d.ts.map +1 -0
- package/dist/lib/tenant-context.js +54 -0
- package/dist/lib/tenant-context.js.map +1 -0
- package/dist/lib/terminology.d.ts +25 -0
- package/dist/lib/terminology.d.ts.map +1 -0
- package/dist/lib/terminology.js +44 -0
- package/dist/lib/terminology.js.map +1 -0
- package/dist/lib/theme.d.ts +29 -0
- package/dist/lib/theme.d.ts.map +1 -0
- package/dist/lib/theme.js +38 -0
- package/dist/lib/theme.js.map +1 -0
- package/dist/lib/threat-intel-service.d.ts +67 -0
- package/dist/lib/threat-intel-service.d.ts.map +1 -0
- package/dist/lib/threat-intel-service.js +193 -0
- package/dist/lib/threat-intel-service.js.map +1 -0
- package/dist/lib/types/media-reconciliation.d.ts +64 -0
- package/dist/lib/types/media-reconciliation.d.ts.map +1 -0
- package/dist/lib/types/media-reconciliation.js +8 -0
- package/dist/lib/types/media-reconciliation.js.map +1 -0
- package/dist/lib/upload-session-handler.d.ts +56 -0
- package/dist/lib/upload-session-handler.d.ts.map +1 -0
- package/dist/lib/upload-session-handler.js +312 -0
- package/dist/lib/upload-session-handler.js.map +1 -0
- package/dist/lib/user-badge.d.ts +56 -0
- package/dist/lib/user-badge.d.ts.map +1 -0
- package/dist/lib/user-badge.js +92 -0
- package/dist/lib/user-badge.js.map +1 -0
- package/dist/lib/user-deletion-handler-enhanced.d.ts +96 -0
- package/dist/lib/user-deletion-handler-enhanced.d.ts.map +1 -0
- package/dist/lib/user-deletion-handler-enhanced.js +401 -0
- package/dist/lib/user-deletion-handler-enhanced.js.map +1 -0
- package/dist/lib/user-deprovisioning.d.ts +43 -0
- package/dist/lib/user-deprovisioning.d.ts.map +1 -0
- package/dist/lib/user-deprovisioning.js +138 -0
- package/dist/lib/user-deprovisioning.js.map +1 -0
- package/dist/lib/user-export-handler.d.ts +172 -0
- package/dist/lib/user-export-handler.d.ts.map +1 -0
- package/dist/lib/user-export-handler.js +435 -0
- package/dist/lib/user-export-handler.js.map +1 -0
- package/dist/lib/validate-request.d.ts +46 -0
- package/dist/lib/validate-request.d.ts.map +1 -0
- package/dist/lib/validate-request.js +127 -0
- package/dist/lib/validate-request.js.map +1 -0
- package/dist/lib/validation/feature-toggle-schemas.d.ts +410 -0
- package/dist/lib/validation/feature-toggle-schemas.d.ts.map +1 -0
- package/dist/lib/validation/feature-toggle-schemas.js +274 -0
- package/dist/lib/validation/feature-toggle-schemas.js.map +1 -0
- package/dist/lib/validation/validate-request.d.ts +75 -0
- package/dist/lib/validation/validate-request.d.ts.map +1 -0
- package/dist/lib/validation/validate-request.js +183 -0
- package/dist/lib/validation/validate-request.js.map +1 -0
- package/dist/lib/validation.d.ts +50 -0
- package/dist/lib/validation.d.ts.map +1 -0
- package/dist/lib/validation.js +122 -0
- package/dist/lib/validation.js.map +1 -0
- package/dist/lib/version.d.ts +36 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +44 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +254 -0
- package/dist/server.js.map +1 -0
- package/dist/types/cloudflare-compat.d.ts +134 -0
- package/dist/types/cloudflare-compat.d.ts.map +1 -0
- package/dist/types/cloudflare-compat.js +7 -0
- package/dist/types/cloudflare-compat.js.map +1 -0
- package/dist/worker.d.ts +16 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +21 -0
- package/dist/worker.js.map +1 -0
- package/package.json +91 -0
- package/src/lambda/cleanup-cron.ts +37 -0
- package/src/lambda/create-auth-challenge.ts +112 -0
- package/src/lambda/custom-message.ts +30 -0
- package/src/lambda/define-auth-challenge.ts +24 -0
- package/src/lambda/delete-account-worker.ts +96 -0
- package/src/lambda/diagnostics-proxy.ts +139 -0
- package/src/lambda/e2e-sweeper.ts +140 -0
- package/src/lambda/federation-outbox-worker.ts +8 -0
- package/src/lambda/followers-events-worker.ts +8 -0
- package/src/lambda/hourly-cron.ts +103 -0
- package/src/lambda/link-check-worker.ts +8 -0
- package/src/lambda/maintenance-cron.ts +95 -0
- package/src/lambda/media-processing-worker.ts +68 -0
- package/src/lambda/media-reconciliation-worker.ts +8 -0
- package/src/lambda/nightly-cron.ts +338 -0
- package/src/lambda/post-confirmation.ts +80 -0
- package/src/lambda/pre-signup.ts +39 -0
- package/src/lambda/pre-token-generation.ts +93 -0
- package/src/lambda/tools/check-health.ts +22 -0
- package/src/lambda/tools/describe-services.ts +45 -0
- package/src/lambda/tools/get-cost-report.ts +64 -0
- package/src/lambda/tools/get-errors.ts +78 -0
- package/src/lambda/tools/get-feature-flags.ts +27 -0
- package/src/lambda/tools/get-queue-status.ts +60 -0
- package/src/lambda/tools/search-logs.ts +75 -0
- package/src/lambda/tools/send-alert.ts +37 -0
- package/src/lambda/verify-auth-challenge.ts +37 -0
|
@@ -0,0 +1,1544 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Media Handler
|
|
4
|
+
*
|
|
5
|
+
* Handles media collection operations: listing, details, hide/unhide, delete.
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.MediaHandler = void 0;
|
|
42
|
+
const logger_1 = require("./logger");
|
|
43
|
+
const media_metrics_1 = require("./media-metrics");
|
|
44
|
+
class MediaHandler {
|
|
45
|
+
logger;
|
|
46
|
+
metrics;
|
|
47
|
+
constructor(env) {
|
|
48
|
+
this.logger = env ? logger_1.Logger.getInstance(env) : {};
|
|
49
|
+
this.metrics = new media_metrics_1.MediaMetrics(env);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get API domain consistently across all media operations
|
|
53
|
+
* Respects APP_DOMAIN environment variable, converts www. to api., or uses default
|
|
54
|
+
*/
|
|
55
|
+
static getApiDomain(env) {
|
|
56
|
+
if (env.APP_DOMAIN) {
|
|
57
|
+
try {
|
|
58
|
+
const url = new URL(env.APP_DOMAIN);
|
|
59
|
+
let hostname = url.hostname;
|
|
60
|
+
// Convert www. to api.
|
|
61
|
+
if (hostname.startsWith("www.")) {
|
|
62
|
+
hostname = hostname.replace("www.", "api.");
|
|
63
|
+
}
|
|
64
|
+
else if (!hostname.includes("api.")) {
|
|
65
|
+
// If no api. subdomain, add it
|
|
66
|
+
const parts = hostname.split(".");
|
|
67
|
+
if (parts.length >= 2) {
|
|
68
|
+
hostname = `api.${parts.slice(-2).join(".")}`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return `${url.protocol}//${hostname}`;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
// Invalid URL, fall through to default
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Default fallback
|
|
78
|
+
return "https://api.rkm1.de";
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Get media grouped by month or year
|
|
82
|
+
*/
|
|
83
|
+
async listUserMediaGrouped(userId, groupBy, options, env, request) {
|
|
84
|
+
const startTime = Date.now();
|
|
85
|
+
const { sharedDatabaseConnectionManager } = await Promise.resolve().then(() => __importStar(require("./database-connection-manager")));
|
|
86
|
+
const { withQueryTimeoutAndRetry, QueryTimeoutPresets } = await Promise.resolve().then(() => __importStar(require("./db-query-helper")));
|
|
87
|
+
const { DataRouter } = await Promise.resolve().then(() => __importStar(require("./data-router")));
|
|
88
|
+
const { RegionDetector } = await Promise.resolve().then(() => __importStar(require("./region-detection")));
|
|
89
|
+
// Multi-region awareness: detect region from request/session
|
|
90
|
+
const regionDetector = new RegionDetector(env);
|
|
91
|
+
const region = request
|
|
92
|
+
? await regionDetector.detectRegion(request, undefined, undefined)
|
|
93
|
+
: env.DEFAULT_REGION || "EU";
|
|
94
|
+
try {
|
|
95
|
+
const db = request
|
|
96
|
+
? DataRouter.getDatabaseForRegion(region, env, request, userId)
|
|
97
|
+
: DataRouter.getDatabaseForRegion(region, env);
|
|
98
|
+
const includeHidden = options.includeHidden || false;
|
|
99
|
+
const type = options.type || "all";
|
|
100
|
+
// Pagination guardrails: cap limit to prevent excessive load
|
|
101
|
+
const MAX_LIMIT = 10000;
|
|
102
|
+
const DEFAULT_LIMIT = 5000;
|
|
103
|
+
const requestedLimit = options.limit || DEFAULT_LIMIT;
|
|
104
|
+
const fetchLimit = Math.min(requestedLimit, MAX_LIMIT);
|
|
105
|
+
// Warn if limit was truncated (will be logged in response metadata)
|
|
106
|
+
const wasTruncated = requestedLimit > MAX_LIMIT;
|
|
107
|
+
// Get post IDs for the user
|
|
108
|
+
const userPosts = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (dbClient) => {
|
|
109
|
+
return await dbClient.post.findMany({
|
|
110
|
+
where: {
|
|
111
|
+
authorId: userId,
|
|
112
|
+
deletedAt: null,
|
|
113
|
+
},
|
|
114
|
+
select: { id: true },
|
|
115
|
+
});
|
|
116
|
+
}, {
|
|
117
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
118
|
+
maxRetries: 3,
|
|
119
|
+
baseDelayMs: 100,
|
|
120
|
+
context: {
|
|
121
|
+
operation: "listUserMediaGrouped_userPosts",
|
|
122
|
+
userId,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
const postIds = userPosts.map((p) => p.id);
|
|
126
|
+
if (postIds.length === 0) {
|
|
127
|
+
return { groups: [] };
|
|
128
|
+
}
|
|
129
|
+
// Get media IDs for those posts
|
|
130
|
+
const postMedia = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (dbClient) => {
|
|
131
|
+
return await dbClient.postMedia.findMany({
|
|
132
|
+
where: {
|
|
133
|
+
postId: { in: postIds },
|
|
134
|
+
},
|
|
135
|
+
select: { mediaId: true },
|
|
136
|
+
distinct: ["mediaId"],
|
|
137
|
+
});
|
|
138
|
+
}, {
|
|
139
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
140
|
+
maxRetries: 3,
|
|
141
|
+
baseDelayMs: 100,
|
|
142
|
+
context: {
|
|
143
|
+
operation: "listUserMediaGrouped_postMedia",
|
|
144
|
+
userId,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
const mediaIds = postMedia.map((pm) => pm.mediaId);
|
|
148
|
+
if (mediaIds.length === 0) {
|
|
149
|
+
return { groups: [] };
|
|
150
|
+
}
|
|
151
|
+
// Build where clause
|
|
152
|
+
const where = {
|
|
153
|
+
id: { in: mediaIds },
|
|
154
|
+
deletedAt: null,
|
|
155
|
+
};
|
|
156
|
+
if (!includeHidden) {
|
|
157
|
+
where.hidden = false;
|
|
158
|
+
}
|
|
159
|
+
if (type === "photo") {
|
|
160
|
+
where.mimeType = { startsWith: "image/" };
|
|
161
|
+
}
|
|
162
|
+
else if (type === "video") {
|
|
163
|
+
where.mimeType = { startsWith: "video/" };
|
|
164
|
+
}
|
|
165
|
+
// Fetch media (limited to avoid excessive load)
|
|
166
|
+
const media = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (dbClient) => {
|
|
167
|
+
const dbAny = dbClient;
|
|
168
|
+
return await dbAny.mediaFile.findMany({
|
|
169
|
+
where,
|
|
170
|
+
orderBy: { createdAt: "desc" },
|
|
171
|
+
take: fetchLimit,
|
|
172
|
+
});
|
|
173
|
+
}, {
|
|
174
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
175
|
+
maxRetries: 3,
|
|
176
|
+
baseDelayMs: 100,
|
|
177
|
+
context: {
|
|
178
|
+
operation: "listUserMediaGrouped_mediaFiles",
|
|
179
|
+
userId,
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
if (media.length === 0) {
|
|
183
|
+
return { groups: [] };
|
|
184
|
+
}
|
|
185
|
+
// Precompute post counts for each media
|
|
186
|
+
const mediaWithPostCounts = await Promise.all(media.map(async (m) => {
|
|
187
|
+
const postCount = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (dbClient) => {
|
|
188
|
+
return await dbClient.postMedia.count({
|
|
189
|
+
where: {
|
|
190
|
+
mediaId: m.id,
|
|
191
|
+
post: {
|
|
192
|
+
authorId: userId,
|
|
193
|
+
deletedAt: null,
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
}, {
|
|
198
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
199
|
+
maxRetries: 3,
|
|
200
|
+
baseDelayMs: 100,
|
|
201
|
+
context: {
|
|
202
|
+
operation: "listUserMediaGrouped_postCount",
|
|
203
|
+
userId,
|
|
204
|
+
mediaId: m.id,
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
const apiDomain = MediaHandler.getApiDomain(env);
|
|
208
|
+
return {
|
|
209
|
+
id: m.id,
|
|
210
|
+
contentHash: m.contentHash,
|
|
211
|
+
mimeType: m.mimeType,
|
|
212
|
+
size: m.size,
|
|
213
|
+
thumbnailUrl: `${apiDomain}/api/media/${m.contentHash}?variant=thumbnail`,
|
|
214
|
+
optimizedUrl: `${apiDomain}/api/media/${m.contentHash}?variant=optimized`,
|
|
215
|
+
createdAt: m.createdAt.toISOString(),
|
|
216
|
+
hidden: m.hidden || false,
|
|
217
|
+
postCount,
|
|
218
|
+
};
|
|
219
|
+
}));
|
|
220
|
+
// Group by period
|
|
221
|
+
const groupsMap = new Map();
|
|
222
|
+
for (const item of mediaWithPostCounts) {
|
|
223
|
+
const date = new Date(item.createdAt);
|
|
224
|
+
let period;
|
|
225
|
+
if (groupBy === "month") {
|
|
226
|
+
const year = date.getFullYear();
|
|
227
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
228
|
+
period = `${year}-${month}`;
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
period = String(date.getFullYear());
|
|
232
|
+
}
|
|
233
|
+
if (!groupsMap.has(period)) {
|
|
234
|
+
groupsMap.set(period, []);
|
|
235
|
+
}
|
|
236
|
+
groupsMap.get(period).push(item);
|
|
237
|
+
}
|
|
238
|
+
// Convert to array and sort newest-first
|
|
239
|
+
const groups = Array.from(groupsMap.entries())
|
|
240
|
+
.map(([period, items]) => {
|
|
241
|
+
const displayName = groupBy === "month"
|
|
242
|
+
? new Date(`${period}-01`).toLocaleDateString("en-US", {
|
|
243
|
+
month: "long",
|
|
244
|
+
year: "numeric",
|
|
245
|
+
})
|
|
246
|
+
: period;
|
|
247
|
+
return {
|
|
248
|
+
period,
|
|
249
|
+
displayName,
|
|
250
|
+
count: items.length,
|
|
251
|
+
media: items.sort((a, b) => new Date(b.createdAt).getTime() -
|
|
252
|
+
new Date(a.createdAt).getTime()),
|
|
253
|
+
};
|
|
254
|
+
})
|
|
255
|
+
.sort((a, b) => b.period.localeCompare(a.period));
|
|
256
|
+
const result = {
|
|
257
|
+
groups,
|
|
258
|
+
...(wasTruncated && {
|
|
259
|
+
warning: `Limit was capped at ${MAX_LIMIT} items. Requested limit (${requestedLimit}) exceeded maximum.`,
|
|
260
|
+
truncated: true,
|
|
261
|
+
}),
|
|
262
|
+
};
|
|
263
|
+
const duration = Date.now() - startTime;
|
|
264
|
+
const totalItems = groups.reduce((sum, g) => sum + g.count, 0);
|
|
265
|
+
// Structured logging
|
|
266
|
+
this.logger.info("[MediaHandler] Media grouped", {
|
|
267
|
+
operation: "listUserMediaGrouped",
|
|
268
|
+
userId,
|
|
269
|
+
region,
|
|
270
|
+
duration,
|
|
271
|
+
result: {
|
|
272
|
+
groupCount: groups.length,
|
|
273
|
+
totalItems,
|
|
274
|
+
truncated: wasTruncated,
|
|
275
|
+
},
|
|
276
|
+
metadata: {
|
|
277
|
+
groupBy,
|
|
278
|
+
includeHidden: options.includeHidden || false,
|
|
279
|
+
type: options.type || "all",
|
|
280
|
+
limit: options.limit || 5000,
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
return result;
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
const duration = Date.now() - startTime;
|
|
287
|
+
const errorType = error?.name || "UnknownError";
|
|
288
|
+
// Error logging
|
|
289
|
+
this.logger.error("[MediaHandler] Failed to group media", {
|
|
290
|
+
operation: "listUserMediaGrouped",
|
|
291
|
+
userId,
|
|
292
|
+
region,
|
|
293
|
+
duration,
|
|
294
|
+
error: error?.message,
|
|
295
|
+
errorType,
|
|
296
|
+
metadata: {
|
|
297
|
+
groupBy,
|
|
298
|
+
includeHidden: options.includeHidden || false,
|
|
299
|
+
type: options.type || "all",
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
throw error;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Get statistics for a user's media collection
|
|
307
|
+
*/
|
|
308
|
+
async getUserMediaStats(userId, options, env, request) {
|
|
309
|
+
const startTime = Date.now();
|
|
310
|
+
const { sharedDatabaseConnectionManager } = await Promise.resolve().then(() => __importStar(require("./database-connection-manager")));
|
|
311
|
+
const { withQueryTimeoutAndRetry, QueryTimeoutPresets } = await Promise.resolve().then(() => __importStar(require("./db-query-helper")));
|
|
312
|
+
const { DataRouter } = await Promise.resolve().then(() => __importStar(require("./data-router")));
|
|
313
|
+
const { RegionDetector } = await Promise.resolve().then(() => __importStar(require("./region-detection")));
|
|
314
|
+
// Multi-region awareness: detect region from request/session
|
|
315
|
+
const regionDetector = new RegionDetector(env);
|
|
316
|
+
const region = request
|
|
317
|
+
? await regionDetector.detectRegion(request, undefined, undefined)
|
|
318
|
+
: env.DEFAULT_REGION || "EU";
|
|
319
|
+
try {
|
|
320
|
+
const db = request
|
|
321
|
+
? DataRouter.getDatabaseForRegion(region, env, request, userId)
|
|
322
|
+
: DataRouter.getDatabaseForRegion(region, env);
|
|
323
|
+
const includeHidden = options.includeHidden || false;
|
|
324
|
+
const type = options.type || "all";
|
|
325
|
+
// Get user's post IDs
|
|
326
|
+
const userPosts = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (dbClient) => {
|
|
327
|
+
return await dbClient.post.findMany({
|
|
328
|
+
where: {
|
|
329
|
+
authorId: userId,
|
|
330
|
+
deletedAt: null,
|
|
331
|
+
},
|
|
332
|
+
select: { id: true },
|
|
333
|
+
});
|
|
334
|
+
}, {
|
|
335
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
336
|
+
maxRetries: 3,
|
|
337
|
+
baseDelayMs: 100,
|
|
338
|
+
context: {
|
|
339
|
+
operation: "getUserMediaStats_userPosts",
|
|
340
|
+
userId,
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
const postIds = userPosts.map((p) => p.id);
|
|
344
|
+
// Get media IDs from posts
|
|
345
|
+
const postMedia = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (dbClient) => {
|
|
346
|
+
if (postIds.length === 0) {
|
|
347
|
+
return [];
|
|
348
|
+
}
|
|
349
|
+
return await dbClient.postMedia.findMany({
|
|
350
|
+
where: {
|
|
351
|
+
postId: { in: postIds },
|
|
352
|
+
},
|
|
353
|
+
select: { mediaId: true },
|
|
354
|
+
distinct: ["mediaId"],
|
|
355
|
+
});
|
|
356
|
+
}, {
|
|
357
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
358
|
+
maxRetries: 3,
|
|
359
|
+
baseDelayMs: 100,
|
|
360
|
+
context: {
|
|
361
|
+
operation: "getUserMediaStats_postMedia",
|
|
362
|
+
userId,
|
|
363
|
+
},
|
|
364
|
+
});
|
|
365
|
+
const mediaIdsFromPosts = postMedia.map((pm) => pm.mediaId);
|
|
366
|
+
// Get all Entity avatars owned by the user - with timeout/retry
|
|
367
|
+
const userEntities = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (dbClient) => {
|
|
368
|
+
return await dbClient.entity.findMany({
|
|
369
|
+
where: {
|
|
370
|
+
owners: { some: { userId: userId, status: 'ACTIVE' } },
|
|
371
|
+
},
|
|
372
|
+
select: { metadata: true },
|
|
373
|
+
});
|
|
374
|
+
}, {
|
|
375
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
376
|
+
maxRetries: 3,
|
|
377
|
+
baseDelayMs: 100,
|
|
378
|
+
context: {
|
|
379
|
+
operation: "getUserMediaStats_userEntities",
|
|
380
|
+
userId,
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
// Extract contentHashes and media IDs from Entity avatar URLs
|
|
384
|
+
// Avatar URLs can be stored in multiple formats:
|
|
385
|
+
// 1. Full URL: https://api.rkm1.de/api/media/{contentHash}?variant=...
|
|
386
|
+
// 2. ContentHash: just the hash string
|
|
387
|
+
// 3. Media ID: the media ID (CUID) directly
|
|
388
|
+
const avatarContentHashes = new Set();
|
|
389
|
+
const avatarMediaIdsDirect = new Set();
|
|
390
|
+
for (const entity of userEntities) {
|
|
391
|
+
if (entity.metadata && typeof entity.metadata === "object") {
|
|
392
|
+
const metadata = entity.metadata;
|
|
393
|
+
const avatarUrl = metadata.avatar;
|
|
394
|
+
if (typeof avatarUrl === "string" && avatarUrl) {
|
|
395
|
+
// Check if avatar URL is a media ID directly (CUID format: starts with 'c' and has alphanumeric chars)
|
|
396
|
+
// Media IDs are typically CUIDs like 'cmji7uq2l0000l1j23af3r8bo'
|
|
397
|
+
if (/^c[a-z0-9]{24}$/i.test(avatarUrl)) {
|
|
398
|
+
avatarMediaIdsDirect.add(avatarUrl);
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
// Check if it's a contentHash (hex string, typically 64 chars)
|
|
402
|
+
if (/^[a-f0-9]{32,64}$/i.test(avatarUrl)) {
|
|
403
|
+
avatarContentHashes.add(avatarUrl);
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
// Extract contentHash from URL format: /api/media/{contentHash}?variant=...
|
|
407
|
+
// Or: https://api.rkm1.de/api/media/{contentHash}?variant=...
|
|
408
|
+
const match = avatarUrl.match(/\/api\/media\/([a-f0-9]+)(?:\?|$)/i);
|
|
409
|
+
if (match && match[1]) {
|
|
410
|
+
avatarContentHashes.add(match[1]);
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
// Extract media ID from URL format: /api/media/{mediaId}
|
|
414
|
+
// Or: https://api.rkm1.de/api/media/{mediaId}
|
|
415
|
+
const mediaIdMatch = avatarUrl.match(/\/api\/media\/([a-z0-9]+)(?:\?|$)/i);
|
|
416
|
+
if (mediaIdMatch &&
|
|
417
|
+
mediaIdMatch[1] &&
|
|
418
|
+
/^c[a-z0-9]{24}$/i.test(mediaIdMatch[1])) {
|
|
419
|
+
avatarMediaIdsDirect.add(mediaIdMatch[1]);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
// Get media IDs from avatar contentHashes - with timeout/retry
|
|
425
|
+
const avatarMediaIds = [...avatarMediaIdsDirect];
|
|
426
|
+
if (avatarContentHashes.size > 0) {
|
|
427
|
+
const avatarMedia = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (dbClient) => {
|
|
428
|
+
const dbAny = dbClient;
|
|
429
|
+
return await dbAny.mediaFile.findMany({
|
|
430
|
+
where: {
|
|
431
|
+
contentHash: { in: Array.from(avatarContentHashes) },
|
|
432
|
+
deletedAt: null,
|
|
433
|
+
},
|
|
434
|
+
select: { id: true },
|
|
435
|
+
});
|
|
436
|
+
}, {
|
|
437
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
438
|
+
maxRetries: 3,
|
|
439
|
+
baseDelayMs: 100,
|
|
440
|
+
context: {
|
|
441
|
+
operation: "getUserMediaStats_avatarMedia",
|
|
442
|
+
userId,
|
|
443
|
+
},
|
|
444
|
+
});
|
|
445
|
+
avatarMediaIds.push(...avatarMedia.map((m) => m.id));
|
|
446
|
+
}
|
|
447
|
+
// Combine media IDs from posts and avatars
|
|
448
|
+
const allMediaIds = [
|
|
449
|
+
...new Set([...mediaIdsFromPosts, ...avatarMediaIds]),
|
|
450
|
+
];
|
|
451
|
+
if (allMediaIds.length === 0) {
|
|
452
|
+
return {
|
|
453
|
+
totalCount: 0,
|
|
454
|
+
photoCount: 0,
|
|
455
|
+
videoCount: 0,
|
|
456
|
+
hiddenCount: 0,
|
|
457
|
+
totalSize: 0,
|
|
458
|
+
oldestMedia: null,
|
|
459
|
+
newestMedia: null,
|
|
460
|
+
byMonth: [],
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
const whereBase = {
|
|
464
|
+
id: { in: allMediaIds },
|
|
465
|
+
deletedAt: null,
|
|
466
|
+
};
|
|
467
|
+
if (!includeHidden) {
|
|
468
|
+
whereBase.hidden = false;
|
|
469
|
+
}
|
|
470
|
+
// Type filter for top-level total (when requested)
|
|
471
|
+
const applyType = (where) => {
|
|
472
|
+
if (type === "photo") {
|
|
473
|
+
where.mimeType = { startsWith: "image/" };
|
|
474
|
+
}
|
|
475
|
+
else if (type === "video") {
|
|
476
|
+
where.mimeType = { startsWith: "video/" };
|
|
477
|
+
}
|
|
478
|
+
return where;
|
|
479
|
+
};
|
|
480
|
+
// Fetch all media metadata (minimal fields)
|
|
481
|
+
const mediaRows = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (dbClient) => {
|
|
482
|
+
const dbAny = dbClient;
|
|
483
|
+
return await dbAny.mediaFile.findMany({
|
|
484
|
+
where: applyType({ ...whereBase }),
|
|
485
|
+
select: {
|
|
486
|
+
id: true,
|
|
487
|
+
mimeType: true,
|
|
488
|
+
size: true,
|
|
489
|
+
hidden: true,
|
|
490
|
+
createdAt: true,
|
|
491
|
+
},
|
|
492
|
+
});
|
|
493
|
+
}, {
|
|
494
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
495
|
+
maxRetries: 3,
|
|
496
|
+
baseDelayMs: 100,
|
|
497
|
+
context: {
|
|
498
|
+
operation: "getUserMediaStats_mediaRows",
|
|
499
|
+
userId,
|
|
500
|
+
},
|
|
501
|
+
});
|
|
502
|
+
if (mediaRows.length === 0) {
|
|
503
|
+
return {
|
|
504
|
+
totalCount: 0,
|
|
505
|
+
photoCount: 0,
|
|
506
|
+
videoCount: 0,
|
|
507
|
+
hiddenCount: 0,
|
|
508
|
+
totalSize: 0,
|
|
509
|
+
oldestMedia: null,
|
|
510
|
+
newestMedia: null,
|
|
511
|
+
byMonth: [],
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
// Aggregate stats
|
|
515
|
+
let totalSize = 0;
|
|
516
|
+
let photoCount = 0;
|
|
517
|
+
let videoCount = 0;
|
|
518
|
+
let hiddenCount = 0;
|
|
519
|
+
let oldestMedia = null;
|
|
520
|
+
let newestMedia = null;
|
|
521
|
+
const byMonthMap = new Map();
|
|
522
|
+
for (const row of mediaRows) {
|
|
523
|
+
totalSize += row.size || 0;
|
|
524
|
+
if (row.mimeType?.startsWith("image/"))
|
|
525
|
+
photoCount += 1;
|
|
526
|
+
if (row.mimeType?.startsWith("video/"))
|
|
527
|
+
videoCount += 1;
|
|
528
|
+
if (row.hidden)
|
|
529
|
+
hiddenCount += 1;
|
|
530
|
+
const created = row.createdAt instanceof Date
|
|
531
|
+
? row.createdAt
|
|
532
|
+
: new Date(row.createdAt);
|
|
533
|
+
const iso = created.toISOString();
|
|
534
|
+
if (!newestMedia || created > new Date(newestMedia)) {
|
|
535
|
+
newestMedia = iso;
|
|
536
|
+
}
|
|
537
|
+
if (!oldestMedia || created < new Date(oldestMedia)) {
|
|
538
|
+
oldestMedia = iso;
|
|
539
|
+
}
|
|
540
|
+
const period = `${created.getFullYear()}-${String(created.getMonth() + 1).padStart(2, "0")}`;
|
|
541
|
+
byMonthMap.set(period, (byMonthMap.get(period) || 0) + 1);
|
|
542
|
+
}
|
|
543
|
+
const totalCount = mediaRows.length;
|
|
544
|
+
const byMonth = Array.from(byMonthMap.entries())
|
|
545
|
+
.map(([period, count]) => ({ period, count }))
|
|
546
|
+
.sort((a, b) => b.period.localeCompare(a.period));
|
|
547
|
+
const result = {
|
|
548
|
+
totalCount,
|
|
549
|
+
photoCount,
|
|
550
|
+
videoCount,
|
|
551
|
+
hiddenCount,
|
|
552
|
+
totalSize,
|
|
553
|
+
oldestMedia,
|
|
554
|
+
newestMedia,
|
|
555
|
+
byMonth,
|
|
556
|
+
};
|
|
557
|
+
const duration = Date.now() - startTime;
|
|
558
|
+
// Structured logging
|
|
559
|
+
this.logger.info("[MediaHandler] Media stats retrieved", {
|
|
560
|
+
operation: "getUserMediaStats",
|
|
561
|
+
userId,
|
|
562
|
+
region,
|
|
563
|
+
duration,
|
|
564
|
+
result: {
|
|
565
|
+
totalCount,
|
|
566
|
+
photoCount,
|
|
567
|
+
videoCount,
|
|
568
|
+
hiddenCount,
|
|
569
|
+
totalSize,
|
|
570
|
+
monthCount: byMonth.length,
|
|
571
|
+
},
|
|
572
|
+
metadata: {
|
|
573
|
+
includeHidden: options.includeHidden || false,
|
|
574
|
+
type: options.type || "all",
|
|
575
|
+
},
|
|
576
|
+
});
|
|
577
|
+
return result;
|
|
578
|
+
}
|
|
579
|
+
catch (error) {
|
|
580
|
+
const duration = Date.now() - startTime;
|
|
581
|
+
const errorType = error?.name || "UnknownError";
|
|
582
|
+
// Error logging
|
|
583
|
+
this.logger.error("[MediaHandler] Failed to get media stats", {
|
|
584
|
+
operation: "getUserMediaStats",
|
|
585
|
+
userId,
|
|
586
|
+
region,
|
|
587
|
+
duration,
|
|
588
|
+
error: error?.message,
|
|
589
|
+
errorType,
|
|
590
|
+
metadata: {
|
|
591
|
+
includeHidden: options.includeHidden || false,
|
|
592
|
+
type: options.type || "all",
|
|
593
|
+
},
|
|
594
|
+
});
|
|
595
|
+
throw error;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Factory function to create MediaHandler instance
|
|
600
|
+
* Makes testing easier by allowing dependency injection
|
|
601
|
+
*/
|
|
602
|
+
static create(env) {
|
|
603
|
+
return new MediaHandler(env);
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Get all media files for a user with pagination and filtering
|
|
607
|
+
*/
|
|
608
|
+
async listUserMedia(userId, options, env, request) {
|
|
609
|
+
const startTime = Date.now();
|
|
610
|
+
const { DataRouter } = await Promise.resolve().then(() => __importStar(require("./data-router")));
|
|
611
|
+
const { RegionDetector } = await Promise.resolve().then(() => __importStar(require("./region-detection")));
|
|
612
|
+
// Multi-region awareness: detect region from request/session
|
|
613
|
+
const regionDetector = new RegionDetector(env);
|
|
614
|
+
const region = request
|
|
615
|
+
? await regionDetector.detectRegion(request, undefined, undefined)
|
|
616
|
+
: env.DEFAULT_REGION || "EU";
|
|
617
|
+
try {
|
|
618
|
+
const db = request
|
|
619
|
+
? DataRouter.getDatabaseForRegion(region, env, request, userId)
|
|
620
|
+
: DataRouter.getDatabaseForRegion(region, env);
|
|
621
|
+
const limit = Math.min(options.limit || 50, 100);
|
|
622
|
+
const sort = options.sort || "newest";
|
|
623
|
+
const includeHidden = options.includeHidden || false;
|
|
624
|
+
const type = options.type || "all";
|
|
625
|
+
// Use timeout/retry for all database queries
|
|
626
|
+
const { sharedDatabaseConnectionManager } = await Promise.resolve().then(() => __importStar(require("./database-connection-manager")));
|
|
627
|
+
const { withQueryTimeoutAndRetry, QueryTimeoutPresets } = await Promise.resolve().then(() => __importStar(require("./db-query-helper")));
|
|
628
|
+
// Get all post IDs by user - with timeout/retry
|
|
629
|
+
const userPosts = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
630
|
+
return await db.post.findMany({
|
|
631
|
+
where: {
|
|
632
|
+
authorId: userId,
|
|
633
|
+
deletedAt: null,
|
|
634
|
+
},
|
|
635
|
+
select: { id: true },
|
|
636
|
+
});
|
|
637
|
+
}, {
|
|
638
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
639
|
+
maxRetries: 3,
|
|
640
|
+
baseDelayMs: 100,
|
|
641
|
+
context: {
|
|
642
|
+
operation: "listUserMedia_userPosts",
|
|
643
|
+
userId,
|
|
644
|
+
},
|
|
645
|
+
});
|
|
646
|
+
const postIds = userPosts.map((p) => p.id);
|
|
647
|
+
// Get all media IDs from user's posts - with timeout/retry
|
|
648
|
+
const postMedia = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
649
|
+
if (postIds.length === 0) {
|
|
650
|
+
return [];
|
|
651
|
+
}
|
|
652
|
+
return await db.postMedia.findMany({
|
|
653
|
+
where: {
|
|
654
|
+
postId: { in: postIds },
|
|
655
|
+
},
|
|
656
|
+
select: { mediaId: true },
|
|
657
|
+
distinct: ["mediaId"],
|
|
658
|
+
});
|
|
659
|
+
}, {
|
|
660
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
661
|
+
maxRetries: 3,
|
|
662
|
+
baseDelayMs: 100,
|
|
663
|
+
context: {
|
|
664
|
+
operation: "listUserMedia_postMedia",
|
|
665
|
+
userId,
|
|
666
|
+
},
|
|
667
|
+
});
|
|
668
|
+
const mediaIdsFromPosts = postMedia.map((pm) => pm.mediaId);
|
|
669
|
+
// Get all Entity avatars owned by the user - with timeout/retry
|
|
670
|
+
const userEntities = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
671
|
+
return await db.entity.findMany({
|
|
672
|
+
where: {
|
|
673
|
+
owners: { some: { userId: userId, status: 'ACTIVE' } },
|
|
674
|
+
},
|
|
675
|
+
select: { metadata: true },
|
|
676
|
+
});
|
|
677
|
+
}, {
|
|
678
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
679
|
+
maxRetries: 3,
|
|
680
|
+
baseDelayMs: 100,
|
|
681
|
+
context: {
|
|
682
|
+
operation: "listUserMedia_userEntities",
|
|
683
|
+
userId,
|
|
684
|
+
},
|
|
685
|
+
});
|
|
686
|
+
// Extract contentHashes and media IDs from Entity avatar URLs
|
|
687
|
+
// Avatar URLs can be stored in multiple formats:
|
|
688
|
+
// 1. Full URL: https://api.rkm1.de/api/media/{contentHash}?variant=...
|
|
689
|
+
// 2. ContentHash: just the hash string
|
|
690
|
+
// 3. Media ID: the media ID (CUID) directly
|
|
691
|
+
const avatarContentHashes = new Set();
|
|
692
|
+
const avatarMediaIdsDirect = new Set();
|
|
693
|
+
for (const entity of userEntities) {
|
|
694
|
+
if (entity.metadata && typeof entity.metadata === "object") {
|
|
695
|
+
const metadata = entity.metadata;
|
|
696
|
+
const avatarUrl = metadata.avatar;
|
|
697
|
+
if (typeof avatarUrl === "string" && avatarUrl) {
|
|
698
|
+
// Check if avatar URL is a media ID directly (CUID format: starts with 'c' and has alphanumeric chars)
|
|
699
|
+
// Media IDs are typically CUIDs like 'cmji7uq2l0000l1j23af3r8bo'
|
|
700
|
+
if (/^c[a-z0-9]{24}$/i.test(avatarUrl)) {
|
|
701
|
+
avatarMediaIdsDirect.add(avatarUrl);
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
// Check if it's a contentHash (hex string, typically 64 chars)
|
|
705
|
+
if (/^[a-f0-9]{32,64}$/i.test(avatarUrl)) {
|
|
706
|
+
avatarContentHashes.add(avatarUrl);
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
// Extract contentHash from URL format: /api/media/{contentHash}?variant=...
|
|
710
|
+
// Or: https://api.rkm1.de/api/media/{contentHash}?variant=...
|
|
711
|
+
const match = avatarUrl.match(/\/api\/media\/([a-f0-9]+)(?:\?|$)/i);
|
|
712
|
+
if (match && match[1]) {
|
|
713
|
+
avatarContentHashes.add(match[1]);
|
|
714
|
+
continue;
|
|
715
|
+
}
|
|
716
|
+
// Extract media ID from URL format: /api/media/{mediaId}
|
|
717
|
+
// Or: https://api.rkm1.de/api/media/{mediaId}
|
|
718
|
+
const mediaIdMatch = avatarUrl.match(/\/api\/media\/([a-z0-9]+)(?:\?|$)/i);
|
|
719
|
+
if (mediaIdMatch &&
|
|
720
|
+
mediaIdMatch[1] &&
|
|
721
|
+
/^c[a-z0-9]{24}$/i.test(mediaIdMatch[1])) {
|
|
722
|
+
avatarMediaIdsDirect.add(mediaIdMatch[1]);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
// Get media IDs from avatar contentHashes - with timeout/retry
|
|
728
|
+
const avatarMediaIds = [...avatarMediaIdsDirect];
|
|
729
|
+
if (avatarContentHashes.size > 0) {
|
|
730
|
+
const avatarMedia = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
731
|
+
const dbAny = db;
|
|
732
|
+
return await dbAny.mediaFile.findMany({
|
|
733
|
+
where: {
|
|
734
|
+
contentHash: { in: Array.from(avatarContentHashes) },
|
|
735
|
+
deletedAt: null,
|
|
736
|
+
},
|
|
737
|
+
select: { id: true },
|
|
738
|
+
});
|
|
739
|
+
}, {
|
|
740
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
741
|
+
maxRetries: 3,
|
|
742
|
+
baseDelayMs: 100,
|
|
743
|
+
context: {
|
|
744
|
+
operation: "listUserMedia_avatarMedia",
|
|
745
|
+
userId,
|
|
746
|
+
},
|
|
747
|
+
});
|
|
748
|
+
avatarMediaIds.push(...avatarMedia.map((m) => m.id));
|
|
749
|
+
}
|
|
750
|
+
// Combine media IDs from posts and avatars
|
|
751
|
+
const allMediaIds = [
|
|
752
|
+
...new Set([...mediaIdsFromPosts, ...avatarMediaIds]),
|
|
753
|
+
];
|
|
754
|
+
if (allMediaIds.length === 0) {
|
|
755
|
+
return { media: [], cursor: null };
|
|
756
|
+
}
|
|
757
|
+
// Build where clause
|
|
758
|
+
const where = {
|
|
759
|
+
id: { in: allMediaIds },
|
|
760
|
+
deletedAt: null, // Exclude permanently deleted
|
|
761
|
+
};
|
|
762
|
+
if (!includeHidden) {
|
|
763
|
+
where.hidden = false; // Exclude hidden media
|
|
764
|
+
}
|
|
765
|
+
// Filter by type
|
|
766
|
+
if (type === "photo") {
|
|
767
|
+
where.mimeType = { startsWith: "image/" };
|
|
768
|
+
}
|
|
769
|
+
else if (type === "video") {
|
|
770
|
+
where.mimeType = { startsWith: "video/" };
|
|
771
|
+
}
|
|
772
|
+
// Cursor pagination
|
|
773
|
+
if (options.cursor) {
|
|
774
|
+
const cursorDate = new Date(options.cursor);
|
|
775
|
+
if (sort === "oldest") {
|
|
776
|
+
where.createdAt = { gt: cursorDate };
|
|
777
|
+
}
|
|
778
|
+
else {
|
|
779
|
+
where.createdAt = { lt: cursorDate };
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
// Fetch media - with timeout/retry
|
|
783
|
+
const media = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
784
|
+
const dbAny = db;
|
|
785
|
+
return await dbAny.mediaFile.findMany({
|
|
786
|
+
where,
|
|
787
|
+
orderBy: {
|
|
788
|
+
createdAt: sort === "oldest" ? "asc" : "desc",
|
|
789
|
+
},
|
|
790
|
+
take: limit + 1, // Fetch one extra to check if there's more
|
|
791
|
+
});
|
|
792
|
+
}, {
|
|
793
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
794
|
+
maxRetries: 3,
|
|
795
|
+
baseDelayMs: 100,
|
|
796
|
+
context: {
|
|
797
|
+
operation: "listUserMedia_mediaFiles",
|
|
798
|
+
userId,
|
|
799
|
+
},
|
|
800
|
+
});
|
|
801
|
+
// Check if there's more
|
|
802
|
+
const hasMore = media.length > limit;
|
|
803
|
+
const paginatedMedia = hasMore ? media.slice(0, limit) : media;
|
|
804
|
+
const nextCursor = hasMore && paginatedMedia.length > 0
|
|
805
|
+
? paginatedMedia[paginatedMedia.length - 1].createdAt.toISOString()
|
|
806
|
+
: null;
|
|
807
|
+
// Get post counts for each media - with timeout/retry
|
|
808
|
+
const mediaWithPostCounts = await Promise.all(paginatedMedia.map(async (m) => {
|
|
809
|
+
const postCount = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
810
|
+
return await db.postMedia.count({
|
|
811
|
+
where: {
|
|
812
|
+
mediaId: m.id,
|
|
813
|
+
post: {
|
|
814
|
+
authorId: userId,
|
|
815
|
+
deletedAt: null,
|
|
816
|
+
},
|
|
817
|
+
},
|
|
818
|
+
});
|
|
819
|
+
}, {
|
|
820
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
821
|
+
maxRetries: 3,
|
|
822
|
+
baseDelayMs: 100,
|
|
823
|
+
context: {
|
|
824
|
+
operation: "listUserMedia_postCount",
|
|
825
|
+
userId,
|
|
826
|
+
mediaId: m.id,
|
|
827
|
+
},
|
|
828
|
+
});
|
|
829
|
+
// Generate URLs for media variants
|
|
830
|
+
// Always use API domain for media URLs (not frontend domain)
|
|
831
|
+
const apiDomain = MediaHandler.getApiDomain(env);
|
|
832
|
+
const thumbnailUrl = `${apiDomain}/api/media/${m.contentHash}?variant=thumbnail`;
|
|
833
|
+
const optimizedUrl = `${apiDomain}/api/media/${m.contentHash}?variant=optimized`;
|
|
834
|
+
const originalUrl = `${apiDomain}/api/media/${m.contentHash}?variant=original`;
|
|
835
|
+
// Check if this media is used as an Entity avatar (for postCount calculation)
|
|
836
|
+
// Avatar images will have postCount = 0, which is correct
|
|
837
|
+
const isAvatar = avatarContentHashes.has(m.contentHash);
|
|
838
|
+
return {
|
|
839
|
+
id: m.id,
|
|
840
|
+
contentHash: m.contentHash,
|
|
841
|
+
mimeType: m.mimeType,
|
|
842
|
+
size: m.size,
|
|
843
|
+
thumbnailUrl,
|
|
844
|
+
optimizedUrl,
|
|
845
|
+
originalUrl,
|
|
846
|
+
createdAt: m.createdAt.toISOString(),
|
|
847
|
+
hidden: m.hidden || false,
|
|
848
|
+
postCount, // Will be 0 for avatar images, which is correct
|
|
849
|
+
};
|
|
850
|
+
}));
|
|
851
|
+
// Calculate total count if requested
|
|
852
|
+
let totalCount;
|
|
853
|
+
if (options.includeTotalCount) {
|
|
854
|
+
const totalMedia = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
855
|
+
const dbAny = db;
|
|
856
|
+
return await dbAny.mediaFile.count({
|
|
857
|
+
where,
|
|
858
|
+
});
|
|
859
|
+
}, {
|
|
860
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
861
|
+
maxRetries: 3,
|
|
862
|
+
baseDelayMs: 100,
|
|
863
|
+
context: {
|
|
864
|
+
operation: "listUserMedia_totalCount",
|
|
865
|
+
userId,
|
|
866
|
+
},
|
|
867
|
+
});
|
|
868
|
+
totalCount = totalMedia;
|
|
869
|
+
}
|
|
870
|
+
const result = {
|
|
871
|
+
media: mediaWithPostCounts,
|
|
872
|
+
cursor: nextCursor,
|
|
873
|
+
...(totalCount !== undefined && { totalCount }),
|
|
874
|
+
};
|
|
875
|
+
const duration = Date.now() - startTime;
|
|
876
|
+
// Structured logging
|
|
877
|
+
this.logger.info("[MediaHandler] Media listed", {
|
|
878
|
+
operation: "listUserMedia",
|
|
879
|
+
userId,
|
|
880
|
+
region,
|
|
881
|
+
duration,
|
|
882
|
+
result: {
|
|
883
|
+
mediaCount: result.media.length,
|
|
884
|
+
totalCount: result.totalCount,
|
|
885
|
+
hasMore: result.cursor !== null,
|
|
886
|
+
},
|
|
887
|
+
metadata: {
|
|
888
|
+
includeHidden: options.includeHidden || false,
|
|
889
|
+
type: options.type || "all",
|
|
890
|
+
sort: options.sort || "newest",
|
|
891
|
+
limit: options.limit || 50,
|
|
892
|
+
},
|
|
893
|
+
});
|
|
894
|
+
return result;
|
|
895
|
+
}
|
|
896
|
+
catch (error) {
|
|
897
|
+
const duration = Date.now() - startTime;
|
|
898
|
+
const errorType = error?.name || "UnknownError";
|
|
899
|
+
// Error logging
|
|
900
|
+
this.logger.error("[MediaHandler] Failed to list media", {
|
|
901
|
+
operation: "listUserMedia",
|
|
902
|
+
userId,
|
|
903
|
+
region,
|
|
904
|
+
duration,
|
|
905
|
+
error: error?.message,
|
|
906
|
+
errorType,
|
|
907
|
+
metadata: {
|
|
908
|
+
includeHidden: options.includeHidden || false,
|
|
909
|
+
type: options.type || "all",
|
|
910
|
+
sort: options.sort || "newest",
|
|
911
|
+
},
|
|
912
|
+
});
|
|
913
|
+
throw error;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Get detailed information about a specific media file
|
|
918
|
+
*/
|
|
919
|
+
async getMediaDetails(mediaId, userId, env, request) {
|
|
920
|
+
const startTime = Date.now();
|
|
921
|
+
const { DataRouter } = await Promise.resolve().then(() => __importStar(require("./data-router")));
|
|
922
|
+
const { RegionDetector } = await Promise.resolve().then(() => __importStar(require("./region-detection")));
|
|
923
|
+
// Multi-region awareness: detect region from request/session
|
|
924
|
+
const regionDetector = new RegionDetector(env);
|
|
925
|
+
const region = request
|
|
926
|
+
? await regionDetector.detectRegion(request, undefined, undefined)
|
|
927
|
+
: env.DEFAULT_REGION || "EU";
|
|
928
|
+
try {
|
|
929
|
+
// Use timeout/retry for all database queries
|
|
930
|
+
const { sharedDatabaseConnectionManager } = await Promise.resolve().then(() => __importStar(require("./database-connection-manager")));
|
|
931
|
+
const { withQueryTimeoutAndRetry, QueryTimeoutPresets } = await Promise.resolve().then(() => __importStar(require("./db-query-helper")));
|
|
932
|
+
// Get media file - with timeout/retry
|
|
933
|
+
const media = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
934
|
+
const dbAny = db;
|
|
935
|
+
return await dbAny.mediaFile.findUnique({
|
|
936
|
+
where: { id: mediaId },
|
|
937
|
+
});
|
|
938
|
+
}, {
|
|
939
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
940
|
+
maxRetries: 3,
|
|
941
|
+
baseDelayMs: 100,
|
|
942
|
+
context: {
|
|
943
|
+
operation: "getMediaDetails_findMedia",
|
|
944
|
+
userId,
|
|
945
|
+
mediaId,
|
|
946
|
+
},
|
|
947
|
+
});
|
|
948
|
+
if (!media) {
|
|
949
|
+
throw new Error("Media not found");
|
|
950
|
+
}
|
|
951
|
+
// Verify user owns this media (check if it's in any of their posts OR used as Entity avatar) - with timeout/retry
|
|
952
|
+
const userPosts = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
953
|
+
return await db.post.findMany({
|
|
954
|
+
where: {
|
|
955
|
+
authorId: userId,
|
|
956
|
+
deletedAt: null,
|
|
957
|
+
},
|
|
958
|
+
select: { id: true },
|
|
959
|
+
});
|
|
960
|
+
}, {
|
|
961
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
962
|
+
maxRetries: 3,
|
|
963
|
+
baseDelayMs: 100,
|
|
964
|
+
context: {
|
|
965
|
+
operation: "getMediaDetails_userPosts",
|
|
966
|
+
userId,
|
|
967
|
+
mediaId,
|
|
968
|
+
},
|
|
969
|
+
});
|
|
970
|
+
const postIds = userPosts.map((p) => p.id);
|
|
971
|
+
// Check if media is in user's posts - with timeout/retry
|
|
972
|
+
let isInPosts = false;
|
|
973
|
+
if (postIds.length > 0) {
|
|
974
|
+
const postMedia = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
975
|
+
return await db.postMedia.findFirst({
|
|
976
|
+
where: {
|
|
977
|
+
mediaId: media.id,
|
|
978
|
+
postId: { in: postIds },
|
|
979
|
+
},
|
|
980
|
+
});
|
|
981
|
+
}, {
|
|
982
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
983
|
+
maxRetries: 3,
|
|
984
|
+
baseDelayMs: 100,
|
|
985
|
+
context: {
|
|
986
|
+
operation: "getMediaDetails_verifyOwnership",
|
|
987
|
+
userId,
|
|
988
|
+
mediaId,
|
|
989
|
+
},
|
|
990
|
+
});
|
|
991
|
+
isInPosts = !!postMedia;
|
|
992
|
+
}
|
|
993
|
+
// Check if media is used as Entity avatar - with timeout/retry
|
|
994
|
+
const userEntities = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
995
|
+
return await db.entity.findMany({
|
|
996
|
+
where: {
|
|
997
|
+
owners: { some: { userId: userId, status: 'ACTIVE' } },
|
|
998
|
+
},
|
|
999
|
+
select: { metadata: true },
|
|
1000
|
+
});
|
|
1001
|
+
}, {
|
|
1002
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
1003
|
+
maxRetries: 3,
|
|
1004
|
+
baseDelayMs: 100,
|
|
1005
|
+
context: {
|
|
1006
|
+
operation: "getMediaDetails_userEntities",
|
|
1007
|
+
userId,
|
|
1008
|
+
mediaId,
|
|
1009
|
+
},
|
|
1010
|
+
});
|
|
1011
|
+
// Extract contentHashes from Entity avatar URLs
|
|
1012
|
+
// Avatar URLs can be stored in multiple formats:
|
|
1013
|
+
// 1. Full URL: https://api.rkm1.de/api/media/{contentHash}?variant=...
|
|
1014
|
+
// 2. ContentHash: just the hash string
|
|
1015
|
+
// 3. Media ID: the media ID (CUID)
|
|
1016
|
+
let isAvatar = false;
|
|
1017
|
+
for (const entity of userEntities) {
|
|
1018
|
+
if (entity.metadata && typeof entity.metadata === "object") {
|
|
1019
|
+
const metadata = entity.metadata;
|
|
1020
|
+
const avatarUrl = metadata.avatar;
|
|
1021
|
+
if (typeof avatarUrl === "string" && avatarUrl) {
|
|
1022
|
+
// Check if avatar URL matches media ID directly
|
|
1023
|
+
if (avatarUrl === media.id) {
|
|
1024
|
+
isAvatar = true;
|
|
1025
|
+
break;
|
|
1026
|
+
}
|
|
1027
|
+
// Check if avatar URL matches contentHash directly
|
|
1028
|
+
if (avatarUrl === media.contentHash) {
|
|
1029
|
+
isAvatar = true;
|
|
1030
|
+
break;
|
|
1031
|
+
}
|
|
1032
|
+
// Extract contentHash from URL format: /api/media/{contentHash}?variant=...
|
|
1033
|
+
// Or: https://api.rkm1.de/api/media/{contentHash}?variant=...
|
|
1034
|
+
const match = avatarUrl.match(/\/api\/media\/([a-f0-9]+)(?:\?|$)/i);
|
|
1035
|
+
if (match && match[1] === media.contentHash) {
|
|
1036
|
+
isAvatar = true;
|
|
1037
|
+
break;
|
|
1038
|
+
}
|
|
1039
|
+
// Also check if URL contains media ID (for URLs like /api/media/{mediaId})
|
|
1040
|
+
const mediaIdMatch = avatarUrl.match(/\/api\/media\/([a-z0-9]+)(?:\?|$)/i);
|
|
1041
|
+
if (mediaIdMatch && mediaIdMatch[1] === media.id) {
|
|
1042
|
+
isAvatar = true;
|
|
1043
|
+
break;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
// User must own the media either through posts OR as Entity avatar
|
|
1049
|
+
if (!isInPosts && !isAvatar) {
|
|
1050
|
+
throw new Error("Media not found");
|
|
1051
|
+
}
|
|
1052
|
+
// Get all posts using this media (only user's posts) - with timeout/retry
|
|
1053
|
+
// For Entity avatars, postIds will be empty, so return empty array
|
|
1054
|
+
const postsWithMedia = postIds.length > 0
|
|
1055
|
+
? await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
1056
|
+
return await db.post.findMany({
|
|
1057
|
+
where: {
|
|
1058
|
+
id: { in: postIds },
|
|
1059
|
+
deletedAt: null,
|
|
1060
|
+
media: {
|
|
1061
|
+
some: {
|
|
1062
|
+
mediaId: media.id,
|
|
1063
|
+
},
|
|
1064
|
+
},
|
|
1065
|
+
},
|
|
1066
|
+
select: {
|
|
1067
|
+
id: true,
|
|
1068
|
+
text: true,
|
|
1069
|
+
createdAt: true,
|
|
1070
|
+
radius: true,
|
|
1071
|
+
},
|
|
1072
|
+
});
|
|
1073
|
+
}, {
|
|
1074
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
1075
|
+
maxRetries: 3,
|
|
1076
|
+
baseDelayMs: 100,
|
|
1077
|
+
context: {
|
|
1078
|
+
operation: "getMediaDetails_postsWithMedia",
|
|
1079
|
+
userId,
|
|
1080
|
+
mediaId,
|
|
1081
|
+
},
|
|
1082
|
+
})
|
|
1083
|
+
: [];
|
|
1084
|
+
// Check if media is shared with other users' posts - with timeout/retry
|
|
1085
|
+
const allPostsWithMedia = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
1086
|
+
return await db.postMedia.findMany({
|
|
1087
|
+
where: { mediaId: media.id },
|
|
1088
|
+
include: {
|
|
1089
|
+
post: {
|
|
1090
|
+
select: {
|
|
1091
|
+
authorId: true,
|
|
1092
|
+
},
|
|
1093
|
+
},
|
|
1094
|
+
},
|
|
1095
|
+
});
|
|
1096
|
+
}, {
|
|
1097
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
1098
|
+
maxRetries: 3,
|
|
1099
|
+
baseDelayMs: 100,
|
|
1100
|
+
context: {
|
|
1101
|
+
operation: "getMediaDetails_checkShared",
|
|
1102
|
+
userId,
|
|
1103
|
+
mediaId,
|
|
1104
|
+
},
|
|
1105
|
+
});
|
|
1106
|
+
const otherUsersPosts = allPostsWithMedia.filter((pm) => pm.post.authorId !== userId);
|
|
1107
|
+
const isShared = otherUsersPosts.length > 0;
|
|
1108
|
+
// Generate URLs
|
|
1109
|
+
const apiDomain = MediaHandler.getApiDomain(env);
|
|
1110
|
+
const thumbnailUrl = `${apiDomain}/api/media/${media.contentHash}?variant=thumbnail`;
|
|
1111
|
+
const optimizedUrl = `${apiDomain}/api/media/${media.contentHash}?variant=optimized`;
|
|
1112
|
+
const originalUrl = `${apiDomain}/api/media/${media.contentHash}?variant=original`;
|
|
1113
|
+
// This endpoint is owner-only (ownership verified above).
|
|
1114
|
+
// Always return full metadata to the owner — privacy flags control
|
|
1115
|
+
// what OTHER users see, not the owner. The flags are still included
|
|
1116
|
+
// in the response so the frontend can render the toggle state.
|
|
1117
|
+
const result = {
|
|
1118
|
+
id: media.id,
|
|
1119
|
+
contentHash: media.contentHash,
|
|
1120
|
+
cid: media.cid || null,
|
|
1121
|
+
mimeType: media.mimeType,
|
|
1122
|
+
size: media.size,
|
|
1123
|
+
thumbnailUrl,
|
|
1124
|
+
optimizedUrl,
|
|
1125
|
+
originalUrl,
|
|
1126
|
+
width: media.width ?? undefined,
|
|
1127
|
+
height: media.height ?? undefined,
|
|
1128
|
+
duration: media.duration ?? undefined,
|
|
1129
|
+
exifData: media.exifData ?? undefined,
|
|
1130
|
+
iptcData: media.iptcData ?? undefined,
|
|
1131
|
+
videoMetadata: media.videoMetadata ?? undefined,
|
|
1132
|
+
dateTaken: media.dateTaken?.toISOString(),
|
|
1133
|
+
metadataVisible: media.metadataVisible ?? false,
|
|
1134
|
+
locationVisible: media.locationVisible ?? false,
|
|
1135
|
+
createdAt: media.createdAt.toISOString(),
|
|
1136
|
+
updatedAt: media.updatedAt.toISOString(),
|
|
1137
|
+
hidden: media.hidden || false,
|
|
1138
|
+
hiddenAt: media.hiddenAt?.toISOString() || null,
|
|
1139
|
+
deletedAt: media.deletedAt?.toISOString() || null,
|
|
1140
|
+
posts: postsWithMedia.map((post) => ({
|
|
1141
|
+
id: post.id,
|
|
1142
|
+
text: post.text || "",
|
|
1143
|
+
createdAt: post.createdAt.toISOString(),
|
|
1144
|
+
visibility: post.visibility,
|
|
1145
|
+
url: `/posts/${post.id}`,
|
|
1146
|
+
})),
|
|
1147
|
+
canDelete: !isShared && !media.deletedAt, // Can delete if not shared and not already deleted
|
|
1148
|
+
canHide: !media.hidden && !media.deletedAt, // Can hide if not already hidden/deleted
|
|
1149
|
+
};
|
|
1150
|
+
const duration = Date.now() - startTime;
|
|
1151
|
+
// Structured logging
|
|
1152
|
+
this.logger.info("[MediaHandler] Media details retrieved", {
|
|
1153
|
+
operation: "getMediaDetails",
|
|
1154
|
+
userId,
|
|
1155
|
+
region,
|
|
1156
|
+
duration,
|
|
1157
|
+
result: {
|
|
1158
|
+
mediaId,
|
|
1159
|
+
postCount: result.posts.length,
|
|
1160
|
+
isShared,
|
|
1161
|
+
canDelete: result.canDelete,
|
|
1162
|
+
canHide: result.canHide,
|
|
1163
|
+
},
|
|
1164
|
+
});
|
|
1165
|
+
return result;
|
|
1166
|
+
}
|
|
1167
|
+
catch (error) {
|
|
1168
|
+
const duration = Date.now() - startTime;
|
|
1169
|
+
const errorType = error?.name || "UnknownError";
|
|
1170
|
+
// Error logging
|
|
1171
|
+
this.logger.error("[MediaHandler] Failed to get media details", {
|
|
1172
|
+
operation: "getMediaDetails",
|
|
1173
|
+
userId,
|
|
1174
|
+
region,
|
|
1175
|
+
duration,
|
|
1176
|
+
mediaId,
|
|
1177
|
+
error: error?.message,
|
|
1178
|
+
errorType,
|
|
1179
|
+
});
|
|
1180
|
+
throw error;
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* Hide a media file
|
|
1185
|
+
*/
|
|
1186
|
+
async hideMedia(mediaId, userId, env, request) {
|
|
1187
|
+
const startTime = Date.now();
|
|
1188
|
+
const { RegionDetector } = await Promise.resolve().then(() => __importStar(require("./region-detection")));
|
|
1189
|
+
const regionDetector = new RegionDetector(env);
|
|
1190
|
+
const region = request
|
|
1191
|
+
? await regionDetector.detectRegion(request, undefined, undefined)
|
|
1192
|
+
: env.DEFAULT_REGION || "EU";
|
|
1193
|
+
try {
|
|
1194
|
+
// Verify ownership and get media
|
|
1195
|
+
const details = await this.getMediaDetails(mediaId, userId, env, request);
|
|
1196
|
+
if (details.deletedAt) {
|
|
1197
|
+
throw new Error("Cannot hide deleted media");
|
|
1198
|
+
}
|
|
1199
|
+
if (details.hidden) {
|
|
1200
|
+
throw new Error("Media is already hidden");
|
|
1201
|
+
}
|
|
1202
|
+
// Update media - with timeout/retry
|
|
1203
|
+
const { sharedDatabaseConnectionManager } = await Promise.resolve().then(() => __importStar(require("./database-connection-manager")));
|
|
1204
|
+
const { withQueryTimeoutAndRetry, QueryTimeoutPresets } = await Promise.resolve().then(() => __importStar(require("./db-query-helper")));
|
|
1205
|
+
const { AuditLogger } = await Promise.resolve().then(() => __importStar(require("./audit-logger")));
|
|
1206
|
+
const auditLogger = new AuditLogger(env);
|
|
1207
|
+
const updated = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
1208
|
+
const dbAny = db;
|
|
1209
|
+
return await dbAny.mediaFile.update({
|
|
1210
|
+
where: { id: mediaId },
|
|
1211
|
+
data: {
|
|
1212
|
+
hidden: true,
|
|
1213
|
+
hiddenAt: new Date(),
|
|
1214
|
+
hiddenBy: userId,
|
|
1215
|
+
},
|
|
1216
|
+
});
|
|
1217
|
+
}, {
|
|
1218
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
1219
|
+
maxRetries: 3,
|
|
1220
|
+
baseDelayMs: 100,
|
|
1221
|
+
context: {
|
|
1222
|
+
operation: "hideMedia",
|
|
1223
|
+
userId,
|
|
1224
|
+
mediaId,
|
|
1225
|
+
},
|
|
1226
|
+
});
|
|
1227
|
+
// Audit logging
|
|
1228
|
+
try {
|
|
1229
|
+
const ipAddress = request?.headers.get("CF-Connecting-IP") ||
|
|
1230
|
+
request?.headers.get("X-Forwarded-For")?.split(",")[0]?.trim() ||
|
|
1231
|
+
undefined;
|
|
1232
|
+
const userAgent = request?.headers.get("User-Agent") || undefined;
|
|
1233
|
+
await auditLogger.log({
|
|
1234
|
+
type: "data_update",
|
|
1235
|
+
action: "media_hidden",
|
|
1236
|
+
resource: "media",
|
|
1237
|
+
resourceId: mediaId,
|
|
1238
|
+
userId,
|
|
1239
|
+
region,
|
|
1240
|
+
ipAddress,
|
|
1241
|
+
userAgent,
|
|
1242
|
+
metadata: { mediaId, hidden: true },
|
|
1243
|
+
severity: "low",
|
|
1244
|
+
success: true,
|
|
1245
|
+
}, env);
|
|
1246
|
+
}
|
|
1247
|
+
catch (auditError) {
|
|
1248
|
+
// Don't fail the operation if audit logging fails
|
|
1249
|
+
this.logger.warn("[MediaHandler] Audit logging failed for hideMedia", {
|
|
1250
|
+
error: auditError,
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1253
|
+
const duration = Date.now() - startTime;
|
|
1254
|
+
const result = {
|
|
1255
|
+
id: updated.id,
|
|
1256
|
+
hidden: updated.hidden,
|
|
1257
|
+
hiddenAt: updated.hiddenAt.toISOString(),
|
|
1258
|
+
};
|
|
1259
|
+
// Structured logging
|
|
1260
|
+
this.logger.info("[MediaHandler] Media hidden", {
|
|
1261
|
+
operation: "hideMedia",
|
|
1262
|
+
userId,
|
|
1263
|
+
region,
|
|
1264
|
+
duration,
|
|
1265
|
+
result: {
|
|
1266
|
+
mediaId,
|
|
1267
|
+
hidden: result.hidden,
|
|
1268
|
+
},
|
|
1269
|
+
});
|
|
1270
|
+
return result;
|
|
1271
|
+
}
|
|
1272
|
+
catch (error) {
|
|
1273
|
+
const duration = Date.now() - startTime;
|
|
1274
|
+
const errorType = error?.name || "UnknownError";
|
|
1275
|
+
// Error logging
|
|
1276
|
+
this.logger.error("[MediaHandler] Failed to hide media", {
|
|
1277
|
+
operation: "hideMedia",
|
|
1278
|
+
userId,
|
|
1279
|
+
region,
|
|
1280
|
+
duration,
|
|
1281
|
+
mediaId,
|
|
1282
|
+
error: error?.message,
|
|
1283
|
+
errorType,
|
|
1284
|
+
});
|
|
1285
|
+
throw error;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
/**
|
|
1289
|
+
* Unhide a media file
|
|
1290
|
+
*/
|
|
1291
|
+
async unhideMedia(mediaId, userId, env, request) {
|
|
1292
|
+
const startTime = Date.now();
|
|
1293
|
+
const { RegionDetector } = await Promise.resolve().then(() => __importStar(require("./region-detection")));
|
|
1294
|
+
const regionDetector = new RegionDetector(env);
|
|
1295
|
+
const region = request
|
|
1296
|
+
? await regionDetector.detectRegion(request, undefined, undefined)
|
|
1297
|
+
: env.DEFAULT_REGION || "EU";
|
|
1298
|
+
try {
|
|
1299
|
+
// Verify ownership and get media
|
|
1300
|
+
const details = await this.getMediaDetails(mediaId, userId, env, request);
|
|
1301
|
+
if (details.deletedAt) {
|
|
1302
|
+
throw new Error("Cannot unhide deleted media");
|
|
1303
|
+
}
|
|
1304
|
+
if (!details.hidden) {
|
|
1305
|
+
throw new Error("Media is not hidden");
|
|
1306
|
+
}
|
|
1307
|
+
// Update media - with timeout/retry
|
|
1308
|
+
const { sharedDatabaseConnectionManager } = await Promise.resolve().then(() => __importStar(require("./database-connection-manager")));
|
|
1309
|
+
const { withQueryTimeoutAndRetry, QueryTimeoutPresets } = await Promise.resolve().then(() => __importStar(require("./db-query-helper")));
|
|
1310
|
+
const { AuditLogger } = await Promise.resolve().then(() => __importStar(require("./audit-logger")));
|
|
1311
|
+
const auditLogger = new AuditLogger(env);
|
|
1312
|
+
const updated = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
1313
|
+
const dbAny = db;
|
|
1314
|
+
return await dbAny.mediaFile.update({
|
|
1315
|
+
where: { id: mediaId },
|
|
1316
|
+
data: {
|
|
1317
|
+
hidden: false,
|
|
1318
|
+
hiddenAt: null,
|
|
1319
|
+
hiddenBy: null,
|
|
1320
|
+
},
|
|
1321
|
+
});
|
|
1322
|
+
}, {
|
|
1323
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
1324
|
+
maxRetries: 3,
|
|
1325
|
+
baseDelayMs: 100,
|
|
1326
|
+
context: {
|
|
1327
|
+
operation: "unhideMedia",
|
|
1328
|
+
userId,
|
|
1329
|
+
mediaId,
|
|
1330
|
+
},
|
|
1331
|
+
});
|
|
1332
|
+
// Audit logging
|
|
1333
|
+
try {
|
|
1334
|
+
const ipAddress = request?.headers.get("CF-Connecting-IP") ||
|
|
1335
|
+
request?.headers.get("X-Forwarded-For")?.split(",")[0]?.trim() ||
|
|
1336
|
+
undefined;
|
|
1337
|
+
const userAgent = request?.headers.get("User-Agent") || undefined;
|
|
1338
|
+
await auditLogger.log({
|
|
1339
|
+
type: "data_update",
|
|
1340
|
+
action: "media_unhidden",
|
|
1341
|
+
resource: "media",
|
|
1342
|
+
resourceId: mediaId,
|
|
1343
|
+
userId,
|
|
1344
|
+
region,
|
|
1345
|
+
ipAddress,
|
|
1346
|
+
userAgent,
|
|
1347
|
+
metadata: { mediaId, hidden: false },
|
|
1348
|
+
severity: "low",
|
|
1349
|
+
success: true,
|
|
1350
|
+
}, env);
|
|
1351
|
+
}
|
|
1352
|
+
catch (auditError) {
|
|
1353
|
+
// Don't fail the operation if audit logging fails
|
|
1354
|
+
this.logger.warn("[MediaHandler] Audit logging failed for unhideMedia", { error: auditError });
|
|
1355
|
+
}
|
|
1356
|
+
const duration = Date.now() - startTime;
|
|
1357
|
+
const result = {
|
|
1358
|
+
id: updated.id,
|
|
1359
|
+
hidden: updated.hidden,
|
|
1360
|
+
hiddenAt: null,
|
|
1361
|
+
};
|
|
1362
|
+
// Structured logging
|
|
1363
|
+
this.logger.info("[MediaHandler] Media unhidden", {
|
|
1364
|
+
operation: "unhideMedia",
|
|
1365
|
+
userId,
|
|
1366
|
+
region,
|
|
1367
|
+
duration,
|
|
1368
|
+
result: {
|
|
1369
|
+
mediaId,
|
|
1370
|
+
hidden: result.hidden,
|
|
1371
|
+
},
|
|
1372
|
+
});
|
|
1373
|
+
return result;
|
|
1374
|
+
}
|
|
1375
|
+
catch (error) {
|
|
1376
|
+
const duration = Date.now() - startTime;
|
|
1377
|
+
const errorType = error?.name || "UnknownError";
|
|
1378
|
+
// Error logging
|
|
1379
|
+
this.logger.error("[MediaHandler] Failed to unhide media", {
|
|
1380
|
+
operation: "unhideMedia",
|
|
1381
|
+
userId,
|
|
1382
|
+
region,
|
|
1383
|
+
duration,
|
|
1384
|
+
mediaId,
|
|
1385
|
+
error: error?.message,
|
|
1386
|
+
errorType,
|
|
1387
|
+
});
|
|
1388
|
+
throw error;
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
/**
|
|
1392
|
+
* Delete a media file (soft delete)
|
|
1393
|
+
*/
|
|
1394
|
+
async deleteMedia(mediaId, userId, env, request) {
|
|
1395
|
+
const startTime = Date.now();
|
|
1396
|
+
const { RegionDetector } = await Promise.resolve().then(() => __importStar(require("./region-detection")));
|
|
1397
|
+
const regionDetector = new RegionDetector(env);
|
|
1398
|
+
const region = request
|
|
1399
|
+
? await regionDetector.detectRegion(request, undefined, undefined)
|
|
1400
|
+
: env.DEFAULT_REGION || "EU";
|
|
1401
|
+
try {
|
|
1402
|
+
// Verify ownership and get media
|
|
1403
|
+
const details = await this.getMediaDetails(mediaId, userId, env, request);
|
|
1404
|
+
if (details.deletedAt) {
|
|
1405
|
+
throw new Error("Media is already deleted");
|
|
1406
|
+
}
|
|
1407
|
+
// Check if shared with other users - with timeout/retry
|
|
1408
|
+
const { sharedDatabaseConnectionManager } = await Promise.resolve().then(() => __importStar(require("./database-connection-manager")));
|
|
1409
|
+
const { withQueryTimeoutAndRetry, QueryTimeoutPresets } = await Promise.resolve().then(() => __importStar(require("./db-query-helper")));
|
|
1410
|
+
const { AuditLogger } = await Promise.resolve().then(() => __importStar(require("./audit-logger")));
|
|
1411
|
+
const auditLogger = new AuditLogger(env);
|
|
1412
|
+
const allPostsWithMedia = await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
1413
|
+
return await db.postMedia.findMany({
|
|
1414
|
+
where: { mediaId },
|
|
1415
|
+
include: {
|
|
1416
|
+
post: {
|
|
1417
|
+
select: {
|
|
1418
|
+
authorId: true,
|
|
1419
|
+
},
|
|
1420
|
+
},
|
|
1421
|
+
},
|
|
1422
|
+
});
|
|
1423
|
+
}, {
|
|
1424
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
1425
|
+
maxRetries: 3,
|
|
1426
|
+
baseDelayMs: 100,
|
|
1427
|
+
context: {
|
|
1428
|
+
operation: "deleteMedia_checkShared",
|
|
1429
|
+
userId,
|
|
1430
|
+
mediaId,
|
|
1431
|
+
},
|
|
1432
|
+
});
|
|
1433
|
+
const otherUsersPosts = allPostsWithMedia.filter((pm) => pm.post.authorId !== userId);
|
|
1434
|
+
if (otherUsersPosts.length > 0) {
|
|
1435
|
+
// If shared, hide instead of delete
|
|
1436
|
+
await this.hideMedia(mediaId, userId, env, request);
|
|
1437
|
+
// Audit logging for hide (instead of delete)
|
|
1438
|
+
try {
|
|
1439
|
+
const ipAddress = request?.headers.get("CF-Connecting-IP") ||
|
|
1440
|
+
request?.headers.get("X-Forwarded-For")?.split(",")[0]?.trim() ||
|
|
1441
|
+
undefined;
|
|
1442
|
+
const userAgent = request?.headers.get("User-Agent") || undefined;
|
|
1443
|
+
await auditLogger.log({
|
|
1444
|
+
type: "data_update",
|
|
1445
|
+
action: "media_delete_attempted_shared",
|
|
1446
|
+
resource: "media",
|
|
1447
|
+
resourceId: mediaId,
|
|
1448
|
+
userId,
|
|
1449
|
+
region,
|
|
1450
|
+
ipAddress,
|
|
1451
|
+
userAgent,
|
|
1452
|
+
metadata: {
|
|
1453
|
+
mediaId,
|
|
1454
|
+
action: "hidden_instead_of_deleted",
|
|
1455
|
+
reason: "shared_with_other_users",
|
|
1456
|
+
otherUsersCount: otherUsersPosts.length,
|
|
1457
|
+
},
|
|
1458
|
+
severity: "medium",
|
|
1459
|
+
success: true,
|
|
1460
|
+
}, env);
|
|
1461
|
+
}
|
|
1462
|
+
catch (auditError) {
|
|
1463
|
+
this.logger.warn("[MediaHandler] Audit logging failed for deleteMedia (shared)", { error: auditError });
|
|
1464
|
+
}
|
|
1465
|
+
throw new Error("Media is used by other users. It has been hidden instead of deleted.");
|
|
1466
|
+
}
|
|
1467
|
+
// Soft delete - with timeout/retry
|
|
1468
|
+
await withQueryTimeoutAndRetry(sharedDatabaseConnectionManager, region, env, async (db) => {
|
|
1469
|
+
const dbAny = db;
|
|
1470
|
+
return await dbAny.mediaFile.update({
|
|
1471
|
+
where: { id: mediaId },
|
|
1472
|
+
data: {
|
|
1473
|
+
deletedAt: new Date(),
|
|
1474
|
+
},
|
|
1475
|
+
});
|
|
1476
|
+
}, {
|
|
1477
|
+
...QueryTimeoutPresets.USER_FACING,
|
|
1478
|
+
maxRetries: 3,
|
|
1479
|
+
baseDelayMs: 100,
|
|
1480
|
+
context: {
|
|
1481
|
+
operation: "deleteMedia",
|
|
1482
|
+
userId,
|
|
1483
|
+
mediaId,
|
|
1484
|
+
},
|
|
1485
|
+
});
|
|
1486
|
+
// Audit logging
|
|
1487
|
+
try {
|
|
1488
|
+
const ipAddress = request?.headers.get("CF-Connecting-IP") ||
|
|
1489
|
+
request?.headers.get("X-Forwarded-For")?.split(",")[0]?.trim() ||
|
|
1490
|
+
undefined;
|
|
1491
|
+
const userAgent = request?.headers.get("User-Agent") || undefined;
|
|
1492
|
+
await auditLogger.log({
|
|
1493
|
+
type: "data_delete",
|
|
1494
|
+
action: "media_deleted",
|
|
1495
|
+
resource: "media",
|
|
1496
|
+
resourceId: mediaId,
|
|
1497
|
+
userId,
|
|
1498
|
+
region,
|
|
1499
|
+
ipAddress,
|
|
1500
|
+
userAgent,
|
|
1501
|
+
metadata: { mediaId, softDelete: true },
|
|
1502
|
+
severity: "medium",
|
|
1503
|
+
success: true,
|
|
1504
|
+
}, env);
|
|
1505
|
+
}
|
|
1506
|
+
catch (auditError) {
|
|
1507
|
+
// Don't fail the operation if audit logging fails
|
|
1508
|
+
this.logger.warn("[MediaHandler] Audit logging failed for deleteMedia", { error: auditError });
|
|
1509
|
+
}
|
|
1510
|
+
const duration = Date.now() - startTime;
|
|
1511
|
+
// Structured logging
|
|
1512
|
+
this.logger.info("[MediaHandler] Media deleted", {
|
|
1513
|
+
operation: "deleteMedia",
|
|
1514
|
+
userId,
|
|
1515
|
+
region,
|
|
1516
|
+
duration,
|
|
1517
|
+
result: {
|
|
1518
|
+
mediaId,
|
|
1519
|
+
softDelete: true,
|
|
1520
|
+
},
|
|
1521
|
+
});
|
|
1522
|
+
// R2 object deletion is handled by MediaCleanupHandler scheduled job
|
|
1523
|
+
// See: apps/api/src/lib/media-cleanup-handler.ts
|
|
1524
|
+
// Runs daily at 3:00 AM UTC with 7-day grace period
|
|
1525
|
+
}
|
|
1526
|
+
catch (error) {
|
|
1527
|
+
const duration = Date.now() - startTime;
|
|
1528
|
+
const errorType = error?.name || "UnknownError";
|
|
1529
|
+
// Error logging
|
|
1530
|
+
this.logger.error("[MediaHandler] Failed to delete media", {
|
|
1531
|
+
operation: "deleteMedia",
|
|
1532
|
+
userId,
|
|
1533
|
+
region,
|
|
1534
|
+
duration,
|
|
1535
|
+
mediaId,
|
|
1536
|
+
error: error?.message,
|
|
1537
|
+
errorType,
|
|
1538
|
+
});
|
|
1539
|
+
throw error;
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
exports.MediaHandler = MediaHandler;
|
|
1544
|
+
//# sourceMappingURL=media-handler.js.map
|