@fgv/ts-extras 5.1.0-5 → 5.1.0-50
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/LICENSE +1 -1
- package/README.md +90 -0
- package/dist/index.browser.js +6 -2
- package/dist/index.browser.js.map +1 -0
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -0
- package/dist/packlets/ai-assist/chatRequestBuilders.js +282 -0
- package/dist/packlets/ai-assist/chatRequestBuilders.js.map +1 -0
- package/dist/packlets/ai-assist/{apiClient.js → completionClient.js} +165 -214
- package/dist/packlets/ai-assist/completionClient.js.map +1 -0
- package/dist/packlets/ai-assist/converters.js +47 -3
- package/dist/packlets/ai-assist/converters.js.map +1 -0
- package/dist/packlets/ai-assist/embeddingClient.js +345 -0
- package/dist/packlets/ai-assist/embeddingClient.js.map +1 -0
- package/dist/packlets/ai-assist/endpoint.js +107 -0
- package/dist/packlets/ai-assist/endpoint.js.map +1 -0
- package/dist/packlets/ai-assist/http.js +104 -0
- package/dist/packlets/ai-assist/http.js.map +1 -0
- package/dist/packlets/ai-assist/imageGenerationClient.js +454 -0
- package/dist/packlets/ai-assist/imageGenerationClient.js.map +1 -0
- package/dist/packlets/ai-assist/imageOptionsResolver.js +193 -0
- package/dist/packlets/ai-assist/imageOptionsResolver.js.map +1 -0
- package/dist/packlets/ai-assist/index.js +12 -4
- package/dist/packlets/ai-assist/index.js.map +1 -0
- package/dist/packlets/ai-assist/jsonCompletion.js +93 -0
- package/dist/packlets/ai-assist/jsonCompletion.js.map +1 -0
- package/dist/packlets/ai-assist/jsonResponse.js +423 -0
- package/dist/packlets/ai-assist/jsonResponse.js.map +1 -0
- package/dist/packlets/ai-assist/listModelsClient.js +294 -0
- package/dist/packlets/ai-assist/listModelsClient.js.map +1 -0
- package/dist/packlets/ai-assist/model.js +301 -9
- package/dist/packlets/ai-assist/model.js.map +1 -0
- package/dist/packlets/ai-assist/registry.js +376 -12
- package/dist/packlets/ai-assist/registry.js.map +1 -0
- package/dist/packlets/ai-assist/sseParser.js +123 -0
- package/dist/packlets/ai-assist/sseParser.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js +376 -0
- package/dist/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +687 -0
- package/dist/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/common.js +187 -0
- package/dist/packlets/ai-assist/streamingAdapters/common.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js +208 -0
- package/dist/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js +175 -0
- package/dist/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js +390 -0
- package/dist/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -0
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js +178 -0
- package/dist/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -0
- package/dist/packlets/ai-assist/streamingClient.js +140 -0
- package/dist/packlets/ai-assist/streamingClient.js.map +1 -0
- package/dist/packlets/ai-assist/thinkingOptionsResolver.js +288 -0
- package/dist/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -0
- package/dist/packlets/ai-assist/toolFormats.js +106 -10
- package/dist/packlets/ai-assist/toolFormats.js.map +1 -0
- package/dist/packlets/conversion/converters.js +35 -1
- package/dist/packlets/conversion/converters.js.map +1 -0
- package/dist/packlets/conversion/index.js.map +1 -0
- package/dist/packlets/crypto-utils/constants.js.map +1 -0
- package/dist/packlets/crypto-utils/converters.js +42 -4
- package/dist/packlets/crypto-utils/converters.js.map +1 -0
- package/dist/packlets/crypto-utils/directEncryptionProvider.js.map +1 -0
- package/dist/packlets/crypto-utils/encryptedFile.js +37 -0
- package/dist/packlets/crypto-utils/encryptedFile.js.map +1 -0
- package/dist/packlets/crypto-utils/hpkeProvider.js +355 -0
- package/dist/packlets/crypto-utils/hpkeProvider.js.map +1 -0
- package/dist/packlets/crypto-utils/index.browser.js +13 -2
- package/dist/packlets/crypto-utils/index.browser.js.map +1 -0
- package/dist/packlets/crypto-utils/index.js +9 -1
- package/dist/packlets/crypto-utils/index.js.map +1 -0
- package/dist/packlets/crypto-utils/keyPairAlgorithmParams.js +71 -0
- package/dist/packlets/crypto-utils/keyPairAlgorithmParams.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/converters.js +111 -16
- package/dist/packlets/crypto-utils/keystore/converters.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js +287 -0
- package/dist/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/index.browser.js +36 -0
- package/dist/packlets/crypto-utils/keystore/index.browser.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/index.js +3 -0
- package/dist/packlets/crypto-utils/keystore/index.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/keyStore.js +872 -119
- package/dist/packlets/crypto-utils/keystore/keyStore.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/model.js +35 -4
- package/dist/packlets/crypto-utils/keystore/model.js.map +1 -0
- package/dist/packlets/crypto-utils/keystore/privateKeyStorage.js +21 -0
- package/dist/packlets/crypto-utils/keystore/privateKeyStorage.js.map +1 -0
- package/dist/packlets/crypto-utils/model.js +32 -0
- package/dist/packlets/crypto-utils/model.js.map +1 -0
- package/dist/packlets/crypto-utils/nodeCryptoProvider.js +347 -1
- package/dist/packlets/crypto-utils/nodeCryptoProvider.js.map +1 -0
- package/dist/packlets/crypto-utils/seedDerivedKeyPair.js +120 -0
- package/dist/packlets/crypto-utils/seedDerivedKeyPair.js.map +1 -0
- package/dist/packlets/crypto-utils/spkiHelpers.js +284 -0
- package/dist/packlets/crypto-utils/spkiHelpers.js.map +1 -0
- package/dist/packlets/csv/csvFileHelpers.js +0 -14
- package/dist/packlets/csv/csvFileHelpers.js.map +1 -0
- package/dist/packlets/csv/csvHelpers.js +14 -0
- package/dist/packlets/csv/csvHelpers.js.map +1 -0
- package/dist/packlets/csv/index.browser.js +1 -3
- package/dist/packlets/csv/index.browser.js.map +1 -0
- package/dist/packlets/csv/index.js.map +1 -0
- package/dist/packlets/experimental/extendedArray.js.map +1 -0
- package/dist/packlets/experimental/formatter.js.map +1 -0
- package/dist/packlets/experimental/index.js.map +1 -0
- package/dist/packlets/experimental/rangeOf.js.map +1 -0
- package/dist/packlets/hash/index.browser.js.map +1 -0
- package/dist/packlets/hash/index.js.map +1 -0
- package/dist/packlets/hash/index.node.js.map +1 -0
- package/dist/packlets/hash/md5Normalizer.browser.js.map +1 -0
- package/dist/packlets/hash/md5Normalizer.js.map +1 -0
- package/dist/packlets/mustache/index.js.map +1 -0
- package/dist/packlets/mustache/interfaces.js.map +1 -0
- package/dist/packlets/mustache/mustacheTemplate.js +42 -4
- package/dist/packlets/mustache/mustacheTemplate.js.map +1 -0
- package/dist/packlets/record-jar/index.browser.js +1 -3
- package/dist/packlets/record-jar/index.browser.js.map +1 -0
- package/dist/packlets/record-jar/index.js.map +1 -0
- package/dist/packlets/record-jar/recordJarFileHelpers.js +0 -18
- package/dist/packlets/record-jar/recordJarFileHelpers.js.map +1 -0
- package/dist/packlets/record-jar/recordJarHelpers.js +18 -0
- package/dist/packlets/record-jar/recordJarHelpers.js.map +1 -0
- package/dist/packlets/safer-fetch/addressClassification.js +438 -0
- package/dist/packlets/safer-fetch/addressClassification.js.map +1 -0
- package/dist/packlets/safer-fetch/addressPolicy.js +119 -0
- package/dist/packlets/safer-fetch/addressPolicy.js.map +1 -0
- package/dist/packlets/safer-fetch/contentType.js +120 -0
- package/dist/packlets/safer-fetch/contentType.js.map +1 -0
- package/dist/packlets/safer-fetch/deadline.js +254 -0
- package/dist/packlets/safer-fetch/deadline.js.map +1 -0
- package/dist/packlets/safer-fetch/defaults.js +131 -0
- package/dist/packlets/safer-fetch/defaults.js.map +1 -0
- package/dist/packlets/safer-fetch/failureReason.js +21 -0
- package/dist/packlets/safer-fetch/failureReason.js.map +1 -0
- package/dist/packlets/safer-fetch/guards.js +148 -0
- package/dist/packlets/safer-fetch/guards.js.map +1 -0
- package/dist/packlets/safer-fetch/index.browser.js +58 -0
- package/dist/packlets/safer-fetch/index.browser.js.map +1 -0
- package/dist/packlets/safer-fetch/index.js +52 -0
- package/dist/packlets/safer-fetch/index.js.map +1 -0
- package/dist/packlets/safer-fetch/model.js +21 -0
- package/dist/packlets/safer-fetch/model.js.map +1 -0
- package/dist/packlets/safer-fetch/nodeAddressGuard.js +191 -0
- package/dist/packlets/safer-fetch/nodeAddressGuard.js.map +1 -0
- package/dist/packlets/safer-fetch/redirect.js +93 -0
- package/dist/packlets/safer-fetch/redirect.js.map +1 -0
- package/dist/packlets/safer-fetch/retry.js +188 -0
- package/dist/packlets/safer-fetch/retry.js.map +1 -0
- package/dist/packlets/safer-fetch/saferFetch.js +755 -0
- package/dist/packlets/safer-fetch/saferFetch.js.map +1 -0
- package/dist/packlets/safer-fetch/transport.js +50 -0
- package/dist/packlets/safer-fetch/transport.js.map +1 -0
- package/dist/packlets/yaml/converters.js.map +1 -0
- package/dist/packlets/yaml/index.js +1 -0
- package/dist/packlets/yaml/index.js.map +1 -0
- package/dist/packlets/yaml/serializers.js +48 -0
- package/dist/packlets/yaml/serializers.js.map +1 -0
- package/dist/packlets/zip-file-tree/index.js.map +1 -0
- package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js +99 -9
- package/dist/packlets/zip-file-tree/zipFileTreeAccessors.js.map +1 -0
- package/dist/packlets/zip-file-tree/zipFileTreeWriter.js +16 -1
- package/dist/packlets/zip-file-tree/zipFileTreeWriter.js.map +1 -0
- package/dist/ts-extras.d.ts +6648 -553
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/index.browser.d.ts +5 -2
- package/lib/index.browser.d.ts.map +1 -0
- package/lib/index.browser.js +11 -3
- package/lib/index.browser.js.map +1 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -0
- package/lib/packlets/ai-assist/chatRequestBuilders.d.ts +149 -0
- package/lib/packlets/ai-assist/chatRequestBuilders.d.ts.map +1 -0
- package/lib/packlets/ai-assist/chatRequestBuilders.js +293 -0
- package/lib/packlets/ai-assist/chatRequestBuilders.js.map +1 -0
- package/lib/packlets/ai-assist/completionClient.d.ts +74 -0
- package/lib/packlets/ai-assist/completionClient.d.ts.map +1 -0
- package/lib/packlets/ai-assist/{apiClient.js → completionClient.js} +164 -213
- package/lib/packlets/ai-assist/completionClient.js.map +1 -0
- package/lib/packlets/ai-assist/converters.d.ts +15 -1
- package/lib/packlets/ai-assist/converters.d.ts.map +1 -0
- package/lib/packlets/ai-assist/converters.js +47 -3
- package/lib/packlets/ai-assist/converters.js.map +1 -0
- package/lib/packlets/ai-assist/embeddingClient.d.ts +69 -0
- package/lib/packlets/ai-assist/embeddingClient.d.ts.map +1 -0
- package/lib/packlets/ai-assist/embeddingClient.js +349 -0
- package/lib/packlets/ai-assist/embeddingClient.js.map +1 -0
- package/lib/packlets/ai-assist/endpoint.d.ts +49 -0
- package/lib/packlets/ai-assist/endpoint.d.ts.map +1 -0
- package/lib/packlets/ai-assist/endpoint.js +113 -0
- package/lib/packlets/ai-assist/endpoint.js.map +1 -0
- package/lib/packlets/ai-assist/http.d.ts +34 -0
- package/lib/packlets/ai-assist/http.d.ts.map +1 -0
- package/lib/packlets/ai-assist/http.js +109 -0
- package/lib/packlets/ai-assist/http.js.map +1 -0
- package/lib/packlets/ai-assist/imageGenerationClient.d.ts +46 -0
- package/lib/packlets/ai-assist/imageGenerationClient.d.ts.map +1 -0
- package/lib/packlets/ai-assist/imageGenerationClient.js +458 -0
- package/lib/packlets/ai-assist/imageGenerationClient.js.map +1 -0
- package/lib/packlets/ai-assist/imageOptionsResolver.d.ts +66 -0
- package/lib/packlets/ai-assist/imageOptionsResolver.d.ts.map +1 -0
- package/lib/packlets/ai-assist/imageOptionsResolver.js +197 -0
- package/lib/packlets/ai-assist/imageOptionsResolver.js.map +1 -0
- package/lib/packlets/ai-assist/index.d.ts +12 -4
- package/lib/packlets/ai-assist/index.d.ts.map +1 -0
- package/lib/packlets/ai-assist/index.js +47 -4
- package/lib/packlets/ai-assist/index.js.map +1 -0
- package/lib/packlets/ai-assist/jsonCompletion.d.ts +93 -0
- package/lib/packlets/ai-assist/jsonCompletion.d.ts.map +1 -0
- package/lib/packlets/ai-assist/jsonCompletion.js +97 -0
- package/lib/packlets/ai-assist/jsonCompletion.js.map +1 -0
- package/lib/packlets/ai-assist/jsonResponse.d.ts +194 -0
- package/lib/packlets/ai-assist/jsonResponse.d.ts.map +1 -0
- package/lib/packlets/ai-assist/jsonResponse.js +429 -0
- package/lib/packlets/ai-assist/jsonResponse.js.map +1 -0
- package/lib/packlets/ai-assist/listModelsClient.d.ts +46 -0
- package/lib/packlets/ai-assist/listModelsClient.d.ts.map +1 -0
- package/lib/packlets/ai-assist/listModelsClient.js +298 -0
- package/lib/packlets/ai-assist/listModelsClient.js.map +1 -0
- package/lib/packlets/ai-assist/model.d.ts +1346 -12
- package/lib/packlets/ai-assist/model.d.ts.map +1 -0
- package/lib/packlets/ai-assist/model.js +309 -10
- package/lib/packlets/ai-assist/model.js.map +1 -0
- package/lib/packlets/ai-assist/registry.d.ts +76 -1
- package/lib/packlets/ai-assist/registry.d.ts.map +1 -0
- package/lib/packlets/ai-assist/registry.js +381 -13
- package/lib/packlets/ai-assist/registry.js.map +1 -0
- package/lib/packlets/ai-assist/sseParser.d.ts +45 -0
- package/lib/packlets/ai-assist/sseParser.d.ts.map +1 -0
- package/lib/packlets/ai-assist/sseParser.js +128 -0
- package/lib/packlets/ai-assist/sseParser.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts +72 -0
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js +379 -0
- package/lib/packlets/ai-assist/streamingAdapters/anthropic.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts +269 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js +694 -0
- package/lib/packlets/ai-assist/streamingAdapters/clientToolContinuationBuilder.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts +163 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.js +193 -0
- package/lib/packlets/ai-assist/streamingAdapters/common.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts +43 -0
- package/lib/packlets/ai-assist/streamingAdapters/gemini.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js +211 -0
- package/lib/packlets/ai-assist/streamingAdapters/gemini.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts +19 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js +178 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiChat.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts +33 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js +393 -0
- package/lib/packlets/ai-assist/streamingAdapters/openaiResponses.js.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts +34 -0
- package/lib/packlets/ai-assist/streamingAdapters/proxy.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js +181 -0
- package/lib/packlets/ai-assist/streamingAdapters/proxy.js.map +1 -0
- package/lib/packlets/ai-assist/streamingClient.d.ts +50 -0
- package/lib/packlets/ai-assist/streamingClient.d.ts.map +1 -0
- package/lib/packlets/ai-assist/streamingClient.js +146 -0
- package/lib/packlets/ai-assist/streamingClient.js.map +1 -0
- package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts +87 -0
- package/lib/packlets/ai-assist/thinkingOptionsResolver.d.ts.map +1 -0
- package/lib/packlets/ai-assist/thinkingOptionsResolver.js +294 -0
- package/lib/packlets/ai-assist/thinkingOptionsResolver.js.map +1 -0
- package/lib/packlets/ai-assist/toolFormats.d.ts +40 -9
- package/lib/packlets/ai-assist/toolFormats.d.ts.map +1 -0
- package/lib/packlets/ai-assist/toolFormats.js +107 -10
- package/lib/packlets/ai-assist/toolFormats.js.map +1 -0
- package/lib/packlets/conversion/converters.d.ts +8 -1
- package/lib/packlets/conversion/converters.d.ts.map +1 -0
- package/lib/packlets/conversion/converters.js +36 -2
- package/lib/packlets/conversion/converters.js.map +1 -0
- package/lib/packlets/conversion/index.d.ts.map +1 -0
- package/lib/packlets/conversion/index.js.map +1 -0
- package/lib/packlets/crypto-utils/constants.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/constants.js.map +1 -0
- package/lib/packlets/crypto-utils/converters.d.ts +20 -1
- package/lib/packlets/crypto-utils/converters.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/converters.js +43 -5
- package/lib/packlets/crypto-utils/converters.js.map +1 -0
- package/lib/packlets/crypto-utils/directEncryptionProvider.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/directEncryptionProvider.js.map +1 -0
- package/lib/packlets/crypto-utils/encryptedFile.d.ts +25 -0
- package/lib/packlets/crypto-utils/encryptedFile.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/encryptedFile.js +38 -0
- package/lib/packlets/crypto-utils/encryptedFile.js.map +1 -0
- package/lib/packlets/crypto-utils/hpkeProvider.d.ts +150 -0
- package/lib/packlets/crypto-utils/hpkeProvider.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/hpkeProvider.js +359 -0
- package/lib/packlets/crypto-utils/hpkeProvider.js.map +1 -0
- package/lib/packlets/crypto-utils/index.browser.d.ts +5 -1
- package/lib/packlets/crypto-utils/index.browser.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/index.browser.js +28 -3
- package/lib/packlets/crypto-utils/index.browser.js.map +1 -0
- package/lib/packlets/crypto-utils/index.d.ts +5 -1
- package/lib/packlets/crypto-utils/index.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/index.js +24 -1
- package/lib/packlets/crypto-utils/index.js.map +1 -0
- package/lib/packlets/crypto-utils/keyPairAlgorithmParams.d.ts +54 -0
- package/lib/packlets/crypto-utils/keyPairAlgorithmParams.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keyPairAlgorithmParams.js +74 -0
- package/lib/packlets/crypto-utils/keyPairAlgorithmParams.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/converters.d.ts +68 -6
- package/lib/packlets/crypto-utils/keystore/converters.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/converters.js +109 -14
- package/lib/packlets/crypto-utils/keystore/converters.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.d.ts +148 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js +324 -0
- package/lib/packlets/crypto-utils/keystore/encryptedFilePrivateKeyStorage.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.d.ts +10 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.js +76 -0
- package/lib/packlets/crypto-utils/keystore/index.browser.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.d.ts +2 -0
- package/lib/packlets/crypto-utils/keystore/index.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/index.js +5 -1
- package/lib/packlets/crypto-utils/keystore/index.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/keyStore.d.ts +314 -13
- package/lib/packlets/crypto-utils/keystore/keyStore.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/keyStore.js +877 -124
- package/lib/packlets/crypto-utils/keystore/keyStore.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/model.d.ts +404 -21
- package/lib/packlets/crypto-utils/keystore/model.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/model.js +37 -5
- package/lib/packlets/crypto-utils/keystore/model.js.map +1 -0
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts +53 -0
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.js +22 -0
- package/lib/packlets/crypto-utils/keystore/privateKeyStorage.js.map +1 -0
- package/lib/packlets/crypto-utils/model.d.ts +518 -10
- package/lib/packlets/crypto-utils/model.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/model.js +33 -1
- package/lib/packlets/crypto-utils/model.js.map +1 -0
- package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts +142 -2
- package/lib/packlets/crypto-utils/nodeCryptoProvider.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/nodeCryptoProvider.js +346 -0
- package/lib/packlets/crypto-utils/nodeCryptoProvider.js.map +1 -0
- package/lib/packlets/crypto-utils/seedDerivedKeyPair.d.ts +42 -0
- package/lib/packlets/crypto-utils/seedDerivedKeyPair.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/seedDerivedKeyPair.js +123 -0
- package/lib/packlets/crypto-utils/seedDerivedKeyPair.js.map +1 -0
- package/lib/packlets/crypto-utils/spkiHelpers.d.ts +151 -0
- package/lib/packlets/crypto-utils/spkiHelpers.d.ts.map +1 -0
- package/lib/packlets/crypto-utils/spkiHelpers.js +297 -0
- package/lib/packlets/crypto-utils/spkiHelpers.js.map +1 -0
- package/lib/packlets/csv/csvFileHelpers.d.ts +0 -10
- package/lib/packlets/csv/csvFileHelpers.d.ts.map +1 -0
- package/lib/packlets/csv/csvFileHelpers.js +0 -15
- package/lib/packlets/csv/csvFileHelpers.js.map +1 -0
- package/lib/packlets/csv/csvHelpers.d.ts +10 -0
- package/lib/packlets/csv/csvHelpers.d.ts.map +1 -0
- package/lib/packlets/csv/csvHelpers.js +15 -0
- package/lib/packlets/csv/csvHelpers.js.map +1 -0
- package/lib/packlets/csv/index.browser.d.ts +0 -1
- package/lib/packlets/csv/index.browser.d.ts.map +1 -0
- package/lib/packlets/csv/index.browser.js +1 -5
- package/lib/packlets/csv/index.browser.js.map +1 -0
- package/lib/packlets/csv/index.d.ts.map +1 -0
- package/lib/packlets/csv/index.js.map +1 -0
- package/lib/packlets/experimental/extendedArray.d.ts.map +1 -0
- package/lib/packlets/experimental/extendedArray.js.map +1 -0
- package/lib/packlets/experimental/formatter.d.ts.map +1 -0
- package/lib/packlets/experimental/formatter.js.map +1 -0
- package/lib/packlets/experimental/index.d.ts.map +1 -0
- package/lib/packlets/experimental/index.js.map +1 -0
- package/lib/packlets/experimental/rangeOf.d.ts.map +1 -0
- package/lib/packlets/experimental/rangeOf.js.map +1 -0
- package/lib/packlets/hash/index.browser.d.ts.map +1 -0
- package/lib/packlets/hash/index.browser.js.map +1 -0
- package/lib/packlets/hash/index.d.ts.map +1 -0
- package/lib/packlets/hash/index.js.map +1 -0
- package/lib/packlets/hash/index.node.d.ts.map +1 -0
- package/lib/packlets/hash/index.node.js.map +1 -0
- package/lib/packlets/hash/md5Normalizer.browser.d.ts.map +1 -0
- package/lib/packlets/hash/md5Normalizer.browser.js.map +1 -0
- package/lib/packlets/hash/md5Normalizer.d.ts.map +1 -0
- package/lib/packlets/hash/md5Normalizer.js.map +1 -0
- package/lib/packlets/mustache/index.d.ts +1 -1
- package/lib/packlets/mustache/index.d.ts.map +1 -0
- package/lib/packlets/mustache/index.js.map +1 -0
- package/lib/packlets/mustache/interfaces.d.ts +34 -0
- package/lib/packlets/mustache/interfaces.d.ts.map +1 -0
- package/lib/packlets/mustache/interfaces.js.map +1 -0
- package/lib/packlets/mustache/mustacheTemplate.d.ts +2 -0
- package/lib/packlets/mustache/mustacheTemplate.d.ts.map +1 -0
- package/lib/packlets/mustache/mustacheTemplate.js +42 -4
- package/lib/packlets/mustache/mustacheTemplate.js.map +1 -0
- package/lib/packlets/record-jar/index.browser.d.ts +0 -1
- package/lib/packlets/record-jar/index.browser.d.ts.map +1 -0
- package/lib/packlets/record-jar/index.browser.js +1 -5
- package/lib/packlets/record-jar/index.browser.js.map +1 -0
- package/lib/packlets/record-jar/index.d.ts.map +1 -0
- package/lib/packlets/record-jar/index.js.map +1 -0
- package/lib/packlets/record-jar/recordJarFileHelpers.d.ts +0 -11
- package/lib/packlets/record-jar/recordJarFileHelpers.d.ts.map +1 -0
- package/lib/packlets/record-jar/recordJarFileHelpers.js +0 -19
- package/lib/packlets/record-jar/recordJarFileHelpers.js.map +1 -0
- package/lib/packlets/record-jar/recordJarHelpers.d.ts +11 -0
- package/lib/packlets/record-jar/recordJarHelpers.d.ts.map +1 -0
- package/lib/packlets/record-jar/recordJarHelpers.js +19 -0
- package/lib/packlets/record-jar/recordJarHelpers.js.map +1 -0
- package/lib/packlets/safer-fetch/addressClassification.d.ts +144 -0
- package/lib/packlets/safer-fetch/addressClassification.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/addressClassification.js +441 -0
- package/lib/packlets/safer-fetch/addressClassification.js.map +1 -0
- package/lib/packlets/safer-fetch/addressPolicy.d.ts +113 -0
- package/lib/packlets/safer-fetch/addressPolicy.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/addressPolicy.js +123 -0
- package/lib/packlets/safer-fetch/addressPolicy.js.map +1 -0
- package/lib/packlets/safer-fetch/contentType.d.ts +51 -0
- package/lib/packlets/safer-fetch/contentType.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/contentType.js +127 -0
- package/lib/packlets/safer-fetch/contentType.js.map +1 -0
- package/lib/packlets/safer-fetch/deadline.d.ts +138 -0
- package/lib/packlets/safer-fetch/deadline.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/deadline.js +258 -0
- package/lib/packlets/safer-fetch/deadline.js.map +1 -0
- package/lib/packlets/safer-fetch/defaults.d.ts +108 -0
- package/lib/packlets/safer-fetch/defaults.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/defaults.js +134 -0
- package/lib/packlets/safer-fetch/defaults.js.map +1 -0
- package/lib/packlets/safer-fetch/failureReason.d.ts +148 -0
- package/lib/packlets/safer-fetch/failureReason.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/failureReason.js +22 -0
- package/lib/packlets/safer-fetch/failureReason.js.map +1 -0
- package/lib/packlets/safer-fetch/guards.d.ts +62 -0
- package/lib/packlets/safer-fetch/guards.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/guards.js +153 -0
- package/lib/packlets/safer-fetch/guards.js.map +1 -0
- package/lib/packlets/safer-fetch/index.browser.d.ts +33 -0
- package/lib/packlets/safer-fetch/index.browser.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/index.browser.js +82 -0
- package/lib/packlets/safer-fetch/index.browser.js.map +1 -0
- package/lib/packlets/safer-fetch/index.d.ts +27 -0
- package/lib/packlets/safer-fetch/index.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/index.js +78 -0
- package/lib/packlets/safer-fetch/index.js.map +1 -0
- package/lib/packlets/safer-fetch/model.d.ts +373 -0
- package/lib/packlets/safer-fetch/model.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/model.js +22 -0
- package/lib/packlets/safer-fetch/model.js.map +1 -0
- package/lib/packlets/safer-fetch/nodeAddressGuard.d.ts +129 -0
- package/lib/packlets/safer-fetch/nodeAddressGuard.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/nodeAddressGuard.js +196 -0
- package/lib/packlets/safer-fetch/nodeAddressGuard.js.map +1 -0
- package/lib/packlets/safer-fetch/redirect.d.ts +62 -0
- package/lib/packlets/safer-fetch/redirect.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/redirect.js +98 -0
- package/lib/packlets/safer-fetch/redirect.js.map +1 -0
- package/lib/packlets/safer-fetch/retry.d.ts +162 -0
- package/lib/packlets/safer-fetch/retry.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/retry.js +197 -0
- package/lib/packlets/safer-fetch/retry.js.map +1 -0
- package/lib/packlets/safer-fetch/saferFetch.d.ts +108 -0
- package/lib/packlets/safer-fetch/saferFetch.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/saferFetch.js +760 -0
- package/lib/packlets/safer-fetch/saferFetch.js.map +1 -0
- package/lib/packlets/safer-fetch/transport.d.ts +18 -0
- package/lib/packlets/safer-fetch/transport.d.ts.map +1 -0
- package/lib/packlets/safer-fetch/transport.js +53 -0
- package/lib/packlets/safer-fetch/transport.js.map +1 -0
- package/lib/packlets/yaml/converters.d.ts.map +1 -0
- package/lib/packlets/yaml/converters.js.map +1 -0
- package/lib/packlets/yaml/index.d.ts +1 -0
- package/lib/packlets/yaml/index.d.ts.map +1 -0
- package/lib/packlets/yaml/index.js +1 -0
- package/lib/packlets/yaml/index.js.map +1 -0
- package/lib/packlets/yaml/serializers.d.ts +45 -0
- package/lib/packlets/yaml/serializers.d.ts.map +1 -0
- package/lib/packlets/yaml/serializers.js +84 -0
- package/lib/packlets/yaml/serializers.js.map +1 -0
- package/lib/packlets/zip-file-tree/index.d.ts.map +1 -0
- package/lib/packlets/zip-file-tree/index.js.map +1 -0
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts +84 -8
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.d.ts.map +1 -0
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js +99 -9
- package/lib/packlets/zip-file-tree/zipFileTreeAccessors.js.map +1 -0
- package/lib/packlets/zip-file-tree/zipFileTreeWriter.d.ts +26 -1
- package/lib/packlets/zip-file-tree/zipFileTreeWriter.d.ts.map +1 -0
- package/lib/packlets/zip-file-tree/zipFileTreeWriter.js +17 -1
- package/lib/packlets/zip-file-tree/zipFileTreeWriter.js.map +1 -0
- package/package.json +30 -15
- package/lib/packlets/ai-assist/apiClient.d.ts +0 -60
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/endpoint.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AACxE,2DAA2D;AAC3D,EAAE;AACF,iFAAiF;AACjF,kDAAkD;AAClD,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,8EAA8E;AAC9E,yEAAyE;AACzE,gFAAgF;AAChF,gFAAgF;AAChF,YAAY;AAEZ;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAU,OAAO,EAAE,MAAM,eAAe,CAAC;AAItD;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACxE,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAc;IACjD,OAAO;QACL,WAAW,EAAE,MAAM;QACnB,mBAAmB,EAAE,YAAY;QACjC,2CAA2C,EAAE,MAAM;KACpD,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAC;AACtC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CACrC,UAAiC,EACjC,QAAiB;IAEjB,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,aAAa,UAAU,CAAC,EAAE,kCAAkC,CAAC,CAAC;QAC5E,CAAC;QACD,OAAO,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC;IACD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1D,OAAO,IAAI,CAAC,aAAa,UAAU,CAAC,EAAE,6CAA6C,CAAC,CAAC;IACvF,CAAC;IACD,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,IAAI,CAAC,aAAa,UAAU,CAAC,EAAE,gCAAgC,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAChE,OAAO,IAAI,CAAC,aAAa,UAAU,CAAC,EAAE,2CAA2C,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvG,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvD,OAAO,IAAI,CAAC,aAAa,UAAU,CAAC,EAAE,yDAAyD,CAAC,CAAC;IACnG,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7D,OAAO,IAAI,CACT,aAAa,UAAU,CAAC,EAAE,4EAA4E,CACvG,CAAC;IACJ,CAAC;IACD,uEAAuE;IACvE,wEAAwE;IACxE,sCAAsC;IACtC,OAAO,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3E,CAAC","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Helper for resolving a request's effective base URL from a provider\n * descriptor and an optional caller-supplied endpoint override.\n *\n * @packageDocumentation\n */\n\nimport { fail, Result, succeed } from '@fgv/ts-utils';\n\nimport { type IAiProviderDescriptor } from './model';\n\n/**\n * Builds an OpenAI-style `Authorization: Bearer ${key}` header, or an empty\n * record when the key is empty. Self-hosted/local OpenAI-compatible servers\n * (Ollama, LM Studio, llama.cpp) often reject `Authorization: Bearer ` with\n * an empty key, so we omit the header entirely in that case.\n *\n * @internal\n */\nexport function bearerAuthHeader(apiKey: string): Record<string, string> {\n return apiKey.length > 0 ? { Authorization: `Bearer ${apiKey}` } : {};\n}\n\n/**\n * The Anthropic Messages API auth + protocol headers.\n *\n * @remarks\n * `anthropic-version` is a **wire-protocol pin**, and single-sourcing it here is\n * the point of this helper: it was previously replicated across the completion\n * client, the list-models client and the streaming adapter, so bumping it was a\n * three-file edit with nothing to catch a miss.\n *\n * `anthropic-dangerous-direct-browser-access` is required for browser callers;\n * it is sent unconditionally because the same client code serves both runtimes.\n *\n * @internal\n */\nexport function anthropicAuthHeaders(apiKey: string): Record<string, string> {\n return {\n 'x-api-key': apiKey,\n 'anthropic-version': '2023-06-01',\n 'anthropic-dangerous-direct-browser-access': 'true'\n };\n}\n\n/**\n * The Gemini API auth header. Gemini keys ride in `x-goog-api-key` rather than\n * an `Authorization` bearer.\n * @internal\n */\nexport function geminiAuthHeader(apiKey: string): Record<string, string> {\n return { 'x-goog-api-key': apiKey };\n}\n\n/**\n * Resolves the effective base URL for a request, validating the optional\n * `endpoint` override when present. Returns the URL with any trailing slash\n * stripped so per-route suffix concatenation (e.g. `/chat/completions`)\n * produces the same shape regardless of whether the caller supplied an\n * override or the descriptor's default is used.\n *\n * @internal\n */\nexport function resolveEffectiveBaseUrl(\n descriptor: IAiProviderDescriptor,\n endpoint?: string\n): Result<string> {\n if (endpoint === undefined) {\n if (!descriptor.baseUrl) {\n return fail(`provider \"${descriptor.id}\" has no API endpoint configured`);\n }\n return succeed(descriptor.baseUrl.replace(/\\/+$/, ''));\n }\n if (typeof endpoint !== 'string' || endpoint.length === 0) {\n return fail(`provider \"${descriptor.id}\": endpoint must be a non-empty http(s) URL`);\n }\n let parsed: URL;\n try {\n parsed = new URL(endpoint);\n } catch {\n return fail(`provider \"${descriptor.id}\": endpoint is not a valid URL`);\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n return fail(`provider \"${descriptor.id}\": endpoint must use http or https (got ${parsed.protocol})`);\n }\n if (parsed.search.length > 0 || parsed.hash.length > 0) {\n return fail(`provider \"${descriptor.id}\": endpoint must not include a query string or fragment`);\n }\n if (parsed.username.length > 0 || parsed.password.length > 0) {\n return fail(\n `provider \"${descriptor.id}\": endpoint must not include userinfo; pass credentials via apiKey instead`\n );\n }\n // Reconstruct from origin + pathname so the returned URL is normalized\n // (no userinfo, no query, no fragment) and the suffix concat in callers\n // produces a well-formed request URL.\n return succeed(`${parsed.origin}${parsed.pathname}`.replace(/\\/+$/, ''));\n}\n"]}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Copyright (c) 2026 Erik Fortune
|
|
2
|
+
//
|
|
3
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
// in the Software without restriction, including without limitation the rights
|
|
6
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
// furnished to do so, subject to the following conditions:
|
|
9
|
+
//
|
|
10
|
+
// The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
// copies or substantial portions of the Software.
|
|
12
|
+
//
|
|
13
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
// SOFTWARE.
|
|
20
|
+
/**
|
|
21
|
+
* Shared low-level HTTP helpers for the AI-assist provider clients (completion,
|
|
22
|
+
* image generation, embedding). Internal to the packlet.
|
|
23
|
+
* @packageDocumentation
|
|
24
|
+
*/
|
|
25
|
+
import { isJsonObject } from '@fgv/ts-json-base';
|
|
26
|
+
import { captureAsyncResult, fail, succeed } from '@fgv/ts-utils';
|
|
27
|
+
/**
|
|
28
|
+
* Issue one request and parse a JSON object body, or fail.
|
|
29
|
+
*
|
|
30
|
+
* @remarks
|
|
31
|
+
* The single implementation behind {@link fetchJson}, {@link fetchGetJson} and
|
|
32
|
+
* {@link fetchMultipart} — the three differed *only* in how they built their
|
|
33
|
+
* `RequestInit` and what they logged, and carried byte-identical copies of
|
|
34
|
+
* everything after the `fetch` call. Non-2xx responses, network errors, invalid
|
|
35
|
+
* JSON and non-object JSON bodies are all surfaced as `Result.fail`.
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
async function _fetchAndParseJson(url, init, requestLabel, logger) {
|
|
39
|
+
/* c8 ignore next 1 - optional logger */
|
|
40
|
+
logger === null || logger === void 0 ? void 0 : logger.detail(`AI API request: ${requestLabel}`);
|
|
41
|
+
// `captureAsyncResult` normalizes both a synchronous throw and a rejected
|
|
42
|
+
// promise, and its `_errorMessage` is the same `instanceof Error` shaping this
|
|
43
|
+
// used to spell out by hand — so the failure text is unchanged and the
|
|
44
|
+
// defensive `c8 ignore` on the non-Error branch is no longer needed here.
|
|
45
|
+
const fetched = await captureAsyncResult(() => fetch(url, init)).withErrorFormat((msg) => `AI API request failed: ${msg}`);
|
|
46
|
+
if (fetched.isFailure()) {
|
|
47
|
+
/* c8 ignore next 1 - optional logger */
|
|
48
|
+
logger === null || logger === void 0 ? void 0 : logger.error(fetched.message);
|
|
49
|
+
return fail(fetched.message);
|
|
50
|
+
}
|
|
51
|
+
const response = fetched.value;
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
const errorText = await response.text().catch(() => 'unknown error');
|
|
54
|
+
/* c8 ignore next 1 - optional logger */
|
|
55
|
+
logger === null || logger === void 0 ? void 0 : logger.error(`AI API returned ${response.status}: ${errorText}`);
|
|
56
|
+
return fail(`AI API returned ${response.status}: ${errorText}`);
|
|
57
|
+
}
|
|
58
|
+
/* c8 ignore next 1 - optional logger */
|
|
59
|
+
logger === null || logger === void 0 ? void 0 : logger.detail(`AI API response: ${response.status}`);
|
|
60
|
+
let json;
|
|
61
|
+
try {
|
|
62
|
+
json = await response.json();
|
|
63
|
+
}
|
|
64
|
+
catch (_a) {
|
|
65
|
+
/* c8 ignore next 1 - optional logger */
|
|
66
|
+
logger === null || logger === void 0 ? void 0 : logger.error('AI API returned invalid JSON response');
|
|
67
|
+
return fail('AI API returned invalid JSON response');
|
|
68
|
+
}
|
|
69
|
+
if (!isJsonObject(json)) {
|
|
70
|
+
/* c8 ignore next 1 - optional logger */
|
|
71
|
+
logger === null || logger === void 0 ? void 0 : logger.error('AI API returned non-object JSON response');
|
|
72
|
+
return fail('AI API returned non-object JSON response');
|
|
73
|
+
}
|
|
74
|
+
return succeed(json);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Makes a JSON POST request and returns the parsed object body, or a failure.
|
|
78
|
+
* @internal
|
|
79
|
+
*/
|
|
80
|
+
export async function fetchJson(url, headers, body, logger, signal) {
|
|
81
|
+
return _fetchAndParseJson(url, {
|
|
82
|
+
method: 'POST',
|
|
83
|
+
headers: Object.assign({ 'Content-Type': 'application/json' }, headers),
|
|
84
|
+
body: JSON.stringify(body),
|
|
85
|
+
signal
|
|
86
|
+
}, `POST ${url}`, logger);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Makes an HTTP GET request and returns the parsed JSON, or a failure.
|
|
90
|
+
* @internal
|
|
91
|
+
*/
|
|
92
|
+
export async function fetchGetJson(url, headers, logger, signal) {
|
|
93
|
+
return _fetchAndParseJson(url, { method: 'GET', headers, signal }, `GET ${url}`, logger);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Makes a multipart/form-data POST request and returns the parsed JSON, or a
|
|
97
|
+
* failure. The Content-Type header (with boundary) is set automatically by
|
|
98
|
+
* `fetch` from the `FormData` body — callers must NOT pass it explicitly.
|
|
99
|
+
* @internal
|
|
100
|
+
*/
|
|
101
|
+
export async function fetchMultipart(url, headers, body, logger, signal) {
|
|
102
|
+
return _fetchAndParseJson(url, { method: 'POST', headers, body, signal }, `POST ${url} (multipart)`, logger);
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/packlets/ai-assist/http.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AACxE,2DAA2D;AAC3D,EAAE;AACF,iFAAiF;AACjF,kDAAkD;AAClD,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,8EAA8E;AAC9E,yEAAyE;AACzE,gFAAgF;AAChF,gFAAgF;AAChF,YAAY;AAEZ;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAmB,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAwB,OAAO,EAAE,MAAM,eAAe,CAAC;AAYxF;;;;;;;;;;GAUG;AACH,KAAK,UAAU,kBAAkB,CAC/B,GAAW,EACX,IAAiB,EACjB,YAAoB,EACpB,MAAwB;IAExB,wCAAwC;IACxC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,MAAM,CAAC,mBAAmB,YAAY,EAAE,CAAC,CAAC;IAElD,0EAA0E;IAC1E,+EAA+E;IAC/E,uEAAuE;IACvE,0EAA0E;IAC1E,MAAM,OAAO,GAAqB,MAAM,kBAAkB,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,eAAe,CAChG,CAAC,GAAG,EAAE,EAAE,CAAC,0BAA0B,GAAG,EAAE,CACzC,CAAC;IACF,IAAI,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;QACxB,wCAAwC;QACxC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IACD,MAAM,QAAQ,GAAa,OAAO,CAAC,KAAK,CAAC;IAEzC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC;QACrE,wCAAwC;QACxC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,CAAC,mBAAmB,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC,mBAAmB,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,wCAAwC;IACxC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,MAAM,CAAC,oBAAoB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAEtD,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAAC,WAAM,CAAC;QACP,wCAAwC;QACxC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC,uCAAuC,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,wCAAwC;QACxC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC,0CAA0C,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;AACvB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,GAAW,EACX,OAA+B,EAC/B,IAAa,EACb,MAAwB,EACxB,MAAoB;IAEpB,OAAO,kBAAkB,CACvB,GAAG,EACH;QACE,MAAM,EAAE,MAAM;QACd,OAAO,kBAAI,cAAc,EAAE,kBAAkB,IAAK,OAAO,CAAE;QAC3D,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;QAC1B,MAAM;KACP,EACD,QAAQ,GAAG,EAAE,EACb,MAAM,CACP,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAW,EACX,OAA+B,EAC/B,MAAwB,EACxB,MAAoB;IAEpB,OAAO,kBAAkB,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;AAC3F,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAW,EACX,OAA+B,EAC/B,IAAc,EACd,MAAwB,EACxB,MAAoB;IAEpB,OAAO,kBAAkB,CACvB,GAAG,EACH,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EACzC,QAAQ,GAAG,cAAc,EACzB,MAAM,CACP,CAAC;AACJ,CAAC","sourcesContent":["// Copyright (c) 2026 Erik Fortune\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in all\n// copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n// SOFTWARE.\n\n/**\n * Shared low-level HTTP helpers for the AI-assist provider clients (completion,\n * image generation, embedding). Internal to the packlet.\n * @packageDocumentation\n */\n\nimport { isJsonObject, type JsonObject } from '@fgv/ts-json-base';\nimport { captureAsyncResult, fail, type Logging, Result, succeed } from '@fgv/ts-utils';\n\n/**\n * Internal API configuration built from a provider descriptor.\n * @internal\n */\nexport interface IAiApiConfig {\n readonly baseUrl: string;\n readonly apiKey: string;\n readonly model: string;\n}\n\n/**\n * Issue one request and parse a JSON object body, or fail.\n *\n * @remarks\n * The single implementation behind {@link fetchJson}, {@link fetchGetJson} and\n * {@link fetchMultipart} — the three differed *only* in how they built their\n * `RequestInit` and what they logged, and carried byte-identical copies of\n * everything after the `fetch` call. Non-2xx responses, network errors, invalid\n * JSON and non-object JSON bodies are all surfaced as `Result.fail`.\n * @internal\n */\nasync function _fetchAndParseJson(\n url: string,\n init: RequestInit,\n requestLabel: string,\n logger?: Logging.ILogger\n): Promise<Result<JsonObject>> {\n /* c8 ignore next 1 - optional logger */\n logger?.detail(`AI API request: ${requestLabel}`);\n\n // `captureAsyncResult` normalizes both a synchronous throw and a rejected\n // promise, and its `_errorMessage` is the same `instanceof Error` shaping this\n // used to spell out by hand — so the failure text is unchanged and the\n // defensive `c8 ignore` on the non-Error branch is no longer needed here.\n const fetched: Result<Response> = await captureAsyncResult(() => fetch(url, init)).withErrorFormat(\n (msg) => `AI API request failed: ${msg}`\n );\n if (fetched.isFailure()) {\n /* c8 ignore next 1 - optional logger */\n logger?.error(fetched.message);\n return fail(fetched.message);\n }\n const response: Response = fetched.value;\n\n if (!response.ok) {\n const errorText = await response.text().catch(() => 'unknown error');\n /* c8 ignore next 1 - optional logger */\n logger?.error(`AI API returned ${response.status}: ${errorText}`);\n return fail(`AI API returned ${response.status}: ${errorText}`);\n }\n\n /* c8 ignore next 1 - optional logger */\n logger?.detail(`AI API response: ${response.status}`);\n\n let json: unknown;\n try {\n json = await response.json();\n } catch {\n /* c8 ignore next 1 - optional logger */\n logger?.error('AI API returned invalid JSON response');\n return fail('AI API returned invalid JSON response');\n }\n\n if (!isJsonObject(json)) {\n /* c8 ignore next 1 - optional logger */\n logger?.error('AI API returned non-object JSON response');\n return fail('AI API returned non-object JSON response');\n }\n return succeed(json);\n}\n\n/**\n * Makes a JSON POST request and returns the parsed object body, or a failure.\n * @internal\n */\nexport async function fetchJson(\n url: string,\n headers: Record<string, string>,\n body: unknown,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<JsonObject>> {\n return _fetchAndParseJson(\n url,\n {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...headers },\n body: JSON.stringify(body),\n signal\n },\n `POST ${url}`,\n logger\n );\n}\n\n/**\n * Makes an HTTP GET request and returns the parsed JSON, or a failure.\n * @internal\n */\nexport async function fetchGetJson(\n url: string,\n headers: Record<string, string>,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<JsonObject>> {\n return _fetchAndParseJson(url, { method: 'GET', headers, signal }, `GET ${url}`, logger);\n}\n\n/**\n * Makes a multipart/form-data POST request and returns the parsed JSON, or a\n * failure. The Content-Type header (with boundary) is set automatically by\n * `fetch` from the `FormData` body — callers must NOT pass it explicitly.\n * @internal\n */\nexport async function fetchMultipart(\n url: string,\n headers: Record<string, string>,\n body: FormData,\n logger?: Logging.ILogger,\n signal?: AbortSignal\n): Promise<Result<JsonObject>> {\n return _fetchAndParseJson(\n url,\n { method: 'POST', headers, body, signal },\n `POST ${url} (multipart)`,\n logger\n );\n}\n"]}
|
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
// Copyright (c) 2026 Erik Fortune
|
|
2
|
+
//
|
|
3
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
// in the Software without restriction, including without limitation the rights
|
|
6
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
// furnished to do so, subject to the following conditions:
|
|
9
|
+
//
|
|
10
|
+
// The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
// copies or substantial portions of the Software.
|
|
12
|
+
//
|
|
13
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
// SOFTWARE.
|
|
20
|
+
import { fail, mapResults, succeed, Validators } from '@fgv/ts-utils';
|
|
21
|
+
import { resolveProviderModel } from './model';
|
|
22
|
+
import { bearerAuthHeader, geminiAuthHeader, resolveEffectiveBaseUrl } from './endpoint';
|
|
23
|
+
import { fetchJson, fetchMultipart } from './http';
|
|
24
|
+
import { resolveImageCapability, supportsImageGeneration } from './registry';
|
|
25
|
+
import { resolveImageOptions, validateResolvedOptions } from './imageOptionsResolver';
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// Image attachment helpers
|
|
28
|
+
// ============================================================================
|
|
29
|
+
/**
|
|
30
|
+
* Decodes a base64-encoded image attachment into a `Blob` suitable for use as
|
|
31
|
+
* a multipart file field. On Node hands the `Buffer` straight to `Blob`
|
|
32
|
+
* (Buffer extends Uint8Array) to skip an intermediate copy; falls back to
|
|
33
|
+
* `atob` in browsers. Inputs come from `FileReader` or prior provider
|
|
34
|
+
* responses, which are trusted to be valid. Note that Node's
|
|
35
|
+
* `Buffer.from(..., 'base64')` silently strips invalid characters rather
|
|
36
|
+
* than throwing, so failures are only observable in the browser path.
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
function attachmentToBlob(attachment) {
|
|
40
|
+
if (typeof Buffer !== 'undefined') {
|
|
41
|
+
return succeed(new Blob([Buffer.from(attachment.base64, 'base64')], { type: attachment.mimeType }));
|
|
42
|
+
}
|
|
43
|
+
/* c8 ignore start - Browser-only fallback cannot be tested in Node.js environment */
|
|
44
|
+
try {
|
|
45
|
+
const binary = atob(attachment.base64);
|
|
46
|
+
const bytes = new Uint8Array(binary.length);
|
|
47
|
+
for (let i = 0; i < binary.length; i++) {
|
|
48
|
+
bytes[i] = binary.charCodeAt(i);
|
|
49
|
+
}
|
|
50
|
+
return succeed(new Blob([bytes], { type: attachment.mimeType }));
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
54
|
+
return fail(`Invalid base64: ${message}`);
|
|
55
|
+
}
|
|
56
|
+
/* c8 ignore stop */
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Maps a MIME type to a sensible file extension for multipart filenames.
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
62
|
+
function extensionForMimeType(mimeType) {
|
|
63
|
+
switch (mimeType) {
|
|
64
|
+
case 'image/png':
|
|
65
|
+
return 'png';
|
|
66
|
+
case 'image/jpeg':
|
|
67
|
+
case 'image/jpg':
|
|
68
|
+
return 'jpg';
|
|
69
|
+
case 'image/webp':
|
|
70
|
+
return 'webp';
|
|
71
|
+
case 'image/gif':
|
|
72
|
+
return 'gif';
|
|
73
|
+
default:
|
|
74
|
+
return 'bin';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const openAiImageItem = Validators.object({
|
|
78
|
+
b64_json: Validators.string,
|
|
79
|
+
revised_prompt: Validators.string.optional()
|
|
80
|
+
});
|
|
81
|
+
const openAiImageResponse = Validators.object({
|
|
82
|
+
data: Validators.arrayOf(openAiImageItem).withConstraint((arr) => arr.length > 0)
|
|
83
|
+
});
|
|
84
|
+
const geminiImageInlineData = Validators.object({
|
|
85
|
+
mimeType: Validators.string,
|
|
86
|
+
data: Validators.string
|
|
87
|
+
});
|
|
88
|
+
const geminiImageOutPart = Validators.object({
|
|
89
|
+
text: Validators.string.optional(),
|
|
90
|
+
inlineData: geminiImageInlineData.optional()
|
|
91
|
+
});
|
|
92
|
+
const geminiImageOutContent = Validators.object({
|
|
93
|
+
parts: Validators.arrayOf(geminiImageOutPart)
|
|
94
|
+
});
|
|
95
|
+
const geminiImageOutCandidate = Validators.object({
|
|
96
|
+
content: geminiImageOutContent.optional(),
|
|
97
|
+
finishReason: Validators.string.optional(),
|
|
98
|
+
finishMessage: Validators.string.optional()
|
|
99
|
+
});
|
|
100
|
+
const geminiImageOutResponse = Validators.object({
|
|
101
|
+
candidates: Validators.arrayOf(geminiImageOutCandidate).withConstraint((arr) => arr.length > 0)
|
|
102
|
+
});
|
|
103
|
+
// ---- Proxied image generation response ----
|
|
104
|
+
const proxiedGeneratedImage = Validators.object({
|
|
105
|
+
mimeType: Validators.string,
|
|
106
|
+
base64: Validators.string,
|
|
107
|
+
revisedPrompt: Validators.string.optional()
|
|
108
|
+
});
|
|
109
|
+
const proxiedImageGenerationResponse = Validators.object({
|
|
110
|
+
images: Validators.arrayOf(proxiedGeneratedImage).withConstraint((arr) => arr.length > 0)
|
|
111
|
+
});
|
|
112
|
+
// ============================================================================
|
|
113
|
+
// Image generation — adapters
|
|
114
|
+
// ============================================================================
|
|
115
|
+
/** Routes to /images/generations or /images/edits; handles outputParamStyle. @internal */
|
|
116
|
+
async function callOpenAiImageGeneration(config, request, capability, resolved, logger, signal) {
|
|
117
|
+
var _a, _b;
|
|
118
|
+
const refs = (_a = request.referenceImages) !== null && _a !== void 0 ? _a : [];
|
|
119
|
+
const headers = bearerAuthHeader(config.apiKey);
|
|
120
|
+
const effectiveMimeType = resolved.outputFormat !== undefined
|
|
121
|
+
? `image/${resolved.outputFormat}`
|
|
122
|
+
: (_b = capability.defaultOutputMimeType) !== null && _b !== void 0 ? _b : 'image/png';
|
|
123
|
+
const fetched = refs.length > 0
|
|
124
|
+
? await callOpenAiImagesEdits(config, capability, request, headers, resolved, logger, signal)
|
|
125
|
+
: await callOpenAiImagesGenerations(config, request, headers, resolved, capability, logger, signal);
|
|
126
|
+
return fetched.onSuccess((json) => openAiImageResponse
|
|
127
|
+
.validate(json)
|
|
128
|
+
.withErrorFormat((msg) => `OpenAI images API response: ${msg}`)
|
|
129
|
+
.onSuccess((response) => succeed({
|
|
130
|
+
images: response.data.map((item) => (Object.assign({ mimeType: effectiveMimeType, base64: item.b64_json }, (item.revised_prompt !== undefined ? { revisedPrompt: item.revised_prompt } : {}))))
|
|
131
|
+
})));
|
|
132
|
+
}
|
|
133
|
+
/** Builds the JSON /images/generations request; handles outputParamStyle. @internal */
|
|
134
|
+
function callOpenAiImagesGenerations(config, request, headers, resolved, capability, logger, signal) {
|
|
135
|
+
var _a;
|
|
136
|
+
const body = {
|
|
137
|
+
model: config.model,
|
|
138
|
+
prompt: request.prompt,
|
|
139
|
+
n: resolved.n
|
|
140
|
+
};
|
|
141
|
+
// Output format param — conditional on model capability
|
|
142
|
+
if (capability.outputParamStyle === 'response-format') {
|
|
143
|
+
body.response_format = 'b64_json';
|
|
144
|
+
}
|
|
145
|
+
else if (capability.outputParamStyle === 'output-format') {
|
|
146
|
+
body.output_format = (_a = resolved.outputFormat) !== null && _a !== void 0 ? _a : 'png';
|
|
147
|
+
}
|
|
148
|
+
if (resolved.size !== undefined) {
|
|
149
|
+
body.size = resolved.size;
|
|
150
|
+
}
|
|
151
|
+
if (capability.supportsQualityParam && resolved.quality !== undefined) {
|
|
152
|
+
body.quality = resolved.quality;
|
|
153
|
+
}
|
|
154
|
+
if (resolved.seed !== undefined) {
|
|
155
|
+
body.seed = resolved.seed;
|
|
156
|
+
}
|
|
157
|
+
if (resolved.background !== undefined) {
|
|
158
|
+
body.background = resolved.background;
|
|
159
|
+
}
|
|
160
|
+
if (resolved.moderation !== undefined) {
|
|
161
|
+
body.moderation = resolved.moderation;
|
|
162
|
+
}
|
|
163
|
+
if (resolved.outputCompression !== undefined) {
|
|
164
|
+
body.output_compression = resolved.outputCompression;
|
|
165
|
+
}
|
|
166
|
+
if (resolved.otherParams !== undefined) {
|
|
167
|
+
Object.assign(body, resolved.otherParams);
|
|
168
|
+
}
|
|
169
|
+
/* c8 ignore next 1 - optional logger */
|
|
170
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`Image generation: model=${config.model}, n=${resolved.n}`);
|
|
171
|
+
return fetchJson(`${config.baseUrl}/images/generations`, headers, body, logger, signal);
|
|
172
|
+
}
|
|
173
|
+
/** Builds the multipart /images/edits request with ref images. @internal */
|
|
174
|
+
async function callOpenAiImagesEdits(config, capability, request, headers, resolved, logger, signal) {
|
|
175
|
+
const refs = request.referenceImages; // callers verify refs.length > 0 before calling this function
|
|
176
|
+
const blobsResult = mapResults(refs.map((ref, i) => attachmentToBlob(ref).withErrorFormat((msg) => `reference image ${i}: ${msg}`)));
|
|
177
|
+
/* c8 ignore next 3 - decode failure unreachable via Node's Buffer.from (silently strips invalid input) */
|
|
178
|
+
if (blobsResult.isFailure()) {
|
|
179
|
+
return fail(blobsResult.message);
|
|
180
|
+
}
|
|
181
|
+
const form = new FormData();
|
|
182
|
+
form.append('model', config.model);
|
|
183
|
+
form.append('prompt', request.prompt);
|
|
184
|
+
form.append('n', String(resolved.n));
|
|
185
|
+
if (capability.outputParamStyle !== 'output-format') {
|
|
186
|
+
form.append('response_format', 'b64_json');
|
|
187
|
+
}
|
|
188
|
+
if (resolved.size !== undefined) {
|
|
189
|
+
form.append('size', resolved.size);
|
|
190
|
+
}
|
|
191
|
+
blobsResult.value.forEach((blob, i) => {
|
|
192
|
+
form.append('image[]', blob, `ref-${i}.${extensionForMimeType(refs[i].mimeType)}`);
|
|
193
|
+
});
|
|
194
|
+
/* c8 ignore next 1 - optional logger */
|
|
195
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`Image edit: model=${config.model}, n=${resolved.n}, refs=${refs.length}`);
|
|
196
|
+
return fetchMultipart(`${config.baseUrl}/images/edits`, headers, form, logger, signal);
|
|
197
|
+
}
|
|
198
|
+
/** Calls xAI /images/edits with JSON body (not multipart); up to 3 source images. @internal */
|
|
199
|
+
async function callXaiImagesEdits(config, request, resolved, logger, signal) {
|
|
200
|
+
var _a;
|
|
201
|
+
/* c8 ignore next 1 - defensive: referenceImages always defined when this function is called */
|
|
202
|
+
const refs = (_a = request.referenceImages) !== null && _a !== void 0 ? _a : [];
|
|
203
|
+
if (refs.length > 3) {
|
|
204
|
+
return fail(`xAI image edits supports at most 3 reference images; got ${refs.length}`);
|
|
205
|
+
}
|
|
206
|
+
const images = refs.map((ref) => ({
|
|
207
|
+
type: 'image_url',
|
|
208
|
+
url: `data:${ref.mimeType};base64,${ref.base64}`
|
|
209
|
+
}));
|
|
210
|
+
const body = {
|
|
211
|
+
model: config.model,
|
|
212
|
+
prompt: request.prompt,
|
|
213
|
+
n: resolved.n,
|
|
214
|
+
response_format: 'b64_json',
|
|
215
|
+
image: images
|
|
216
|
+
};
|
|
217
|
+
if (resolved.aspectRatio !== undefined) {
|
|
218
|
+
body.aspect_ratio = resolved.aspectRatio;
|
|
219
|
+
}
|
|
220
|
+
if (resolved.resolution !== undefined) {
|
|
221
|
+
body.resolution = resolved.resolution;
|
|
222
|
+
}
|
|
223
|
+
if (resolved.otherParams !== undefined) {
|
|
224
|
+
Object.assign(body, resolved.otherParams);
|
|
225
|
+
}
|
|
226
|
+
/* c8 ignore next 1 - optional logger */
|
|
227
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`xAI image edit: model=${config.model}, n=${resolved.n}, refs=${refs.length}`);
|
|
228
|
+
return fetchJson(`${config.baseUrl}/images/edits`, bearerAuthHeader(config.apiKey), body, logger, signal);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Normalizes an xAI images API response (OpenAI-shaped) into the provider-neutral
|
|
232
|
+
* generated-image result.
|
|
233
|
+
*
|
|
234
|
+
* @remarks
|
|
235
|
+
* Shared by the generations path and the edits path. These were two independent
|
|
236
|
+
* copies 160 lines apart — identical but for the receiver name — so the
|
|
237
|
+
* `defaultOutputMimeType` fallback and the error prefix each existed twice, and a
|
|
238
|
+
* fix to one would silently have missed the other.
|
|
239
|
+
* @internal
|
|
240
|
+
*/
|
|
241
|
+
function normalizeXaiImageResponse(json, capability) {
|
|
242
|
+
return openAiImageResponse
|
|
243
|
+
.validate(json)
|
|
244
|
+
.withErrorFormat((msg) => `xAI images API response: ${msg}`)
|
|
245
|
+
.onSuccess((response) => succeed({
|
|
246
|
+
images: response.data.map((item) => {
|
|
247
|
+
var _a;
|
|
248
|
+
return ({
|
|
249
|
+
mimeType: (_a = capability.defaultOutputMimeType) !== null && _a !== void 0 ? _a : 'image/jpeg',
|
|
250
|
+
base64: item.b64_json
|
|
251
|
+
});
|
|
252
|
+
})
|
|
253
|
+
}));
|
|
254
|
+
}
|
|
255
|
+
/** Calls xAI /images/generations; uses aspect_ratio instead of size. @internal */
|
|
256
|
+
async function callXaiImageGeneration(config, request, capability, resolved, logger, signal) {
|
|
257
|
+
const headers = bearerAuthHeader(config.apiKey);
|
|
258
|
+
const body = {
|
|
259
|
+
model: config.model,
|
|
260
|
+
prompt: request.prompt,
|
|
261
|
+
n: resolved.n,
|
|
262
|
+
response_format: 'b64_json'
|
|
263
|
+
};
|
|
264
|
+
if (resolved.aspectRatio !== undefined) {
|
|
265
|
+
body.aspect_ratio = resolved.aspectRatio;
|
|
266
|
+
}
|
|
267
|
+
if (resolved.resolution !== undefined) {
|
|
268
|
+
body.resolution = resolved.resolution;
|
|
269
|
+
}
|
|
270
|
+
if (resolved.otherParams !== undefined) {
|
|
271
|
+
Object.assign(body, resolved.otherParams);
|
|
272
|
+
}
|
|
273
|
+
/* c8 ignore next 1 - optional logger */
|
|
274
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`xAI image generation: model=${config.model}, n=${resolved.n}`);
|
|
275
|
+
const fetched = await fetchJson(`${config.baseUrl}/images/generations`, headers, body, logger, signal);
|
|
276
|
+
return fetched.onSuccess((json) => normalizeXaiImageResponse(json, capability));
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Gemini `finishReason` values that indicate a normal terminal completion rather
|
|
280
|
+
* than a refusal. `STOP` is set on every successful generation (and on completions
|
|
281
|
+
* that return a text part instead of an image); `MAX_TOKENS` is a benign truncation.
|
|
282
|
+
* A candidate carrying only one of these is NOT a decline — treating it as one would
|
|
283
|
+
* mislabel an ordinary no-image outcome as a policy refusal. @internal
|
|
284
|
+
*/
|
|
285
|
+
const benignGeminiImageFinishReasons = new Set(['STOP', 'MAX_TOKENS']);
|
|
286
|
+
/** Calls Gemini :generateContent for image output; accepts ref images as inlineData. @internal */
|
|
287
|
+
async function callGeminiImageOutGeneration(config, request, resolved, logger, signal) {
|
|
288
|
+
var _a;
|
|
289
|
+
const url = `${config.baseUrl}/models/${config.model}:generateContent`;
|
|
290
|
+
const refs = (_a = request.referenceImages) !== null && _a !== void 0 ? _a : [];
|
|
291
|
+
const parts = [{ text: request.prompt }];
|
|
292
|
+
for (const ref of refs) {
|
|
293
|
+
parts.push({ inlineData: { mimeType: ref.mimeType, data: ref.base64 } });
|
|
294
|
+
}
|
|
295
|
+
const generationConfig = {};
|
|
296
|
+
if (resolved.geminiAspectRatio !== undefined) {
|
|
297
|
+
generationConfig.imageConfig = { aspectRatio: resolved.geminiAspectRatio };
|
|
298
|
+
}
|
|
299
|
+
if (resolved.otherParams !== undefined) {
|
|
300
|
+
Object.assign(generationConfig, resolved.otherParams);
|
|
301
|
+
}
|
|
302
|
+
const body = { contents: [{ role: 'user', parts }] };
|
|
303
|
+
if (Object.keys(generationConfig).length > 0) {
|
|
304
|
+
body.generationConfig = generationConfig;
|
|
305
|
+
}
|
|
306
|
+
const headers = geminiAuthHeader(config.apiKey);
|
|
307
|
+
/* c8 ignore next 1 - optional logger */
|
|
308
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`Gemini image-out: model=${config.model}, refs=${refs.length}`);
|
|
309
|
+
return (await fetchJson(url, headers, body, logger, signal)).onSuccess((json) => geminiImageOutResponse
|
|
310
|
+
.validate(json)
|
|
311
|
+
.withErrorFormat((msg) => `Gemini image API response: ${msg}`)
|
|
312
|
+
.onSuccess((response) => {
|
|
313
|
+
var _a, _b;
|
|
314
|
+
const images = [];
|
|
315
|
+
for (const candidate of response.candidates) {
|
|
316
|
+
for (const part of (_b = (_a = candidate.content) === null || _a === void 0 ? void 0 : _a.parts) !== null && _b !== void 0 ? _b : []) {
|
|
317
|
+
if (part.inlineData) {
|
|
318
|
+
images.push({
|
|
319
|
+
mimeType: part.inlineData.mimeType,
|
|
320
|
+
base64: part.inlineData.data
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (images.length === 0) {
|
|
326
|
+
// A candidate with no image parts is a *decline* only when it carries a
|
|
327
|
+
// refusal-shaped finishReason — i.e. present and not a benign terminal reason
|
|
328
|
+
// (`STOP`/`MAX_TOKENS`). A normal completion that emitted text-instead-of-image
|
|
329
|
+
// carries `finishReason: 'STOP'` and must fall through to the no-image message.
|
|
330
|
+
const declined = response.candidates.find((candidate) => candidate.finishReason !== undefined &&
|
|
331
|
+
!benignGeminiImageFinishReasons.has(candidate.finishReason));
|
|
332
|
+
if ((declined === null || declined === void 0 ? void 0 : declined.finishReason) !== undefined) {
|
|
333
|
+
// Truthiness (not `!== undefined`) so an empty-string finishMessage is treated
|
|
334
|
+
// as "no message" and produces no dangling ` — ` separator.
|
|
335
|
+
const suffix = declined.finishMessage ? ` — ${declined.finishMessage}` : '';
|
|
336
|
+
return fail(`Gemini image generation declined: ${declined.finishReason}${suffix}`);
|
|
337
|
+
}
|
|
338
|
+
return fail('Gemini image API response: no image parts in response');
|
|
339
|
+
}
|
|
340
|
+
return succeed({ images });
|
|
341
|
+
}));
|
|
342
|
+
}
|
|
343
|
+
// ============================================================================
|
|
344
|
+
// Image generation — dispatcher
|
|
345
|
+
// ============================================================================
|
|
346
|
+
/**
|
|
347
|
+
* Calls the appropriate image-generation API for a given provider. Routes by the
|
|
348
|
+
* `format` field of the resolved {@link IAiImageModelCapability}:
|
|
349
|
+
* `'openai-images'`, `'xai-images'`, `'xai-images-edits'`, or
|
|
350
|
+
* `'gemini-image-out'`. Rejects up front if `referenceImages` is set but the
|
|
351
|
+
* capability does not declare `acceptsImageReferenceInput`.
|
|
352
|
+
* @param params - Request parameters including descriptor, API key, and prompt
|
|
353
|
+
* @public
|
|
354
|
+
*/
|
|
355
|
+
export async function callProviderImageGeneration(params) {
|
|
356
|
+
var _a, _b, _c;
|
|
357
|
+
const { descriptor, apiKey, params: request, modelOverride, logger, signal, endpoint } = params;
|
|
358
|
+
if (!supportsImageGeneration(descriptor)) {
|
|
359
|
+
return fail(`provider "${descriptor.id}" does not support image generation`);
|
|
360
|
+
}
|
|
361
|
+
const baseUrlResult = resolveEffectiveBaseUrl(descriptor, endpoint);
|
|
362
|
+
if (baseUrlResult.isFailure()) {
|
|
363
|
+
return fail(baseUrlResult.message);
|
|
364
|
+
}
|
|
365
|
+
const modelResult = resolveProviderModel(descriptor, modelOverride, 'image');
|
|
366
|
+
if (modelResult.isFailure()) {
|
|
367
|
+
return fail(modelResult.message);
|
|
368
|
+
}
|
|
369
|
+
const model = modelResult.value;
|
|
370
|
+
const capability = resolveImageCapability(descriptor, model);
|
|
371
|
+
if (capability === undefined) {
|
|
372
|
+
return fail(`provider "${descriptor.id}" does not support image generation for model "${model}"`);
|
|
373
|
+
}
|
|
374
|
+
if (((_b = (_a = request.referenceImages) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0 && !capability.acceptsImageReferenceInput) {
|
|
375
|
+
return fail(`model "${model}" does not support reference images`);
|
|
376
|
+
}
|
|
377
|
+
const resolved = resolveImageOptions(model, capability, request.options);
|
|
378
|
+
const validationResult = validateResolvedOptions(model, capability, resolved);
|
|
379
|
+
if (validationResult.isFailure()) {
|
|
380
|
+
return fail(validationResult.message);
|
|
381
|
+
}
|
|
382
|
+
const config = {
|
|
383
|
+
baseUrl: baseUrlResult.value,
|
|
384
|
+
apiKey,
|
|
385
|
+
model
|
|
386
|
+
};
|
|
387
|
+
/* c8 ignore next 6 - optional logger diagnostic output */
|
|
388
|
+
if (logger) {
|
|
389
|
+
logger.info(`AI image generation: provider=${descriptor.id}, format=${capability.format}, ` +
|
|
390
|
+
`model=${config.model}`);
|
|
391
|
+
}
|
|
392
|
+
switch (capability.format) {
|
|
393
|
+
case 'openai-images':
|
|
394
|
+
return callOpenAiImageGeneration(config, request, capability, resolved, logger, signal);
|
|
395
|
+
case 'xai-images':
|
|
396
|
+
return callXaiImageGeneration(config, request, capability, resolved, logger, signal);
|
|
397
|
+
case 'xai-images-edits': {
|
|
398
|
+
const refs = (_c = request.referenceImages) !== null && _c !== void 0 ? _c : [];
|
|
399
|
+
if (refs.length > 0) {
|
|
400
|
+
const editsResult = await callXaiImagesEdits(config, request, resolved, logger, signal);
|
|
401
|
+
return editsResult.onSuccess((json) => normalizeXaiImageResponse(json, capability));
|
|
402
|
+
}
|
|
403
|
+
return callXaiImageGeneration(config, request, capability, resolved, logger, signal);
|
|
404
|
+
}
|
|
405
|
+
case 'gemini-image-out':
|
|
406
|
+
return callGeminiImageOutGeneration(config, request, resolved, logger, signal);
|
|
407
|
+
/* c8 ignore next 4 - defensive coding: exhaustive switch guaranteed by TypeScript */
|
|
408
|
+
default: {
|
|
409
|
+
const _exhaustive = capability.format;
|
|
410
|
+
return fail(`unsupported image API format: ${String(_exhaustive)}`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
// ============================================================================
|
|
415
|
+
// Proxied image generation
|
|
416
|
+
// ============================================================================
|
|
417
|
+
/**
|
|
418
|
+
* Calls the image-generation endpoint on a proxy server instead of calling
|
|
419
|
+
* the provider API directly from the browser.
|
|
420
|
+
* Endpoint: `POST ${proxyUrl}/api/ai/image-generation`. Request body:
|
|
421
|
+
* `{providerId, apiKey, params, modelOverride?}`. The proxy handles descriptor
|
|
422
|
+
* lookup, model resolution, provider dispatch, and response normalization
|
|
423
|
+
* (including repackaging `referenceImages` for the upstream wire format).
|
|
424
|
+
* Error body `{error: string}` is surfaced as `proxy: ${error}`.
|
|
425
|
+
* @param proxyUrl - Base URL of the proxy server
|
|
426
|
+
* @param params - Same parameters as {@link callProviderImageGeneration}
|
|
427
|
+
* @public
|
|
428
|
+
*/
|
|
429
|
+
export async function callProxiedImageGeneration(proxyUrl, params) {
|
|
430
|
+
const { descriptor, apiKey, params: request, modelOverride, logger, signal } = params;
|
|
431
|
+
const body = {
|
|
432
|
+
providerId: descriptor.id,
|
|
433
|
+
apiKey,
|
|
434
|
+
params: request
|
|
435
|
+
};
|
|
436
|
+
if (modelOverride !== undefined) {
|
|
437
|
+
body.modelOverride = modelOverride;
|
|
438
|
+
}
|
|
439
|
+
/* c8 ignore next 1 - optional logger */
|
|
440
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`AI image proxy request: provider=${descriptor.id}, proxy=${proxyUrl}`);
|
|
441
|
+
const url = `${proxyUrl}/api/ai/image-generation`;
|
|
442
|
+
const jsonResult = await fetchJson(url, {}, body, logger, signal);
|
|
443
|
+
if (jsonResult.isFailure()) {
|
|
444
|
+
return fail(jsonResult.message);
|
|
445
|
+
}
|
|
446
|
+
const response = jsonResult.value;
|
|
447
|
+
if (typeof response.error === 'string') {
|
|
448
|
+
return fail(`proxy: ${response.error}`);
|
|
449
|
+
}
|
|
450
|
+
return proxiedImageGenerationResponse
|
|
451
|
+
.validate(response)
|
|
452
|
+
.withErrorFormat((msg) => `proxy returned invalid response: ${msg}`);
|
|
453
|
+
}
|
|
454
|
+
//# sourceMappingURL=imageGenerationClient.js.map
|