@juspay/neurolink 9.64.0 → 9.65.1
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/CHANGELOG.md +12 -0
- package/README.md +18 -17
- package/dist/adapters/providerImageAdapter.js +29 -1
- package/dist/adapters/replicate/auth.d.ts +19 -0
- package/dist/adapters/replicate/auth.js +32 -0
- package/dist/adapters/replicate/predictionLifecycle.d.ts +46 -0
- package/dist/adapters/replicate/predictionLifecycle.js +283 -0
- package/dist/adapters/video/klingVideoHandler.d.ts +37 -0
- package/dist/adapters/video/klingVideoHandler.js +305 -0
- package/dist/adapters/video/replicateVideoHandler.d.ts +29 -0
- package/dist/adapters/video/replicateVideoHandler.js +157 -0
- package/dist/adapters/video/runwayVideoHandler.d.ts +32 -0
- package/dist/adapters/video/runwayVideoHandler.js +316 -0
- package/dist/adapters/video/vertexVideoHandler.d.ts +19 -1
- package/dist/adapters/video/vertexVideoHandler.js +33 -9
- package/dist/agent/directTools.js +11 -3
- package/dist/autoresearch/runner.js +8 -2
- package/dist/avatar/index.d.ts +13 -0
- package/dist/avatar/index.js +13 -0
- package/dist/avatar/providers/DIDAvatar.d.ts +49 -0
- package/dist/avatar/providers/DIDAvatar.js +501 -0
- package/dist/avatar/providers/HeyGenAvatar.d.ts +30 -0
- package/dist/avatar/providers/HeyGenAvatar.js +337 -0
- package/dist/avatar/providers/ReplicateAvatar.d.ts +36 -0
- package/dist/avatar/providers/ReplicateAvatar.js +267 -0
- package/dist/browser/neurolink.min.js +624 -601
- package/dist/cli/commands/mcp.js +29 -0
- package/dist/cli/commands/proxy.js +24 -5
- package/dist/cli/factories/commandFactory.d.ts +11 -1
- package/dist/cli/factories/commandFactory.js +291 -38
- package/dist/constants/contextWindows.js +101 -0
- package/dist/constants/enums.d.ts +273 -2
- package/dist/constants/enums.js +290 -1
- package/dist/constants/videoErrors.d.ts +4 -0
- package/dist/constants/videoErrors.js +4 -0
- package/dist/core/baseProvider.d.ts +22 -2
- package/dist/core/baseProvider.js +217 -11
- package/dist/core/constants.d.ts +12 -0
- package/dist/core/constants.js +72 -1
- package/dist/evaluation/index.d.ts +2 -0
- package/dist/evaluation/index.js +4 -0
- package/dist/factories/providerFactory.js +7 -1
- package/dist/factories/providerRegistry.js +202 -5
- package/dist/features/ppt/contentPlanner.js +42 -14
- package/dist/index.d.ts +9 -1
- package/dist/index.js +16 -1
- package/dist/lib/adapters/providerImageAdapter.js +29 -1
- package/dist/lib/adapters/replicate/auth.d.ts +19 -0
- package/dist/lib/adapters/replicate/auth.js +33 -0
- package/dist/lib/adapters/replicate/predictionLifecycle.d.ts +46 -0
- package/dist/lib/adapters/replicate/predictionLifecycle.js +284 -0
- package/dist/lib/adapters/video/klingVideoHandler.d.ts +37 -0
- package/dist/lib/adapters/video/klingVideoHandler.js +306 -0
- package/dist/lib/adapters/video/replicateVideoHandler.d.ts +29 -0
- package/dist/lib/adapters/video/replicateVideoHandler.js +158 -0
- package/dist/lib/adapters/video/runwayVideoHandler.d.ts +32 -0
- package/dist/lib/adapters/video/runwayVideoHandler.js +317 -0
- package/dist/lib/adapters/video/vertexVideoHandler.d.ts +19 -1
- package/dist/lib/adapters/video/vertexVideoHandler.js +33 -9
- package/dist/lib/agent/directTools.js +11 -3
- package/dist/lib/autoresearch/runner.js +8 -2
- package/dist/lib/avatar/index.d.ts +13 -0
- package/dist/lib/avatar/index.js +14 -0
- package/dist/lib/avatar/providers/DIDAvatar.d.ts +49 -0
- package/dist/lib/avatar/providers/DIDAvatar.js +502 -0
- package/dist/lib/avatar/providers/HeyGenAvatar.d.ts +30 -0
- package/dist/lib/avatar/providers/HeyGenAvatar.js +338 -0
- package/dist/lib/avatar/providers/ReplicateAvatar.d.ts +36 -0
- package/dist/lib/avatar/providers/ReplicateAvatar.js +268 -0
- package/dist/lib/constants/contextWindows.js +101 -0
- package/dist/lib/constants/enums.d.ts +273 -2
- package/dist/lib/constants/enums.js +290 -1
- package/dist/lib/constants/videoErrors.d.ts +4 -0
- package/dist/lib/constants/videoErrors.js +4 -0
- package/dist/lib/core/baseProvider.d.ts +22 -2
- package/dist/lib/core/baseProvider.js +217 -11
- package/dist/lib/core/constants.d.ts +12 -0
- package/dist/lib/core/constants.js +72 -1
- package/dist/lib/evaluation/index.d.ts +2 -0
- package/dist/lib/evaluation/index.js +4 -0
- package/dist/lib/factories/providerFactory.js +7 -1
- package/dist/lib/factories/providerRegistry.js +202 -5
- package/dist/lib/features/ppt/contentPlanner.js +42 -14
- package/dist/lib/index.d.ts +9 -1
- package/dist/lib/index.js +16 -1
- package/dist/lib/middleware/builtin/lifecycle.js +39 -9
- package/dist/lib/music/index.d.ts +13 -0
- package/dist/lib/music/index.js +14 -0
- package/dist/lib/music/providers/BeatovenMusic.d.ts +31 -0
- package/dist/lib/music/providers/BeatovenMusic.js +334 -0
- package/dist/lib/music/providers/ElevenLabsMusic.d.ts +30 -0
- package/dist/lib/music/providers/ElevenLabsMusic.js +169 -0
- package/dist/lib/music/providers/LyriaMusic.d.ts +29 -0
- package/dist/lib/music/providers/LyriaMusic.js +173 -0
- package/dist/lib/music/providers/ReplicateMusic.d.ts +31 -0
- package/dist/lib/music/providers/ReplicateMusic.js +262 -0
- package/dist/lib/neurolink.d.ts +30 -0
- package/dist/lib/neurolink.js +323 -77
- package/dist/lib/providers/amazonBedrock.d.ts +10 -0
- package/dist/lib/providers/amazonBedrock.js +94 -39
- package/dist/lib/providers/anthropic.js +55 -7
- package/dist/lib/providers/anthropicBaseProvider.js +1 -1
- package/dist/lib/providers/azureOpenai.js +66 -17
- package/dist/lib/providers/cloudflare.d.ts +35 -0
- package/dist/lib/providers/cloudflare.js +174 -0
- package/dist/lib/providers/cohere.d.ts +52 -0
- package/dist/lib/providers/cohere.js +253 -0
- package/dist/lib/providers/deepseek.js +72 -17
- package/dist/lib/providers/fireworks.d.ts +33 -0
- package/dist/lib/providers/fireworks.js +164 -0
- package/dist/lib/providers/googleAiStudio.js +126 -10
- package/dist/lib/providers/googleNativeGemini3.d.ts +26 -6
- package/dist/lib/providers/googleNativeGemini3.js +276 -29
- package/dist/lib/providers/googleVertex.js +639 -181
- package/dist/lib/providers/groq.d.ts +33 -0
- package/dist/lib/providers/groq.js +181 -0
- package/dist/lib/providers/huggingFace.js +9 -8
- package/dist/lib/providers/ideogram.d.ts +34 -0
- package/dist/lib/providers/ideogram.js +184 -0
- package/dist/lib/providers/index.d.ts +13 -0
- package/dist/lib/providers/index.js +13 -0
- package/dist/lib/providers/jina.d.ts +59 -0
- package/dist/lib/providers/jina.js +218 -0
- package/dist/lib/providers/llamaCpp.js +14 -46
- package/dist/lib/providers/lmStudio.js +14 -47
- package/dist/lib/providers/mistral.js +7 -7
- package/dist/lib/providers/nvidiaNim.js +160 -19
- package/dist/lib/providers/ollama.js +7 -7
- package/dist/lib/providers/openAI.d.ts +22 -1
- package/dist/lib/providers/openAI.js +181 -0
- package/dist/lib/providers/openRouter.js +35 -23
- package/dist/lib/providers/openaiCompatible.js +9 -8
- package/dist/lib/providers/perplexity.d.ts +33 -0
- package/dist/lib/providers/perplexity.js +179 -0
- package/dist/lib/providers/recraft.d.ts +34 -0
- package/dist/lib/providers/recraft.js +197 -0
- package/dist/lib/providers/replicate.d.ts +75 -0
- package/dist/lib/providers/replicate.js +403 -0
- package/dist/lib/providers/stability.d.ts +37 -0
- package/dist/lib/providers/stability.js +191 -0
- package/dist/lib/providers/togetherAi.d.ts +33 -0
- package/dist/lib/providers/togetherAi.js +176 -0
- package/dist/lib/providers/voyage.d.ts +47 -0
- package/dist/lib/providers/voyage.js +177 -0
- package/dist/lib/providers/xai.d.ts +33 -0
- package/dist/lib/providers/xai.js +172 -0
- package/dist/lib/telemetry/index.d.ts +1 -1
- package/dist/lib/telemetry/index.js +1 -1
- package/dist/lib/telemetry/tracers.d.ts +19 -0
- package/dist/lib/telemetry/tracers.js +19 -0
- package/dist/lib/telemetry/withSpan.d.ts +35 -0
- package/dist/lib/telemetry/withSpan.js +103 -0
- package/dist/lib/types/avatar.d.ts +143 -0
- package/dist/lib/types/avatar.js +20 -0
- package/dist/lib/types/cli.d.ts +6 -0
- package/dist/lib/types/conversation.d.ts +16 -0
- package/dist/lib/types/generate.d.ts +62 -5
- package/dist/lib/types/index.d.ts +5 -0
- package/dist/lib/types/index.js +7 -0
- package/dist/lib/types/middleware.d.ts +27 -0
- package/dist/lib/types/multimodal.d.ts +35 -2
- package/dist/lib/types/music.d.ts +165 -0
- package/dist/lib/types/music.js +21 -0
- package/dist/lib/types/providers.d.ts +144 -1
- package/dist/lib/types/replicate.d.ts +67 -0
- package/dist/lib/types/replicate.js +10 -0
- package/dist/lib/types/safeFetch.d.ts +15 -0
- package/dist/lib/types/safeFetch.js +7 -0
- package/dist/lib/types/stream.d.ts +2 -1
- package/dist/lib/types/tools.d.ts +13 -0
- package/dist/lib/types/video.d.ts +89 -0
- package/dist/lib/types/video.js +15 -0
- package/dist/lib/utils/avatarProcessor.d.ts +68 -0
- package/dist/lib/utils/avatarProcessor.js +172 -0
- package/dist/lib/utils/cloneOptions.d.ts +36 -0
- package/dist/lib/utils/cloneOptions.js +62 -0
- package/dist/lib/utils/lifecycleCallbacks.d.ts +51 -8
- package/dist/lib/utils/lifecycleCallbacks.js +82 -26
- package/dist/lib/utils/lifecycleTimeout.d.ts +25 -0
- package/dist/lib/utils/lifecycleTimeout.js +39 -0
- package/dist/lib/utils/logSanitize.d.ts +49 -0
- package/dist/lib/utils/logSanitize.js +170 -0
- package/dist/lib/utils/loggingFetch.d.ts +29 -0
- package/dist/lib/utils/loggingFetch.js +60 -0
- package/dist/lib/utils/messageBuilder.js +43 -25
- package/dist/lib/utils/modelChoices.js +236 -3
- package/dist/lib/utils/musicProcessor.d.ts +67 -0
- package/dist/lib/utils/musicProcessor.js +189 -0
- package/dist/lib/utils/optionsConversion.js +3 -2
- package/dist/lib/utils/parameterValidation.js +14 -4
- package/dist/lib/utils/pricing.js +193 -0
- package/dist/lib/utils/providerConfig.d.ts +55 -0
- package/dist/lib/utils/providerConfig.js +224 -0
- package/dist/lib/utils/safeFetch.d.ts +26 -0
- package/dist/lib/utils/safeFetch.js +83 -0
- package/dist/lib/utils/sizeGuard.d.ts +34 -0
- package/dist/lib/utils/sizeGuard.js +45 -0
- package/dist/lib/utils/ssrfGuard.d.ts +52 -0
- package/dist/lib/utils/ssrfGuard.js +411 -0
- package/dist/lib/utils/videoProcessor.d.ts +60 -0
- package/dist/lib/utils/videoProcessor.js +201 -0
- package/dist/lib/voice/providers/FishAudioTTS.d.ts +27 -0
- package/dist/lib/voice/providers/FishAudioTTS.js +183 -0
- package/dist/lib/workflow/core/ensembleExecutor.js +26 -9
- package/dist/middleware/builtin/lifecycle.js +39 -9
- package/dist/music/index.d.ts +13 -0
- package/dist/music/index.js +13 -0
- package/dist/music/providers/BeatovenMusic.d.ts +31 -0
- package/dist/music/providers/BeatovenMusic.js +333 -0
- package/dist/music/providers/ElevenLabsMusic.d.ts +30 -0
- package/dist/music/providers/ElevenLabsMusic.js +168 -0
- package/dist/music/providers/LyriaMusic.d.ts +29 -0
- package/dist/music/providers/LyriaMusic.js +172 -0
- package/dist/music/providers/ReplicateMusic.d.ts +31 -0
- package/dist/music/providers/ReplicateMusic.js +261 -0
- package/dist/neurolink.d.ts +30 -0
- package/dist/neurolink.js +323 -77
- package/dist/providers/amazonBedrock.d.ts +10 -0
- package/dist/providers/amazonBedrock.js +94 -39
- package/dist/providers/anthropic.js +55 -7
- package/dist/providers/anthropicBaseProvider.js +1 -1
- package/dist/providers/azureOpenai.js +66 -17
- package/dist/providers/cloudflare.d.ts +35 -0
- package/dist/providers/cloudflare.js +173 -0
- package/dist/providers/cohere.d.ts +52 -0
- package/dist/providers/cohere.js +252 -0
- package/dist/providers/deepseek.js +72 -17
- package/dist/providers/fireworks.d.ts +33 -0
- package/dist/providers/fireworks.js +163 -0
- package/dist/providers/googleAiStudio.js +126 -10
- package/dist/providers/googleNativeGemini3.d.ts +26 -6
- package/dist/providers/googleNativeGemini3.js +276 -29
- package/dist/providers/googleVertex.js +639 -181
- package/dist/providers/groq.d.ts +33 -0
- package/dist/providers/groq.js +180 -0
- package/dist/providers/huggingFace.js +9 -8
- package/dist/providers/ideogram.d.ts +34 -0
- package/dist/providers/ideogram.js +183 -0
- package/dist/providers/index.d.ts +13 -0
- package/dist/providers/index.js +13 -0
- package/dist/providers/jina.d.ts +59 -0
- package/dist/providers/jina.js +217 -0
- package/dist/providers/llamaCpp.js +14 -46
- package/dist/providers/lmStudio.js +14 -47
- package/dist/providers/mistral.js +7 -7
- package/dist/providers/nvidiaNim.js +160 -19
- package/dist/providers/ollama.js +7 -7
- package/dist/providers/openAI.d.ts +22 -1
- package/dist/providers/openAI.js +181 -0
- package/dist/providers/openRouter.js +35 -23
- package/dist/providers/openaiCompatible.js +9 -8
- package/dist/providers/perplexity.d.ts +33 -0
- package/dist/providers/perplexity.js +178 -0
- package/dist/providers/recraft.d.ts +34 -0
- package/dist/providers/recraft.js +196 -0
- package/dist/providers/replicate.d.ts +75 -0
- package/dist/providers/replicate.js +402 -0
- package/dist/providers/stability.d.ts +37 -0
- package/dist/providers/stability.js +190 -0
- package/dist/providers/togetherAi.d.ts +33 -0
- package/dist/providers/togetherAi.js +175 -0
- package/dist/providers/voyage.d.ts +47 -0
- package/dist/providers/voyage.js +176 -0
- package/dist/providers/xai.d.ts +33 -0
- package/dist/providers/xai.js +171 -0
- package/dist/telemetry/index.d.ts +1 -1
- package/dist/telemetry/index.js +1 -1
- package/dist/telemetry/tracers.d.ts +19 -0
- package/dist/telemetry/tracers.js +19 -0
- package/dist/telemetry/withSpan.d.ts +35 -0
- package/dist/telemetry/withSpan.js +103 -0
- package/dist/types/avatar.d.ts +143 -0
- package/dist/types/avatar.js +19 -0
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/conversation.d.ts +16 -0
- package/dist/types/generate.d.ts +62 -5
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +7 -0
- package/dist/types/middleware.d.ts +27 -0
- package/dist/types/multimodal.d.ts +35 -2
- package/dist/types/music.d.ts +165 -0
- package/dist/types/music.js +20 -0
- package/dist/types/providers.d.ts +144 -1
- package/dist/types/replicate.d.ts +67 -0
- package/dist/types/replicate.js +9 -0
- package/dist/types/safeFetch.d.ts +15 -0
- package/dist/types/safeFetch.js +6 -0
- package/dist/types/stream.d.ts +2 -1
- package/dist/types/tools.d.ts +13 -0
- package/dist/types/video.d.ts +89 -0
- package/dist/types/video.js +14 -0
- package/dist/utils/avatarProcessor.d.ts +68 -0
- package/dist/utils/avatarProcessor.js +171 -0
- package/dist/utils/cloneOptions.d.ts +36 -0
- package/dist/utils/cloneOptions.js +61 -0
- package/dist/utils/lifecycleCallbacks.d.ts +51 -8
- package/dist/utils/lifecycleCallbacks.js +82 -26
- package/dist/utils/lifecycleTimeout.d.ts +25 -0
- package/dist/utils/lifecycleTimeout.js +38 -0
- package/dist/utils/logSanitize.d.ts +49 -0
- package/dist/utils/logSanitize.js +169 -0
- package/dist/utils/loggingFetch.d.ts +29 -0
- package/dist/utils/loggingFetch.js +59 -0
- package/dist/utils/messageBuilder.js +43 -25
- package/dist/utils/modelChoices.js +236 -3
- package/dist/utils/musicProcessor.d.ts +67 -0
- package/dist/utils/musicProcessor.js +188 -0
- package/dist/utils/optionsConversion.js +3 -2
- package/dist/utils/parameterValidation.js +14 -4
- package/dist/utils/pricing.js +193 -0
- package/dist/utils/providerConfig.d.ts +55 -0
- package/dist/utils/providerConfig.js +224 -0
- package/dist/utils/safeFetch.d.ts +26 -0
- package/dist/utils/safeFetch.js +82 -0
- package/dist/utils/sizeGuard.d.ts +34 -0
- package/dist/utils/sizeGuard.js +44 -0
- package/dist/utils/ssrfGuard.d.ts +52 -0
- package/dist/utils/ssrfGuard.js +410 -0
- package/dist/utils/videoProcessor.d.ts +60 -0
- package/dist/utils/videoProcessor.js +200 -0
- package/dist/voice/providers/FishAudioTTS.d.ts +27 -0
- package/dist/voice/providers/FishAudioTTS.js +182 -0
- package/dist/workflow/core/ensembleExecutor.js +26 -9
- package/package.json +32 -5
package/dist/utils/pricing.js
CHANGED
|
@@ -285,6 +285,177 @@ const PRICING = {
|
|
|
285
285
|
llamacpp: {
|
|
286
286
|
_default: { input: 0, output: 0 },
|
|
287
287
|
},
|
|
288
|
+
xai: {
|
|
289
|
+
_default: { input: 3.0 / 1_000_000, output: 15.0 / 1_000_000 },
|
|
290
|
+
"grok-3": { input: 3.0 / 1_000_000, output: 15.0 / 1_000_000 },
|
|
291
|
+
"grok-3-mini": { input: 0.3 / 1_000_000, output: 0.5 / 1_000_000 },
|
|
292
|
+
"grok-2-latest": { input: 2.0 / 1_000_000, output: 10.0 / 1_000_000 },
|
|
293
|
+
"grok-2-vision-latest": {
|
|
294
|
+
input: 2.0 / 1_000_000,
|
|
295
|
+
output: 10.0 / 1_000_000,
|
|
296
|
+
},
|
|
297
|
+
"grok-beta": { input: 5.0 / 1_000_000, output: 15.0 / 1_000_000 },
|
|
298
|
+
},
|
|
299
|
+
groq: {
|
|
300
|
+
_default: { input: 0.59 / 1_000_000, output: 0.79 / 1_000_000 },
|
|
301
|
+
"llama-3.3-70b-versatile": {
|
|
302
|
+
input: 0.59 / 1_000_000,
|
|
303
|
+
output: 0.79 / 1_000_000,
|
|
304
|
+
},
|
|
305
|
+
"llama-3.1-8b-instant": {
|
|
306
|
+
input: 0.05 / 1_000_000,
|
|
307
|
+
output: 0.08 / 1_000_000,
|
|
308
|
+
},
|
|
309
|
+
"llama-3.2-90b-vision-preview": {
|
|
310
|
+
input: 0.9 / 1_000_000,
|
|
311
|
+
output: 0.9 / 1_000_000,
|
|
312
|
+
},
|
|
313
|
+
"llama-3.2-11b-vision-preview": {
|
|
314
|
+
input: 0.18 / 1_000_000,
|
|
315
|
+
output: 0.18 / 1_000_000,
|
|
316
|
+
},
|
|
317
|
+
"gemma2-9b-it": { input: 0.2 / 1_000_000, output: 0.2 / 1_000_000 },
|
|
318
|
+
"mixtral-8x7b-32768": {
|
|
319
|
+
input: 0.24 / 1_000_000,
|
|
320
|
+
output: 0.24 / 1_000_000,
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
cohere: {
|
|
324
|
+
_default: { input: 2.5 / 1_000_000, output: 10.0 / 1_000_000 },
|
|
325
|
+
"command-r-plus": { input: 2.5 / 1_000_000, output: 10.0 / 1_000_000 },
|
|
326
|
+
"command-r": { input: 0.15 / 1_000_000, output: 0.6 / 1_000_000 },
|
|
327
|
+
"command-r7b-12-2024": {
|
|
328
|
+
input: 0.0375 / 1_000_000,
|
|
329
|
+
output: 0.15 / 1_000_000,
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
"together-ai": {
|
|
333
|
+
_default: { input: 0.88 / 1_000_000, output: 0.88 / 1_000_000 },
|
|
334
|
+
"meta-llama/Llama-3.3-70B-Instruct-Turbo": {
|
|
335
|
+
input: 0.88 / 1_000_000,
|
|
336
|
+
output: 0.88 / 1_000_000,
|
|
337
|
+
},
|
|
338
|
+
"meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo": {
|
|
339
|
+
input: 3.5 / 1_000_000,
|
|
340
|
+
output: 3.5 / 1_000_000,
|
|
341
|
+
},
|
|
342
|
+
"meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo": {
|
|
343
|
+
input: 0.88 / 1_000_000,
|
|
344
|
+
output: 0.88 / 1_000_000,
|
|
345
|
+
},
|
|
346
|
+
"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo": {
|
|
347
|
+
input: 0.18 / 1_000_000,
|
|
348
|
+
output: 0.18 / 1_000_000,
|
|
349
|
+
},
|
|
350
|
+
"mistralai/Mixtral-8x22B-Instruct-v0.1": {
|
|
351
|
+
input: 1.2 / 1_000_000,
|
|
352
|
+
output: 1.2 / 1_000_000,
|
|
353
|
+
},
|
|
354
|
+
"mistralai/Mixtral-8x7B-Instruct-v0.1": {
|
|
355
|
+
input: 0.6 / 1_000_000,
|
|
356
|
+
output: 0.6 / 1_000_000,
|
|
357
|
+
},
|
|
358
|
+
"Qwen/Qwen2.5-72B-Instruct-Turbo": {
|
|
359
|
+
input: 1.2 / 1_000_000,
|
|
360
|
+
output: 1.2 / 1_000_000,
|
|
361
|
+
},
|
|
362
|
+
"deepseek-ai/DeepSeek-R1": {
|
|
363
|
+
input: 7.0 / 1_000_000,
|
|
364
|
+
output: 7.0 / 1_000_000,
|
|
365
|
+
},
|
|
366
|
+
"deepseek-ai/DeepSeek-V3": {
|
|
367
|
+
input: 1.25 / 1_000_000,
|
|
368
|
+
output: 1.25 / 1_000_000,
|
|
369
|
+
},
|
|
370
|
+
},
|
|
371
|
+
fireworks: {
|
|
372
|
+
_default: { input: 0.9 / 1_000_000, output: 0.9 / 1_000_000 },
|
|
373
|
+
"accounts/fireworks/models/llama-v3p1-70b-instruct": {
|
|
374
|
+
input: 0.9 / 1_000_000,
|
|
375
|
+
output: 0.9 / 1_000_000,
|
|
376
|
+
},
|
|
377
|
+
"accounts/fireworks/models/llama-v3p1-405b-instruct": {
|
|
378
|
+
input: 3.0 / 1_000_000,
|
|
379
|
+
output: 3.0 / 1_000_000,
|
|
380
|
+
},
|
|
381
|
+
"accounts/fireworks/models/llama-v3p1-8b-instruct": {
|
|
382
|
+
input: 0.2 / 1_000_000,
|
|
383
|
+
output: 0.2 / 1_000_000,
|
|
384
|
+
},
|
|
385
|
+
"accounts/fireworks/models/llama-v3p3-70b-instruct": {
|
|
386
|
+
input: 0.9 / 1_000_000,
|
|
387
|
+
output: 0.9 / 1_000_000,
|
|
388
|
+
},
|
|
389
|
+
"accounts/fireworks/models/mixtral-8x22b-instruct": {
|
|
390
|
+
input: 1.2 / 1_000_000,
|
|
391
|
+
output: 1.2 / 1_000_000,
|
|
392
|
+
},
|
|
393
|
+
"accounts/fireworks/models/qwen2p5-72b-instruct": {
|
|
394
|
+
input: 0.9 / 1_000_000,
|
|
395
|
+
output: 0.9 / 1_000_000,
|
|
396
|
+
},
|
|
397
|
+
"accounts/fireworks/models/qwen2p5-coder-32b-instruct": {
|
|
398
|
+
input: 0.9 / 1_000_000,
|
|
399
|
+
output: 0.9 / 1_000_000,
|
|
400
|
+
},
|
|
401
|
+
"accounts/fireworks/models/deepseek-v3": {
|
|
402
|
+
input: 0.75 / 1_000_000,
|
|
403
|
+
output: 3.0 / 1_000_000,
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
perplexity: {
|
|
407
|
+
_default: { input: 1.0 / 1_000_000, output: 1.0 / 1_000_000 },
|
|
408
|
+
sonar: { input: 1.0 / 1_000_000, output: 1.0 / 1_000_000 },
|
|
409
|
+
"sonar-pro": { input: 3.0 / 1_000_000, output: 15.0 / 1_000_000 },
|
|
410
|
+
"sonar-reasoning": { input: 1.0 / 1_000_000, output: 5.0 / 1_000_000 },
|
|
411
|
+
"sonar-reasoning-pro": {
|
|
412
|
+
input: 2.0 / 1_000_000,
|
|
413
|
+
output: 8.0 / 1_000_000,
|
|
414
|
+
},
|
|
415
|
+
"sonar-deep-research": {
|
|
416
|
+
input: 2.0 / 1_000_000,
|
|
417
|
+
output: 8.0 / 1_000_000,
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
cloudflare: {
|
|
421
|
+
// Cloudflare bills per "neuron"; symbolic per-token rate so cost
|
|
422
|
+
// attribution dashboards have non-zero values.
|
|
423
|
+
_default: { input: 0.011 / 1_000_000, output: 0.011 / 1_000_000 },
|
|
424
|
+
},
|
|
425
|
+
replicate: {
|
|
426
|
+
// Replicate bills per compute-second, not per-token. Symbolic rate.
|
|
427
|
+
_default: { input: 0.5 / 1_000_000, output: 1.5 / 1_000_000 },
|
|
428
|
+
},
|
|
429
|
+
voyage: {
|
|
430
|
+
// Voyage bills per million input tokens — output dimension is the
|
|
431
|
+
// embedding vector, not generated tokens. We charge to input only.
|
|
432
|
+
_default: { input: 0.18 / 1_000_000, output: 0 },
|
|
433
|
+
"voyage-3.5": { input: 0.06 / 1_000_000, output: 0 },
|
|
434
|
+
"voyage-3.5-lite": { input: 0.02 / 1_000_000, output: 0 },
|
|
435
|
+
"voyage-3-large": { input: 0.18 / 1_000_000, output: 0 },
|
|
436
|
+
"voyage-code-3": { input: 0.18 / 1_000_000, output: 0 },
|
|
437
|
+
"voyage-finance-2": { input: 0.12 / 1_000_000, output: 0 },
|
|
438
|
+
"voyage-law-2": { input: 0.12 / 1_000_000, output: 0 },
|
|
439
|
+
"voyage-multilingual-2": { input: 0.12 / 1_000_000, output: 0 },
|
|
440
|
+
},
|
|
441
|
+
jina: {
|
|
442
|
+
_default: { input: 0.02 / 1_000_000, output: 0 },
|
|
443
|
+
"jina-embeddings-v3": { input: 0.02 / 1_000_000, output: 0 },
|
|
444
|
+
"jina-reranker-v2-base-multilingual": {
|
|
445
|
+
input: 0.05 / 1_000_000,
|
|
446
|
+
output: 0,
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
stability: {
|
|
450
|
+
// Stability AI bills per image; symbolic per-token rate.
|
|
451
|
+
_default: { input: 0, output: 0.04 / 1_000 },
|
|
452
|
+
},
|
|
453
|
+
ideogram: {
|
|
454
|
+
_default: { input: 0, output: 0.08 / 1_000 },
|
|
455
|
+
},
|
|
456
|
+
recraft: {
|
|
457
|
+
_default: { input: 0, output: 0.04 / 1_000 },
|
|
458
|
+
},
|
|
288
459
|
};
|
|
289
460
|
/**
|
|
290
461
|
* Map of normalized provider aliases to canonical PRICING keys.
|
|
@@ -313,6 +484,28 @@ const PROVIDER_ALIASES = {
|
|
|
313
484
|
nvidia: "nvidia-nim",
|
|
314
485
|
lmstudio: "lm-studio",
|
|
315
486
|
llamacpp: "llamacpp",
|
|
487
|
+
xai: "xai",
|
|
488
|
+
grok: "xai",
|
|
489
|
+
groq: "groq",
|
|
490
|
+
cohere: "cohere",
|
|
491
|
+
togetherai: "together-ai",
|
|
492
|
+
together: "together-ai",
|
|
493
|
+
fireworks: "fireworks",
|
|
494
|
+
perplexity: "perplexity",
|
|
495
|
+
pplx: "perplexity",
|
|
496
|
+
cloudflare: "cloudflare",
|
|
497
|
+
workersai: "cloudflare",
|
|
498
|
+
cfai: "cloudflare",
|
|
499
|
+
replicate: "replicate",
|
|
500
|
+
voyage: "voyage",
|
|
501
|
+
voyageai: "voyage",
|
|
502
|
+
jina: "jina",
|
|
503
|
+
jinaai: "jina",
|
|
504
|
+
stability: "stability",
|
|
505
|
+
stabilityai: "stability",
|
|
506
|
+
sd: "stability",
|
|
507
|
+
ideogram: "ideogram",
|
|
508
|
+
recraft: "recraft",
|
|
316
509
|
};
|
|
317
510
|
/**
|
|
318
511
|
* Look up per-token rates for a provider/model combination.
|
|
@@ -123,6 +123,61 @@ export declare function createLmStudioConfig(): ProviderConfigOptions;
|
|
|
123
123
|
* Creates llama.cpp provider configuration (local server)
|
|
124
124
|
*/
|
|
125
125
|
export declare function createLlamaCppConfig(): ProviderConfigOptions;
|
|
126
|
+
/**
|
|
127
|
+
* Creates xAI Grok provider configuration.
|
|
128
|
+
*/
|
|
129
|
+
export declare function createXaiConfig(): ProviderConfigOptions;
|
|
130
|
+
/**
|
|
131
|
+
* Creates Groq provider configuration.
|
|
132
|
+
*/
|
|
133
|
+
export declare function createGroqConfig(): ProviderConfigOptions;
|
|
134
|
+
/**
|
|
135
|
+
* Creates Cohere provider configuration.
|
|
136
|
+
*/
|
|
137
|
+
export declare function createCohereConfig(): ProviderConfigOptions;
|
|
138
|
+
/**
|
|
139
|
+
* Creates Replicate provider configuration.
|
|
140
|
+
*/
|
|
141
|
+
export declare function createReplicateConfig(): ProviderConfigOptions;
|
|
142
|
+
/**
|
|
143
|
+
* Creates Together AI provider configuration.
|
|
144
|
+
*/
|
|
145
|
+
export declare function createTogetherAIConfig(): ProviderConfigOptions;
|
|
146
|
+
/**
|
|
147
|
+
* Creates Fireworks AI provider configuration.
|
|
148
|
+
*/
|
|
149
|
+
export declare function createFireworksConfig(): ProviderConfigOptions;
|
|
150
|
+
/**
|
|
151
|
+
* Creates Perplexity provider configuration.
|
|
152
|
+
*/
|
|
153
|
+
export declare function createPerplexityConfig(): ProviderConfigOptions;
|
|
154
|
+
/**
|
|
155
|
+
* Creates Voyage AI provider configuration (embedding-only).
|
|
156
|
+
*/
|
|
157
|
+
export declare function createVoyageConfig(): ProviderConfigOptions;
|
|
158
|
+
/**
|
|
159
|
+
* Creates Jina AI provider configuration (embeddings + reranking).
|
|
160
|
+
*/
|
|
161
|
+
export declare function createJinaConfig(): ProviderConfigOptions;
|
|
162
|
+
/**
|
|
163
|
+
* Creates Stability AI provider configuration (image generation).
|
|
164
|
+
*/
|
|
165
|
+
export declare function createStabilityConfig(): ProviderConfigOptions;
|
|
166
|
+
/**
|
|
167
|
+
* Creates Ideogram provider configuration (image generation).
|
|
168
|
+
*/
|
|
169
|
+
export declare function createIdeogramConfig(): ProviderConfigOptions;
|
|
170
|
+
/**
|
|
171
|
+
* Creates Recraft provider configuration (image generation, vector focus).
|
|
172
|
+
*/
|
|
173
|
+
export declare function createRecraftConfig(): ProviderConfigOptions;
|
|
174
|
+
/**
|
|
175
|
+
* Creates Cloudflare Workers AI provider configuration.
|
|
176
|
+
*
|
|
177
|
+
* Cloudflare requires both `CLOUDFLARE_API_KEY` (workers-AI-scoped token)
|
|
178
|
+
* AND `CLOUDFLARE_ACCOUNT_ID` since the endpoint is per-account.
|
|
179
|
+
*/
|
|
180
|
+
export declare function createCloudflareConfig(): ProviderConfigOptions;
|
|
126
181
|
/**
|
|
127
182
|
* Creates Google Vertex Project ID configuration
|
|
128
183
|
*/
|
|
@@ -448,6 +448,230 @@ export function createLlamaCppConfig() {
|
|
|
448
448
|
optional: true,
|
|
449
449
|
};
|
|
450
450
|
}
|
|
451
|
+
/**
|
|
452
|
+
* Creates xAI Grok provider configuration.
|
|
453
|
+
*/
|
|
454
|
+
export function createXaiConfig() {
|
|
455
|
+
return {
|
|
456
|
+
providerName: "xAI",
|
|
457
|
+
envVarName: "XAI_API_KEY",
|
|
458
|
+
setupUrl: "https://console.x.ai/",
|
|
459
|
+
description: "API key",
|
|
460
|
+
instructions: [
|
|
461
|
+
"1. Visit: https://console.x.ai/",
|
|
462
|
+
"2. Sign in with your xAI account",
|
|
463
|
+
"3. Create an API key",
|
|
464
|
+
"4. Set XAI_API_KEY in your .env file",
|
|
465
|
+
],
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Creates Groq provider configuration.
|
|
470
|
+
*/
|
|
471
|
+
export function createGroqConfig() {
|
|
472
|
+
return {
|
|
473
|
+
providerName: "Groq",
|
|
474
|
+
envVarName: "GROQ_API_KEY",
|
|
475
|
+
setupUrl: "https://console.groq.com/keys",
|
|
476
|
+
description: "API key",
|
|
477
|
+
instructions: [
|
|
478
|
+
"1. Visit: https://console.groq.com/keys",
|
|
479
|
+
"2. Sign in to your Groq account",
|
|
480
|
+
"3. Create a new API key",
|
|
481
|
+
"4. Set GROQ_API_KEY in your .env file",
|
|
482
|
+
],
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Creates Cohere provider configuration.
|
|
487
|
+
*/
|
|
488
|
+
export function createCohereConfig() {
|
|
489
|
+
return {
|
|
490
|
+
providerName: "Cohere",
|
|
491
|
+
envVarName: "COHERE_API_KEY",
|
|
492
|
+
setupUrl: "https://dashboard.cohere.com/api-keys",
|
|
493
|
+
description: "API key",
|
|
494
|
+
instructions: [
|
|
495
|
+
"1. Visit: https://dashboard.cohere.com/api-keys",
|
|
496
|
+
"2. Sign in to your Cohere account",
|
|
497
|
+
"3. Create a new API key",
|
|
498
|
+
"4. Set COHERE_API_KEY in your .env file",
|
|
499
|
+
],
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Creates Replicate provider configuration.
|
|
504
|
+
*/
|
|
505
|
+
export function createReplicateConfig() {
|
|
506
|
+
return {
|
|
507
|
+
providerName: "Replicate",
|
|
508
|
+
envVarName: "REPLICATE_API_TOKEN",
|
|
509
|
+
setupUrl: "https://replicate.com/account/api-tokens",
|
|
510
|
+
description: "API token",
|
|
511
|
+
instructions: [
|
|
512
|
+
"1. Visit: https://replicate.com/account/api-tokens",
|
|
513
|
+
"2. Sign in to your Replicate account",
|
|
514
|
+
"3. Create a new API token",
|
|
515
|
+
"4. Set REPLICATE_API_TOKEN in your .env file",
|
|
516
|
+
],
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Creates Together AI provider configuration.
|
|
521
|
+
*/
|
|
522
|
+
export function createTogetherAIConfig() {
|
|
523
|
+
return {
|
|
524
|
+
providerName: "Together AI",
|
|
525
|
+
envVarName: "TOGETHER_API_KEY",
|
|
526
|
+
setupUrl: "https://api.together.xyz/settings/api-keys",
|
|
527
|
+
description: "API key",
|
|
528
|
+
instructions: [
|
|
529
|
+
"1. Visit: https://api.together.xyz/settings/api-keys",
|
|
530
|
+
"2. Sign in to your Together AI account",
|
|
531
|
+
"3. Create a new API key",
|
|
532
|
+
"4. Set TOGETHER_API_KEY in your .env file",
|
|
533
|
+
],
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Creates Fireworks AI provider configuration.
|
|
538
|
+
*/
|
|
539
|
+
export function createFireworksConfig() {
|
|
540
|
+
return {
|
|
541
|
+
providerName: "Fireworks AI",
|
|
542
|
+
envVarName: "FIREWORKS_API_KEY",
|
|
543
|
+
setupUrl: "https://fireworks.ai/account/api-keys",
|
|
544
|
+
description: "API key",
|
|
545
|
+
instructions: [
|
|
546
|
+
"1. Visit: https://fireworks.ai/account/api-keys",
|
|
547
|
+
"2. Sign in to your Fireworks AI account",
|
|
548
|
+
"3. Create a new API key",
|
|
549
|
+
"4. Set FIREWORKS_API_KEY in your .env file",
|
|
550
|
+
],
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Creates Perplexity provider configuration.
|
|
555
|
+
*/
|
|
556
|
+
export function createPerplexityConfig() {
|
|
557
|
+
return {
|
|
558
|
+
providerName: "Perplexity",
|
|
559
|
+
envVarName: "PERPLEXITY_API_KEY",
|
|
560
|
+
setupUrl: "https://www.perplexity.ai/settings/api",
|
|
561
|
+
description: "API key",
|
|
562
|
+
instructions: [
|
|
563
|
+
"1. Visit: https://www.perplexity.ai/settings/api",
|
|
564
|
+
"2. Sign in to your Perplexity account",
|
|
565
|
+
"3. Create a new API key (Sonar tier)",
|
|
566
|
+
"4. Set PERPLEXITY_API_KEY in your .env file",
|
|
567
|
+
],
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Creates Voyage AI provider configuration (embedding-only).
|
|
572
|
+
*/
|
|
573
|
+
export function createVoyageConfig() {
|
|
574
|
+
return {
|
|
575
|
+
providerName: "Voyage AI",
|
|
576
|
+
envVarName: "VOYAGE_API_KEY",
|
|
577
|
+
setupUrl: "https://dash.voyageai.com/api-keys",
|
|
578
|
+
description: "API key",
|
|
579
|
+
instructions: [
|
|
580
|
+
"1. Visit: https://dash.voyageai.com/api-keys",
|
|
581
|
+
"2. Sign in to your Voyage AI account",
|
|
582
|
+
"3. Create a new API key",
|
|
583
|
+
"4. Set VOYAGE_API_KEY in your .env file",
|
|
584
|
+
],
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Creates Jina AI provider configuration (embeddings + reranking).
|
|
589
|
+
*/
|
|
590
|
+
export function createJinaConfig() {
|
|
591
|
+
return {
|
|
592
|
+
providerName: "Jina AI",
|
|
593
|
+
envVarName: "JINA_API_KEY",
|
|
594
|
+
setupUrl: "https://jina.ai/?sui=apikey",
|
|
595
|
+
description: "API key",
|
|
596
|
+
instructions: [
|
|
597
|
+
"1. Visit: https://jina.ai/?sui=apikey",
|
|
598
|
+
"2. Sign in / create account",
|
|
599
|
+
"3. Copy your API key",
|
|
600
|
+
"4. Set JINA_API_KEY in your .env file",
|
|
601
|
+
],
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Creates Stability AI provider configuration (image generation).
|
|
606
|
+
*/
|
|
607
|
+
export function createStabilityConfig() {
|
|
608
|
+
return {
|
|
609
|
+
providerName: "Stability AI",
|
|
610
|
+
envVarName: "STABILITY_API_KEY",
|
|
611
|
+
setupUrl: "https://platform.stability.ai/account/keys",
|
|
612
|
+
description: "API key",
|
|
613
|
+
instructions: [
|
|
614
|
+
"1. Visit: https://platform.stability.ai/account/keys",
|
|
615
|
+
"2. Sign in to your Stability AI account",
|
|
616
|
+
"3. Create a new API key",
|
|
617
|
+
"4. Set STABILITY_API_KEY in your .env file",
|
|
618
|
+
],
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Creates Ideogram provider configuration (image generation).
|
|
623
|
+
*/
|
|
624
|
+
export function createIdeogramConfig() {
|
|
625
|
+
return {
|
|
626
|
+
providerName: "Ideogram",
|
|
627
|
+
envVarName: "IDEOGRAM_API_KEY",
|
|
628
|
+
setupUrl: "https://developer.ideogram.ai/",
|
|
629
|
+
description: "API key",
|
|
630
|
+
instructions: [
|
|
631
|
+
"1. Visit: https://developer.ideogram.ai/",
|
|
632
|
+
"2. Sign in / create account",
|
|
633
|
+
"3. Generate a new API key",
|
|
634
|
+
"4. Set IDEOGRAM_API_KEY in your .env file",
|
|
635
|
+
],
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Creates Recraft provider configuration (image generation, vector focus).
|
|
640
|
+
*/
|
|
641
|
+
export function createRecraftConfig() {
|
|
642
|
+
return {
|
|
643
|
+
providerName: "Recraft",
|
|
644
|
+
envVarName: "RECRAFT_API_KEY",
|
|
645
|
+
setupUrl: "https://www.recraft.ai/api",
|
|
646
|
+
description: "API token",
|
|
647
|
+
instructions: [
|
|
648
|
+
"1. Visit: https://www.recraft.ai/api",
|
|
649
|
+
"2. Sign in / create account",
|
|
650
|
+
"3. Create an API token",
|
|
651
|
+
"4. Set RECRAFT_API_KEY in your .env file",
|
|
652
|
+
],
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Creates Cloudflare Workers AI provider configuration.
|
|
657
|
+
*
|
|
658
|
+
* Cloudflare requires both `CLOUDFLARE_API_KEY` (workers-AI-scoped token)
|
|
659
|
+
* AND `CLOUDFLARE_ACCOUNT_ID` since the endpoint is per-account.
|
|
660
|
+
*/
|
|
661
|
+
export function createCloudflareConfig() {
|
|
662
|
+
return {
|
|
663
|
+
providerName: "Cloudflare Workers AI",
|
|
664
|
+
envVarName: "CLOUDFLARE_API_KEY",
|
|
665
|
+
setupUrl: "https://dash.cloudflare.com/profile/api-tokens",
|
|
666
|
+
description: "API token (Workers AI Read+Write scope)",
|
|
667
|
+
instructions: [
|
|
668
|
+
"1. Visit: https://dash.cloudflare.com/profile/api-tokens",
|
|
669
|
+
"2. Create a token with 'Workers AI: Read + Write' scope",
|
|
670
|
+
"3. Set CLOUDFLARE_API_KEY in your .env file",
|
|
671
|
+
"4. Also set CLOUDFLARE_ACCOUNT_ID (find it in the dashboard URL or under 'Account ID')",
|
|
672
|
+
],
|
|
673
|
+
};
|
|
674
|
+
}
|
|
451
675
|
/**
|
|
452
676
|
* Creates Google Vertex Project ID configuration
|
|
453
677
|
*/
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe Fetch — SSRF-hardened binary download helper.
|
|
3
|
+
*
|
|
4
|
+
* Combines:
|
|
5
|
+
* - `assertSafeUrl` (validates and rejects blocked IPs)
|
|
6
|
+
* - undici `Agent` with custom `connect.lookup` so the actual connection
|
|
7
|
+
* uses the IP we validated (closes the DNS-rebinding window where the
|
|
8
|
+
* resolver returns a public IP for the guard but a private IP for the
|
|
9
|
+
* real request).
|
|
10
|
+
* - `readBoundedBuffer` for size cap.
|
|
11
|
+
* - `redirect: "manual"` so a 3xx → private-IP redirect can't bypass
|
|
12
|
+
* the guard.
|
|
13
|
+
*
|
|
14
|
+
* Use this for **every** download of an external (caller-supplied or
|
|
15
|
+
* third-party-returned) URL. Direct `fetch(url)` of such URLs is unsafe.
|
|
16
|
+
*
|
|
17
|
+
* @module utils/safeFetch
|
|
18
|
+
*/
|
|
19
|
+
import type { SafeDownloadOptions } from "../types/index.js";
|
|
20
|
+
/**
|
|
21
|
+
* Safely download a binary asset from an external URL.
|
|
22
|
+
*
|
|
23
|
+
* @throws {Error} if the URL is unsafe, the response is too large, a redirect
|
|
24
|
+
* is encountered, or the HTTP status indicates failure.
|
|
25
|
+
*/
|
|
26
|
+
export declare function safeDownload(url: string, options: SafeDownloadOptions): Promise<Buffer>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe Fetch — SSRF-hardened binary download helper.
|
|
3
|
+
*
|
|
4
|
+
* Combines:
|
|
5
|
+
* - `assertSafeUrl` (validates and rejects blocked IPs)
|
|
6
|
+
* - undici `Agent` with custom `connect.lookup` so the actual connection
|
|
7
|
+
* uses the IP we validated (closes the DNS-rebinding window where the
|
|
8
|
+
* resolver returns a public IP for the guard but a private IP for the
|
|
9
|
+
* real request).
|
|
10
|
+
* - `readBoundedBuffer` for size cap.
|
|
11
|
+
* - `redirect: "manual"` so a 3xx → private-IP redirect can't bypass
|
|
12
|
+
* the guard.
|
|
13
|
+
*
|
|
14
|
+
* Use this for **every** download of an external (caller-supplied or
|
|
15
|
+
* third-party-returned) URL. Direct `fetch(url)` of such URLs is unsafe.
|
|
16
|
+
*
|
|
17
|
+
* @module utils/safeFetch
|
|
18
|
+
*/
|
|
19
|
+
import { Agent, fetch as undiciFetch } from "undici";
|
|
20
|
+
import { readBoundedBuffer } from "./sizeGuard.js";
|
|
21
|
+
import { validateAndResolveUrl } from "./ssrfGuard.js";
|
|
22
|
+
const DEFAULT_TIMEOUT_MS = 60_000;
|
|
23
|
+
/**
|
|
24
|
+
* Build a once-off undici Agent whose connect lookup resolves `hostname` to a
|
|
25
|
+
* fixed IP. This pins the actual TCP connection to the IP we validated,
|
|
26
|
+
* removing the DNS-rebinding window.
|
|
27
|
+
*/
|
|
28
|
+
function buildPinnedAgent(hostname, ip, family) {
|
|
29
|
+
return new Agent({
|
|
30
|
+
connect: {
|
|
31
|
+
lookup: (host, _options, callback) => {
|
|
32
|
+
if (host.toLowerCase() !== hostname.toLowerCase()) {
|
|
33
|
+
// The host the connect layer asks for differs from the URL host —
|
|
34
|
+
// this happens for absolute Host headers etc. Reject defensively.
|
|
35
|
+
callback(new Error(`safeFetch: refusing to resolve "${host}" — expected "${hostname}"`), "", 0);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
callback(null, ip, family);
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Safely download a binary asset from an external URL.
|
|
45
|
+
*
|
|
46
|
+
* @throws {Error} if the URL is unsafe, the response is too large, a redirect
|
|
47
|
+
* is encountered, or the HTTP status indicates failure.
|
|
48
|
+
*/
|
|
49
|
+
export async function safeDownload(url, options) {
|
|
50
|
+
const { url: validatedUrl, ip, family } = await validateAndResolveUrl(url);
|
|
51
|
+
const parsed = new URL(validatedUrl);
|
|
52
|
+
const hostname = parsed.hostname.replace(/^\[|\]$/g, "");
|
|
53
|
+
const agent = buildPinnedAgent(hostname, ip, family);
|
|
54
|
+
const timeoutCtrl = new AbortController();
|
|
55
|
+
const timeoutId = setTimeout(() => timeoutCtrl.abort(), options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
56
|
+
const composedSignal = options.signal
|
|
57
|
+
? AbortSignal.any([options.signal, timeoutCtrl.signal])
|
|
58
|
+
: timeoutCtrl.signal;
|
|
59
|
+
let response;
|
|
60
|
+
try {
|
|
61
|
+
response = await undiciFetch(validatedUrl, {
|
|
62
|
+
method: "GET",
|
|
63
|
+
signal: composedSignal,
|
|
64
|
+
redirect: "manual", // a 3xx → private-IP redirect would bypass the guard
|
|
65
|
+
dispatcher: agent,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
clearTimeout(timeoutId);
|
|
70
|
+
// Close the per-request agent so the pinned connection isn't pooled.
|
|
71
|
+
agent.close().catch(() => undefined);
|
|
72
|
+
}
|
|
73
|
+
if (response.status >= 300 && response.status < 400) {
|
|
74
|
+
throw new Error(`safeDownload(${options.label}): refused to follow redirect ${response.status} → ${response.headers.get("location") ?? "<no-location>"} (for ${url})`);
|
|
75
|
+
}
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
throw new Error(`safeDownload(${options.label}) failed: HTTP ${response.status} for ${url}`);
|
|
78
|
+
}
|
|
79
|
+
// readBoundedBuffer expects a Response that exposes Content-Length and
|
|
80
|
+
// arrayBuffer(). undici Response satisfies both.
|
|
81
|
+
return readBoundedBuffer(response, options.maxBytes, options.label);
|
|
82
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Size Guard Utility
|
|
3
|
+
*
|
|
4
|
+
* Provides bounded binary downloads to prevent OOM when fetching generated
|
|
5
|
+
* media from external providers. Applies a Content-Length pre-check and a
|
|
6
|
+
* post-buffer guard so multi-GB responses are rejected before they fully
|
|
7
|
+
* materialise in process memory.
|
|
8
|
+
*
|
|
9
|
+
* @module utils/sizeGuard
|
|
10
|
+
*/
|
|
11
|
+
/** 256 MiB — suitable for video output (MP4). */
|
|
12
|
+
export declare const MAX_VIDEO_BYTES: number;
|
|
13
|
+
/** 50 MiB — suitable for audio output (MP3/WAV). */
|
|
14
|
+
export declare const MAX_AUDIO_BYTES: number;
|
|
15
|
+
/** 25 MiB — suitable for image output (PNG/JPEG/WebP). */
|
|
16
|
+
export declare const MAX_IMAGE_BYTES: number;
|
|
17
|
+
/**
|
|
18
|
+
* Download the body of a {@link Response} into a {@link Buffer}, enforcing an
|
|
19
|
+
* upper-bound on the number of bytes consumed.
|
|
20
|
+
*
|
|
21
|
+
* Two checks are performed:
|
|
22
|
+
* 1. If the response includes a `Content-Length` header that exceeds
|
|
23
|
+
* `maxBytes`, the download is rejected immediately (no data is read).
|
|
24
|
+
* 2. After buffering, the actual buffer size is verified against `maxBytes`.
|
|
25
|
+
* This catches chunked transfers where no `Content-Length` was provided.
|
|
26
|
+
*
|
|
27
|
+
* @param response The fetch {@link Response} to drain.
|
|
28
|
+
* @param maxBytes Maximum number of bytes allowed.
|
|
29
|
+
* @param label Human-readable identifier used in error messages
|
|
30
|
+
* (e.g. "Kling video", "D-ID result").
|
|
31
|
+
* @returns The response body as a {@link Buffer}.
|
|
32
|
+
* @throws {@link Error} when either size check fails.
|
|
33
|
+
*/
|
|
34
|
+
export declare function readBoundedBuffer(response: Response, maxBytes: number, label: string): Promise<Buffer>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Size Guard Utility
|
|
3
|
+
*
|
|
4
|
+
* Provides bounded binary downloads to prevent OOM when fetching generated
|
|
5
|
+
* media from external providers. Applies a Content-Length pre-check and a
|
|
6
|
+
* post-buffer guard so multi-GB responses are rejected before they fully
|
|
7
|
+
* materialise in process memory.
|
|
8
|
+
*
|
|
9
|
+
* @module utils/sizeGuard
|
|
10
|
+
*/
|
|
11
|
+
/** 256 MiB — suitable for video output (MP4). */
|
|
12
|
+
export const MAX_VIDEO_BYTES = 256 * 1024 * 1024;
|
|
13
|
+
/** 50 MiB — suitable for audio output (MP3/WAV). */
|
|
14
|
+
export const MAX_AUDIO_BYTES = 50 * 1024 * 1024;
|
|
15
|
+
/** 25 MiB — suitable for image output (PNG/JPEG/WebP). */
|
|
16
|
+
export const MAX_IMAGE_BYTES = 25 * 1024 * 1024;
|
|
17
|
+
/**
|
|
18
|
+
* Download the body of a {@link Response} into a {@link Buffer}, enforcing an
|
|
19
|
+
* upper-bound on the number of bytes consumed.
|
|
20
|
+
*
|
|
21
|
+
* Two checks are performed:
|
|
22
|
+
* 1. If the response includes a `Content-Length` header that exceeds
|
|
23
|
+
* `maxBytes`, the download is rejected immediately (no data is read).
|
|
24
|
+
* 2. After buffering, the actual buffer size is verified against `maxBytes`.
|
|
25
|
+
* This catches chunked transfers where no `Content-Length` was provided.
|
|
26
|
+
*
|
|
27
|
+
* @param response The fetch {@link Response} to drain.
|
|
28
|
+
* @param maxBytes Maximum number of bytes allowed.
|
|
29
|
+
* @param label Human-readable identifier used in error messages
|
|
30
|
+
* (e.g. "Kling video", "D-ID result").
|
|
31
|
+
* @returns The response body as a {@link Buffer}.
|
|
32
|
+
* @throws {@link Error} when either size check fails.
|
|
33
|
+
*/
|
|
34
|
+
export async function readBoundedBuffer(response, maxBytes, label) {
|
|
35
|
+
const contentLength = parseInt(response.headers.get("content-length") ?? "0", 10);
|
|
36
|
+
if (contentLength > 0 && contentLength > maxBytes) {
|
|
37
|
+
throw new Error(`${label} download too large: ${contentLength} bytes (max ${maxBytes})`);
|
|
38
|
+
}
|
|
39
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
40
|
+
if (buffer.length > maxBytes) {
|
|
41
|
+
throw new Error(`${label} download exceeded size cap after fetch: ${buffer.length} bytes (max ${maxBytes})`);
|
|
42
|
+
}
|
|
43
|
+
return buffer;
|
|
44
|
+
}
|