vidspotai-shared 1.0.68 → 1.0.69-dev.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/lib/globals/aiModels/enums.d.ts +63 -6
- package/lib/globals/aiModels/enums.d.ts.map +1 -1
- package/lib/globals/aiModels/enums.js +78 -9
- package/lib/globals/aiModels/index.d.ts +2 -30
- package/lib/globals/aiModels/index.d.ts.map +1 -1
- package/lib/globals/aiModels/index.js +7 -35
- package/lib/globals/aiModels/providers/alibaba.d.ts +4 -0
- package/lib/globals/aiModels/providers/alibaba.d.ts.map +1 -0
- package/lib/globals/aiModels/providers/alibaba.js +194 -0
- package/lib/globals/aiModels/providers/bytedance.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/bytedance.js +19 -0
- package/lib/globals/aiModels/providers/elevenlabs.d.ts +14 -0
- package/lib/globals/aiModels/providers/elevenlabs.d.ts.map +1 -0
- package/lib/globals/aiModels/providers/elevenlabs.js +29 -0
- package/lib/globals/aiModels/providers/google.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/google.js +150 -2
- package/lib/globals/aiModels/providers/kling.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/kling.js +280 -37
- package/lib/globals/aiModels/providers/minimax.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/minimax.js +76 -11
- package/lib/globals/aiModels/providers/openai.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/openai.js +90 -6
- package/lib/globals/aiModels/providers/pixverse.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/pixverse.js +111 -29
- package/lib/globals/aiModels/providers/pixverseTemplates.d.ts +36 -0
- package/lib/globals/aiModels/providers/pixverseTemplates.d.ts.map +1 -0
- package/lib/globals/aiModels/providers/pixverseTemplates.js +42 -0
- package/lib/globals/aiModels/providers/runway.d.ts.map +1 -1
- package/lib/globals/aiModels/providers/runway.js +64 -2
- package/lib/globals/aiModels/tierHelpers.d.ts +33 -0
- package/lib/globals/aiModels/tierHelpers.d.ts.map +1 -0
- package/lib/globals/aiModels/tierHelpers.js +109 -0
- package/lib/globals/aiModels/types.d.ts +20 -1
- package/lib/globals/aiModels/types.d.ts.map +1 -1
- package/lib/globals/ttsModels/index.d.ts +2 -0
- package/lib/globals/ttsModels/index.d.ts.map +1 -1
- package/lib/globals/ttsModels/index.js +9 -1
- package/lib/globals/ttsModels/providers/minimax.d.ts +8 -0
- package/lib/globals/ttsModels/providers/minimax.d.ts.map +1 -0
- package/lib/globals/ttsModels/providers/minimax.js +18 -0
- package/lib/globals/ttsModels/providers/openai.d.ts +12 -0
- package/lib/globals/ttsModels/providers/openai.d.ts.map +1 -0
- package/lib/globals/ttsModels/providers/openai.js +22 -0
- package/lib/globals/ttsModels/types.d.ts +1 -1
- package/lib/globals/ttsModels/types.d.ts.map +1 -1
- package/lib/globals/ttsModels/voices.d.ts +39 -4
- package/lib/globals/ttsModels/voices.d.ts.map +1 -1
- package/lib/globals/ttsModels/voices.js +273 -26
- package/lib/globals/types.d.ts +59 -1
- package/lib/globals/types.d.ts.map +1 -1
- package/lib/globals/types.js +81 -2
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/models/agent.model.d.ts +357 -0
- package/lib/models/agent.model.d.ts.map +1 -0
- package/lib/models/agent.model.js +21 -0
- package/lib/models/cachedAsset.model.d.ts +18 -0
- package/lib/models/cachedAsset.model.d.ts.map +1 -0
- package/lib/models/cachedAsset.model.js +2 -0
- package/lib/models/cachedRawAsset.model.d.ts +20 -0
- package/lib/models/cachedRawAsset.model.d.ts.map +1 -0
- package/lib/models/cachedRawAsset.model.js +2 -0
- package/lib/models/image.model.d.ts +47 -0
- package/lib/models/image.model.d.ts.map +1 -0
- package/lib/models/image.model.js +2 -0
- package/lib/models/index.d.ts +6 -0
- package/lib/models/index.d.ts.map +1 -1
- package/lib/models/index.js +6 -0
- package/lib/models/notification.model.d.ts +25 -0
- package/lib/models/notification.model.d.ts.map +1 -0
- package/lib/models/notification.model.js +2 -0
- package/lib/models/ref.model.d.ts +80 -0
- package/lib/models/ref.model.d.ts.map +1 -0
- package/lib/models/ref.model.js +13 -0
- package/lib/models/share.model.d.ts +29 -0
- package/lib/models/share.model.d.ts.map +1 -0
- package/lib/models/share.model.js +2 -0
- package/lib/models/user.model.d.ts +12 -1
- package/lib/models/user.model.d.ts.map +1 -1
- package/lib/models/video.model.d.ts +120 -8
- package/lib/models/video.model.d.ts.map +1 -1
- package/lib/models/video.model.js +10 -0
- package/lib/schemas/agentPersona.schema.d.ts +10 -0
- package/lib/schemas/agentPersona.schema.d.ts.map +1 -0
- package/lib/schemas/agentPersona.schema.js +11 -0
- package/lib/schemas/agentRunJob.schema.d.ts +105 -0
- package/lib/schemas/agentRunJob.schema.d.ts.map +1 -0
- package/lib/schemas/agentRunJob.schema.js +88 -0
- package/lib/schemas/brandKit.schema.d.ts +113 -0
- package/lib/schemas/brandKit.schema.d.ts.map +1 -0
- package/lib/schemas/brandKit.schema.js +46 -0
- package/lib/schemas/brief.schema.d.ts +263 -0
- package/lib/schemas/brief.schema.d.ts.map +1 -0
- package/lib/schemas/brief.schema.js +157 -0
- package/lib/schemas/index.d.ts +7 -0
- package/lib/schemas/index.d.ts.map +1 -0
- package/lib/schemas/index.js +22 -0
- package/lib/schemas/project.schema.d.ts +1025 -0
- package/lib/schemas/project.schema.d.ts.map +1 -0
- package/lib/schemas/project.schema.js +256 -0
- package/lib/schemas/videoPlan.schema.d.ts +590 -0
- package/lib/schemas/videoPlan.schema.d.ts.map +1 -0
- package/lib/schemas/videoPlan.schema.js +412 -0
- package/lib/services/agent/beatSnap.d.ts +10 -0
- package/lib/services/agent/beatSnap.d.ts.map +1 -0
- package/lib/services/agent/beatSnap.js +128 -0
- package/lib/services/agent/bibleBuilder.d.ts +43 -0
- package/lib/services/agent/bibleBuilder.d.ts.map +1 -0
- package/lib/services/agent/bibleBuilder.js +102 -0
- package/lib/services/agent/bibleImageVision.d.ts +45 -0
- package/lib/services/agent/bibleImageVision.d.ts.map +1 -0
- package/lib/services/agent/bibleImageVision.js +169 -0
- package/lib/services/agent/chatAgent.d.ts +79 -0
- package/lib/services/agent/chatAgent.d.ts.map +1 -0
- package/lib/services/agent/chatAgent.js +136 -0
- package/lib/services/agent/costPreflight.d.ts +61 -0
- package/lib/services/agent/costPreflight.d.ts.map +1 -0
- package/lib/services/agent/costPreflight.js +143 -0
- package/lib/services/agent/critic.d.ts +103 -0
- package/lib/services/agent/critic.d.ts.map +1 -0
- package/lib/services/agent/critic.js +139 -0
- package/lib/services/agent/editClassifier.d.ts +262 -0
- package/lib/services/agent/editClassifier.d.ts.map +1 -0
- package/lib/services/agent/editClassifier.js +186 -0
- package/lib/services/agent/eval/index.d.ts +5 -0
- package/lib/services/agent/eval/index.d.ts.map +1 -0
- package/lib/services/agent/eval/index.js +20 -0
- package/lib/services/agent/eval/judge.d.ts +14 -0
- package/lib/services/agent/eval/judge.d.ts.map +1 -0
- package/lib/services/agent/eval/judge.js +96 -0
- package/lib/services/agent/eval/recorder.d.ts +28 -0
- package/lib/services/agent/eval/recorder.d.ts.map +1 -0
- package/lib/services/agent/eval/recorder.js +100 -0
- package/lib/services/agent/eval/seedBriefs.d.ts +16 -0
- package/lib/services/agent/eval/seedBriefs.d.ts.map +1 -0
- package/lib/services/agent/eval/seedBriefs.js +1188 -0
- package/lib/services/agent/eval/types.d.ts +230 -0
- package/lib/services/agent/eval/types.d.ts.map +1 -0
- package/lib/services/agent/eval/types.js +73 -0
- package/lib/services/agent/executor.d.ts +141 -0
- package/lib/services/agent/executor.d.ts.map +1 -0
- package/lib/services/agent/executor.js +561 -0
- package/lib/services/agent/globalActions.d.ts +49 -0
- package/lib/services/agent/globalActions.d.ts.map +1 -0
- package/lib/services/agent/globalActions.js +328 -0
- package/lib/services/agent/index.d.ts +38 -0
- package/lib/services/agent/index.d.ts.map +1 -0
- package/lib/services/agent/index.js +53 -0
- package/lib/services/agent/llmCaller.d.ts +144 -0
- package/lib/services/agent/llmCaller.d.ts.map +1 -0
- package/lib/services/agent/llmCaller.js +16 -0
- package/lib/services/agent/llmCallerAnthropic.d.ts +90 -0
- package/lib/services/agent/llmCallerAnthropic.d.ts.map +1 -0
- package/lib/services/agent/llmCallerAnthropic.js +255 -0
- package/lib/services/agent/llmCallerGateway.d.ts +61 -0
- package/lib/services/agent/llmCallerGateway.d.ts.map +1 -0
- package/lib/services/agent/llmCallerGateway.js +360 -0
- package/lib/services/agent/llmCallerRegistry.d.ts +6 -0
- package/lib/services/agent/llmCallerRegistry.d.ts.map +1 -0
- package/lib/services/agent/llmCallerRegistry.js +39 -0
- package/lib/services/agent/modelQualityNotes.d.ts +100 -0
- package/lib/services/agent/modelQualityNotes.d.ts.map +1 -0
- package/lib/services/agent/modelQualityNotes.js +248 -0
- package/lib/services/agent/modelRouter.d.ts +41 -0
- package/lib/services/agent/modelRouter.d.ts.map +1 -0
- package/lib/services/agent/modelRouter.js +65 -0
- package/lib/services/agent/musicSelect.d.ts +23 -0
- package/lib/services/agent/musicSelect.d.ts.map +1 -0
- package/lib/services/agent/musicSelect.js +109 -0
- package/lib/services/agent/overlayRenderer.d.ts +67 -0
- package/lib/services/agent/overlayRenderer.d.ts.map +1 -0
- package/lib/services/agent/overlayRenderer.js +253 -0
- package/lib/services/agent/perSceneCritic.d.ts +90 -0
- package/lib/services/agent/perSceneCritic.d.ts.map +1 -0
- package/lib/services/agent/perSceneCritic.js +125 -0
- package/lib/services/agent/personas.d.ts +78 -0
- package/lib/services/agent/personas.d.ts.map +1 -0
- package/lib/services/agent/personas.js +177 -0
- package/lib/services/agent/planDiff.d.ts +76 -0
- package/lib/services/agent/planDiff.d.ts.map +1 -0
- package/lib/services/agent/planDiff.js +182 -0
- package/lib/services/agent/planMutations.d.ts +46 -0
- package/lib/services/agent/planMutations.d.ts.map +1 -0
- package/lib/services/agent/planMutations.js +120 -0
- package/lib/services/agent/planner/Planner.d.ts +107 -0
- package/lib/services/agent/planner/Planner.d.ts.map +1 -0
- package/lib/services/agent/planner/Planner.js +591 -0
- package/lib/services/agent/planner/overlaySanity.d.ts +7 -0
- package/lib/services/agent/planner/overlaySanity.d.ts.map +1 -0
- package/lib/services/agent/planner/overlaySanity.js +86 -0
- package/lib/services/agent/planner/promptSections.d.ts +25 -0
- package/lib/services/agent/planner/promptSections.d.ts.map +1 -0
- package/lib/services/agent/planner/promptSections.js +174 -0
- package/lib/services/agent/planner/repair.d.ts +16 -0
- package/lib/services/agent/planner/repair.d.ts.map +1 -0
- package/lib/services/agent/planner/repair.js +51 -0
- package/lib/services/agent/planner/structuralRules.d.ts +10 -0
- package/lib/services/agent/planner/structuralRules.d.ts.map +1 -0
- package/lib/services/agent/planner/structuralRules.js +111 -0
- package/lib/services/agent/planner/validators.d.ts +65 -0
- package/lib/services/agent/planner/validators.d.ts.map +1 -0
- package/lib/services/agent/planner/validators.js +284 -0
- package/lib/services/agent/planner.d.ts +3 -0
- package/lib/services/agent/planner.d.ts.map +1 -0
- package/lib/services/agent/planner.js +14 -0
- package/lib/services/agent/providerFallback/chains.d.ts +100 -0
- package/lib/services/agent/providerFallback/chains.d.ts.map +1 -0
- package/lib/services/agent/providerFallback/chains.js +198 -0
- package/lib/services/agent/providerFallback/classifier.d.ts +36 -0
- package/lib/services/agent/providerFallback/classifier.d.ts.map +1 -0
- package/lib/services/agent/providerFallback/classifier.js +103 -0
- package/lib/services/agent/providerFallback/index.d.ts +4 -0
- package/lib/services/agent/providerFallback/index.d.ts.map +1 -0
- package/lib/services/agent/providerFallback/index.js +19 -0
- package/lib/services/agent/providerFallback/withFallback.d.ts +60 -0
- package/lib/services/agent/providerFallback/withFallback.d.ts.map +1 -0
- package/lib/services/agent/providerFallback/withFallback.js +93 -0
- package/lib/services/agent/providerTaskCache.d.ts +50 -0
- package/lib/services/agent/providerTaskCache.d.ts.map +1 -0
- package/lib/services/agent/providerTaskCache.js +98 -0
- package/lib/services/agent/qualityGate.d.ts +82 -0
- package/lib/services/agent/qualityGate.d.ts.map +1 -0
- package/lib/services/agent/qualityGate.js +232 -0
- package/lib/services/agent/referenceImageRenderer.d.ts +37 -0
- package/lib/services/agent/referenceImageRenderer.d.ts.map +1 -0
- package/lib/services/agent/referenceImageRenderer.js +92 -0
- package/lib/services/agent/regenCore.d.ts +60 -0
- package/lib/services/agent/regenCore.d.ts.map +1 -0
- package/lib/services/agent/regenCore.js +487 -0
- package/lib/services/agent/runHelpers.d.ts +44 -0
- package/lib/services/agent/runHelpers.d.ts.map +1 -0
- package/lib/services/agent/runHelpers.js +196 -0
- package/lib/services/agent/sceneLayoutVision.d.ts +90 -0
- package/lib/services/agent/sceneLayoutVision.d.ts.map +1 -0
- package/lib/services/agent/sceneLayoutVision.js +212 -0
- package/lib/services/agent/stitchedVideoCritic.d.ts +136 -0
- package/lib/services/agent/stitchedVideoCritic.d.ts.map +1 -0
- package/lib/services/agent/stitchedVideoCritic.gemini.d.ts +26 -0
- package/lib/services/agent/stitchedVideoCritic.gemini.d.ts.map +1 -0
- package/lib/services/agent/stitchedVideoCritic.gemini.js +198 -0
- package/lib/services/agent/stitchedVideoCritic.js +162 -0
- package/lib/services/agent/taskPoller.d.ts +65 -0
- package/lib/services/agent/taskPoller.d.ts.map +1 -0
- package/lib/services/agent/taskPoller.js +176 -0
- package/lib/services/agent/textOverlayStyles.d.ts +60 -0
- package/lib/services/agent/textOverlayStyles.d.ts.map +1 -0
- package/lib/services/agent/textOverlayStyles.js +174 -0
- package/lib/services/agent/toolRegistry.d.ts +73 -0
- package/lib/services/agent/toolRegistry.d.ts.map +1 -0
- package/lib/services/agent/toolRegistry.js +95 -0
- package/lib/services/agent/tools/analyzeReference.tool.d.ts +36 -0
- package/lib/services/agent/tools/analyzeReference.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/analyzeReference.tool.js +44 -0
- package/lib/services/agent/tools/animateImage.tool.d.ts +24 -0
- package/lib/services/agent/tools/animateImage.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/animateImage.tool.js +115 -0
- package/lib/services/agent/tools/animateImageWithMotionBrush.tool.d.ts +32 -0
- package/lib/services/agent/tools/animateImageWithMotionBrush.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/animateImageWithMotionBrush.tool.js +135 -0
- package/lib/services/agent/tools/composeScene.tool.d.ts +978 -0
- package/lib/services/agent/tools/composeScene.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/composeScene.tool.js +90 -0
- package/lib/services/agent/tools/estimateCost.tool.d.ts +352 -0
- package/lib/services/agent/tools/estimateCost.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/estimateCost.tool.js +62 -0
- package/lib/services/agent/tools/generateAvatarVideo.tool.d.ts +32 -0
- package/lib/services/agent/tools/generateAvatarVideo.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/generateAvatarVideo.tool.js +143 -0
- package/lib/services/agent/tools/generateCaptions.tool.d.ts +42 -0
- package/lib/services/agent/tools/generateCaptions.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/generateCaptions.tool.js +196 -0
- package/lib/services/agent/tools/generateImage.tool.d.ts +74 -0
- package/lib/services/agent/tools/generateImage.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/generateImage.tool.js +206 -0
- package/lib/services/agent/tools/generateVideo.tool.d.ts +31 -0
- package/lib/services/agent/tools/generateVideo.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/generateVideo.tool.js +153 -0
- package/lib/services/agent/tools/generateVoiceover.tool.d.ts +44 -0
- package/lib/services/agent/tools/generateVoiceover.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/generateVoiceover.tool.js +206 -0
- package/lib/services/agent/tools/index.d.ts +20 -0
- package/lib/services/agent/tools/index.d.ts.map +1 -0
- package/lib/services/agent/tools/index.js +35 -0
- package/lib/services/agent/tools/planVideo.tool.d.ts +343 -0
- package/lib/services/agent/tools/planVideo.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/planVideo.tool.js +46 -0
- package/lib/services/agent/tools/render.tool.d.ts +367 -0
- package/lib/services/agent/tools/render.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/render.tool.js +48 -0
- package/lib/services/agent/tools/searchMusic.tool.d.ts +49 -0
- package/lib/services/agent/tools/searchMusic.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/searchMusic.tool.js +74 -0
- package/lib/services/agent/tools/searchStock.tool.d.ts +41 -0
- package/lib/services/agent/tools/searchStock.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/searchStock.tool.js +314 -0
- package/lib/services/agent/tools/searchUserLibrary.tool.d.ts +59 -0
- package/lib/services/agent/tools/searchUserLibrary.tool.d.ts.map +1 -0
- package/lib/services/agent/tools/searchUserLibrary.tool.js +58 -0
- package/lib/services/agent/ttsDuration.d.ts +29 -0
- package/lib/services/agent/ttsDuration.d.ts.map +1 -0
- package/lib/services/agent/ttsDuration.js +60 -0
- package/lib/services/aiGen/aiGenFactory.service.d.ts +21 -1
- package/lib/services/aiGen/aiGenFactory.service.d.ts.map +1 -1
- package/lib/services/aiGen/aiGenFactory.service.js +84 -21
- package/lib/services/aiGen/canonicalAdapters/cameraControl.types.d.ts +31 -0
- package/lib/services/aiGen/canonicalAdapters/cameraControl.types.d.ts.map +1 -0
- package/lib/services/aiGen/canonicalAdapters/cameraControl.types.js +2 -0
- package/lib/services/aiGen/canonicalAdapters/index.d.ts +3 -0
- package/lib/services/aiGen/canonicalAdapters/index.d.ts.map +1 -0
- package/lib/services/aiGen/canonicalAdapters/index.js +18 -0
- package/lib/services/aiGen/canonicalAdapters/multiShot.types.d.ts +23 -0
- package/lib/services/aiGen/canonicalAdapters/multiShot.types.d.ts.map +1 -0
- package/lib/services/aiGen/canonicalAdapters/multiShot.types.js +12 -0
- package/lib/services/aiGen/helpers.d.ts.map +1 -1
- package/lib/services/aiGen/helpers.js +10 -0
- package/lib/services/aiGen/providers/alibaba/alibaba.d.ts +14 -3
- package/lib/services/aiGen/providers/alibaba/alibaba.d.ts.map +1 -1
- package/lib/services/aiGen/providers/alibaba/alibaba.js +155 -22
- package/lib/services/aiGen/providers/baseAiGenProvider.service.d.ts +22 -4
- package/lib/services/aiGen/providers/baseAiGenProvider.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/baseAiGenProvider.service.js +32 -0
- package/lib/services/aiGen/providers/bytedance/bytedance.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/bytedance/bytedance.service.js +13 -19
- package/lib/services/aiGen/providers/elevenlabs/elevenlabs.service.d.ts +18 -0
- package/lib/services/aiGen/providers/elevenlabs/elevenlabs.service.d.ts.map +1 -0
- package/lib/services/aiGen/providers/elevenlabs/elevenlabs.service.js +102 -0
- package/lib/services/aiGen/providers/fal/falImage.service.d.ts +15 -0
- package/lib/services/aiGen/providers/fal/falImage.service.d.ts.map +1 -0
- package/lib/services/aiGen/providers/fal/falImage.service.js +141 -0
- package/lib/services/aiGen/providers/fal/index.d.ts +2 -0
- package/lib/services/aiGen/providers/fal/index.d.ts.map +1 -0
- package/lib/services/aiGen/providers/fal/index.js +17 -0
- package/lib/services/aiGen/providers/google/google.service.d.ts +11 -2
- package/lib/services/aiGen/providers/google/google.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/google/google.service.js +245 -28
- package/lib/services/aiGen/providers/index.d.ts +3 -0
- package/lib/services/aiGen/providers/index.d.ts.map +1 -1
- package/lib/services/aiGen/providers/index.js +3 -0
- package/lib/services/aiGen/providers/kling/cameraAdapter.d.ts +4 -0
- package/lib/services/aiGen/providers/kling/cameraAdapter.d.ts.map +1 -0
- package/lib/services/aiGen/providers/kling/cameraAdapter.js +53 -0
- package/lib/services/aiGen/providers/kling/index.d.ts +1 -0
- package/lib/services/aiGen/providers/kling/index.d.ts.map +1 -1
- package/lib/services/aiGen/providers/kling/index.js +1 -0
- package/lib/services/aiGen/providers/kling/kling.service.d.ts +12 -1
- package/lib/services/aiGen/providers/kling/kling.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/kling/kling.service.js +357 -26
- package/lib/services/aiGen/providers/kling/klingImage.service.d.ts +21 -0
- package/lib/services/aiGen/providers/kling/klingImage.service.d.ts.map +1 -0
- package/lib/services/aiGen/providers/kling/klingImage.service.js +208 -0
- package/lib/services/aiGen/providers/kling/types.d.ts +105 -0
- package/lib/services/aiGen/providers/kling/types.d.ts.map +1 -1
- package/lib/services/aiGen/providers/minimax/minimax.service.d.ts +15 -2
- package/lib/services/aiGen/providers/minimax/minimax.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/minimax/minimax.service.js +128 -5
- package/lib/services/aiGen/providers/minimax/types.d.ts +10 -1
- package/lib/services/aiGen/providers/minimax/types.d.ts.map +1 -1
- package/lib/services/aiGen/providers/openai/openai.service.d.ts +8 -2
- package/lib/services/aiGen/providers/openai/openai.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/openai/openai.service.js +184 -7
- package/lib/services/aiGen/providers/pexels/index.d.ts +2 -0
- package/lib/services/aiGen/providers/pexels/index.d.ts.map +1 -0
- package/lib/services/aiGen/providers/{azure → pexels}/index.js +1 -1
- package/lib/services/aiGen/providers/pexels/pexels.service.d.ts +11 -0
- package/lib/services/aiGen/providers/pexels/pexels.service.d.ts.map +1 -0
- package/lib/services/aiGen/providers/pexels/pexels.service.js +150 -0
- package/lib/services/aiGen/providers/pixabay/index.d.ts +2 -0
- package/lib/services/aiGen/providers/pixabay/index.d.ts.map +1 -0
- package/lib/services/aiGen/providers/pixabay/index.js +17 -0
- package/lib/services/aiGen/providers/pixabay/pixabay.service.d.ts +12 -0
- package/lib/services/aiGen/providers/pixabay/pixabay.service.d.ts.map +1 -0
- package/lib/services/aiGen/providers/pixabay/pixabay.service.js +156 -0
- package/lib/services/aiGen/providers/pixverse/pixverse.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/pixverse/pixverse.service.js +125 -2
- package/lib/services/aiGen/providers/runway/cameraAdapter.d.ts +3 -0
- package/lib/services/aiGen/providers/runway/cameraAdapter.d.ts.map +1 -0
- package/lib/services/aiGen/providers/runway/cameraAdapter.js +46 -0
- package/lib/services/aiGen/providers/runway/runway.service.d.ts +12 -2
- package/lib/services/aiGen/providers/runway/runway.service.d.ts.map +1 -1
- package/lib/services/aiGen/providers/runway/runway.service.js +224 -21
- package/lib/services/aiGen/providers/types.d.ts +263 -6
- package/lib/services/aiGen/providers/types.d.ts.map +1 -1
- package/lib/services/aiGen/providers/unsplash/index.d.ts +2 -0
- package/lib/services/aiGen/providers/unsplash/index.d.ts.map +1 -0
- package/lib/services/aiGen/providers/unsplash/index.js +17 -0
- package/lib/services/aiGen/providers/unsplash/unsplash.service.d.ts +16 -0
- package/lib/services/aiGen/providers/unsplash/unsplash.service.d.ts.map +1 -0
- package/lib/services/aiGen/providers/unsplash/unsplash.service.js +131 -0
- package/lib/services/analytics.service.js +2 -4
- package/lib/services/apiUsageCounter.service.d.ts +20 -0
- package/lib/services/apiUsageCounter.service.d.ts.map +1 -0
- package/lib/services/apiUsageCounter.service.js +84 -0
- package/lib/services/asr/assemblyai.service.d.ts +72 -0
- package/lib/services/asr/assemblyai.service.d.ts.map +1 -0
- package/lib/services/asr/assemblyai.service.js +89 -0
- package/lib/services/asr/index.d.ts +3 -0
- package/lib/services/asr/index.d.ts.map +1 -0
- package/lib/services/asr/index.js +18 -0
- package/lib/services/asr/whisper.service.d.ts +18 -0
- package/lib/services/asr/whisper.service.d.ts.map +1 -0
- package/lib/services/asr/whisper.service.js +151 -0
- package/lib/services/assetCache.service.d.ts +54 -0
- package/lib/services/assetCache.service.d.ts.map +1 -0
- package/lib/services/assetCache.service.js +109 -0
- package/lib/services/audioAnalysis/index.d.ts +2 -0
- package/lib/services/audioAnalysis/index.d.ts.map +1 -0
- package/lib/services/audioAnalysis/index.js +17 -0
- package/lib/services/audioAnalysis/onsetDetection.service.d.ts +50 -0
- package/lib/services/audioAnalysis/onsetDetection.service.d.ts.map +1 -0
- package/lib/services/audioAnalysis/onsetDetection.service.js +140 -0
- package/lib/services/bullmq.service.d.ts +6 -1
- package/lib/services/bullmq.service.d.ts.map +1 -1
- package/lib/services/bullmq.service.js +62 -14
- package/lib/services/credit.service.d.ts.map +1 -1
- package/lib/services/credit.service.js +45 -7
- package/lib/services/credits/pricing.d.ts +58 -0
- package/lib/services/credits/pricing.d.ts.map +1 -0
- package/lib/services/credits/pricing.js +111 -0
- package/lib/services/editor/designToProject.d.ts +75 -0
- package/lib/services/editor/designToProject.d.ts.map +1 -0
- package/lib/services/editor/designToProject.js +295 -0
- package/lib/services/editor/planToProject.d.ts +84 -0
- package/lib/services/editor/planToProject.d.ts.map +1 -0
- package/lib/services/editor/planToProject.js +395 -0
- package/lib/services/editor/projectToDesign.d.ts +4 -0
- package/lib/services/editor/projectToDesign.d.ts.map +1 -0
- package/lib/services/editor/projectToDesign.js +186 -0
- package/lib/services/firestore.service.d.ts +17 -0
- package/lib/services/firestore.service.d.ts.map +1 -1
- package/lib/services/firestore.service.js +30 -0
- package/lib/services/gcp/index.d.ts +1 -0
- package/lib/services/gcp/index.d.ts.map +1 -1
- package/lib/services/gcp/index.js +1 -0
- package/lib/services/gcp/uploadAudioBuffer.d.ts +13 -0
- package/lib/services/gcp/uploadAudioBuffer.d.ts.map +1 -0
- package/lib/services/gcp/uploadAudioBuffer.js +28 -0
- package/lib/services/index.d.ts +13 -0
- package/lib/services/index.d.ts.map +1 -1
- package/lib/services/index.js +13 -0
- package/lib/services/musicGen/index.d.ts +6 -0
- package/lib/services/musicGen/index.d.ts.map +1 -0
- package/lib/services/musicGen/index.js +26 -0
- package/lib/services/musicGen/musicSearchFactory.service.d.ts +14 -0
- package/lib/services/musicGen/musicSearchFactory.service.d.ts.map +1 -0
- package/lib/services/musicGen/musicSearchFactory.service.js +59 -0
- package/lib/services/musicGen/providers/curated.service.d.ts +24 -0
- package/lib/services/musicGen/providers/curated.service.d.ts.map +1 -0
- package/lib/services/musicGen/providers/curated.service.js +173 -0
- package/lib/services/musicGen/providers/jamendo.service.d.ts +8 -0
- package/lib/services/musicGen/providers/jamendo.service.d.ts.map +1 -0
- package/lib/services/musicGen/providers/jamendo.service.js +113 -0
- package/lib/services/musicGen/providers/mubert.service.d.ts +10 -0
- package/lib/services/musicGen/providers/mubert.service.d.ts.map +1 -0
- package/lib/services/musicGen/providers/mubert.service.js +128 -0
- package/lib/services/musicGen/types.d.ts +46 -0
- package/lib/services/musicGen/types.d.ts.map +1 -0
- package/lib/services/musicGen/types.js +10 -0
- package/lib/services/notification.service.d.ts +22 -0
- package/lib/services/notification.service.d.ts.map +1 -0
- package/lib/services/notification.service.js +76 -0
- package/lib/services/rateLimiter/distributedRateLimiter.service.d.ts +78 -0
- package/lib/services/rateLimiter/distributedRateLimiter.service.d.ts.map +1 -0
- package/lib/services/rateLimiter/distributedRateLimiter.service.js +269 -0
- package/lib/services/rateLimiter/index.d.ts +2 -0
- package/lib/services/rateLimiter/index.d.ts.map +1 -0
- package/lib/services/rateLimiter/index.js +17 -0
- package/lib/services/redis.service.d.ts +9 -0
- package/lib/services/redis.service.d.ts.map +1 -1
- package/lib/services/redis.service.js +20 -11
- package/lib/services/redisOptions.d.ts +22 -0
- package/lib/services/redisOptions.d.ts.map +1 -0
- package/lib/services/redisOptions.js +51 -0
- package/lib/services/tts/index.d.ts +2 -0
- package/lib/services/tts/index.d.ts.map +1 -1
- package/lib/services/tts/index.js +2 -0
- package/lib/services/tts/providers/elevenlabs.service.d.ts.map +1 -1
- package/lib/services/tts/providers/elevenlabs.service.js +91 -24
- package/lib/services/tts/providers/minimax.service.d.ts +14 -0
- package/lib/services/tts/providers/minimax.service.d.ts.map +1 -0
- package/lib/services/tts/providers/minimax.service.js +78 -0
- package/lib/services/tts/providers/openai.service.d.ts +14 -0
- package/lib/services/tts/providers/openai.service.d.ts.map +1 -0
- package/lib/services/tts/providers/openai.service.js +73 -0
- package/lib/services/tts/ttsFactory.service.d.ts.map +1 -1
- package/lib/services/tts/ttsFactory.service.js +6 -0
- package/lib/services/tts/types.d.ts +33 -0
- package/lib/services/tts/types.d.ts.map +1 -1
- package/lib/utils/errors.d.ts +8 -0
- package/lib/utils/errors.d.ts.map +1 -1
- package/lib/utils/errors.js +8 -0
- package/lib/utils/helpers.d.ts +13 -0
- package/lib/utils/helpers.d.ts.map +1 -1
- package/lib/utils/helpers.js +48 -11
- package/lib/utils/logger.d.ts.map +1 -1
- package/lib/utils/logger.js +37 -1
- package/package.json +5 -1
- package/lib/services/aiGen/providers/azure/azure.service.d.ts +0 -14
- package/lib/services/aiGen/providers/azure/azure.service.d.ts.map +0 -1
- package/lib/services/aiGen/providers/azure/azure.service.js +0 -108
- package/lib/services/aiGen/providers/azure/index.d.ts +0 -2
- package/lib/services/aiGen/providers/azure/index.d.ts.map +0 -1
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.MubertMusicProvider = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
const logger_1 = require("../../../utils/logger");
|
|
9
|
+
/**
|
|
10
|
+
* Mubert generative music — Public API v3.
|
|
11
|
+
*
|
|
12
|
+
* Conceptually a "search" replacement: instead of looking up an existing
|
|
13
|
+
* track, we generate one from a prompt + duration. The provider presents the
|
|
14
|
+
* same MusicSearchProvider surface so the planner doesn't have to special-case it.
|
|
15
|
+
*
|
|
16
|
+
* Two-step flow:
|
|
17
|
+
* 1. POST /api/v3/public/tracks → returns `data.id` (track id)
|
|
18
|
+
* 2. Poll GET /api/v3/public/tracks/{id} until
|
|
19
|
+
* `data.generations[0].status === "done"`, then read `generations[0].url`.
|
|
20
|
+
*
|
|
21
|
+
* Auth: HTTP headers `customer-id` + `access-token`. These are minted per
|
|
22
|
+
* customer from the company-level `(company-id, license-token)` via
|
|
23
|
+
* `POST /api/v3/service/customers`. The company credentials must NEVER leave
|
|
24
|
+
* the server — we provision a customer at boot (or once per user) and cache
|
|
25
|
+
* the resulting customer pair. For now we accept pre-provisioned customer
|
|
26
|
+
* credentials via env: MUBERT_CUSTOMER_ID + MUBERT_ACCESS_TOKEN.
|
|
27
|
+
*
|
|
28
|
+
* Cost: pay-per-track per license tier; budget gates live in estimate_cost
|
|
29
|
+
* upstream — this provider just executes when called.
|
|
30
|
+
*/
|
|
31
|
+
const MUBERT_BASE_URL = "https://music-api.mubert.com/api/v3/public";
|
|
32
|
+
const MUBERT_TIMEOUT_MS = 25000;
|
|
33
|
+
const POLL_INTERVAL_MS = 1500;
|
|
34
|
+
const MOOD_TO_PROMPT = {
|
|
35
|
+
energetic: "energetic upbeat pop",
|
|
36
|
+
cinematic: "cinematic orchestral epic",
|
|
37
|
+
calm: "calm ambient piano",
|
|
38
|
+
uplifting: "uplifting inspirational corporate",
|
|
39
|
+
dark: "dark moody trap",
|
|
40
|
+
acoustic: "acoustic folk guitar",
|
|
41
|
+
retro: "retro synthwave 80s",
|
|
42
|
+
quirky: "quirky playful indie",
|
|
43
|
+
};
|
|
44
|
+
class MubertMusicProvider {
|
|
45
|
+
constructor() {
|
|
46
|
+
this.source = "mubert";
|
|
47
|
+
this.customerId = process.env.MUBERT_CUSTOMER_ID;
|
|
48
|
+
this.accessToken = process.env.MUBERT_ACCESS_TOKEN;
|
|
49
|
+
}
|
|
50
|
+
isAvailable() {
|
|
51
|
+
return Boolean(this.customerId && this.accessToken);
|
|
52
|
+
}
|
|
53
|
+
async search(params) {
|
|
54
|
+
if (!this.customerId || !this.accessToken)
|
|
55
|
+
return { tracks: [] };
|
|
56
|
+
const prompt = (params.query
|
|
57
|
+
?? (params.mood && MOOD_TO_PROMPT[params.mood.toLowerCase()])
|
|
58
|
+
?? "energetic upbeat").slice(0, 200); // Mubert caps prompt at 200 chars
|
|
59
|
+
const duration = Math.max(30, params.durationSecMin ?? 60);
|
|
60
|
+
const headers = {
|
|
61
|
+
"customer-id": this.customerId,
|
|
62
|
+
"access-token": this.accessToken,
|
|
63
|
+
"Content-Type": "application/json",
|
|
64
|
+
};
|
|
65
|
+
try {
|
|
66
|
+
const startResp = await axios_1.default.post(`${MUBERT_BASE_URL}/tracks`, {
|
|
67
|
+
prompt,
|
|
68
|
+
duration,
|
|
69
|
+
bitrate: 128,
|
|
70
|
+
format: "mp3",
|
|
71
|
+
intensity: "medium",
|
|
72
|
+
mode: "track",
|
|
73
|
+
}, { headers, timeout: 8000 });
|
|
74
|
+
const trackId = startResp.data?.data?.id;
|
|
75
|
+
if (!trackId)
|
|
76
|
+
return { tracks: [] };
|
|
77
|
+
const trackUrl = await this.pollTrackUrl(trackId, headers);
|
|
78
|
+
if (!trackUrl)
|
|
79
|
+
return { tracks: [] };
|
|
80
|
+
return {
|
|
81
|
+
tracks: [
|
|
82
|
+
{
|
|
83
|
+
id: `mubert-${trackId}`,
|
|
84
|
+
url: trackUrl,
|
|
85
|
+
durationSec: duration,
|
|
86
|
+
bpm: params.bpmTarget,
|
|
87
|
+
mood: params.mood,
|
|
88
|
+
attribution: "Mubert (generated)",
|
|
89
|
+
source: "mubert",
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
// Provider down or rejected the prompt — caller falls through, but log
|
|
96
|
+
// so we notice persistent failures.
|
|
97
|
+
logger_1.logger.error("mubert: search failed", {
|
|
98
|
+
query: prompt,
|
|
99
|
+
durationSec: duration,
|
|
100
|
+
err: err instanceof Error ? err.stack ?? err.message : String(err),
|
|
101
|
+
});
|
|
102
|
+
return { tracks: [] };
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async pollTrackUrl(trackId, headers) {
|
|
106
|
+
const deadline = Date.now() + MUBERT_TIMEOUT_MS;
|
|
107
|
+
while (Date.now() < deadline) {
|
|
108
|
+
try {
|
|
109
|
+
const resp = await axios_1.default.get(`${MUBERT_BASE_URL}/tracks/${trackId}`, { headers, timeout: 5000 });
|
|
110
|
+
const gen = resp.data?.data?.generations?.[0];
|
|
111
|
+
if (gen?.status === "done" && gen.url)
|
|
112
|
+
return gen.url;
|
|
113
|
+
if (gen?.status === "failed")
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
// Transient — retry next tick, but log so a persistent poll loop is visible.
|
|
118
|
+
logger_1.logger.warn("mubert: track poll transient error", {
|
|
119
|
+
trackId,
|
|
120
|
+
err: err instanceof Error ? err.stack ?? err.message : String(err),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
124
|
+
}
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.MubertMusicProvider = MubertMusicProvider;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Music search/generation provider surface used by the agent's `search_music`
|
|
3
|
+
* tool and the post-planner `selectMusicForPlan` step.
|
|
4
|
+
*
|
|
5
|
+
* Three sources ship under one interface deliberately — the planner doesn't
|
|
6
|
+
* care whether a track is curated, fetched, or generated; it only needs
|
|
7
|
+
* `{ url, bpm, durationSec }` to drive the beat-snap pass.
|
|
8
|
+
*/
|
|
9
|
+
export type MusicSource = "curated" | "jamendo" | "mubert";
|
|
10
|
+
export interface MusicSearchParams {
|
|
11
|
+
query?: string;
|
|
12
|
+
/** "energetic" / "cinematic" / "calm" / "uplifting" / "dark" / "quirky" / "retro" / "acoustic". */
|
|
13
|
+
mood?: string;
|
|
14
|
+
/** Soft target — providers prefer matches near this BPM but may return others. */
|
|
15
|
+
bpmTarget?: number;
|
|
16
|
+
bpmMin?: number;
|
|
17
|
+
bpmMax?: number;
|
|
18
|
+
/** Required minimum length so the track covers the whole video. */
|
|
19
|
+
durationSecMin?: number;
|
|
20
|
+
/** Hard upper bound on duration (paired with min for server-side filter). */
|
|
21
|
+
durationSecMax?: number;
|
|
22
|
+
/** Jamendo: prefer vocal vs instrumental tracks (useful when video has VO). */
|
|
23
|
+
vocalInstrumental?: "vocal" | "instrumental";
|
|
24
|
+
/** Cap result count. */
|
|
25
|
+
limit?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface MusicTrack {
|
|
28
|
+
id: string;
|
|
29
|
+
url: string;
|
|
30
|
+
durationSec: number;
|
|
31
|
+
bpm?: number;
|
|
32
|
+
mood?: string;
|
|
33
|
+
tags?: string[];
|
|
34
|
+
attribution?: string;
|
|
35
|
+
source: MusicSource;
|
|
36
|
+
}
|
|
37
|
+
export interface MusicSearchResult {
|
|
38
|
+
tracks: MusicTrack[];
|
|
39
|
+
}
|
|
40
|
+
export interface MusicSearchProvider {
|
|
41
|
+
source: MusicSource;
|
|
42
|
+
/** True when the provider is configured (env vars / catalog) and ready to call. */
|
|
43
|
+
isAvailable(): boolean;
|
|
44
|
+
search(params: MusicSearchParams): Promise<MusicSearchResult>;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/musicGen/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE3D,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mGAAmG;IACnG,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,iBAAiB,CAAC,EAAE,OAAO,GAAG,cAAc,CAAC;IAC7C,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,WAAW,CAAC;IACpB,mFAAmF;IACnF,WAAW,IAAI,OAAO,CAAC;IACvB,MAAM,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAC/D"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Music search/generation provider surface used by the agent's `search_music`
|
|
4
|
+
* tool and the post-planner `selectMusicForPlan` step.
|
|
5
|
+
*
|
|
6
|
+
* Three sources ship under one interface deliberately — the planner doesn't
|
|
7
|
+
* care whether a track is curated, fetched, or generated; it only needs
|
|
8
|
+
* `{ url, bpm, durationSec }` to drive the beat-snap pass.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ENotificationSeverity, ENotificationType } from "../globals/types";
|
|
2
|
+
export interface CreateNotificationInput {
|
|
3
|
+
userId: string;
|
|
4
|
+
type: ENotificationType;
|
|
5
|
+
severity?: ENotificationSeverity;
|
|
6
|
+
title: string;
|
|
7
|
+
body?: string;
|
|
8
|
+
link?: string;
|
|
9
|
+
data?: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Writes an in-app notification doc IF the user hasn't muted this type.
|
|
13
|
+
*
|
|
14
|
+
* Best-effort: failures are logged but never re-thrown — callers (worker
|
|
15
|
+
* processors, webhook handlers, credit service) should not be blocked by a
|
|
16
|
+
* notification write. The user reads via Firestore onSnapshot, so a missed
|
|
17
|
+
* write just means a missing bell entry, not a broken job.
|
|
18
|
+
*/
|
|
19
|
+
export declare class NotificationService {
|
|
20
|
+
static create(input: CreateNotificationInput): Promise<string | null>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=notification.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification.service.d.ts","sourceRoot":"","sources":["../../src/services/notification.service.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,kBAAkB,CAAC;AAM1B,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,qBAAa,mBAAmB;WACjB,MAAM,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CA+B5E"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NotificationService = void 0;
|
|
4
|
+
const firestore_1 = require("firebase-admin/firestore");
|
|
5
|
+
const types_1 = require("../globals/types");
|
|
6
|
+
const logger_1 = require("../utils/logger");
|
|
7
|
+
const firestore_service_1 = require("./firestore.service");
|
|
8
|
+
/**
|
|
9
|
+
* Writes an in-app notification doc IF the user hasn't muted this type.
|
|
10
|
+
*
|
|
11
|
+
* Best-effort: failures are logged but never re-thrown — callers (worker
|
|
12
|
+
* processors, webhook handlers, credit service) should not be blocked by a
|
|
13
|
+
* notification write. The user reads via Firestore onSnapshot, so a missed
|
|
14
|
+
* write just means a missing bell entry, not a broken job.
|
|
15
|
+
*/
|
|
16
|
+
class NotificationService {
|
|
17
|
+
static async create(input) {
|
|
18
|
+
try {
|
|
19
|
+
const user = await firestore_service_1.FirestoreService.getUserById(input.userId);
|
|
20
|
+
if (!user)
|
|
21
|
+
return null;
|
|
22
|
+
if (!isEnabled(user, input.type))
|
|
23
|
+
return null;
|
|
24
|
+
const doc = {
|
|
25
|
+
userId: input.userId,
|
|
26
|
+
type: input.type,
|
|
27
|
+
severity: input.severity ?? defaultSeverity(input.type),
|
|
28
|
+
title: input.title,
|
|
29
|
+
...(input.body && { body: input.body }),
|
|
30
|
+
...(input.link && { link: input.link }),
|
|
31
|
+
...(input.data && { data: input.data }),
|
|
32
|
+
read: false,
|
|
33
|
+
createdAt: firestore_1.FieldValue.serverTimestamp(),
|
|
34
|
+
};
|
|
35
|
+
const ref = await firestore_service_1.FirestoreService.appendNewRecord(firestore_service_1.FirestoreService.notificationsCol, doc);
|
|
36
|
+
return ref.id;
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
// Intentionally swallowed for caller — notifications must never break the
|
|
40
|
+
// worker / webhook handler / credit service. But surface to ops so we
|
|
41
|
+
// notice persistent write failures.
|
|
42
|
+
logger_1.logger.error("notification create failed", {
|
|
43
|
+
userId: input.userId,
|
|
44
|
+
type: input.type,
|
|
45
|
+
err: err instanceof Error ? err.stack ?? err.message : String(err),
|
|
46
|
+
});
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.NotificationService = NotificationService;
|
|
52
|
+
function isEnabled(user, type) {
|
|
53
|
+
const prefs = user.notificationPreferences ?? {};
|
|
54
|
+
if (type in prefs)
|
|
55
|
+
return prefs[type] !== false;
|
|
56
|
+
return types_1.DEFAULT_NOTIFICATION_PREFERENCES[type] !== false;
|
|
57
|
+
}
|
|
58
|
+
function defaultSeverity(type) {
|
|
59
|
+
switch (type) {
|
|
60
|
+
case types_1.ENotificationType.VIDEO_FAILED:
|
|
61
|
+
case types_1.ENotificationType.IMAGE_FAILED:
|
|
62
|
+
case types_1.ENotificationType.SUBSCRIPTION_PAYMENT_FAILED:
|
|
63
|
+
return types_1.ENotificationSeverity.ERROR;
|
|
64
|
+
case types_1.ENotificationType.VIDEO_PARTIAL:
|
|
65
|
+
case types_1.ENotificationType.CREDITS_LOW:
|
|
66
|
+
case types_1.ENotificationType.SUBSCRIPTION_TRIAL_ENDING:
|
|
67
|
+
case types_1.ENotificationType.SUBSCRIPTION_CANCELED:
|
|
68
|
+
return types_1.ENotificationSeverity.WARNING;
|
|
69
|
+
case types_1.ENotificationType.VIDEO_COMPLETED:
|
|
70
|
+
case types_1.ENotificationType.IMAGE_COMPLETED:
|
|
71
|
+
case types_1.ENotificationType.SUBSCRIPTION_RENEWED:
|
|
72
|
+
return types_1.ENotificationSeverity.SUCCESS;
|
|
73
|
+
default:
|
|
74
|
+
return types_1.ENotificationSeverity.INFO;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { TAiGenModel } from "../../globals/aiModels";
|
|
2
|
+
import { TtsProvider } from "../../globals/ttsModels/types";
|
|
3
|
+
/**
|
|
4
|
+
* DistributedRateLimiter — three-tier provider quota gate.
|
|
5
|
+
*
|
|
6
|
+
* concurrent (in-process, Promise wait queue, single-process-correct)
|
|
7
|
+
* per-minute (Redis sliding-window sorted set, atomic via Lua)
|
|
8
|
+
* per-day (Redis counter with midnight-UTC TTL, atomic via Lua)
|
|
9
|
+
*
|
|
10
|
+
* Replaces the original in-memory AiGenModelRateLimiter so the per-minute
|
|
11
|
+
* and per-day quotas survive process restarts — the old version's counters
|
|
12
|
+
* reset on every nodemon reload / deploy, which let us blow past a provider's
|
|
13
|
+
* daily cap with a few restarts.
|
|
14
|
+
*
|
|
15
|
+
* API mirrors the old class (`waitUntilAvailable()` + `releaseSlot()`) so the
|
|
16
|
+
* legacy /v1/video processors don't need any callsite changes. Two new entry
|
|
17
|
+
* points added for the agent path:
|
|
18
|
+
* - waitUntilAvailableForOneShot(): used by poll calls that consume rate
|
|
19
|
+
* budget but should NOT count toward the concurrent-in-flight cap.
|
|
20
|
+
* - snapshot(): used by /health/rate-limits for live utilization.
|
|
21
|
+
*
|
|
22
|
+
* Single-process design: concurrent counter is intentionally in-process — at
|
|
23
|
+
* one Express server it's a true global cap with zero Redis round-trip. If
|
|
24
|
+
* we ever scale horizontally that gate alone needs promoting to Redis; the
|
|
25
|
+
* caller API stays the same.
|
|
26
|
+
*/
|
|
27
|
+
interface DistributedRateLimiterConfig {
|
|
28
|
+
concurrentRequests?: number;
|
|
29
|
+
requestPerMin?: number;
|
|
30
|
+
requestPerDay?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface LimiterSnapshot {
|
|
33
|
+
modelKey: string;
|
|
34
|
+
active: number;
|
|
35
|
+
waitQueueDepth: number;
|
|
36
|
+
perMinUsed: number;
|
|
37
|
+
perDayUsed: number;
|
|
38
|
+
concurrentLimit?: number;
|
|
39
|
+
perMinLimit?: number;
|
|
40
|
+
perDayLimit?: number;
|
|
41
|
+
}
|
|
42
|
+
export declare class DistributedRateLimiter {
|
|
43
|
+
private readonly modelKey;
|
|
44
|
+
private readonly concurrentLimit;
|
|
45
|
+
private readonly perMinLimit;
|
|
46
|
+
private readonly perDayLimit;
|
|
47
|
+
private activeRequests;
|
|
48
|
+
private waitQueue;
|
|
49
|
+
constructor(modelKey: string, config: DistributedRateLimiterConfig);
|
|
50
|
+
/**
|
|
51
|
+
* Block until concurrent + per-min + per-day all have headroom, then claim
|
|
52
|
+
* a slot in each. Caller MUST call releaseSlot() when the in-flight task
|
|
53
|
+
* settles — per-min / per-day auto-expire but the concurrent counter does
|
|
54
|
+
* not. Mirrors the old AiGenModelRateLimiter API.
|
|
55
|
+
*/
|
|
56
|
+
waitUntilAvailable(): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Bumps per-min + per-day only — does NOT count toward the concurrent cap.
|
|
59
|
+
* Use for short-lived calls that share a provider's rate budget but aren't
|
|
60
|
+
* "in-flight tasks" (status polls, sync image/TTS gens that complete in the
|
|
61
|
+
* same call). No release is needed — Redis auto-expires the counters.
|
|
62
|
+
*/
|
|
63
|
+
waitUntilAvailableForOneShot(): Promise<void>;
|
|
64
|
+
/** Free a concurrent slot acquired via waitUntilAvailable(). */
|
|
65
|
+
releaseSlot(): void;
|
|
66
|
+
get activeConcurrentCount(): number;
|
|
67
|
+
snapshot(): Promise<LimiterSnapshot>;
|
|
68
|
+
private acquireConcurrent;
|
|
69
|
+
private releaseConcurrent;
|
|
70
|
+
private consumeRedisGates;
|
|
71
|
+
}
|
|
72
|
+
export declare function getAiGenModelRateLimiter(modelKey: TAiGenModel): DistributedRateLimiter;
|
|
73
|
+
export declare function getTtsProviderRateLimiter(provider: TtsProvider): DistributedRateLimiter;
|
|
74
|
+
/** Snapshot every limiter that has ever been instantiated. Used by the
|
|
75
|
+
* /health/rate-limits endpoint for live ops visibility. */
|
|
76
|
+
export declare function snapshotAllRateLimiters(): Promise<LimiterSnapshot[]>;
|
|
77
|
+
export {};
|
|
78
|
+
//# sourceMappingURL=distributedRateLimiter.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"distributedRateLimiter.service.d.ts","sourceRoot":"","sources":["../../../src/services/rateLimiter/distributedRateLimiter.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAU5D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,UAAU,4BAA4B;IACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAuDD,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,SAAS,CAAyB;gBAE9B,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,4BAA4B;IAOlE;;;;;OAKG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAUzC;;;;;OAKG;IACG,4BAA4B,IAAI,OAAO,CAAC,IAAI,CAAC;IAInD,gEAAgE;IAChE,WAAW,IAAI,IAAI;IAInB,IAAI,qBAAqB,IAAI,MAAM,CAElC;IAEK,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC;YAoC5B,iBAAiB;IAc/B,OAAO,CAAC,iBAAiB;YAQX,iBAAiB;CA6DhC;AAwBD,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,WAAW,GACpB,sBAAsB,CAaxB;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,WAAW,GACpB,sBAAsB,CAexB;AAED;4DAC4D;AAC5D,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAM1E"}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DistributedRateLimiter = void 0;
|
|
7
|
+
exports.getAiGenModelRateLimiter = getAiGenModelRateLimiter;
|
|
8
|
+
exports.getTtsProviderRateLimiter = getTtsProviderRateLimiter;
|
|
9
|
+
exports.snapshotAllRateLimiters = snapshotAllRateLimiters;
|
|
10
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
11
|
+
const aiModels_1 = require("../../globals/aiModels");
|
|
12
|
+
const ttsModels_1 = require("../../globals/ttsModels");
|
|
13
|
+
const logger_1 = require("../../utils/logger");
|
|
14
|
+
const redis_service_1 = require("../redis.service");
|
|
15
|
+
// Module-level throttle so Redis outages don't fire a Slack error every
|
|
16
|
+
// request. First failure goes through; subsequent failures within the
|
|
17
|
+
// window log at warn level (Console + Loki only) until the window resets.
|
|
18
|
+
const RATE_LIMITER_ERROR_THROTTLE_MS = 60000;
|
|
19
|
+
let lastRateLimiterErrorLoggedAt = 0;
|
|
20
|
+
/**
|
|
21
|
+
* Atomic Redis check-and-consume for per-min + per-day gates. Returns
|
|
22
|
+
* { 1, 0, "ok" } — both gates passed, slot consumed
|
|
23
|
+
* { 0, retryMs, "min"|"day" } — gate hit, caller should sleep retryMs and retry
|
|
24
|
+
*
|
|
25
|
+
* Per-minute is a sorted-set sliding window (score = ms timestamp). Per-day
|
|
26
|
+
* is a plain counter keyed by UTC date with TTL set on first INCR to
|
|
27
|
+
* seconds-until-midnight, so the key self-expires.
|
|
28
|
+
*/
|
|
29
|
+
const CONSUME_SCRIPT = `
|
|
30
|
+
local minKey = KEYS[1]
|
|
31
|
+
local dayKey = KEYS[2]
|
|
32
|
+
local nowMs = tonumber(ARGV[1])
|
|
33
|
+
local minLimit = tonumber(ARGV[2])
|
|
34
|
+
local dayLimit = tonumber(ARGV[3])
|
|
35
|
+
local secsTilMidnight = tonumber(ARGV[4])
|
|
36
|
+
local uniqueId = ARGV[5]
|
|
37
|
+
|
|
38
|
+
redis.call('ZREMRANGEBYSCORE', minKey, 0, nowMs - 60000)
|
|
39
|
+
|
|
40
|
+
if minLimit > 0 then
|
|
41
|
+
local minCount = redis.call('ZCARD', minKey)
|
|
42
|
+
if minCount >= minLimit then
|
|
43
|
+
local oldest = redis.call('ZRANGE', minKey, 0, 0, 'WITHSCORES')
|
|
44
|
+
local retryMs = 1000
|
|
45
|
+
if oldest[2] then
|
|
46
|
+
retryMs = 60000 - (nowMs - tonumber(oldest[2]))
|
|
47
|
+
if retryMs < 50 then retryMs = 50 end
|
|
48
|
+
if retryMs > 60000 then retryMs = 60000 end
|
|
49
|
+
end
|
|
50
|
+
return { 0, retryMs, 'min' }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if dayLimit > 0 then
|
|
55
|
+
local dayCount = tonumber(redis.call('GET', dayKey) or '0')
|
|
56
|
+
if dayCount >= dayLimit then
|
|
57
|
+
local retryMs = secsTilMidnight * 1000
|
|
58
|
+
if retryMs > 60000 then retryMs = 60000 end
|
|
59
|
+
return { 0, retryMs, 'day' }
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
redis.call('ZADD', minKey, nowMs, uniqueId)
|
|
64
|
+
redis.call('PEXPIRE', minKey, 90000)
|
|
65
|
+
local newDay = redis.call('INCR', dayKey)
|
|
66
|
+
if newDay == 1 then
|
|
67
|
+
redis.call('EXPIRE', dayKey, secsTilMidnight)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
return { 1, 0, 'ok' }
|
|
71
|
+
`;
|
|
72
|
+
class DistributedRateLimiter {
|
|
73
|
+
constructor(modelKey, config) {
|
|
74
|
+
this.activeRequests = 0;
|
|
75
|
+
this.waitQueue = [];
|
|
76
|
+
this.modelKey = modelKey;
|
|
77
|
+
this.concurrentLimit = config.concurrentRequests ?? 0;
|
|
78
|
+
this.perMinLimit = config.requestPerMin ?? 0;
|
|
79
|
+
this.perDayLimit = config.requestPerDay ?? 0;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Block until concurrent + per-min + per-day all have headroom, then claim
|
|
83
|
+
* a slot in each. Caller MUST call releaseSlot() when the in-flight task
|
|
84
|
+
* settles — per-min / per-day auto-expire but the concurrent counter does
|
|
85
|
+
* not. Mirrors the old AiGenModelRateLimiter API.
|
|
86
|
+
*/
|
|
87
|
+
async waitUntilAvailable() {
|
|
88
|
+
await this.acquireConcurrent();
|
|
89
|
+
try {
|
|
90
|
+
await this.consumeRedisGates();
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
this.releaseConcurrent();
|
|
94
|
+
throw err;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Bumps per-min + per-day only — does NOT count toward the concurrent cap.
|
|
99
|
+
* Use for short-lived calls that share a provider's rate budget but aren't
|
|
100
|
+
* "in-flight tasks" (status polls, sync image/TTS gens that complete in the
|
|
101
|
+
* same call). No release is needed — Redis auto-expires the counters.
|
|
102
|
+
*/
|
|
103
|
+
async waitUntilAvailableForOneShot() {
|
|
104
|
+
await this.consumeRedisGates();
|
|
105
|
+
}
|
|
106
|
+
/** Free a concurrent slot acquired via waitUntilAvailable(). */
|
|
107
|
+
releaseSlot() {
|
|
108
|
+
this.releaseConcurrent();
|
|
109
|
+
}
|
|
110
|
+
get activeConcurrentCount() {
|
|
111
|
+
return this.activeRequests;
|
|
112
|
+
}
|
|
113
|
+
async snapshot() {
|
|
114
|
+
const snap = {
|
|
115
|
+
modelKey: this.modelKey,
|
|
116
|
+
active: this.activeRequests,
|
|
117
|
+
waitQueueDepth: this.waitQueue.length,
|
|
118
|
+
perMinUsed: 0,
|
|
119
|
+
perDayUsed: 0,
|
|
120
|
+
concurrentLimit: this.concurrentLimit || undefined,
|
|
121
|
+
perMinLimit: this.perMinLimit || undefined,
|
|
122
|
+
perDayLimit: this.perDayLimit || undefined,
|
|
123
|
+
};
|
|
124
|
+
const client = redis_service_1.redis.getClient();
|
|
125
|
+
if (!client)
|
|
126
|
+
return snap;
|
|
127
|
+
const minKey = `ratelimit:${this.modelKey}:min`;
|
|
128
|
+
const dayKey = `ratelimit:${this.modelKey}:day:${utcDateKey()}`;
|
|
129
|
+
try {
|
|
130
|
+
const [minCount, dayCountRaw] = await Promise.all([
|
|
131
|
+
client.zcount(minKey, Date.now() - 60000, "+inf"),
|
|
132
|
+
client.get(dayKey),
|
|
133
|
+
]);
|
|
134
|
+
snap.perMinUsed = minCount;
|
|
135
|
+
snap.perDayUsed = dayCountRaw ? Number(dayCountRaw) : 0;
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
// best-effort; leave snapshot zeros if Redis blips
|
|
139
|
+
logger_1.logger.warn("distributedRateLimiter: snapshot read failed", {
|
|
140
|
+
modelKey: this.modelKey,
|
|
141
|
+
err: err instanceof Error ? err.stack ?? err.message : String(err),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return snap;
|
|
145
|
+
}
|
|
146
|
+
// ── Internals ──────────────────────────────────────────────────────────
|
|
147
|
+
async acquireConcurrent() {
|
|
148
|
+
if (!this.concurrentLimit) {
|
|
149
|
+
this.activeRequests++;
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
while (this.activeRequests >= this.concurrentLimit) {
|
|
153
|
+
// Promise wait queue — woken by releaseConcurrent. Replaces the old
|
|
154
|
+
// 1s setTimeout busy-poll; latency drops from up-to-1s to ~0ms when
|
|
155
|
+
// a slot frees.
|
|
156
|
+
await new Promise((resolve) => this.waitQueue.push(resolve));
|
|
157
|
+
}
|
|
158
|
+
this.activeRequests++;
|
|
159
|
+
}
|
|
160
|
+
releaseConcurrent() {
|
|
161
|
+
if (this.activeRequests > 0) {
|
|
162
|
+
this.activeRequests--;
|
|
163
|
+
}
|
|
164
|
+
const next = this.waitQueue.shift();
|
|
165
|
+
if (next)
|
|
166
|
+
next();
|
|
167
|
+
}
|
|
168
|
+
async consumeRedisGates() {
|
|
169
|
+
if (!this.perMinLimit && !this.perDayLimit)
|
|
170
|
+
return;
|
|
171
|
+
const client = redis_service_1.redis.getClient();
|
|
172
|
+
if (!client) {
|
|
173
|
+
// REDIS_URL unset (local dev with caching off, or a degraded boot).
|
|
174
|
+
// Fail open — a missed gate is better than blocking the entire
|
|
175
|
+
// generation pipeline. The legacy in-memory limiter behaved the
|
|
176
|
+
// same way (no Redis dependency at all).
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const minKey = `ratelimit:${this.modelKey}:min`;
|
|
180
|
+
const secsTilMidnight = secsUntilMidnight();
|
|
181
|
+
const uniqueId = `${Date.now()}-${crypto_1.default.randomBytes(4).toString("hex")}`;
|
|
182
|
+
while (true) {
|
|
183
|
+
const nowMs = Date.now();
|
|
184
|
+
// Day key resolved per-iteration so a retry across midnight UTC
|
|
185
|
+
// rolls into the new day's counter naturally.
|
|
186
|
+
const dayKey = `ratelimit:${this.modelKey}:day:${utcDateKey()}`;
|
|
187
|
+
let result;
|
|
188
|
+
try {
|
|
189
|
+
result = (await client.eval(CONSUME_SCRIPT, 2, minKey, dayKey, String(nowMs), String(this.perMinLimit), String(this.perDayLimit), String(secsTilMidnight), uniqueId));
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
// Redis blip — fail open rather than blocking the pipeline. Throttle
|
|
193
|
+
// the Slack-routed error so a sustained Redis outage doesn't fire a
|
|
194
|
+
// ping per request; subsequent failures inside the window log at
|
|
195
|
+
// warn (Console + Loki only).
|
|
196
|
+
const now = Date.now();
|
|
197
|
+
const errMeta = {
|
|
198
|
+
key: `${this.modelKey}`,
|
|
199
|
+
modelKey: this.modelKey,
|
|
200
|
+
err: err instanceof Error ? err.stack ?? err.message : String(err),
|
|
201
|
+
};
|
|
202
|
+
if (now - lastRateLimiterErrorLoggedAt > RATE_LIMITER_ERROR_THROTTLE_MS) {
|
|
203
|
+
lastRateLimiterErrorLoggedAt = now;
|
|
204
|
+
logger_1.logger.error("distributedRateLimiter: Redis EVAL failed, fail-open active", errMeta);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
logger_1.logger.warn("distributedRateLimiter: Redis EVAL failed, fail-open active (throttled)", errMeta);
|
|
208
|
+
}
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (result[0] === 1)
|
|
212
|
+
return;
|
|
213
|
+
const waitMs = Math.max(50, Math.min(1000, result[1]));
|
|
214
|
+
await sleep(waitMs);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
exports.DistributedRateLimiter = DistributedRateLimiter;
|
|
219
|
+
function utcDateKey() {
|
|
220
|
+
// YYYY-MM-DD in UTC — matches the TTL set on first INCR
|
|
221
|
+
return new Date().toISOString().slice(0, 10);
|
|
222
|
+
}
|
|
223
|
+
function secsUntilMidnight() {
|
|
224
|
+
const now = new Date();
|
|
225
|
+
const midnight = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() + 1));
|
|
226
|
+
return Math.ceil((midnight.getTime() - now.getTime()) / 1000);
|
|
227
|
+
}
|
|
228
|
+
function sleep(ms) {
|
|
229
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
230
|
+
}
|
|
231
|
+
// ── Singleton registries ─────────────────────────────────────────────────
|
|
232
|
+
const aiModelLimiters = {};
|
|
233
|
+
const ttsProviderLimiters = {};
|
|
234
|
+
function getAiGenModelRateLimiter(modelKey) {
|
|
235
|
+
if (!aiModelLimiters[modelKey]) {
|
|
236
|
+
const config = aiModels_1.aiModelConfigs[modelKey];
|
|
237
|
+
if (!config) {
|
|
238
|
+
throw new Error(`No model config for model key: ${modelKey}`);
|
|
239
|
+
}
|
|
240
|
+
aiModelLimiters[modelKey] = new DistributedRateLimiter(modelKey, {
|
|
241
|
+
concurrentRequests: config.concurrentRequests,
|
|
242
|
+
requestPerMin: config.requestPerMin,
|
|
243
|
+
requestPerDay: config.requestPerDay,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
return aiModelLimiters[modelKey];
|
|
247
|
+
}
|
|
248
|
+
function getTtsProviderRateLimiter(provider) {
|
|
249
|
+
if (!ttsProviderLimiters[provider]) {
|
|
250
|
+
const config = ttsModels_1.ttsProviderConfigs[provider];
|
|
251
|
+
if (!config) {
|
|
252
|
+
throw new Error(`No TTS provider config for: ${provider}`);
|
|
253
|
+
}
|
|
254
|
+
ttsProviderLimiters[provider] = new DistributedRateLimiter(`tts:${provider}`, {
|
|
255
|
+
concurrentRequests: config.concurrentRequests,
|
|
256
|
+
requestPerMin: config.requestPerMin,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
return ttsProviderLimiters[provider];
|
|
260
|
+
}
|
|
261
|
+
/** Snapshot every limiter that has ever been instantiated. Used by the
|
|
262
|
+
* /health/rate-limits endpoint for live ops visibility. */
|
|
263
|
+
async function snapshotAllRateLimiters() {
|
|
264
|
+
const all = [
|
|
265
|
+
...Object.values(aiModelLimiters),
|
|
266
|
+
...Object.values(ttsProviderLimiters),
|
|
267
|
+
];
|
|
268
|
+
return Promise.all(all.map((l) => l.snapshot()));
|
|
269
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/rateLimiter/index.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./distributedRateLimiter.service"), exports);
|