@prometheus-ai/ai 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +1184 -0
- package/dist/types/api-registry.d.ts +30 -0
- package/dist/types/auth-broker/client.d.ts +66 -0
- package/dist/types/auth-broker/index.d.ts +6 -0
- package/dist/types/auth-broker/refresher.d.ts +25 -0
- package/dist/types/auth-broker/remote-store.d.ts +101 -0
- package/dist/types/auth-broker/server.d.ts +32 -0
- package/dist/types/auth-broker/snapshot-cache.d.ts +17 -0
- package/dist/types/auth-broker/types.d.ts +107 -0
- package/dist/types/auth-broker/wire-schemas.d.ts +412 -0
- package/dist/types/auth-gateway/http.d.ts +39 -0
- package/dist/types/auth-gateway/index.d.ts +3 -0
- package/dist/types/auth-gateway/server.d.ts +36 -0
- package/dist/types/auth-gateway/types.d.ts +117 -0
- package/dist/types/auth-storage.d.ts +762 -0
- package/dist/types/index.d.ts +49 -0
- package/dist/types/model-cache.d.ts +17 -0
- package/dist/types/model-manager.d.ts +64 -0
- package/dist/types/model-thinking.d.ts +100 -0
- package/dist/types/models.d.ts +12 -0
- package/dist/types/provider-details.d.ts +24 -0
- package/dist/types/provider-models/bundled-references.d.ts +4 -0
- package/dist/types/provider-models/descriptors.d.ts +50 -0
- package/dist/types/provider-models/google.d.ts +24 -0
- package/dist/types/provider-models/index.d.ts +5 -0
- package/dist/types/provider-models/ollama.d.ts +7 -0
- package/dist/types/provider-models/openai-compat.d.ts +323 -0
- package/dist/types/provider-models/special.d.ts +16 -0
- package/dist/types/providers/amazon-bedrock.d.ts +38 -0
- package/dist/types/providers/anthropic-client.d.ts +99 -0
- package/dist/types/providers/anthropic-messages-server-schema.d.ts +465 -0
- package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
- package/dist/types/providers/anthropic-wire.d.ts +262 -0
- package/dist/types/providers/anthropic.d.ts +206 -0
- package/dist/types/providers/aws-credentials.d.ts +43 -0
- package/dist/types/providers/aws-eventstream.d.ts +38 -0
- package/dist/types/providers/aws-sigv4.d.ts +55 -0
- package/dist/types/providers/azure-openai-responses.d.ts +15 -0
- package/dist/types/providers/cursor/gen/agent_pb.d.ts +13022 -0
- package/dist/types/providers/cursor.d.ts +43 -0
- package/dist/types/providers/error-message.d.ts +27 -0
- package/dist/types/providers/github-copilot-headers.d.ts +40 -0
- package/dist/types/providers/gitlab-duo.d.ts +27 -0
- package/dist/types/providers/google-auth.d.ts +24 -0
- package/dist/types/providers/google-gemini-cli.d.ts +81 -0
- package/dist/types/providers/google-gemini-headers.d.ts +18 -0
- package/dist/types/providers/google-shared.d.ts +171 -0
- package/dist/types/providers/google-types.d.ts +138 -0
- package/dist/types/providers/google-vertex.d.ts +7 -0
- package/dist/types/providers/google.d.ts +4 -0
- package/dist/types/providers/grammar.d.ts +1 -0
- package/dist/types/providers/kimi.d.ts +27 -0
- package/dist/types/providers/mock.d.ts +173 -0
- package/dist/types/providers/ollama.d.ts +6 -0
- package/dist/types/providers/openai-anthropic-shim.d.ts +31 -0
- package/dist/types/providers/openai-chat-server-schema.d.ts +817 -0
- package/dist/types/providers/openai-chat-server.d.ts +16 -0
- package/dist/types/providers/openai-codex/constants.d.ts +26 -0
- package/dist/types/providers/openai-codex/request-transformer.d.ts +49 -0
- package/dist/types/providers/openai-codex/response-handler.d.ts +17 -0
- package/dist/types/providers/openai-codex-responses.d.ts +67 -0
- package/dist/types/providers/openai-completions-compat.d.ts +27 -0
- package/dist/types/providers/openai-completions.d.ts +54 -0
- package/dist/types/providers/openai-responses-server-schema.d.ts +392 -0
- package/dist/types/providers/openai-responses-server.d.ts +17 -0
- package/dist/types/providers/openai-responses-shared.d.ts +105 -0
- package/dist/types/providers/openai-responses.d.ts +66 -0
- package/dist/types/providers/prometheus-native-client.d.ts +13 -0
- package/dist/types/providers/prometheus-native-server.d.ts +68 -0
- package/dist/types/providers/register-builtins.d.ts +31 -0
- package/dist/types/providers/synthetic.d.ts +26 -0
- package/dist/types/providers/transform-messages.d.ts +12 -0
- package/dist/types/providers/vision-guard.d.ts +20 -0
- package/dist/types/providers/xai-responses.d.ts +23 -0
- package/dist/types/rate-limit-utils.d.ts +19 -0
- package/dist/types/stream.d.ts +28 -0
- package/dist/types/types.d.ts +819 -0
- package/dist/types/usage/claude.d.ts +4 -0
- package/dist/types/usage/gemini.d.ts +2 -0
- package/dist/types/usage/github-copilot.d.ts +7 -0
- package/dist/types/usage/google-antigravity.d.ts +2 -0
- package/dist/types/usage/kimi.d.ts +2 -0
- package/dist/types/usage/minimax-code.d.ts +2 -0
- package/dist/types/usage/openai-codex.d.ts +3 -0
- package/dist/types/usage/shared.d.ts +1 -0
- package/dist/types/usage/zai.d.ts +2 -0
- package/dist/types/usage.d.ts +260 -0
- package/dist/types/utils/abort.d.ts +19 -0
- package/dist/types/utils/abortable-iterator.d.ts +4 -0
- package/dist/types/utils/anthropic-auth.d.ts +35 -0
- package/dist/types/utils/discovery/antigravity.d.ts +61 -0
- package/dist/types/utils/discovery/codex.d.ts +38 -0
- package/dist/types/utils/discovery/cursor.d.ts +23 -0
- package/dist/types/utils/discovery/gemini.d.ts +25 -0
- package/dist/types/utils/discovery/index.d.ts +4 -0
- package/dist/types/utils/discovery/openai-compatible.d.ts +72 -0
- package/dist/types/utils/event-stream.d.ts +28 -0
- package/dist/types/utils/fireworks-model-id.d.ts +10 -0
- package/dist/types/utils/foundry.d.ts +1 -0
- package/dist/types/utils/http-inspector.d.ts +31 -0
- package/dist/types/utils/idle-iterator.d.ts +78 -0
- package/dist/types/utils/json-parse.d.ts +37 -0
- package/dist/types/utils/oauth/__tests__/xai-oauth.test.d.ts +1 -0
- package/dist/types/utils/oauth/alibaba-coding-plan.d.ts +18 -0
- package/dist/types/utils/oauth/anthropic.d.ts +22 -0
- package/dist/types/utils/oauth/api-key-login.d.ts +35 -0
- package/dist/types/utils/oauth/api-key-validation.d.ts +27 -0
- package/dist/types/utils/oauth/callback-server.d.ts +57 -0
- package/dist/types/utils/oauth/cerebras.d.ts +1 -0
- package/dist/types/utils/oauth/cloudflare-ai-gateway.d.ts +18 -0
- package/dist/types/utils/oauth/cursor.d.ts +15 -0
- package/dist/types/utils/oauth/deepseek.d.ts +10 -0
- package/dist/types/utils/oauth/firepass.d.ts +1 -0
- package/dist/types/utils/oauth/fireworks.d.ts +1 -0
- package/dist/types/utils/oauth/github-copilot.d.ts +38 -0
- package/dist/types/utils/oauth/gitlab-duo.d.ts +3 -0
- package/dist/types/utils/oauth/google-antigravity.d.ts +11 -0
- package/dist/types/utils/oauth/google-gemini-cli.d.ts +10 -0
- package/dist/types/utils/oauth/google-oauth-shared.d.ts +28 -0
- package/dist/types/utils/oauth/huggingface.d.ts +19 -0
- package/dist/types/utils/oauth/index.d.ts +38 -0
- package/dist/types/utils/oauth/kagi.d.ts +17 -0
- package/dist/types/utils/oauth/kilo.d.ts +5 -0
- package/dist/types/utils/oauth/kimi.d.ts +21 -0
- package/dist/types/utils/oauth/litellm.d.ts +18 -0
- package/dist/types/utils/oauth/lm-studio.d.ts +17 -0
- package/dist/types/utils/oauth/minimax-code.d.ts +28 -0
- package/dist/types/utils/oauth/moonshot.d.ts +1 -0
- package/dist/types/utils/oauth/nanogpt.d.ts +1 -0
- package/dist/types/utils/oauth/nvidia.d.ts +18 -0
- package/dist/types/utils/oauth/ollama-cloud.d.ts +2 -0
- package/dist/types/utils/oauth/ollama.d.ts +18 -0
- package/dist/types/utils/oauth/openai-codex.d.ts +21 -0
- package/dist/types/utils/oauth/opencode.d.ts +18 -0
- package/dist/types/utils/oauth/openrouter.d.ts +1 -0
- package/dist/types/utils/oauth/parallel.d.ts +17 -0
- package/dist/types/utils/oauth/perplexity.d.ts +9 -0
- package/dist/types/utils/oauth/pkce.d.ts +8 -0
- package/dist/types/utils/oauth/qianfan.d.ts +17 -0
- package/dist/types/utils/oauth/qwen-portal.d.ts +19 -0
- package/dist/types/utils/oauth/synthetic.d.ts +1 -0
- package/dist/types/utils/oauth/tavily.d.ts +17 -0
- package/dist/types/utils/oauth/together.d.ts +1 -0
- package/dist/types/utils/oauth/types.d.ts +44 -0
- package/dist/types/utils/oauth/venice.d.ts +18 -0
- package/dist/types/utils/oauth/vercel-ai-gateway.d.ts +18 -0
- package/dist/types/utils/oauth/vllm.d.ts +16 -0
- package/dist/types/utils/oauth/wafer.d.ts +2 -0
- package/dist/types/utils/oauth/xai-oauth.d.ts +60 -0
- package/dist/types/utils/oauth/xiaomi.d.ts +25 -0
- package/dist/types/utils/oauth/zai.d.ts +18 -0
- package/dist/types/utils/oauth/zenmux.d.ts +1 -0
- package/dist/types/utils/oauth/zhipu.d.ts +18 -0
- package/dist/types/utils/overflow.d.ts +54 -0
- package/dist/types/utils/parse-bind.d.ts +23 -0
- package/dist/types/utils/provider-response.d.ts +3 -0
- package/dist/types/utils/request-debug.d.ts +29 -0
- package/dist/types/utils/retry-after.d.ts +3 -0
- package/dist/types/utils/retry.d.ts +26 -0
- package/dist/types/utils/schema/adapt.d.ts +24 -0
- package/dist/types/utils/schema/compatibility.d.ts +30 -0
- package/dist/types/utils/schema/dereference.d.ts +11 -0
- package/dist/types/utils/schema/draft.d.ts +10 -0
- package/dist/types/utils/schema/equality.d.ts +4 -0
- package/dist/types/utils/schema/fields.d.ts +49 -0
- package/dist/types/utils/schema/index.d.ts +13 -0
- package/dist/types/utils/schema/json-schema-validator.d.ts +12 -0
- package/dist/types/utils/schema/meta-validator.d.ts +2 -0
- package/dist/types/utils/schema/normalize.d.ts +93 -0
- package/dist/types/utils/schema/spill.d.ts +8 -0
- package/dist/types/utils/schema/stamps.d.ts +25 -0
- package/dist/types/utils/schema/types.d.ts +4 -0
- package/dist/types/utils/schema/wire.d.ts +53 -0
- package/dist/types/utils/schema/zod-decontaminate.d.ts +31 -0
- package/dist/types/utils/sdk-stream-timeout.d.ts +33 -0
- package/dist/types/utils/sse-debug.d.ts +10 -0
- package/dist/types/utils/stream-markup-healing.d.ts +80 -0
- package/dist/types/utils/tool-choice.d.ts +50 -0
- package/dist/types/utils/validation.d.ts +17 -0
- package/dist/types/utils.d.ts +28 -0
- package/package.json +142 -0
- package/src/api-registry.ts +96 -0
- package/src/auth-broker/client.ts +358 -0
- package/src/auth-broker/index.ts +6 -0
- package/src/auth-broker/refresher.ts +117 -0
- package/src/auth-broker/remote-store.ts +637 -0
- package/src/auth-broker/server.ts +644 -0
- package/src/auth-broker/snapshot-cache.ts +174 -0
- package/src/auth-broker/types.ts +130 -0
- package/src/auth-broker/wire-schemas.ts +200 -0
- package/src/auth-gateway/http.ts +194 -0
- package/src/auth-gateway/index.ts +3 -0
- package/src/auth-gateway/server.ts +822 -0
- package/src/auth-gateway/types.ts +143 -0
- package/src/auth-storage.ts +4608 -0
- package/src/index.ts +54 -0
- package/src/model-cache.ts +129 -0
- package/src/model-manager.ts +469 -0
- package/src/model-thinking.ts +756 -0
- package/src/models.json +60287 -0
- package/src/models.json.d.ts +9 -0
- package/src/models.ts +56 -0
- package/src/prompts/turn-aborted-guidance.md +4 -0
- package/src/provider-details.ts +90 -0
- package/src/provider-models/bundled-references.ts +38 -0
- package/src/provider-models/descriptors.ts +364 -0
- package/src/provider-models/google.ts +88 -0
- package/src/provider-models/index.ts +5 -0
- package/src/provider-models/ollama.ts +153 -0
- package/src/provider-models/openai-compat.ts +2904 -0
- package/src/provider-models/special.ts +67 -0
- package/src/providers/amazon-bedrock.ts +873 -0
- package/src/providers/anthropic-client.ts +318 -0
- package/src/providers/anthropic-messages-server-schema.ts +243 -0
- package/src/providers/anthropic-messages-server.ts +681 -0
- package/src/providers/anthropic-wire.ts +268 -0
- package/src/providers/anthropic.ts +3106 -0
- package/src/providers/aws-credentials.ts +501 -0
- package/src/providers/aws-eventstream.ts +185 -0
- package/src/providers/aws-sigv4.ts +218 -0
- package/src/providers/azure-openai-responses.ts +361 -0
- package/src/providers/cursor/gen/agent_pb.ts +15274 -0
- package/src/providers/cursor/proto/agent.proto +3526 -0
- package/src/providers/cursor/proto/buf.gen.yaml +6 -0
- package/src/providers/cursor/proto/buf.yaml +17 -0
- package/src/providers/cursor.ts +2621 -0
- package/src/providers/error-message.ts +21 -0
- package/src/providers/github-copilot-headers.ts +140 -0
- package/src/providers/gitlab-duo.ts +372 -0
- package/src/providers/google-auth.ts +252 -0
- package/src/providers/google-gemini-cli.ts +809 -0
- package/src/providers/google-gemini-headers.ts +41 -0
- package/src/providers/google-shared.ts +917 -0
- package/src/providers/google-types.ts +167 -0
- package/src/providers/google-vertex.ts +91 -0
- package/src/providers/google.ts +41 -0
- package/src/providers/grammar.ts +70 -0
- package/src/providers/kimi.ts +52 -0
- package/src/providers/mock.ts +496 -0
- package/src/providers/ollama.ts +644 -0
- package/src/providers/openai-anthropic-shim.ts +138 -0
- package/src/providers/openai-chat-server-schema.ts +252 -0
- package/src/providers/openai-chat-server.ts +647 -0
- package/src/providers/openai-codex/constants.ts +43 -0
- package/src/providers/openai-codex/request-transformer.ts +161 -0
- package/src/providers/openai-codex/response-handler.ts +81 -0
- package/src/providers/openai-codex-responses.ts +3027 -0
- package/src/providers/openai-completions-compat.ts +320 -0
- package/src/providers/openai-completions.ts +2002 -0
- package/src/providers/openai-responses-server-schema.ts +290 -0
- package/src/providers/openai-responses-server.ts +1183 -0
- package/src/providers/openai-responses-shared.ts +956 -0
- package/src/providers/openai-responses.ts +679 -0
- package/src/providers/prometheus-native-client.ts +228 -0
- package/src/providers/prometheus-native-server.ts +212 -0
- package/src/providers/register-builtins.ts +457 -0
- package/src/providers/synthetic.ts +50 -0
- package/src/providers/transform-messages.ts +382 -0
- package/src/providers/vision-guard.ts +52 -0
- package/src/providers/xai-responses.ts +82 -0
- package/src/rate-limit-utils.ts +91 -0
- package/src/stream.ts +1068 -0
- package/src/types.ts +965 -0
- package/src/usage/claude.ts +482 -0
- package/src/usage/gemini.ts +250 -0
- package/src/usage/github-copilot.ts +421 -0
- package/src/usage/google-antigravity.ts +201 -0
- package/src/usage/kimi.ts +271 -0
- package/src/usage/minimax-code.ts +31 -0
- package/src/usage/openai-codex.ts +503 -0
- package/src/usage/shared.ts +10 -0
- package/src/usage/zai.ts +247 -0
- package/src/usage.ts +185 -0
- package/src/utils/abort.ts +51 -0
- package/src/utils/abortable-iterator.ts +69 -0
- package/src/utils/anthropic-auth.ts +93 -0
- package/src/utils/discovery/antigravity.ts +261 -0
- package/src/utils/discovery/codex.ts +371 -0
- package/src/utils/discovery/cursor.ts +306 -0
- package/src/utils/discovery/gemini.ts +248 -0
- package/src/utils/discovery/index.ts +4 -0
- package/src/utils/discovery/openai-compatible.ts +224 -0
- package/src/utils/event-stream.ts +142 -0
- package/src/utils/fireworks-model-id.ts +30 -0
- package/src/utils/foundry.ts +8 -0
- package/src/utils/http-inspector.ts +176 -0
- package/src/utils/idle-iterator.ts +273 -0
- package/src/utils/json-parse.ts +182 -0
- package/src/utils/oauth/__tests__/xai-oauth.test.ts +107 -0
- package/src/utils/oauth/alibaba-coding-plan.ts +59 -0
- package/src/utils/oauth/anthropic.ts +273 -0
- package/src/utils/oauth/api-key-login.ts +87 -0
- package/src/utils/oauth/api-key-validation.ts +92 -0
- package/src/utils/oauth/callback-server.ts +276 -0
- package/src/utils/oauth/cerebras.ts +16 -0
- package/src/utils/oauth/cloudflare-ai-gateway.ts +48 -0
- package/src/utils/oauth/cursor.ts +157 -0
- package/src/utils/oauth/deepseek.ts +53 -0
- package/src/utils/oauth/firepass.ts +24 -0
- package/src/utils/oauth/fireworks.ts +15 -0
- package/src/utils/oauth/github-copilot.ts +362 -0
- package/src/utils/oauth/gitlab-duo.ts +123 -0
- package/src/utils/oauth/google-antigravity.ts +200 -0
- package/src/utils/oauth/google-gemini-cli.ts +256 -0
- package/src/utils/oauth/google-oauth-shared.ts +110 -0
- package/src/utils/oauth/huggingface.ts +62 -0
- package/src/utils/oauth/index.ts +502 -0
- package/src/utils/oauth/kagi.ts +47 -0
- package/src/utils/oauth/kilo.ts +87 -0
- package/src/utils/oauth/kimi.ts +254 -0
- package/src/utils/oauth/litellm.ts +47 -0
- package/src/utils/oauth/lm-studio.ts +38 -0
- package/src/utils/oauth/minimax-code.ts +80 -0
- package/src/utils/oauth/moonshot.ts +23 -0
- package/src/utils/oauth/nanogpt.ts +15 -0
- package/src/utils/oauth/nvidia.ts +70 -0
- package/src/utils/oauth/oauth.html +199 -0
- package/src/utils/oauth/ollama-cloud.ts +28 -0
- package/src/utils/oauth/ollama.ts +47 -0
- package/src/utils/oauth/openai-codex.ts +299 -0
- package/src/utils/oauth/opencode.ts +49 -0
- package/src/utils/oauth/openrouter.ts +20 -0
- package/src/utils/oauth/parallel.ts +46 -0
- package/src/utils/oauth/perplexity.ts +206 -0
- package/src/utils/oauth/pkce.ts +18 -0
- package/src/utils/oauth/qianfan.ts +58 -0
- package/src/utils/oauth/qwen-portal.ts +60 -0
- package/src/utils/oauth/synthetic.ts +15 -0
- package/src/utils/oauth/tavily.ts +46 -0
- package/src/utils/oauth/together.ts +16 -0
- package/src/utils/oauth/types.ts +102 -0
- package/src/utils/oauth/venice.ts +59 -0
- package/src/utils/oauth/vercel-ai-gateway.ts +47 -0
- package/src/utils/oauth/vllm.ts +40 -0
- package/src/utils/oauth/wafer.ts +50 -0
- package/src/utils/oauth/xai-oauth.ts +342 -0
- package/src/utils/oauth/xiaomi.ts +194 -0
- package/src/utils/oauth/zai.ts +60 -0
- package/src/utils/oauth/zenmux.ts +15 -0
- package/src/utils/oauth/zhipu.ts +60 -0
- package/src/utils/overflow.ts +137 -0
- package/src/utils/parse-bind.ts +54 -0
- package/src/utils/provider-response.ts +30 -0
- package/src/utils/request-debug.ts +336 -0
- package/src/utils/retry-after.ts +110 -0
- package/src/utils/retry.ts +54 -0
- package/src/utils/schema/CONSTRAINTS.md +164 -0
- package/src/utils/schema/adapt.ts +36 -0
- package/src/utils/schema/compatibility.ts +435 -0
- package/src/utils/schema/dereference.ts +98 -0
- package/src/utils/schema/draft.ts +341 -0
- package/src/utils/schema/equality.ts +97 -0
- package/src/utils/schema/fields.ts +191 -0
- package/src/utils/schema/index.ts +13 -0
- package/src/utils/schema/json-schema-validator.ts +577 -0
- package/src/utils/schema/meta-validator.ts +167 -0
- package/src/utils/schema/normalize.ts +1588 -0
- package/src/utils/schema/spill.ts +43 -0
- package/src/utils/schema/stamps.ts +97 -0
- package/src/utils/schema/types.ts +10 -0
- package/src/utils/schema/wire.ts +293 -0
- package/src/utils/schema/zod-decontaminate.ts +331 -0
- package/src/utils/sdk-stream-timeout.ts +43 -0
- package/src/utils/sse-debug.ts +289 -0
- package/src/utils/stream-markup-healing.ts +612 -0
- package/src/utils/tool-choice.ts +99 -0
- package/src/utils/validation.ts +1024 -0
- package/src/utils.ts +166 -0
package/package.json
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "module",
|
|
3
|
+
"name": "@prometheus-ai/ai",
|
|
4
|
+
"version": "0.5.0",
|
|
5
|
+
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
6
|
+
"homepage": "https://prometheus.trivlab.com",
|
|
7
|
+
"author": "Uttam Trivedi",
|
|
8
|
+
"contributors": [
|
|
9
|
+
"Mario Zechner"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/uttamtrivedi/Prometheus.git",
|
|
15
|
+
"directory": "packages/ai"
|
|
16
|
+
},
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/uttamtrivedi/Prometheus/issues"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"ai",
|
|
22
|
+
"llm",
|
|
23
|
+
"openai",
|
|
24
|
+
"anthropic",
|
|
25
|
+
"gemini",
|
|
26
|
+
"unified",
|
|
27
|
+
"api"
|
|
28
|
+
],
|
|
29
|
+
"main": "./src/index.ts",
|
|
30
|
+
"types": "./dist/types/index.d.ts",
|
|
31
|
+
"scripts": {
|
|
32
|
+
"check": "biome check . && bun run check:types",
|
|
33
|
+
"check:types": "tsgo -p tsconfig.json --noEmit",
|
|
34
|
+
"lint": "biome lint .",
|
|
35
|
+
"test": "bun test --parallel --timeout=15000",
|
|
36
|
+
"fix": "biome check --write --unsafe .",
|
|
37
|
+
"fmt": "biome format --write .",
|
|
38
|
+
"generate-models": "bun scripts/generate-models.ts"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@bufbuild/protobuf": "^2.12.0",
|
|
42
|
+
"@prometheus-ai/utils": "0.5.0",
|
|
43
|
+
"openai": "^6.39.0",
|
|
44
|
+
"partial-json": "^0.1.7",
|
|
45
|
+
"zod": "4.4.3"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/bun": "^1.3.14"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"bun": ">=1.3.14"
|
|
52
|
+
},
|
|
53
|
+
"files": [
|
|
54
|
+
"src",
|
|
55
|
+
"README.md",
|
|
56
|
+
"CHANGELOG.md",
|
|
57
|
+
"dist/types"
|
|
58
|
+
],
|
|
59
|
+
"exports": {
|
|
60
|
+
".": {
|
|
61
|
+
"types": "./dist/types/index.d.ts",
|
|
62
|
+
"import": "./src/index.ts"
|
|
63
|
+
},
|
|
64
|
+
"./*": {
|
|
65
|
+
"types": "./dist/types/*.d.ts",
|
|
66
|
+
"import": "./src/*.ts"
|
|
67
|
+
},
|
|
68
|
+
"./auth-broker": {
|
|
69
|
+
"types": "./dist/types/auth-broker/index.d.ts",
|
|
70
|
+
"import": "./src/auth-broker/index.ts"
|
|
71
|
+
},
|
|
72
|
+
"./auth-broker/*": {
|
|
73
|
+
"types": "./dist/types/auth-broker/*.d.ts",
|
|
74
|
+
"import": "./src/auth-broker/*.ts"
|
|
75
|
+
},
|
|
76
|
+
"./auth-gateway": {
|
|
77
|
+
"types": "./dist/types/auth-gateway/index.d.ts",
|
|
78
|
+
"import": "./src/auth-gateway/index.ts"
|
|
79
|
+
},
|
|
80
|
+
"./auth-gateway/*": {
|
|
81
|
+
"types": "./dist/types/auth-gateway/*.d.ts",
|
|
82
|
+
"import": "./src/auth-gateway/*.ts"
|
|
83
|
+
},
|
|
84
|
+
"./models.json": {
|
|
85
|
+
"types": "./dist/types/models.json.d.d.ts",
|
|
86
|
+
"import": "./src/models.json"
|
|
87
|
+
},
|
|
88
|
+
"./provider-models": {
|
|
89
|
+
"types": "./dist/types/provider-models/index.d.ts",
|
|
90
|
+
"import": "./src/provider-models/index.ts"
|
|
91
|
+
},
|
|
92
|
+
"./provider-models/*": {
|
|
93
|
+
"types": "./dist/types/provider-models/*.d.ts",
|
|
94
|
+
"import": "./src/provider-models/*.ts"
|
|
95
|
+
},
|
|
96
|
+
"./providers/*": {
|
|
97
|
+
"types": "./dist/types/providers/*.d.ts",
|
|
98
|
+
"import": "./src/providers/*.ts"
|
|
99
|
+
},
|
|
100
|
+
"./providers/cursor/gen/*": {
|
|
101
|
+
"types": "./dist/types/providers/cursor/gen/*.d.ts",
|
|
102
|
+
"import": "./src/providers/cursor/gen/*.ts"
|
|
103
|
+
},
|
|
104
|
+
"./providers/openai-codex/*": {
|
|
105
|
+
"types": "./dist/types/providers/openai-codex/*.d.ts",
|
|
106
|
+
"import": "./src/providers/openai-codex/*.ts"
|
|
107
|
+
},
|
|
108
|
+
"./usage/*": {
|
|
109
|
+
"types": "./dist/types/usage/*.d.ts",
|
|
110
|
+
"import": "./src/usage/*.ts"
|
|
111
|
+
},
|
|
112
|
+
"./utils/*": {
|
|
113
|
+
"types": "./dist/types/utils/*.d.ts",
|
|
114
|
+
"import": "./src/utils/*.ts"
|
|
115
|
+
},
|
|
116
|
+
"./utils/discovery": {
|
|
117
|
+
"types": "./dist/types/utils/discovery/index.d.ts",
|
|
118
|
+
"import": "./src/utils/discovery/index.ts"
|
|
119
|
+
},
|
|
120
|
+
"./utils/discovery/*": {
|
|
121
|
+
"types": "./dist/types/utils/discovery/*.d.ts",
|
|
122
|
+
"import": "./src/utils/discovery/*.ts"
|
|
123
|
+
},
|
|
124
|
+
"./utils/oauth": {
|
|
125
|
+
"types": "./dist/types/utils/oauth/index.d.ts",
|
|
126
|
+
"import": "./src/utils/oauth/index.ts"
|
|
127
|
+
},
|
|
128
|
+
"./utils/oauth/*": {
|
|
129
|
+
"types": "./dist/types/utils/oauth/*.d.ts",
|
|
130
|
+
"import": "./src/utils/oauth/*.ts"
|
|
131
|
+
},
|
|
132
|
+
"./utils/schema": {
|
|
133
|
+
"types": "./dist/types/utils/schema/index.d.ts",
|
|
134
|
+
"import": "./src/utils/schema/index.ts"
|
|
135
|
+
},
|
|
136
|
+
"./utils/schema/*": {
|
|
137
|
+
"types": "./dist/types/utils/schema/*.d.ts",
|
|
138
|
+
"import": "./src/utils/schema/*.ts"
|
|
139
|
+
},
|
|
140
|
+
"./*.js": "./src/*.ts"
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom API provider registry.
|
|
3
|
+
*
|
|
4
|
+
* Allows extensions to register streaming functions for custom API types
|
|
5
|
+
* (e.g., "vertex-claude-api") that are not built into stream.ts.
|
|
6
|
+
*/
|
|
7
|
+
import type {
|
|
8
|
+
Api,
|
|
9
|
+
AssistantMessageEventStream,
|
|
10
|
+
Context,
|
|
11
|
+
KnownApi,
|
|
12
|
+
Model,
|
|
13
|
+
SimpleStreamOptions,
|
|
14
|
+
StreamOptions,
|
|
15
|
+
} from "./types";
|
|
16
|
+
|
|
17
|
+
const BUILTIN_APIS = new Set<KnownApi>([
|
|
18
|
+
"openai-completions",
|
|
19
|
+
"openai-responses",
|
|
20
|
+
"openai-codex-responses",
|
|
21
|
+
"azure-openai-responses",
|
|
22
|
+
"anthropic-messages",
|
|
23
|
+
"bedrock-converse-stream",
|
|
24
|
+
"google-generative-ai",
|
|
25
|
+
"google-gemini-cli",
|
|
26
|
+
"google-vertex",
|
|
27
|
+
"ollama-chat",
|
|
28
|
+
"cursor-agent",
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
export type CustomStreamFn = (
|
|
32
|
+
model: Model<Api>,
|
|
33
|
+
context: Context,
|
|
34
|
+
options?: StreamOptions,
|
|
35
|
+
) => AssistantMessageEventStream;
|
|
36
|
+
export type CustomStreamSimpleFn = (
|
|
37
|
+
model: Model<Api>,
|
|
38
|
+
context: Context,
|
|
39
|
+
options?: SimpleStreamOptions,
|
|
40
|
+
) => AssistantMessageEventStream;
|
|
41
|
+
|
|
42
|
+
export interface RegisteredCustomApi {
|
|
43
|
+
stream: CustomStreamFn;
|
|
44
|
+
streamSimple: CustomStreamSimpleFn;
|
|
45
|
+
sourceId?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const customApiRegistry = new Map<string, RegisteredCustomApi>();
|
|
49
|
+
|
|
50
|
+
function assertCustomApiName(api: string): void {
|
|
51
|
+
if (BUILTIN_APIS.has(api as KnownApi)) {
|
|
52
|
+
throw new Error(`Cannot register custom API "${api}": built-in API names are reserved.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Register a custom API streaming function.
|
|
58
|
+
*/
|
|
59
|
+
export function registerCustomApi(
|
|
60
|
+
api: string,
|
|
61
|
+
streamSimple: CustomStreamSimpleFn,
|
|
62
|
+
sourceId?: string,
|
|
63
|
+
stream?: CustomStreamFn,
|
|
64
|
+
): void {
|
|
65
|
+
assertCustomApiName(api);
|
|
66
|
+
customApiRegistry.set(api, {
|
|
67
|
+
stream: stream ?? ((model, context, options) => streamSimple(model, context, options as SimpleStreamOptions)),
|
|
68
|
+
streamSimple,
|
|
69
|
+
sourceId,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get a custom API provider by API identifier.
|
|
75
|
+
*/
|
|
76
|
+
export function getCustomApi(api: string): RegisteredCustomApi | undefined {
|
|
77
|
+
return customApiRegistry.get(api);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Remove all custom APIs registered by a specific source (e.g., extension path).
|
|
82
|
+
*/
|
|
83
|
+
export function unregisterCustomApis(sourceId: string): void {
|
|
84
|
+
for (const [api, entry] of customApiRegistry.entries()) {
|
|
85
|
+
if (entry.sourceId === sourceId) {
|
|
86
|
+
customApiRegistry.delete(api);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Clear all custom API registrations.
|
|
93
|
+
*/
|
|
94
|
+
export function clearCustomApis(): void {
|
|
95
|
+
customApiRegistry.clear();
|
|
96
|
+
}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client for the prometheus auth-broker server.
|
|
3
|
+
*
|
|
4
|
+
* Used by {@link RemoteAuthCredentialStore} (snapshot pulls) and by
|
|
5
|
+
* `prometheus auth-broker status` (liveness checks). All endpoints except
|
|
6
|
+
* `/v1/healthz` require a bearer token.
|
|
7
|
+
*/
|
|
8
|
+
import { readSseEvents } from "@prometheus-ai/utils";
|
|
9
|
+
import type { ZodType, infer as zInfer } from "zod/v4";
|
|
10
|
+
import type { AuthCredential } from "../auth-storage";
|
|
11
|
+
import type {
|
|
12
|
+
CredentialDisableRequest,
|
|
13
|
+
CredentialDisableResponse,
|
|
14
|
+
CredentialRefreshResponse,
|
|
15
|
+
CredentialUploadRequest,
|
|
16
|
+
CredentialUploadResponse,
|
|
17
|
+
HealthzResponse,
|
|
18
|
+
SnapshotResponse,
|
|
19
|
+
SnapshotStreamEvent,
|
|
20
|
+
UsageResponse,
|
|
21
|
+
} from "./types";
|
|
22
|
+
import {
|
|
23
|
+
credentialDisableResponseSchema,
|
|
24
|
+
credentialRefreshResponseSchema,
|
|
25
|
+
credentialUploadResponseSchema,
|
|
26
|
+
healthzResponseSchema,
|
|
27
|
+
snapshotResponseSchema,
|
|
28
|
+
snapshotStreamEventSchema,
|
|
29
|
+
usageResponseSchema,
|
|
30
|
+
} from "./wire-schemas";
|
|
31
|
+
|
|
32
|
+
export interface AuthBrokerClientOptions {
|
|
33
|
+
/** Base URL (e.g. `https://broker.tailnet:8765`). Trailing slashes are trimmed. */
|
|
34
|
+
url: string;
|
|
35
|
+
/** Bearer token used for everything except `healthz`. */
|
|
36
|
+
token: string;
|
|
37
|
+
/** Per-request timeout in milliseconds. Default 10s. */
|
|
38
|
+
timeoutMs?: number;
|
|
39
|
+
/** Retry connection errors this many times. Default 1. */
|
|
40
|
+
maxRetries?: number;
|
|
41
|
+
/** Override fetch (used in tests). Default global `fetch`. */
|
|
42
|
+
fetchImpl?: typeof fetch;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class AuthBrokerError extends Error {
|
|
46
|
+
readonly status: number | undefined;
|
|
47
|
+
readonly body: string | undefined;
|
|
48
|
+
constructor(message: string, opts: { status?: number; body?: string; cause?: unknown } = {}) {
|
|
49
|
+
super(message, { cause: opts.cause });
|
|
50
|
+
this.name = "AuthBrokerError";
|
|
51
|
+
this.status = opts.status;
|
|
52
|
+
this.body = opts.body;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Thrown when a broker responds 404 to `GET /v1/snapshot/stream` — old
|
|
58
|
+
* brokers that predate the SSE endpoint. Callers (`RemoteAuthCredentialStore`)
|
|
59
|
+
* detect this sentinel to fall back to long-polling permanently.
|
|
60
|
+
*/
|
|
61
|
+
export class AuthBrokerStreamUnsupportedError extends AuthBrokerError {
|
|
62
|
+
constructor(message = "Auth broker does not support /v1/snapshot/stream") {
|
|
63
|
+
super(message, { status: 404 });
|
|
64
|
+
this.name = "AuthBrokerStreamUnsupportedError";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface FetchSnapshotOptions {
|
|
69
|
+
ifGenerationGt?: number;
|
|
70
|
+
waitMs?: number;
|
|
71
|
+
signal?: AbortSignal;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type FetchSnapshotResult =
|
|
75
|
+
| { status: 200; snapshot: SnapshotResponse; generation: number }
|
|
76
|
+
| { status: 304; generation: number };
|
|
77
|
+
|
|
78
|
+
function parseGenerationTag(header: string | null): number | undefined {
|
|
79
|
+
if (!header) return undefined;
|
|
80
|
+
let value = header.trim();
|
|
81
|
+
if (value.startsWith("W/")) value = value.slice(2).trim();
|
|
82
|
+
if (value.startsWith('"') && value.endsWith('"') && value.length >= 2) {
|
|
83
|
+
value = value.slice(1, -1);
|
|
84
|
+
}
|
|
85
|
+
const generation = Number(value);
|
|
86
|
+
if (!Number.isInteger(generation) || generation < 0) return undefined;
|
|
87
|
+
return generation;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
91
|
+
const DEFAULT_MAX_RETRIES = 1;
|
|
92
|
+
|
|
93
|
+
export class AuthBrokerClient {
|
|
94
|
+
readonly #baseUrl: string;
|
|
95
|
+
readonly #token: string;
|
|
96
|
+
readonly #timeoutMs: number;
|
|
97
|
+
readonly #maxRetries: number;
|
|
98
|
+
readonly #fetch: typeof fetch;
|
|
99
|
+
|
|
100
|
+
constructor(opts: AuthBrokerClientOptions) {
|
|
101
|
+
this.#baseUrl = opts.url.replace(/\/+$/, "");
|
|
102
|
+
this.#token = opts.token;
|
|
103
|
+
this.#timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
104
|
+
this.#maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
105
|
+
this.#fetch = opts.fetchImpl ?? fetch;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
healthz(signal?: AbortSignal): Promise<HealthzResponse> {
|
|
109
|
+
return this.#request("GET", "/v1/healthz", { schema: healthzResponseSchema, auth: false, signal });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async fetchSnapshot(opts: FetchSnapshotOptions = {}): Promise<FetchSnapshotResult> {
|
|
113
|
+
return this.#fetchSnapshotResult(opts);
|
|
114
|
+
}
|
|
115
|
+
async #fetchSnapshotResult(opts: FetchSnapshotOptions): Promise<FetchSnapshotResult> {
|
|
116
|
+
const query = new URLSearchParams();
|
|
117
|
+
if (opts.waitMs !== undefined) query.set("wait", String(opts.waitMs));
|
|
118
|
+
const path = `/v1/snapshot${query.size > 0 ? `?${query.toString()}` : ""}`;
|
|
119
|
+
const headers: Record<string, string> = {};
|
|
120
|
+
if (opts.ifGenerationGt !== undefined) headers["If-None-Match"] = `"${opts.ifGenerationGt}"`;
|
|
121
|
+
const timeoutMs =
|
|
122
|
+
opts.waitMs !== undefined && opts.waitMs > 0 ? Math.max(this.#timeoutMs, opts.waitMs + 1000) : undefined;
|
|
123
|
+
const response = await this.#fetchRaw("GET", path, {
|
|
124
|
+
auth: true,
|
|
125
|
+
headers,
|
|
126
|
+
signal: opts.signal,
|
|
127
|
+
timeoutMs,
|
|
128
|
+
});
|
|
129
|
+
const etagGeneration = parseGenerationTag(response.headers.get("etag"));
|
|
130
|
+
if (response.status === 304) {
|
|
131
|
+
return { status: 304, generation: etagGeneration ?? opts.ifGenerationGt ?? 0 };
|
|
132
|
+
}
|
|
133
|
+
const text = await response.text();
|
|
134
|
+
const raw = this.#parseJson(text, response.status);
|
|
135
|
+
const validated = snapshotResponseSchema.safeParse(raw);
|
|
136
|
+
if (!validated.success) {
|
|
137
|
+
throw new AuthBrokerError("Auth broker response failed schema validation", {
|
|
138
|
+
status: response.status,
|
|
139
|
+
body: validated.error.message,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
const snapshot = validated.data as SnapshotResponse;
|
|
143
|
+
return { status: 200, snapshot, generation: etagGeneration ?? snapshot.generation };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Subscribe to the broker's SSE snapshot stream. The first frame is always
|
|
148
|
+
* a full `snapshot`; subsequent frames are `entry` upserts / refreshes or
|
|
149
|
+
* `removed` deletes. Caller controls lifecycle via `opts.signal`.
|
|
150
|
+
*
|
|
151
|
+
* Throws {@link AuthBrokerStreamUnsupportedError} when the broker responds
|
|
152
|
+
* 404 — older brokers predate this endpoint and the caller should fall back
|
|
153
|
+
* to long-polling for the remainder of its lifetime.
|
|
154
|
+
*/
|
|
155
|
+
async *openSnapshotStream(opts: { signal?: AbortSignal } = {}): AsyncGenerator<SnapshotStreamEvent> {
|
|
156
|
+
const url = `${this.#baseUrl}/v1/snapshot/stream`;
|
|
157
|
+
const headers: Record<string, string> = {
|
|
158
|
+
Accept: "text/event-stream",
|
|
159
|
+
Authorization: `Bearer ${this.#token}`,
|
|
160
|
+
};
|
|
161
|
+
if (opts.signal?.aborted) {
|
|
162
|
+
throw new AuthBrokerError("Auth broker request aborted", { cause: opts.signal.reason });
|
|
163
|
+
}
|
|
164
|
+
// No timeout: this connection is intentionally long-lived. Caller's signal
|
|
165
|
+
// is the only cancel path.
|
|
166
|
+
const response = await this.#fetch(url, { method: "GET", headers, signal: opts.signal });
|
|
167
|
+
if (response.status === 404) {
|
|
168
|
+
// Drain the body so the socket can be reused; tiny payload.
|
|
169
|
+
await response.text().catch(() => {});
|
|
170
|
+
throw new AuthBrokerStreamUnsupportedError();
|
|
171
|
+
}
|
|
172
|
+
if (!response.ok) {
|
|
173
|
+
const text = await response.text().catch(() => "");
|
|
174
|
+
throw new AuthBrokerError(`Auth broker stream failed: ${response.status} ${response.statusText}`, {
|
|
175
|
+
status: response.status,
|
|
176
|
+
body: text,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
if (!response.body) {
|
|
180
|
+
throw new AuthBrokerError("Auth broker stream response had no body", { status: response.status });
|
|
181
|
+
}
|
|
182
|
+
const contentType = response.headers.get("content-type")?.toLowerCase();
|
|
183
|
+
if (contentType?.split(";", 1)[0].trim() !== "text/event-stream") {
|
|
184
|
+
await response.body.cancel().catch(() => {});
|
|
185
|
+
throw new AuthBrokerError("Auth broker stream returned non-SSE response", {
|
|
186
|
+
status: response.status,
|
|
187
|
+
body: contentType ?? "",
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
let sawFirstEvent = false;
|
|
192
|
+
for await (const sse of readSseEvents(response.body, opts.signal)) {
|
|
193
|
+
if (sse.event === null && sse.data === "") continue; // keepalive comment frames
|
|
194
|
+
let parsed: unknown;
|
|
195
|
+
try {
|
|
196
|
+
parsed = JSON.parse(sse.data);
|
|
197
|
+
} catch (err) {
|
|
198
|
+
throw new AuthBrokerError("Auth broker stream returned malformed JSON", {
|
|
199
|
+
body: sse.data,
|
|
200
|
+
cause: err,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
const validated = snapshotStreamEventSchema.safeParse(parsed);
|
|
204
|
+
if (!validated.success) {
|
|
205
|
+
throw new AuthBrokerError("Auth broker stream event failed schema validation", {
|
|
206
|
+
body: validated.error.message,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
const event = validated.data;
|
|
210
|
+
if (!sawFirstEvent) {
|
|
211
|
+
sawFirstEvent = true;
|
|
212
|
+
if (event.kind !== "snapshot") {
|
|
213
|
+
throw new AuthBrokerError("Auth broker stream did not start with snapshot", { body: sse.data });
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
yield event;
|
|
217
|
+
}
|
|
218
|
+
if (!opts.signal?.aborted) {
|
|
219
|
+
throw new AuthBrokerError(
|
|
220
|
+
sawFirstEvent
|
|
221
|
+
? "Auth broker stream ended unexpectedly"
|
|
222
|
+
: "Auth broker stream ended before initial snapshot",
|
|
223
|
+
{ status: response.status },
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
fetchUsage(signal?: AbortSignal): Promise<UsageResponse> {
|
|
229
|
+
// Validates the envelope (`generatedAt`, `reports[].provider`, `limits`,
|
|
230
|
+
// `metadata`) but leaves provider-specific extension fields permissive so
|
|
231
|
+
// the broker can ship new shapes ahead of the client. `raw` is accepted
|
|
232
|
+
// but normally stripped by the broker before send.
|
|
233
|
+
return this.#request("GET", "/v1/usage", { schema: usageResponseSchema, signal }) as Promise<UsageResponse>;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async refreshCredential(id: number, signal?: AbortSignal): Promise<CredentialRefreshResponse> {
|
|
237
|
+
return this.#request("POST", `/v1/credential/${id}/refresh`, {
|
|
238
|
+
schema: credentialRefreshResponseSchema,
|
|
239
|
+
signal,
|
|
240
|
+
}) as Promise<CredentialRefreshResponse>;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async disableCredential(id: number, cause: string, signal?: AbortSignal): Promise<CredentialDisableResponse> {
|
|
244
|
+
const body: CredentialDisableRequest = { cause };
|
|
245
|
+
return this.#request("POST", `/v1/credential/${id}/disable`, {
|
|
246
|
+
body,
|
|
247
|
+
schema: credentialDisableResponseSchema,
|
|
248
|
+
signal,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async uploadCredential(
|
|
253
|
+
provider: string,
|
|
254
|
+
credential: AuthCredential,
|
|
255
|
+
signal?: AbortSignal,
|
|
256
|
+
): Promise<CredentialUploadResponse> {
|
|
257
|
+
const body: CredentialUploadRequest = { provider, credential };
|
|
258
|
+
return this.#request("POST", "/v1/credential", {
|
|
259
|
+
body,
|
|
260
|
+
schema: credentialUploadResponseSchema,
|
|
261
|
+
signal,
|
|
262
|
+
}) as Promise<CredentialUploadResponse>;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async #request<TSchema extends ZodType>(
|
|
266
|
+
method: "GET" | "POST",
|
|
267
|
+
path: string,
|
|
268
|
+
opts: { schema: TSchema; auth?: boolean; body?: unknown; signal?: AbortSignal },
|
|
269
|
+
): Promise<zInfer<TSchema>> {
|
|
270
|
+
const response = await this.#fetchRaw(method, path, opts);
|
|
271
|
+
const text = await response.text();
|
|
272
|
+
const raw = this.#parseJson(text, response.status);
|
|
273
|
+
const validated = opts.schema.safeParse(raw);
|
|
274
|
+
if (!validated.success) {
|
|
275
|
+
throw new AuthBrokerError("Auth broker response failed schema validation", {
|
|
276
|
+
status: response.status,
|
|
277
|
+
body: validated.error.message,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
return validated.data;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
#parseJson(text: string, status: number): unknown {
|
|
284
|
+
try {
|
|
285
|
+
return text.length === 0 ? null : JSON.parse(text);
|
|
286
|
+
} catch (parseError) {
|
|
287
|
+
throw new AuthBrokerError("Auth broker returned malformed JSON", {
|
|
288
|
+
status,
|
|
289
|
+
body: text,
|
|
290
|
+
cause: parseError,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async #fetchRaw(
|
|
296
|
+
method: "GET" | "POST",
|
|
297
|
+
path: string,
|
|
298
|
+
opts: {
|
|
299
|
+
auth?: boolean;
|
|
300
|
+
body?: unknown;
|
|
301
|
+
signal?: AbortSignal;
|
|
302
|
+
headers?: Record<string, string>;
|
|
303
|
+
timeoutMs?: number;
|
|
304
|
+
},
|
|
305
|
+
): Promise<Response> {
|
|
306
|
+
const auth = opts.auth ?? true;
|
|
307
|
+
const url = `${this.#baseUrl}${path}`;
|
|
308
|
+
const headers: Record<string, string> = { Accept: "application/json", ...(opts.headers ?? {}) };
|
|
309
|
+
if (auth) headers.Authorization = `Bearer ${this.#token}`;
|
|
310
|
+
let payload: string | undefined;
|
|
311
|
+
if (opts.body !== undefined) {
|
|
312
|
+
payload = JSON.stringify(opts.body);
|
|
313
|
+
headers["Content-Type"] = "application/json";
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Fast-fail when the caller's signal is already aborted — avoids spinning
|
|
317
|
+
// up a fetch + timer that the first `await` would just abort anyway.
|
|
318
|
+
if (opts.signal?.aborted) {
|
|
319
|
+
throw new AuthBrokerError("Auth broker request aborted", { cause: opts.signal.reason });
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
let lastError: unknown;
|
|
323
|
+
for (let attempt = 0; attempt <= this.#maxRetries; attempt += 1) {
|
|
324
|
+
const timeoutSignal = AbortSignal.timeout(opts.timeoutMs ?? this.#timeoutMs);
|
|
325
|
+
const signal = opts.signal ? AbortSignal.any([opts.signal, timeoutSignal]) : timeoutSignal;
|
|
326
|
+
try {
|
|
327
|
+
const response = await this.#fetch(url, {
|
|
328
|
+
method,
|
|
329
|
+
headers,
|
|
330
|
+
body: payload,
|
|
331
|
+
signal,
|
|
332
|
+
});
|
|
333
|
+
if (!response.ok && response.status !== 304) {
|
|
334
|
+
const text = await response.text();
|
|
335
|
+
throw new AuthBrokerError(`Auth broker request failed: ${response.status} ${response.statusText}`, {
|
|
336
|
+
status: response.status,
|
|
337
|
+
body: text,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
return response;
|
|
341
|
+
} catch (error) {
|
|
342
|
+
lastError = error;
|
|
343
|
+
// Caller-driven abort wins over retry — the caller said stop.
|
|
344
|
+
if (opts.signal?.aborted) {
|
|
345
|
+
throw new AuthBrokerError("Auth broker request aborted", { cause: opts.signal.reason });
|
|
346
|
+
}
|
|
347
|
+
if (error instanceof AuthBrokerError && error.status !== undefined) {
|
|
348
|
+
// HTTP errors (4xx/5xx) don't retry — caller knows what to do.
|
|
349
|
+
throw error;
|
|
350
|
+
}
|
|
351
|
+
if (attempt >= this.#maxRetries) break;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
throw new AuthBrokerError(`Auth broker request failed after ${this.#maxRetries + 1} attempt(s)`, {
|
|
355
|
+
cause: lastError,
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
}
|