@earendil-works/pi-ai 0.87.1 → 0.99.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/README.md +207 -27
- package/dist/api/anthropic-messages.d.ts.map +1 -1
- package/dist/api/anthropic-messages.js +6 -0
- package/dist/api/anthropic-messages.js.map +1 -1
- package/dist/api/anthropic-messages.lazy.d.ts.map +1 -1
- package/dist/api/azure-openai-responses.d.ts.map +1 -1
- package/dist/api/azure-openai-responses.js +6 -5
- package/dist/api/azure-openai-responses.js.map +1 -1
- package/dist/api/azure-openai-responses.lazy.d.ts.map +1 -1
- package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
- package/dist/api/bedrock-converse-stream.js +1 -0
- package/dist/api/bedrock-converse-stream.js.map +1 -1
- package/dist/api/bedrock-converse-stream.lazy.d.ts.map +1 -1
- package/dist/api/bedrock-converse-stream.lazy.js.map +1 -1
- package/dist/api/cloudflare-ai-binding.d.ts.map +1 -1
- package/dist/api/cloudflare-ai-binding.js.map +1 -1
- package/dist/api/cloudflare-workers-ai-system-one.d.ts +4 -0
- package/dist/api/cloudflare-workers-ai-system-one.d.ts.map +1 -0
- package/dist/api/cloudflare-workers-ai-system-one.js +43 -0
- package/dist/api/cloudflare-workers-ai-system-one.js.map +1 -0
- package/dist/api/cloudflare-workers-ai-system-one.lazy.d.ts +3 -0
- package/dist/api/cloudflare-workers-ai-system-one.lazy.d.ts.map +1 -0
- package/dist/api/cloudflare-workers-ai-system-one.lazy.js +4 -0
- package/dist/api/cloudflare-workers-ai-system-one.lazy.js.map +1 -0
- package/dist/api/cloudflare.d.ts +2 -0
- package/dist/api/cloudflare.d.ts.map +1 -1
- package/dist/api/cloudflare.js +2 -0
- package/dist/api/cloudflare.js.map +1 -1
- package/dist/api/constrained-sampling.d.ts.map +1 -1
- package/dist/api/constrained-sampling.js.map +1 -1
- package/dist/api/github-copilot-headers.d.ts.map +1 -1
- package/dist/api/github-copilot-headers.js.map +1 -1
- package/dist/api/google-generative-ai.d.ts.map +1 -1
- package/dist/api/google-generative-ai.js +1 -0
- package/dist/api/google-generative-ai.js.map +1 -1
- package/dist/api/google-generative-ai.lazy.d.ts.map +1 -1
- package/dist/api/google-shared.d.ts.map +1 -1
- package/dist/api/google-shared.js.map +1 -1
- package/dist/api/google-vertex.d.ts.map +1 -1
- package/dist/api/google-vertex.js +1 -0
- package/dist/api/google-vertex.js.map +1 -1
- package/dist/api/google-vertex.lazy.d.ts.map +1 -1
- package/dist/api/lazy.d.ts.map +1 -1
- package/dist/api/lazy.js.map +1 -1
- package/dist/api/llama-cpp-classify.d.ts +33 -0
- package/dist/api/llama-cpp-classify.d.ts.map +1 -0
- package/dist/api/llama-cpp-classify.js +365 -0
- package/dist/api/llama-cpp-classify.js.map +1 -0
- package/dist/api/llama-cpp-classify.lazy.d.ts +3 -0
- package/dist/api/llama-cpp-classify.lazy.d.ts.map +1 -0
- package/dist/api/llama-cpp-classify.lazy.js +4 -0
- package/dist/api/llama-cpp-classify.lazy.js.map +1 -0
- package/dist/api/mistral-conversations.d.ts +1 -1
- package/dist/api/mistral-conversations.d.ts.map +1 -1
- package/dist/api/mistral-conversations.js +18 -17
- package/dist/api/mistral-conversations.js.map +1 -1
- package/dist/api/mistral-conversations.lazy.d.ts.map +1 -1
- package/dist/api/openai-codex-responses.d.ts.map +1 -1
- package/dist/api/openai-codex-responses.js +20 -4
- package/dist/api/openai-codex-responses.js.map +1 -1
- package/dist/api/openai-codex-responses.lazy.d.ts.map +1 -1
- package/dist/api/openai-completions.d.ts.map +1 -1
- package/dist/api/openai-completions.js +4 -4
- package/dist/api/openai-completions.js.map +1 -1
- package/dist/api/openai-completions.lazy.d.ts.map +1 -1
- package/dist/api/openai-prompt-cache.d.ts.map +1 -1
- package/dist/api/openai-prompt-cache.js.map +1 -1
- package/dist/api/openai-responses-shared.d.ts +2 -1
- package/dist/api/openai-responses-shared.d.ts.map +1 -1
- package/dist/api/openai-responses-shared.js +14 -0
- package/dist/api/openai-responses-shared.js.map +1 -1
- package/dist/api/openai-responses.d.ts.map +1 -1
- package/dist/api/openai-responses.js +26 -9
- package/dist/api/openai-responses.js.map +1 -1
- package/dist/api/openai-responses.lazy.d.ts.map +1 -1
- package/dist/api/openrouter-images.d.ts +2 -1
- package/dist/api/openrouter-images.d.ts.map +1 -1
- package/dist/api/openrouter-images.js +1 -0
- package/dist/api/openrouter-images.js.map +1 -1
- package/dist/api/openrouter-images.lazy.d.ts.map +1 -1
- package/dist/api/openrouter-images.lazy.js.map +1 -1
- package/dist/api/pi-messages.d.ts.map +1 -1
- package/dist/api/pi-messages.js +1 -0
- package/dist/api/pi-messages.js.map +1 -1
- package/dist/api/pi-messages.lazy.d.ts.map +1 -1
- package/dist/api/simple-options.d.ts.map +1 -1
- package/dist/api/simple-options.js +2 -4
- package/dist/api/simple-options.js.map +1 -1
- package/dist/api/system-one-shared.d.ts +23 -0
- package/dist/api/system-one-shared.d.ts.map +1 -0
- package/dist/api/system-one-shared.js +183 -0
- package/dist/api/system-one-shared.js.map +1 -0
- package/dist/api/transform-messages.d.ts.map +1 -1
- package/dist/api/transform-messages.js.map +1 -1
- package/dist/api/typesafe-system-one.d.ts +4 -0
- package/dist/api/typesafe-system-one.d.ts.map +1 -0
- package/dist/api/typesafe-system-one.js +19 -0
- package/dist/api/typesafe-system-one.js.map +1 -0
- package/dist/api/typesafe-system-one.lazy.d.ts +3 -0
- package/dist/api/typesafe-system-one.lazy.d.ts.map +1 -0
- package/dist/api/typesafe-system-one.lazy.js +4 -0
- package/dist/api/typesafe-system-one.lazy.js.map +1 -0
- package/dist/auth/context.d.ts.map +1 -1
- package/dist/auth/context.js.map +1 -1
- package/dist/auth/credential-store.d.ts.map +1 -1
- package/dist/auth/credential-store.js.map +1 -1
- package/dist/auth/helpers.d.ts.map +1 -1
- package/dist/auth/helpers.js +1 -1
- package/dist/auth/helpers.js.map +1 -1
- package/dist/auth/oauth/anthropic.d.ts.map +1 -1
- package/dist/auth/oauth/anthropic.js +19 -128
- package/dist/auth/oauth/anthropic.js.map +1 -1
- package/dist/auth/oauth/callback-server.d.ts +55 -0
- package/dist/auth/oauth/callback-server.d.ts.map +1 -0
- package/dist/auth/oauth/callback-server.js +146 -0
- package/dist/auth/oauth/callback-server.js.map +1 -0
- package/dist/auth/oauth/device-code.d.ts.map +1 -1
- package/dist/auth/oauth/device-code.js.map +1 -1
- package/dist/auth/oauth/github-copilot.d.ts.map +1 -1
- package/dist/auth/oauth/github-copilot.js.map +1 -1
- package/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
- package/dist/auth/oauth/kimi-coding.js.map +1 -1
- package/dist/auth/oauth/load.d.ts +2 -0
- package/dist/auth/oauth/load.d.ts.map +1 -1
- package/dist/auth/oauth/load.js +5 -0
- package/dist/auth/oauth/load.js.map +1 -1
- package/dist/auth/oauth/meta.d.ts.map +1 -1
- package/dist/auth/oauth/meta.js.map +1 -1
- package/dist/auth/oauth/openai-chatgpt.d.ts +9 -0
- package/dist/auth/oauth/openai-chatgpt.d.ts.map +1 -0
- package/dist/auth/oauth/openai-chatgpt.js +266 -0
- package/dist/auth/oauth/openai-chatgpt.js.map +1 -0
- package/dist/auth/oauth/openai-codex.d.ts +1 -1
- package/dist/auth/oauth/openai-codex.d.ts.map +1 -1
- package/dist/auth/oauth/openai-codex.js +20 -124
- package/dist/auth/oauth/openai-codex.js.map +1 -1
- package/dist/auth/oauth/openrouter.d.ts +1 -1
- package/dist/auth/oauth/openrouter.d.ts.map +1 -1
- package/dist/auth/oauth/openrouter.js +19 -138
- package/dist/auth/oauth/openrouter.js.map +1 -1
- package/dist/auth/oauth/pkce.d.ts.map +1 -1
- package/dist/auth/oauth/pkce.js.map +1 -1
- package/dist/auth/oauth/radius.d.ts +1 -1
- package/dist/auth/oauth/radius.d.ts.map +1 -1
- package/dist/auth/oauth/radius.js +21 -89
- package/dist/auth/oauth/radius.js.map +1 -1
- package/dist/auth/oauth/xai.d.ts.map +1 -1
- package/dist/auth/oauth/xai.js.map +1 -1
- package/dist/auth/resolve.d.ts +2 -8
- package/dist/auth/resolve.d.ts.map +1 -1
- package/dist/auth/resolve.js +3 -19
- package/dist/auth/resolve.js.map +1 -1
- package/dist/auth/types.d.ts +10 -1
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/auth/types.js.map +1 -1
- package/dist/bedrock-provider.d.ts.map +1 -1
- package/dist/bun-oauth.d.ts.map +1 -1
- package/dist/bun-oauth.js +2 -0
- package/dist/bun-oauth.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/compat/extension-oauth-types.d.ts.map +1 -1
- package/dist/compat.d.ts.map +1 -1
- package/dist/compat.js.map +1 -1
- package/dist/env-api-keys.d.ts.map +1 -1
- package/dist/env-api-keys.js +1 -0
- package/dist/env-api-keys.js.map +1 -1
- package/dist/image-models.d.ts +19 -8
- package/dist/image-models.d.ts.map +1 -1
- package/dist/image-models.js +14 -13
- package/dist/image-models.js.map +1 -1
- package/dist/images-api-registry.d.ts +7 -7
- package/dist/images-api-registry.d.ts.map +1 -1
- package/dist/images-api-registry.js.map +1 -1
- package/dist/images.d.ts +7 -2
- package/dist/images.d.ts.map +1 -1
- package/dist/images.js +5 -0
- package/dist/images.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/legacy-api-aliases.d.ts.map +1 -1
- package/dist/model-catalog.d.ts +25 -9
- package/dist/model-catalog.d.ts.map +1 -1
- package/dist/model-catalog.js +14 -2
- package/dist/model-catalog.js.map +1 -1
- package/dist/models-store.d.ts +3 -2
- package/dist/models-store.d.ts.map +1 -1
- package/dist/models-store.js.map +1 -1
- package/dist/models.d.ts +97 -30
- package/dist/models.d.ts.map +1 -1
- package/dist/models.generated.d.ts +131 -41
- package/dist/models.generated.d.ts.map +1 -1
- package/dist/models.generated.js +131 -41
- package/dist/models.generated.js.map +1 -1
- package/dist/models.js +157 -30
- package/dist/models.js.map +1 -1
- package/dist/oauth.d.ts.map +1 -1
- package/dist/providers/all.d.ts +19 -13
- package/dist/providers/all.d.ts.map +1 -1
- package/dist/providers/all.js +25 -21
- package/dist/providers/all.js.map +1 -1
- package/dist/providers/amazon-bedrock.d.ts.map +1 -1
- package/dist/providers/amazon-bedrock.js.map +1 -1
- package/dist/providers/amazon-bedrock.models.d.ts +4 -2
- package/dist/providers/amazon-bedrock.models.d.ts.map +1 -1
- package/dist/providers/amazon-bedrock.models.js +4 -2
- package/dist/providers/amazon-bedrock.models.js.map +1 -1
- package/dist/providers/ant-ling.d.ts.map +1 -1
- package/dist/providers/ant-ling.js.map +1 -1
- package/dist/providers/ant-ling.models.d.ts +4 -2
- package/dist/providers/ant-ling.models.d.ts.map +1 -1
- package/dist/providers/ant-ling.models.js +4 -2
- package/dist/providers/ant-ling.models.js.map +1 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/anthropic.models.d.ts +4 -2
- package/dist/providers/anthropic.models.d.ts.map +1 -1
- package/dist/providers/anthropic.models.js +4 -2
- package/dist/providers/anthropic.models.js.map +1 -1
- package/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/dist/providers/azure-openai-responses.js.map +1 -1
- package/dist/providers/azure-openai-responses.models.d.ts +4 -2
- package/dist/providers/azure-openai-responses.models.d.ts.map +1 -1
- package/dist/providers/azure-openai-responses.models.js +4 -2
- package/dist/providers/azure-openai-responses.models.js.map +1 -1
- package/dist/providers/baseten.d.ts.map +1 -1
- package/dist/providers/baseten.js.map +1 -1
- package/dist/providers/baseten.models.d.ts +4 -2
- package/dist/providers/baseten.models.d.ts.map +1 -1
- package/dist/providers/baseten.models.js +4 -2
- package/dist/providers/baseten.models.js.map +1 -1
- package/dist/providers/cerebras.d.ts.map +1 -1
- package/dist/providers/cerebras.js.map +1 -1
- package/dist/providers/cerebras.models.d.ts +4 -2
- package/dist/providers/cerebras.models.d.ts.map +1 -1
- package/dist/providers/cerebras.models.js +4 -2
- package/dist/providers/cerebras.models.js.map +1 -1
- package/dist/providers/cloudflare-ai-gateway.d.ts.map +1 -1
- package/dist/providers/cloudflare-ai-gateway.js.map +1 -1
- package/dist/providers/cloudflare-ai-gateway.models.d.ts +4 -2
- package/dist/providers/cloudflare-ai-gateway.models.d.ts.map +1 -1
- package/dist/providers/cloudflare-ai-gateway.models.js +4 -2
- package/dist/providers/cloudflare-ai-gateway.models.js.map +1 -1
- package/dist/providers/cloudflare-auth.d.ts.map +1 -1
- package/dist/providers/cloudflare-auth.js.map +1 -1
- package/dist/providers/cloudflare-stream.d.ts +6 -2
- package/dist/providers/cloudflare-stream.d.ts.map +1 -1
- package/dist/providers/cloudflare-stream.js +6 -0
- package/dist/providers/cloudflare-stream.js.map +1 -1
- package/dist/providers/cloudflare-workers-ai.d.ts.map +1 -1
- package/dist/providers/cloudflare-workers-ai.js +10 -3
- package/dist/providers/cloudflare-workers-ai.js.map +1 -1
- package/dist/providers/cloudflare-workers-ai.models.d.ts +4 -2
- package/dist/providers/cloudflare-workers-ai.models.d.ts.map +1 -1
- package/dist/providers/cloudflare-workers-ai.models.js +4 -2
- package/dist/providers/cloudflare-workers-ai.models.js.map +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/amazon-bedrock.json +1 -1
- package/dist/providers/data/ant-ling.json +1 -1
- package/dist/providers/data/anthropic.json +1 -1
- package/dist/providers/data/azure-openai-responses.json +1 -1
- package/dist/providers/data/baseten.json +1 -1
- package/dist/providers/data/cerebras.json +1 -1
- package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/dist/providers/data/cloudflare-workers-ai.json +1 -1
- package/dist/providers/data/deepseek.json +1 -1
- package/dist/providers/data/fireworks.json +1 -1
- package/dist/providers/data/github-copilot.json +1 -1
- package/dist/providers/data/google-vertex.json +1 -1
- package/dist/providers/data/google.json +1 -1
- package/dist/providers/data/groq.json +1 -1
- package/dist/providers/data/huggingface.json +1 -1
- package/dist/providers/data/kimi-coding.json +1 -1
- package/dist/providers/data/meta.json +1 -1
- package/dist/providers/data/minimax-cn.json +1 -1
- package/dist/providers/data/minimax.json +1 -1
- package/dist/providers/data/mistral.json +1 -1
- package/dist/providers/data/moonshotai-cn.json +1 -1
- package/dist/providers/data/moonshotai.json +1 -1
- package/dist/providers/data/nvidia.json +1 -1
- package/dist/providers/data/openai-codex.json +1 -1
- package/dist/providers/data/openai.json +1 -1
- package/dist/providers/data/opencode-go.json +1 -1
- package/dist/providers/data/opencode.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/qwen-token-plan-cn.json +1 -1
- package/dist/providers/data/qwen-token-plan-individual.json +1 -1
- package/dist/providers/data/qwen-token-plan.json +1 -1
- package/dist/providers/data/radius.json +1 -1
- package/dist/providers/data/together.json +1 -1
- package/dist/providers/data/typesafe.json +1 -0
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/providers/data/xai.json +1 -1
- package/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
- package/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
- package/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
- package/dist/providers/data/xiaomi.json +1 -1
- package/dist/providers/data/zai-coding-cn.json +1 -1
- package/dist/providers/data/zai.json +1 -1
- package/dist/providers/deepseek.d.ts.map +1 -1
- package/dist/providers/deepseek.js.map +1 -1
- package/dist/providers/deepseek.models.d.ts +4 -2
- package/dist/providers/deepseek.models.d.ts.map +1 -1
- package/dist/providers/deepseek.models.js +4 -2
- package/dist/providers/deepseek.models.js.map +1 -1
- package/dist/providers/faux.d.ts +2 -2
- package/dist/providers/faux.d.ts.map +1 -1
- package/dist/providers/faux.js.map +1 -1
- package/dist/providers/fireworks.d.ts.map +1 -1
- package/dist/providers/fireworks.js.map +1 -1
- package/dist/providers/fireworks.models.d.ts +4 -2
- package/dist/providers/fireworks.models.d.ts.map +1 -1
- package/dist/providers/fireworks.models.js +4 -2
- package/dist/providers/fireworks.models.js.map +1 -1
- package/dist/providers/github-copilot.d.ts.map +1 -1
- package/dist/providers/github-copilot.js.map +1 -1
- package/dist/providers/github-copilot.models.d.ts +4 -2
- package/dist/providers/github-copilot.models.d.ts.map +1 -1
- package/dist/providers/github-copilot.models.js +4 -2
- package/dist/providers/github-copilot.models.js.map +1 -1
- package/dist/providers/google-vertex.d.ts.map +1 -1
- package/dist/providers/google-vertex.js.map +1 -1
- package/dist/providers/google-vertex.models.d.ts +4 -2
- package/dist/providers/google-vertex.models.d.ts.map +1 -1
- package/dist/providers/google-vertex.models.js +4 -2
- package/dist/providers/google-vertex.models.js.map +1 -1
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/google.models.d.ts +4 -2
- package/dist/providers/google.models.d.ts.map +1 -1
- package/dist/providers/google.models.js +4 -2
- package/dist/providers/google.models.js.map +1 -1
- package/dist/providers/groq.d.ts.map +1 -1
- package/dist/providers/groq.js.map +1 -1
- package/dist/providers/groq.models.d.ts +4 -2
- package/dist/providers/groq.models.d.ts.map +1 -1
- package/dist/providers/groq.models.js +4 -2
- package/dist/providers/groq.models.js.map +1 -1
- package/dist/providers/huggingface.d.ts.map +1 -1
- package/dist/providers/huggingface.js.map +1 -1
- package/dist/providers/huggingface.models.d.ts +4 -2
- package/dist/providers/huggingface.models.d.ts.map +1 -1
- package/dist/providers/huggingface.models.js +4 -2
- package/dist/providers/huggingface.models.js.map +1 -1
- package/dist/providers/images/register-builtins.d.ts +1 -1
- package/dist/providers/images/register-builtins.d.ts.map +1 -1
- package/dist/providers/images/register-builtins.js.map +1 -1
- package/dist/providers/kimi-coding.d.ts.map +1 -1
- package/dist/providers/kimi-coding.js.map +1 -1
- package/dist/providers/kimi-coding.models.d.ts +4 -2
- package/dist/providers/kimi-coding.models.d.ts.map +1 -1
- package/dist/providers/kimi-coding.models.js +4 -2
- package/dist/providers/kimi-coding.models.js.map +1 -1
- package/dist/providers/meta.d.ts.map +1 -1
- package/dist/providers/meta.js.map +1 -1
- package/dist/providers/meta.models.d.ts +4 -2
- package/dist/providers/meta.models.d.ts.map +1 -1
- package/dist/providers/meta.models.js +4 -2
- package/dist/providers/meta.models.js.map +1 -1
- package/dist/providers/minimax-cn.d.ts.map +1 -1
- package/dist/providers/minimax-cn.js.map +1 -1
- package/dist/providers/minimax-cn.models.d.ts +4 -2
- package/dist/providers/minimax-cn.models.d.ts.map +1 -1
- package/dist/providers/minimax-cn.models.js +4 -2
- package/dist/providers/minimax-cn.models.js.map +1 -1
- package/dist/providers/minimax.d.ts.map +1 -1
- package/dist/providers/minimax.js.map +1 -1
- package/dist/providers/minimax.models.d.ts +4 -2
- package/dist/providers/minimax.models.d.ts.map +1 -1
- package/dist/providers/minimax.models.js +4 -2
- package/dist/providers/minimax.models.js.map +1 -1
- package/dist/providers/mistral.d.ts.map +1 -1
- package/dist/providers/mistral.js.map +1 -1
- package/dist/providers/mistral.models.d.ts +4 -2
- package/dist/providers/mistral.models.d.ts.map +1 -1
- package/dist/providers/mistral.models.js +4 -2
- package/dist/providers/mistral.models.js.map +1 -1
- package/dist/providers/moonshotai-cn.d.ts.map +1 -1
- package/dist/providers/moonshotai-cn.js.map +1 -1
- package/dist/providers/moonshotai-cn.models.d.ts +4 -2
- package/dist/providers/moonshotai-cn.models.d.ts.map +1 -1
- package/dist/providers/moonshotai-cn.models.js +4 -2
- package/dist/providers/moonshotai-cn.models.js.map +1 -1
- package/dist/providers/moonshotai.d.ts.map +1 -1
- package/dist/providers/moonshotai.js.map +1 -1
- package/dist/providers/moonshotai.models.d.ts +4 -2
- package/dist/providers/moonshotai.models.d.ts.map +1 -1
- package/dist/providers/moonshotai.models.js +4 -2
- package/dist/providers/moonshotai.models.js.map +1 -1
- package/dist/providers/nvidia.d.ts.map +1 -1
- package/dist/providers/nvidia.js.map +1 -1
- package/dist/providers/nvidia.models.d.ts +4 -2
- package/dist/providers/nvidia.models.d.ts.map +1 -1
- package/dist/providers/nvidia.models.js +4 -2
- package/dist/providers/nvidia.models.js.map +1 -1
- package/dist/providers/openai-codex.d.ts.map +1 -1
- package/dist/providers/openai-codex.js +1 -1
- package/dist/providers/openai-codex.js.map +1 -1
- package/dist/providers/openai-codex.models.d.ts +4 -2
- package/dist/providers/openai-codex.models.d.ts.map +1 -1
- package/dist/providers/openai-codex.models.js +4 -2
- package/dist/providers/openai-codex.models.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +11 -2
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openai.models.d.ts +4 -2
- package/dist/providers/openai.models.d.ts.map +1 -1
- package/dist/providers/openai.models.js +4 -2
- package/dist/providers/openai.models.js.map +1 -1
- package/dist/providers/opencode-go.d.ts.map +1 -1
- package/dist/providers/opencode-go.js.map +1 -1
- package/dist/providers/opencode-go.models.d.ts +4 -2
- package/dist/providers/opencode-go.models.d.ts.map +1 -1
- package/dist/providers/opencode-go.models.js +4 -2
- package/dist/providers/opencode-go.models.js.map +1 -1
- package/dist/providers/opencode-headers.d.ts.map +1 -1
- package/dist/providers/opencode-headers.js.map +1 -1
- package/dist/providers/opencode.d.ts +3 -1
- package/dist/providers/opencode.d.ts.map +1 -1
- package/dist/providers/opencode.js +5 -2
- package/dist/providers/opencode.js.map +1 -1
- package/dist/providers/opencode.models.d.ts +4 -2
- package/dist/providers/opencode.models.d.ts.map +1 -1
- package/dist/providers/opencode.models.js +4 -2
- package/dist/providers/opencode.models.js.map +1 -1
- package/dist/providers/openrouter.d.ts.map +1 -1
- package/dist/providers/openrouter.js +11 -2
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/openrouter.models.d.ts +4 -2
- package/dist/providers/openrouter.models.d.ts.map +1 -1
- package/dist/providers/openrouter.models.js +4 -2
- package/dist/providers/openrouter.models.js.map +1 -1
- package/dist/providers/qwen-token-plan-cn.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan-cn.js.map +1 -1
- package/dist/providers/qwen-token-plan-cn.models.d.ts +4 -2
- package/dist/providers/qwen-token-plan-cn.models.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan-cn.models.js +4 -2
- package/dist/providers/qwen-token-plan-cn.models.js.map +1 -1
- package/dist/providers/qwen-token-plan-individual.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan-individual.js.map +1 -1
- package/dist/providers/qwen-token-plan-individual.models.d.ts +4 -2
- package/dist/providers/qwen-token-plan-individual.models.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan-individual.models.js +4 -2
- package/dist/providers/qwen-token-plan-individual.models.js.map +1 -1
- package/dist/providers/qwen-token-plan.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan.js.map +1 -1
- package/dist/providers/qwen-token-plan.models.d.ts +4 -2
- package/dist/providers/qwen-token-plan.models.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan.models.js +4 -2
- package/dist/providers/qwen-token-plan.models.js.map +1 -1
- package/dist/providers/radius-config.d.ts.map +1 -1
- package/dist/providers/radius-config.js.map +1 -1
- package/dist/providers/radius.d.ts.map +1 -1
- package/dist/providers/radius.js.map +1 -1
- package/dist/providers/radius.models.d.ts +4 -2
- package/dist/providers/radius.models.d.ts.map +1 -1
- package/dist/providers/radius.models.js +4 -2
- package/dist/providers/radius.models.js.map +1 -1
- package/dist/providers/together.d.ts.map +1 -1
- package/dist/providers/together.js.map +1 -1
- package/dist/providers/together.models.d.ts +4 -2
- package/dist/providers/together.models.d.ts.map +1 -1
- package/dist/providers/together.models.js +4 -2
- package/dist/providers/together.models.js.map +1 -1
- package/dist/providers/typesafe.d.ts +3 -0
- package/dist/providers/typesafe.d.ts.map +1 -0
- package/dist/providers/typesafe.js +18 -0
- package/dist/providers/typesafe.js.map +1 -0
- package/dist/providers/typesafe.models.d.ts +6 -0
- package/dist/providers/typesafe.models.d.ts.map +1 -0
- package/dist/providers/typesafe.models.js +8 -0
- package/dist/providers/typesafe.models.js.map +1 -0
- package/dist/providers/vercel-ai-gateway.d.ts.map +1 -1
- package/dist/providers/vercel-ai-gateway.js +5 -2
- package/dist/providers/vercel-ai-gateway.js.map +1 -1
- package/dist/providers/vercel-ai-gateway.models.d.ts +4 -2
- package/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
- package/dist/providers/vercel-ai-gateway.models.js +4 -2
- package/dist/providers/vercel-ai-gateway.models.js.map +1 -1
- package/dist/providers/xai.d.ts.map +1 -1
- package/dist/providers/xai.js.map +1 -1
- package/dist/providers/xai.models.d.ts +4 -2
- package/dist/providers/xai.models.d.ts.map +1 -1
- package/dist/providers/xai.models.js +4 -2
- package/dist/providers/xai.models.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-ams.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-ams.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-ams.models.d.ts +4 -2
- package/dist/providers/xiaomi-token-plan-ams.models.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-ams.models.js +4 -2
- package/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-cn.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-cn.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-cn.models.d.ts +4 -2
- package/dist/providers/xiaomi-token-plan-cn.models.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-cn.models.js +4 -2
- package/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-sgp.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-sgp.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-sgp.models.d.ts +4 -2
- package/dist/providers/xiaomi-token-plan-sgp.models.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-sgp.models.js +4 -2
- package/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
- package/dist/providers/xiaomi.d.ts.map +1 -1
- package/dist/providers/xiaomi.js.map +1 -1
- package/dist/providers/xiaomi.models.d.ts +4 -2
- package/dist/providers/xiaomi.models.d.ts.map +1 -1
- package/dist/providers/xiaomi.models.js +4 -2
- package/dist/providers/xiaomi.models.js.map +1 -1
- package/dist/providers/zai-coding-cn.d.ts.map +1 -1
- package/dist/providers/zai-coding-cn.js.map +1 -1
- package/dist/providers/zai-coding-cn.models.d.ts +4 -2
- package/dist/providers/zai-coding-cn.models.d.ts.map +1 -1
- package/dist/providers/zai-coding-cn.models.js +4 -2
- package/dist/providers/zai-coding-cn.models.js.map +1 -1
- package/dist/providers/zai.d.ts.map +1 -1
- package/dist/providers/zai.js.map +1 -1
- package/dist/providers/zai.models.d.ts +4 -2
- package/dist/providers/zai.models.d.ts.map +1 -1
- package/dist/providers/zai.models.js +4 -2
- package/dist/providers/zai.models.js.map +1 -1
- package/dist/session-resources.d.ts.map +1 -1
- package/dist/session-resources.js.map +1 -1
- package/dist/types.d.ts +141 -21
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/abort-signals.d.ts.map +1 -1
- package/dist/utils/abort-signals.js.map +1 -1
- package/dist/utils/abort.d.ts.map +1 -1
- package/dist/utils/abort.js.map +1 -1
- package/dist/utils/assistant-message-frame.d.ts.map +1 -1
- package/dist/utils/assistant-message-frame.js.map +1 -1
- package/dist/utils/diagnostics.d.ts.map +1 -1
- package/dist/utils/diagnostics.js.map +1 -1
- package/dist/utils/error-body.d.ts.map +1 -1
- package/dist/utils/error-body.js.map +1 -1
- package/dist/utils/estimate.d.ts.map +1 -1
- package/dist/utils/estimate.js.map +1 -1
- package/dist/utils/event-stream.d.ts.map +1 -1
- package/dist/utils/event-stream.js.map +1 -1
- package/dist/utils/hash.d.ts.map +1 -1
- package/dist/utils/hash.js.map +1 -1
- package/dist/utils/headers.d.ts +1 -1
- package/dist/utils/headers.d.ts.map +1 -1
- package/dist/utils/headers.js +10 -8
- package/dist/utils/headers.js.map +1 -1
- package/dist/utils/json-parse.d.ts.map +1 -1
- package/dist/utils/json-parse.js.map +1 -1
- package/dist/utils/model-operations.d.ts +11 -0
- package/dist/utils/model-operations.d.ts.map +1 -0
- package/dist/utils/model-operations.js +47 -0
- package/dist/utils/model-operations.js.map +1 -0
- package/dist/utils/models-error.d.ts +8 -0
- package/dist/utils/models-error.d.ts.map +1 -0
- package/dist/utils/models-error.js +19 -0
- package/dist/utils/models-error.js.map +1 -0
- package/dist/utils/node-http-proxy.d.ts.map +1 -1
- package/dist/utils/node-http-proxy.js.map +1 -1
- package/dist/utils/oauth-page.d.ts.map +1 -0
- package/dist/utils/oauth-page.js.map +1 -0
- package/dist/utils/overflow.d.ts.map +1 -1
- package/dist/utils/overflow.js.map +1 -1
- package/dist/utils/pi-user-agent.d.ts.map +1 -1
- package/dist/utils/pi-user-agent.js.map +1 -1
- package/dist/utils/provider-env.d.ts.map +1 -1
- package/dist/utils/provider-env.js.map +1 -1
- package/dist/utils/provider-retry.d.ts.map +1 -1
- package/dist/utils/provider-retry.js.map +1 -1
- package/dist/utils/retry.d.ts.map +1 -1
- package/dist/utils/retry.js +7 -0
- package/dist/utils/retry.js.map +1 -1
- package/dist/utils/sanitize-unicode.d.ts.map +1 -1
- package/dist/utils/sanitize-unicode.js.map +1 -1
- package/dist/utils/sleep.d.ts.map +1 -1
- package/dist/utils/sleep.js.map +1 -1
- package/dist/utils/text.d.ts.map +1 -1
- package/dist/utils/text.js.map +1 -1
- package/dist/utils/transcript.d.ts.map +1 -1
- package/dist/utils/transcript.js.map +1 -1
- package/dist/utils/typebox-helpers.d.ts.map +1 -1
- package/dist/utils/typebox-helpers.js.map +1 -1
- package/dist/utils/uuid.d.ts.map +1 -1
- package/dist/utils/uuid.js.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js.map +1 -1
- package/package.json +5 -6
- package/dist/auth/oauth/oauth-page.d.ts.map +0 -1
- package/dist/auth/oauth/oauth-page.js.map +0 -1
- package/dist/image-models.generated.d.ts +0 -830
- package/dist/image-models.generated.d.ts.map +0 -1
- package/dist/image-models.generated.js +0 -832
- package/dist/image-models.generated.js.map +0 -1
- package/dist/images-models.d.ts +0 -95
- package/dist/images-models.d.ts.map +0 -1
- package/dist/images-models.js +0 -143
- package/dist/images-models.js.map +0 -1
- package/dist/providers/openrouter-images.d.ts +0 -3
- package/dist/providers/openrouter-images.d.ts.map +0 -1
- package/dist/providers/openrouter-images.js +0 -22
- package/dist/providers/openrouter-images.js.map +0 -1
- /package/dist/{auth/oauth → utils}/oauth-page.d.ts +0 -0
- /package/dist/{auth/oauth → utils}/oauth-page.js +0 -0
|
@@ -5,19 +5,12 @@
|
|
|
5
5
|
* gateway; only the interactive browser authorization endpoint is discovered.
|
|
6
6
|
* Model catalog loading is owned by the Radius provider.
|
|
7
7
|
*
|
|
8
|
-
* NOTE: This module uses node:http for the OAuth callback server.
|
|
8
|
+
* NOTE: This module uses node:http (via callback-server.ts) for the OAuth callback server.
|
|
9
9
|
* It is only intended for CLI use, not browser environments.
|
|
10
10
|
*/
|
|
11
|
-
// NEVER convert to top-level imports - breaks browser/Vite builds
|
|
12
|
-
let _http = null;
|
|
13
|
-
if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
|
|
14
|
-
import("node:http").then((m) => {
|
|
15
|
-
_http = m;
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
11
|
import { normalizeRadiusGatewayUrl } from "../../providers/radius-config.js";
|
|
12
|
+
import { startOAuthCallbackServer } from "./callback-server.js";
|
|
19
13
|
import { pollOAuthDeviceCodeFlow } from "./device-code.js";
|
|
20
|
-
import { oauthErrorHtml, oauthSuccessHtml } from "./oauth-page.js";
|
|
21
14
|
import { generatePKCE } from "./pkce.js";
|
|
22
15
|
const CALLBACK_HOST = "127.0.0.1";
|
|
23
16
|
const CALLBACK_PORT = 1456;
|
|
@@ -101,71 +94,6 @@ async function requestOAuthToken(gateway, body, signal) {
|
|
|
101
94
|
scope: data.scope,
|
|
102
95
|
};
|
|
103
96
|
}
|
|
104
|
-
function startOAuthCallbackServer(expectedState, signal) {
|
|
105
|
-
if (!_http) {
|
|
106
|
-
throw new Error("Radius OAuth is only available in Node.js environments");
|
|
107
|
-
}
|
|
108
|
-
let settle = () => { };
|
|
109
|
-
let settled = false;
|
|
110
|
-
const wait = new Promise((resolve) => {
|
|
111
|
-
settle = resolve;
|
|
112
|
-
});
|
|
113
|
-
const finish = (code) => {
|
|
114
|
-
if (settled) {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
settled = true;
|
|
118
|
-
signal.removeEventListener("abort", onAbort);
|
|
119
|
-
settle(code);
|
|
120
|
-
};
|
|
121
|
-
const onAbort = () => finish(null);
|
|
122
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
123
|
-
const sendPage = (response, status, html) => {
|
|
124
|
-
response.statusCode = status;
|
|
125
|
-
response.setHeader("content-type", "text/html; charset=utf-8");
|
|
126
|
-
response.end(html);
|
|
127
|
-
};
|
|
128
|
-
const server = _http.createServer((request, response) => {
|
|
129
|
-
const url = new URL(request.url ?? "/", REDIRECT_URI);
|
|
130
|
-
if (url.pathname !== CALLBACK_PATH) {
|
|
131
|
-
sendPage(response, 404, oauthErrorHtml("Callback route not found."));
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
if (url.searchParams.get("state") !== expectedState) {
|
|
135
|
-
sendPage(response, 400, oauthErrorHtml("OAuth state mismatch."));
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
const error = url.searchParams.get("error");
|
|
139
|
-
if (error) {
|
|
140
|
-
sendPage(response, 400, oauthErrorHtml(url.searchParams.get("error_description") ?? error));
|
|
141
|
-
finish(null);
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
const code = url.searchParams.get("code");
|
|
145
|
-
if (!code) {
|
|
146
|
-
sendPage(response, 400, oauthErrorHtml("Missing authorization code."));
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
sendPage(response, 200, oauthSuccessHtml("Signed in to Radius. You may now close this page."));
|
|
150
|
-
finish(code);
|
|
151
|
-
});
|
|
152
|
-
return new Promise((resolve) => {
|
|
153
|
-
server
|
|
154
|
-
.listen(CALLBACK_PORT, CALLBACK_HOST, () => {
|
|
155
|
-
resolve({
|
|
156
|
-
waitForCode: () => wait,
|
|
157
|
-
close: () => {
|
|
158
|
-
finish(null);
|
|
159
|
-
server.close();
|
|
160
|
-
},
|
|
161
|
-
});
|
|
162
|
-
})
|
|
163
|
-
.once("error", () => {
|
|
164
|
-
finish(null);
|
|
165
|
-
resolve({ waitForCode: async () => null, close: () => { } });
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
97
|
async function loginWithBrowser(gateway, authorizationEndpoint, interaction) {
|
|
170
98
|
const { verifier, challenge } = await generatePKCE();
|
|
171
99
|
const state = crypto.randomUUID();
|
|
@@ -180,7 +108,21 @@ async function loginWithBrowser(gateway, authorizationEndpoint, interaction) {
|
|
|
180
108
|
handoff: "url",
|
|
181
109
|
state,
|
|
182
110
|
}).toString();
|
|
183
|
-
const
|
|
111
|
+
const callback = await startOAuthCallbackServer({
|
|
112
|
+
providerName: "Radius",
|
|
113
|
+
host: CALLBACK_HOST,
|
|
114
|
+
port: CALLBACK_PORT,
|
|
115
|
+
path: CALLBACK_PATH,
|
|
116
|
+
state,
|
|
117
|
+
complete: (code) => requestOAuthToken(gateway, new URLSearchParams({
|
|
118
|
+
grant_type: "authorization_code",
|
|
119
|
+
client_id: OAUTH_CLIENT_ID,
|
|
120
|
+
redirect_uri: REDIRECT_URI,
|
|
121
|
+
code,
|
|
122
|
+
code_verifier: verifier,
|
|
123
|
+
}), interaction.signal),
|
|
124
|
+
signal: interaction.signal,
|
|
125
|
+
});
|
|
184
126
|
interaction.notify({ type: "progress", message: `Listening for OAuth callback on ${REDIRECT_URI}` });
|
|
185
127
|
interaction.notify({
|
|
186
128
|
type: "auth_url",
|
|
@@ -188,23 +130,13 @@ async function loginWithBrowser(gateway, authorizationEndpoint, interaction) {
|
|
|
188
130
|
instructions: "Continue in your browser.",
|
|
189
131
|
});
|
|
190
132
|
try {
|
|
191
|
-
const
|
|
192
|
-
if (!
|
|
193
|
-
if (interaction.signal.aborted) {
|
|
194
|
-
throw new Error("Login cancelled");
|
|
195
|
-
}
|
|
133
|
+
const credential = await callback.wait();
|
|
134
|
+
if (!credential)
|
|
196
135
|
throw new Error("OAuth callback did not complete.");
|
|
197
|
-
|
|
198
|
-
return await requestOAuthToken(gateway, new URLSearchParams({
|
|
199
|
-
grant_type: "authorization_code",
|
|
200
|
-
client_id: OAUTH_CLIENT_ID,
|
|
201
|
-
redirect_uri: REDIRECT_URI,
|
|
202
|
-
code,
|
|
203
|
-
code_verifier: verifier,
|
|
204
|
-
}), interaction.signal);
|
|
136
|
+
return credential;
|
|
205
137
|
}
|
|
206
138
|
finally {
|
|
207
|
-
|
|
139
|
+
callback.close();
|
|
208
140
|
}
|
|
209
141
|
}
|
|
210
142
|
async function requestDeviceAuthorization(gateway, signal) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radius.js","sourceRoot":"","sources":["../../../src/auth/oauth/radius.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,kEAAkE;AAClE,IAAI,KAAK,GAAsC,IAAI,CAAC;AACpD,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,IAAI,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC;IACzF,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QAC/B,KAAK,GAAG,CAAC,CAAC;IAAA,CACV,CAAC,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAE7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,MAAM,aAAa,GAAG,WAAW,CAAC;AAClC,MAAM,aAAa,GAAG,IAAI,CAAC;AAC3B,MAAM,aAAa,GAAG,iBAAiB,CAAC;AACxC,MAAM,YAAY,GAAG,UAAU,aAAa,IAAI,aAAa,GAAG,aAAa,EAAE,CAAC;AAChF,MAAM,oBAAoB,GAAG,MAAM,CAAC;AACpC,MAAM,oBAAoB,GAAG,SAAS,CAAC;AACvC,MAAM,wBAAwB,GAAG,aAAa,CAAC;AAC/C,MAAM,eAAe,GAAG,YAAY,CAAC;AACrC,MAAM,WAAW,GAAG,wBAAwB,CAAC;AAC7C,MAAM,4BAA4B,GAAG,8CAA8C,CAAC;AAcpF,KAAK,UAAU,wBAAwB,CAAC,OAAe,EAAE,MAAmB,EAAiC;IAC5G,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE;QAC3D,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;QACvC,MAAM;KACN,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACd,2CAA2C,OAAO,KAAK,QAAQ,CAAC,MAAM,IAAI,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,CACjG,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAkC,CAAC;IAC3E,IAAI,OAAO,SAAS,CAAC,qBAAqB,KAAK,QAAQ,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,oCAAoC,OAAO,EAAE,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,EAAE,qBAAqB,EAAE,SAAS,CAAC,qBAAqB,EAAE,CAAC;AAAA,CAClE;AAED,MAAM,kBAAmB,SAAQ,KAAK;IAC5B,MAAM,CAAS;IACf,UAAU,CAAU;IAE7B,YAAY,MAAc,EAAE,UAA8B,EAAE,WAA+B,EAAE,OAAe,EAAE;QAC7G,MAAM,MAAM,GAAG,UAAU;YACxB,CAAC,CAAC,WAAW;gBACZ,CAAC,CAAC,GAAG,UAAU,KAAK,WAAW,EAAE;gBACjC,CAAC,CAAC,UAAU;YACb,CAAC,CAAC,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;QACjC,KAAK,CAAC,GAAG,OAAO,KAAK,MAAM,EAAE,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAAA,CAC7B;CACD;AAED,KAAK,UAAU,sBAAsB,CAAC,QAAkB,EAAE,OAAe,EAA+B;IACvG,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IACnD,IAAI,UAA8B,CAAC;IACnC,IAAI,WAA+B,CAAC;IAEpC,IAAI,IAAI,EAAE,CAAC;QACV,IAAI,CAAC;YACJ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAqD,CAAC;YAClF,UAAU,GAAG,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;YACrE,WAAW,GAAG,OAAO,IAAI,CAAC,iBAAiB,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC;QAC/F,CAAC;QAAC,MAAM,CAAC;YACR,WAAW,GAAG,IAAI,CAAC;QACpB,CAAC;IACF,CAAC;IAED,OAAO,IAAI,kBAAkB,CAAC,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;AAAA,CACjF;AAED,KAAK,UAAU,iBAAiB,CAC/B,OAAe,EACf,IAAqB,EACrB,MAAmB,EACQ;IAC3B,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACJ,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,OAAO,CAAC,EAAE;YAC3D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAC5F,IAAI;YACJ,MAAM;SACN,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;QACpC,CAAC;QACD,MAAM,KAAK,CAAC;IACb,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAClB,MAAM,MAAM,sBAAsB,CAAC,QAAQ,EAAE,mCAAmC,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAKlC,CAAC;IAEF,OAAO;QACN,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,IAAI,CAAC,YAAY;QACzB,OAAO,EAAE,IAAI,CAAC,aAAa;QAC3B,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,oBAAoB;QACnE,KAAK,EAAE,IAAI,CAAC,KAAK;KACjB,CAAC;AAAA,CACF;AAOD,SAAS,wBAAwB,CAAC,aAAqB,EAAE,MAAmB,EAAgC;IAC3G,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC3E,CAAC;IAED,IAAI,MAAM,GAAkC,GAAG,EAAE,CAAC,EAAC,CAAC,CAAC;IACrD,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,IAAI,GAAG,IAAI,OAAO,CAAgB,CAAC,OAAO,EAAE,EAAE,CAAC;QACpD,MAAM,GAAG,OAAO,CAAC;IAAA,CACjB,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,CAAC,IAAmB,EAAE,EAAE,CAAC;QACvC,IAAI,OAAO,EAAE,CAAC;YACb,OAAO;QACR,CAAC;QACD,OAAO,GAAG,IAAI,CAAC;QACf,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,CAAC;IAAA,CACb,CAAC;IACF,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1D,MAAM,QAAQ,GAAG,CAAC,QAA4C,EAAE,MAAc,EAAE,IAAY,EAAE,EAAE,CAAC;QAChG,QAAQ,CAAC,UAAU,GAAG,MAAM,CAAC;QAC7B,QAAQ,CAAC,SAAS,CAAC,cAAc,EAAE,0BAA0B,CAAC,CAAC;QAC/D,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAAA,CACnB,CAAC;IAEF,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC;QACxD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,EAAE,YAAY,CAAC,CAAC;QACtD,IAAI,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;YACpC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,cAAc,CAAC,2BAA2B,CAAC,CAAC,CAAC;YACrE,OAAO;QACR,CAAC;QACD,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,aAAa,EAAE,CAAC;YACrD,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,cAAc,CAAC,uBAAuB,CAAC,CAAC,CAAC;YACjE,OAAO;QACR,CAAC;QAED,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC5C,IAAI,KAAK,EAAE,CAAC;YACX,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,cAAc,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;YAC5F,MAAM,CAAC,IAAI,CAAC,CAAC;YACb,OAAO;QACR,CAAC;QAED,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,cAAc,CAAC,6BAA6B,CAAC,CAAC,CAAC;YACvE,OAAO;QACR,CAAC;QAED,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,gBAAgB,CAAC,mDAAmD,CAAC,CAAC,CAAC;QAC/F,MAAM,CAAC,IAAI,CAAC,CAAC;IAAA,CACb,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/B,MAAM;aACJ,MAAM,CAAC,aAAa,EAAE,aAAa,EAAE,GAAG,EAAE,CAAC;YAC3C,OAAO,CAAC;gBACP,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI;gBACvB,KAAK,EAAE,GAAG,EAAE,CAAC;oBACZ,MAAM,CAAC,IAAI,CAAC,CAAC;oBACb,MAAM,CAAC,KAAK,EAAE,CAAC;gBAAA,CACf;aACD,CAAC,CAAC;QAAA,CACH,CAAC;aACD,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CAAC,CAAC;YACb,OAAO,CAAC,EAAE,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAC,CAAC,EAAE,CAAC,CAAC;QAAA,CAC5D,CAAC,CAAC;IAAA,CACJ,CAAC,CAAC;AAAA,CACH;AAED,KAAK,UAAU,gBAAgB,CAC9B,OAAe,EACf,qBAA6B,EAC7B,WAAoC,EACT;IAC3B,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;IACrD,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IAClC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,qBAAqB,CAAC,CAAC;IACpD,YAAY,CAAC,MAAM,GAAG,IAAI,eAAe,CAAC;QACzC,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,eAAe;QAC1B,YAAY,EAAE,YAAY;QAC1B,KAAK,EAAE,WAAW;QAClB,cAAc,EAAE,SAAS;QACzB,qBAAqB,EAAE,MAAM;QAC7B,OAAO,EAAE,KAAK;QACd,KAAK;KACL,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEd,MAAM,cAAc,GAAG,MAAM,wBAAwB,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACjF,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,mCAAmC,YAAY,EAAE,EAAE,CAAC,CAAC;IACrG,WAAW,CAAC,MAAM,CAAC;QAClB,IAAI,EAAE,UAAU;QAChB,GAAG,EAAE,YAAY,CAAC,QAAQ,EAAE;QAC5B,YAAY,EAAE,2BAA2B;KACzC,CAAC,CAAC;IAEH,IAAI,CAAC;QACJ,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,WAAW,EAAE,CAAC;QAChD,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,IAAI,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;YACpC,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,MAAM,iBAAiB,CAC7B,OAAO,EACP,IAAI,eAAe,CAAC;YACnB,UAAU,EAAE,oBAAoB;YAChC,SAAS,EAAE,eAAe;YAC1B,YAAY,EAAE,YAAY;YAC1B,IAAI;YACJ,aAAa,EAAE,QAAQ;SACvB,CAAC,EACF,WAAW,CAAC,MAAM,CAClB,CAAC;IACH,CAAC;YAAS,CAAC;QACV,cAAc,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;AAAA,CACD;AAED,KAAK,UAAU,0BAA0B,CAAC,OAAe,EAAE,MAAmB,EAAwC;IACrH,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACJ,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAAE;YAC5D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAC5F,IAAI,EAAE,IAAI,eAAe,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;YAC7E,MAAM;SACN,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;QACpC,CAAC;QACD,MAAM,KAAK,CAAC;IACb,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAClB,MAAM,MAAM,sBAAsB,CAAC,QAAQ,EAAE,0CAA0C,CAAC,CAAC;IAC1F,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAyC,CAAC;IAC7E,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QACxF,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;IAC1F,CAAC;IAED,OAAO;QACN,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;QACvC,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACvB,CAAC;AAAA,CACF;AAED,KAAK,UAAU,mBAAmB,CAAC,OAAe,EAAE,WAAoC,EAA4B;IACnH,MAAM,MAAM,GAAG,MAAM,0BAA0B,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7E,WAAW,CAAC,MAAM,CAAC;QAClB,IAAI,EAAE,aAAa;QACnB,QAAQ,EAAE,MAAM,CAAC,SAAS;QAC1B,eAAe,EAAE,MAAM,CAAC,gBAAgB;QACxC,eAAe,EAAE,MAAM,CAAC,QAAQ;QAChC,gBAAgB,EAAE,MAAM,CAAC,UAAU;KACnC,CAAC,CAAC;IAEH,OAAO,uBAAuB,CAAkB;QAC/C,eAAe,EAAE,MAAM,CAAC,QAAQ;QAChC,gBAAgB,EAAE,MAAM,CAAC,UAAU;QACnC,MAAM,EAAE,WAAW,CAAC,MAAM;QAC1B,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACjB,IAAI,CAAC;gBACJ,MAAM,WAAW,GAAG,MAAM,iBAAiB,CAC1C,OAAO,EACP,IAAI,eAAe,CAAC;oBACnB,UAAU,EAAE,4BAA4B;oBACxC,SAAS,EAAE,eAAe;oBAC1B,WAAW,EAAE,MAAM,CAAC,WAAW;iBAC/B,CAAC,EACF,WAAW,CAAC,MAAM,CAClB,CAAC;gBACF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;YACnD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,IAAI,CAAC,CAAC,KAAK,YAAY,kBAAkB,CAAC,EAAE,CAAC;oBAC5C,MAAM,KAAK,CAAC;gBACb,CAAC;gBACD,QAAQ,KAAK,CAAC,UAAU,EAAE,CAAC;oBAC1B,KAAK,uBAAuB;wBAC3B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;oBAC9B,KAAK,WAAW;wBACf,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;oBAChC,KAAK,eAAe;wBACnB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC;oBACvE,KAAK,eAAe;wBACnB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,kCAAkC,EAAE,CAAC;oBAC1E;wBACC,MAAM,KAAK,CAAC;gBACd,CAAC;YACF,CAAC;QAAA,CACD;KACD,CAAC,CAAC;AAAA,CACH;AAOD,MAAM,UAAU,iBAAiB,CAAC,OAA2B,EAAa;IACzE,MAAM,OAAO,GAAG,yBAAyB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAE3D,OAAO;QACN,IAAI,EAAE,OAAO,CAAC,IAAI;QAElB,KAAK,CAAC,KAAK,CAAC,WAAW,EAA4B;YAClD,MAAM,WAAW,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC;gBAC5C,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,cAAc,OAAO,CAAC,IAAI,GAAG;gBACtC,OAAO,EAAE;oBACR,EAAE,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE,oCAAoC,EAAE;oBACzE;wBACC,EAAE,EAAE,wBAAwB;wBAC5B,KAAK,EAAE,gEAAgE;qBACvE;iBACD;aACD,CAAC,CAAC;YAEH,IAAI,WAAW,KAAK,wBAAwB,EAAE,CAAC;gBAC9C,OAAO,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YAClD,CAAC;YACD,IAAI,WAAW,KAAK,oBAAoB,EAAE,CAAC;gBAC1C,MAAM,SAAS,GAAG,MAAM,wBAAwB,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;gBAC9E,OAAO,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,qBAAqB,EAAE,WAAW,CAAC,CAAC;YAChF,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,WAAW,OAAO,CAAC,IAAI,oBAAoB,WAAW,EAAE,CAAC,CAAC;QAAA,CAC1E;QAED,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,EAA4B;YAC3D,MAAM,SAAS,GAAG,MAAM,iBAAiB,CACxC,OAAO,EACP,IAAI,eAAe,CAAC;gBACnB,UAAU,EAAE,eAAe;gBAC3B,SAAS,EAAE,eAAe;gBAC1B,aAAa,EAAE,UAAU,CAAC,OAAO;aACjC,CAAC,EACF,MAAM,CACN,CAAC;YACF,OAAO,SAAS,CAAC;QAAA,CACjB;QAED,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE;YACxB,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC;QAAA,CACrC;KACD,CAAC;AAAA,CACF","sourcesContent":["/**\n * Radius gateway OAuth flow.\n *\n * Radius is a pi-messages gateway. OAuth client APIs live on the configured\n * gateway; only the interactive browser authorization endpoint is discovered.\n * Model catalog loading is owned by the Radius provider.\n *\n * NOTE: This module uses node:http for the OAuth callback server.\n * It is only intended for CLI use, not browser environments.\n */\n\n// NEVER convert to top-level imports - breaks browser/Vite builds\nlet _http: typeof import(\"node:http\") | null = null;\nif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\timport(\"node:http\").then((m) => {\n\t\t_http = m;\n\t});\n}\n\nimport { normalizeRadiusGatewayUrl } from \"../../providers/radius-config.ts\";\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\nimport { oauthErrorHtml, oauthSuccessHtml } from \"./oauth-page.ts\";\nimport { generatePKCE } from \"./pkce.ts\";\n\nconst CALLBACK_HOST = \"127.0.0.1\";\nconst CALLBACK_PORT = 1456;\nconst CALLBACK_PATH = \"/oauth/callback\";\nconst REDIRECT_URI = `http://${CALLBACK_HOST}:${CALLBACK_PORT}${CALLBACK_PATH}`;\nconst TOKEN_EXPIRY_SKEW_MS = 60_000;\nconst LOGIN_METHOD_BROWSER = \"browser\";\nconst LOGIN_METHOD_DEVICE_CODE = \"device-code\";\nconst OAUTH_CLIENT_ID = \"pi-gateway\";\nconst OAUTH_SCOPE = \"gateway offline_access\";\nconst OAUTH_DEVICE_CODE_GRANT_TYPE = \"urn:ietf:params:oauth:grant-type:device_code\";\n\ntype RadiusOAuthDiscovery = {\n\tauthorizationEndpoint: string;\n};\n\ntype DeviceAuthorizationResponse = {\n\tdevice_code: string;\n\tuser_code: string;\n\tverification_uri: string;\n\texpires_in: number;\n\tinterval?: number;\n};\n\nasync function loadRadiusOAuthDiscovery(gateway: string, signal: AbortSignal): Promise<RadiusOAuthDiscovery> {\n\tconst response = await fetch(new URL(\"/v1/oauth\", gateway), {\n\t\theaders: { accept: \"application/json\" },\n\t\tsignal,\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(\n\t\t\t`Could not load Radius OAuth config from ${gateway}: ${response.status} ${await response.text()}`,\n\t\t);\n\t}\n\n\tconst discovery = (await response.json()) as Partial<RadiusOAuthDiscovery>;\n\tif (typeof discovery.authorizationEndpoint !== \"string\") {\n\t\tthrow new Error(`Invalid Radius OAuth config from ${gateway}`);\n\t}\n\treturn { authorizationEndpoint: discovery.authorizationEndpoint };\n}\n\nclass OAuthResponseError extends Error {\n\treadonly status: number;\n\treadonly oauthError?: string;\n\n\tconstructor(status: number, oauthError: string | undefined, description: string | undefined, message: string) {\n\t\tconst detail = oauthError\n\t\t\t? description\n\t\t\t\t? `${oauthError}: ${description}`\n\t\t\t\t: oauthError\n\t\t\t: description || String(status);\n\t\tsuper(`${message}: ${detail}`);\n\t\tthis.status = status;\n\t\tthis.oauthError = oauthError;\n\t}\n}\n\nasync function readOAuthResponseError(response: Response, message: string): Promise<OAuthResponseError> {\n\tconst text = await response.text().catch(() => \"\");\n\tlet oauthError: string | undefined;\n\tlet description: string | undefined;\n\n\tif (text) {\n\t\ttry {\n\t\t\tconst data = JSON.parse(text) as { error?: unknown; error_description?: unknown };\n\t\t\toauthError = typeof data.error === \"string\" ? data.error : undefined;\n\t\t\tdescription = typeof data.error_description === \"string\" ? data.error_description : undefined;\n\t\t} catch {\n\t\t\tdescription = text;\n\t\t}\n\t}\n\n\treturn new OAuthResponseError(response.status, oauthError, description, message);\n}\n\nasync function requestOAuthToken(\n\tgateway: string,\n\tbody: URLSearchParams,\n\tsignal: AbortSignal,\n): Promise<OAuthCredential> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(new URL(\"/v1/oauth/token\", gateway), {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { accept: \"application/json\", \"content-type\": \"application/x-www-form-urlencoded\" },\n\t\t\tbody,\n\t\t\tsignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\t\tthrow error;\n\t}\n\n\tif (!response.ok) {\n\t\tthrow await readOAuthResponseError(response, \"Radius OAuth token request failed\");\n\t}\n\n\tconst data = (await response.json()) as {\n\t\taccess_token: string;\n\t\trefresh_token: string;\n\t\texpires_in: number;\n\t\tscope?: string;\n\t};\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\taccess: data.access_token,\n\t\trefresh: data.refresh_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - TOKEN_EXPIRY_SKEW_MS,\n\t\tscope: data.scope,\n\t};\n}\n\ntype OAuthCallbackServer = {\n\twaitForCode(): Promise<string | null>;\n\tclose(): void;\n};\n\nfunction startOAuthCallbackServer(expectedState: string, signal: AbortSignal): Promise<OAuthCallbackServer> {\n\tif (!_http) {\n\t\tthrow new Error(\"Radius OAuth is only available in Node.js environments\");\n\t}\n\n\tlet settle: (code: string | null) => void = () => {};\n\tlet settled = false;\n\tconst wait = new Promise<string | null>((resolve) => {\n\t\tsettle = resolve;\n\t});\n\tconst finish = (code: string | null) => {\n\t\tif (settled) {\n\t\t\treturn;\n\t\t}\n\t\tsettled = true;\n\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\tsettle(code);\n\t};\n\tconst onAbort = () => finish(null);\n\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\n\tconst sendPage = (response: import(\"node:http\").ServerResponse, status: number, html: string) => {\n\t\tresponse.statusCode = status;\n\t\tresponse.setHeader(\"content-type\", \"text/html; charset=utf-8\");\n\t\tresponse.end(html);\n\t};\n\n\tconst server = _http.createServer((request, response) => {\n\t\tconst url = new URL(request.url ?? \"/\", REDIRECT_URI);\n\t\tif (url.pathname !== CALLBACK_PATH) {\n\t\t\tsendPage(response, 404, oauthErrorHtml(\"Callback route not found.\"));\n\t\t\treturn;\n\t\t}\n\t\tif (url.searchParams.get(\"state\") !== expectedState) {\n\t\t\tsendPage(response, 400, oauthErrorHtml(\"OAuth state mismatch.\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst error = url.searchParams.get(\"error\");\n\t\tif (error) {\n\t\t\tsendPage(response, 400, oauthErrorHtml(url.searchParams.get(\"error_description\") ?? error));\n\t\t\tfinish(null);\n\t\t\treturn;\n\t\t}\n\n\t\tconst code = url.searchParams.get(\"code\");\n\t\tif (!code) {\n\t\t\tsendPage(response, 400, oauthErrorHtml(\"Missing authorization code.\"));\n\t\t\treturn;\n\t\t}\n\n\t\tsendPage(response, 200, oauthSuccessHtml(\"Signed in to Radius. You may now close this page.\"));\n\t\tfinish(code);\n\t});\n\n\treturn new Promise((resolve) => {\n\t\tserver\n\t\t\t.listen(CALLBACK_PORT, CALLBACK_HOST, () => {\n\t\t\t\tresolve({\n\t\t\t\t\twaitForCode: () => wait,\n\t\t\t\t\tclose: () => {\n\t\t\t\t\t\tfinish(null);\n\t\t\t\t\t\tserver.close();\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t})\n\t\t\t.once(\"error\", () => {\n\t\t\t\tfinish(null);\n\t\t\t\tresolve({ waitForCode: async () => null, close: () => {} });\n\t\t\t});\n\t});\n}\n\nasync function loginWithBrowser(\n\tgateway: string,\n\tauthorizationEndpoint: string,\n\tinteraction: ProviderAuthInteraction,\n): Promise<OAuthCredential> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst state = crypto.randomUUID();\n\tconst authorizeUrl = new URL(authorizationEndpoint);\n\tauthorizeUrl.search = new URLSearchParams({\n\t\tresponse_type: \"code\",\n\t\tclient_id: OAUTH_CLIENT_ID,\n\t\tredirect_uri: REDIRECT_URI,\n\t\tscope: OAUTH_SCOPE,\n\t\tcode_challenge: challenge,\n\t\tcode_challenge_method: \"S256\",\n\t\thandoff: \"url\",\n\t\tstate,\n\t}).toString();\n\n\tconst callbackServer = await startOAuthCallbackServer(state, interaction.signal);\n\tinteraction.notify({ type: \"progress\", message: `Listening for OAuth callback on ${REDIRECT_URI}` });\n\tinteraction.notify({\n\t\ttype: \"auth_url\",\n\t\turl: authorizeUrl.toString(),\n\t\tinstructions: \"Continue in your browser.\",\n\t});\n\n\ttry {\n\t\tconst code = await callbackServer.waitForCode();\n\t\tif (!code) {\n\t\t\tif (interaction.signal.aborted) {\n\t\t\t\tthrow new Error(\"Login cancelled\");\n\t\t\t}\n\t\t\tthrow new Error(\"OAuth callback did not complete.\");\n\t\t}\n\t\treturn await requestOAuthToken(\n\t\t\tgateway,\n\t\t\tnew URLSearchParams({\n\t\t\t\tgrant_type: \"authorization_code\",\n\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\t\tcode,\n\t\t\t\tcode_verifier: verifier,\n\t\t\t}),\n\t\t\tinteraction.signal,\n\t\t);\n\t} finally {\n\t\tcallbackServer.close();\n\t}\n}\n\nasync function requestDeviceAuthorization(gateway: string, signal: AbortSignal): Promise<DeviceAuthorizationResponse> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(new URL(\"/v1/oauth/device\", gateway), {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { accept: \"application/json\", \"content-type\": \"application/x-www-form-urlencoded\" },\n\t\t\tbody: new URLSearchParams({ client_id: OAUTH_CLIENT_ID, scope: OAUTH_SCOPE }),\n\t\t\tsignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\t\tthrow error;\n\t}\n\n\tif (!response.ok) {\n\t\tthrow await readOAuthResponseError(response, \"Radius OAuth device authorization failed\");\n\t}\n\n\tconst data = (await response.json()) as Partial<DeviceAuthorizationResponse>;\n\tif (!data.device_code || !data.user_code || !data.verification_uri || !data.expires_in) {\n\t\tthrow new Error(\"Radius OAuth device authorization response is missing required fields\");\n\t}\n\n\treturn {\n\t\tdevice_code: data.device_code,\n\t\tuser_code: data.user_code,\n\t\tverification_uri: data.verification_uri,\n\t\texpires_in: data.expires_in,\n\t\tinterval: data.interval,\n\t};\n}\n\nasync function loginWithDeviceCode(gateway: string, interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\tconst device = await requestDeviceAuthorization(gateway, interaction.signal);\n\tinteraction.notify({\n\t\ttype: \"device_code\",\n\t\tuserCode: device.user_code,\n\t\tverificationUri: device.verification_uri,\n\t\tintervalSeconds: device.interval,\n\t\texpiresInSeconds: device.expires_in,\n\t});\n\n\treturn pollOAuthDeviceCodeFlow<OAuthCredential>({\n\t\tintervalSeconds: device.interval,\n\t\texpiresInSeconds: device.expires_in,\n\t\tsignal: interaction.signal,\n\t\tpoll: async () => {\n\t\t\ttry {\n\t\t\t\tconst credentials = await requestOAuthToken(\n\t\t\t\t\tgateway,\n\t\t\t\t\tnew URLSearchParams({\n\t\t\t\t\t\tgrant_type: OAUTH_DEVICE_CODE_GRANT_TYPE,\n\t\t\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\t\t\tdevice_code: device.device_code,\n\t\t\t\t\t}),\n\t\t\t\t\tinteraction.signal,\n\t\t\t\t);\n\t\t\t\treturn { status: \"complete\", value: credentials };\n\t\t\t} catch (error) {\n\t\t\t\tif (!(error instanceof OAuthResponseError)) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tswitch (error.oauthError) {\n\t\t\t\t\tcase \"authorization_pending\":\n\t\t\t\t\t\treturn { status: \"pending\" };\n\t\t\t\t\tcase \"slow_down\":\n\t\t\t\t\t\treturn { status: \"slow_down\" };\n\t\t\t\t\tcase \"expired_token\":\n\t\t\t\t\t\treturn { status: \"failed\", message: \"Device authorization expired.\" };\n\t\t\t\t\tcase \"access_denied\":\n\t\t\t\t\t\treturn { status: \"failed\", message: \"Device authorization was denied.\" };\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n}\n\nexport interface RadiusOAuthOptions {\n\tname: string;\n\tgateway: string;\n}\n\nexport function createRadiusOAuth(options: RadiusOAuthOptions): OAuthAuth {\n\tconst gateway = normalizeRadiusGatewayUrl(options.gateway);\n\n\treturn {\n\t\tname: options.name,\n\n\t\tasync login(interaction): Promise<OAuthCredential> {\n\t\t\tconst loginMethod = await interaction.prompt({\n\t\t\t\ttype: \"select\",\n\t\t\t\tmessage: `Sign in to ${options.name}:`,\n\t\t\t\toptions: [\n\t\t\t\t\t{ id: LOGIN_METHOD_BROWSER, label: \"Sign in with browser (recommended)\" },\n\t\t\t\t\t{\n\t\t\t\t\t\tid: LOGIN_METHOD_DEVICE_CODE,\n\t\t\t\t\t\tlabel: \"Sign in with device code (when signing in from another device)\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tif (loginMethod === LOGIN_METHOD_DEVICE_CODE) {\n\t\t\t\treturn loginWithDeviceCode(gateway, interaction);\n\t\t\t}\n\t\t\tif (loginMethod === LOGIN_METHOD_BROWSER) {\n\t\t\t\tconst discovery = await loadRadiusOAuthDiscovery(gateway, interaction.signal);\n\t\t\t\treturn loginWithBrowser(gateway, discovery.authorizationEndpoint, interaction);\n\t\t\t}\n\t\t\tthrow new Error(`Unknown ${options.name} sign-in method: ${loginMethod}`);\n\t\t},\n\n\t\tasync refresh(credential, signal): Promise<OAuthCredential> {\n\t\t\tconst refreshed = await requestOAuthToken(\n\t\t\t\tgateway,\n\t\t\t\tnew URLSearchParams({\n\t\t\t\t\tgrant_type: \"refresh_token\",\n\t\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\t\trefresh_token: credential.refresh,\n\t\t\t\t}),\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\treturn refreshed;\n\t\t},\n\n\t\tasync toAuth(credential) {\n\t\t\treturn { apiKey: credential.access };\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"radius.js","sourceRoot":"","sources":["../../../src/auth/oauth/radius.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Radius gateway OAuth flow.\n *\n * Radius is a pi-messages gateway. OAuth client APIs live on the configured\n * gateway; only the interactive browser authorization endpoint is discovered.\n * Model catalog loading is owned by the Radius provider.\n *\n * NOTE: This module uses node:http (via callback-server.ts) for the OAuth callback server.\n * It is only intended for CLI use, not browser environments.\n */\n\nimport { normalizeRadiusGatewayUrl } from \"../../providers/radius-config.ts\";\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { startOAuthCallbackServer } from \"./callback-server.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\nimport { generatePKCE } from \"./pkce.ts\";\n\nconst CALLBACK_HOST = \"127.0.0.1\";\nconst CALLBACK_PORT = 1456;\nconst CALLBACK_PATH = \"/oauth/callback\";\nconst REDIRECT_URI = `http://${CALLBACK_HOST}:${CALLBACK_PORT}${CALLBACK_PATH}`;\nconst TOKEN_EXPIRY_SKEW_MS = 60_000;\nconst LOGIN_METHOD_BROWSER = \"browser\";\nconst LOGIN_METHOD_DEVICE_CODE = \"device-code\";\nconst OAUTH_CLIENT_ID = \"pi-gateway\";\nconst OAUTH_SCOPE = \"gateway offline_access\";\nconst OAUTH_DEVICE_CODE_GRANT_TYPE = \"urn:ietf:params:oauth:grant-type:device_code\";\n\ntype RadiusOAuthDiscovery = {\n\tauthorizationEndpoint: string;\n};\n\ntype DeviceAuthorizationResponse = {\n\tdevice_code: string;\n\tuser_code: string;\n\tverification_uri: string;\n\texpires_in: number;\n\tinterval?: number;\n};\n\nasync function loadRadiusOAuthDiscovery(gateway: string, signal: AbortSignal): Promise<RadiusOAuthDiscovery> {\n\tconst response = await fetch(new URL(\"/v1/oauth\", gateway), {\n\t\theaders: { accept: \"application/json\" },\n\t\tsignal,\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(\n\t\t\t`Could not load Radius OAuth config from ${gateway}: ${response.status} ${await response.text()}`,\n\t\t);\n\t}\n\n\tconst discovery = (await response.json()) as Partial<RadiusOAuthDiscovery>;\n\tif (typeof discovery.authorizationEndpoint !== \"string\") {\n\t\tthrow new Error(`Invalid Radius OAuth config from ${gateway}`);\n\t}\n\treturn { authorizationEndpoint: discovery.authorizationEndpoint };\n}\n\nclass OAuthResponseError extends Error {\n\treadonly status: number;\n\treadonly oauthError?: string;\n\n\tconstructor(status: number, oauthError: string | undefined, description: string | undefined, message: string) {\n\t\tconst detail = oauthError\n\t\t\t? description\n\t\t\t\t? `${oauthError}: ${description}`\n\t\t\t\t: oauthError\n\t\t\t: description || String(status);\n\t\tsuper(`${message}: ${detail}`);\n\t\tthis.status = status;\n\t\tthis.oauthError = oauthError;\n\t}\n}\n\nasync function readOAuthResponseError(response: Response, message: string): Promise<OAuthResponseError> {\n\tconst text = await response.text().catch(() => \"\");\n\tlet oauthError: string | undefined;\n\tlet description: string | undefined;\n\n\tif (text) {\n\t\ttry {\n\t\t\tconst data = JSON.parse(text) as { error?: unknown; error_description?: unknown };\n\t\t\toauthError = typeof data.error === \"string\" ? data.error : undefined;\n\t\t\tdescription = typeof data.error_description === \"string\" ? data.error_description : undefined;\n\t\t} catch {\n\t\t\tdescription = text;\n\t\t}\n\t}\n\n\treturn new OAuthResponseError(response.status, oauthError, description, message);\n}\n\nasync function requestOAuthToken(\n\tgateway: string,\n\tbody: URLSearchParams,\n\tsignal: AbortSignal,\n): Promise<OAuthCredential> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(new URL(\"/v1/oauth/token\", gateway), {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { accept: \"application/json\", \"content-type\": \"application/x-www-form-urlencoded\" },\n\t\t\tbody,\n\t\t\tsignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\t\tthrow error;\n\t}\n\n\tif (!response.ok) {\n\t\tthrow await readOAuthResponseError(response, \"Radius OAuth token request failed\");\n\t}\n\n\tconst data = (await response.json()) as {\n\t\taccess_token: string;\n\t\trefresh_token: string;\n\t\texpires_in: number;\n\t\tscope?: string;\n\t};\n\n\treturn {\n\t\ttype: \"oauth\",\n\t\taccess: data.access_token,\n\t\trefresh: data.refresh_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - TOKEN_EXPIRY_SKEW_MS,\n\t\tscope: data.scope,\n\t};\n}\n\nasync function loginWithBrowser(\n\tgateway: string,\n\tauthorizationEndpoint: string,\n\tinteraction: ProviderAuthInteraction,\n): Promise<OAuthCredential> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst state = crypto.randomUUID();\n\tconst authorizeUrl = new URL(authorizationEndpoint);\n\tauthorizeUrl.search = new URLSearchParams({\n\t\tresponse_type: \"code\",\n\t\tclient_id: OAUTH_CLIENT_ID,\n\t\tredirect_uri: REDIRECT_URI,\n\t\tscope: OAUTH_SCOPE,\n\t\tcode_challenge: challenge,\n\t\tcode_challenge_method: \"S256\",\n\t\thandoff: \"url\",\n\t\tstate,\n\t}).toString();\n\n\tconst callback = await startOAuthCallbackServer({\n\t\tproviderName: \"Radius\",\n\t\thost: CALLBACK_HOST,\n\t\tport: CALLBACK_PORT,\n\t\tpath: CALLBACK_PATH,\n\t\tstate,\n\t\tcomplete: (code) =>\n\t\t\trequestOAuthToken(\n\t\t\t\tgateway,\n\t\t\t\tnew URLSearchParams({\n\t\t\t\t\tgrant_type: \"authorization_code\",\n\t\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\t\t\tcode,\n\t\t\t\t\tcode_verifier: verifier,\n\t\t\t\t}),\n\t\t\t\tinteraction.signal,\n\t\t\t),\n\t\tsignal: interaction.signal,\n\t});\n\tinteraction.notify({ type: \"progress\", message: `Listening for OAuth callback on ${REDIRECT_URI}` });\n\tinteraction.notify({\n\t\ttype: \"auth_url\",\n\t\turl: authorizeUrl.toString(),\n\t\tinstructions: \"Continue in your browser.\",\n\t});\n\n\ttry {\n\t\tconst credential = await callback.wait();\n\t\tif (!credential) throw new Error(\"OAuth callback did not complete.\");\n\t\treturn credential;\n\t} finally {\n\t\tcallback.close();\n\t}\n}\n\nasync function requestDeviceAuthorization(gateway: string, signal: AbortSignal): Promise<DeviceAuthorizationResponse> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(new URL(\"/v1/oauth/device\", gateway), {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { accept: \"application/json\", \"content-type\": \"application/x-www-form-urlencoded\" },\n\t\t\tbody: new URLSearchParams({ client_id: OAUTH_CLIENT_ID, scope: OAUTH_SCOPE }),\n\t\t\tsignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\t\tthrow error;\n\t}\n\n\tif (!response.ok) {\n\t\tthrow await readOAuthResponseError(response, \"Radius OAuth device authorization failed\");\n\t}\n\n\tconst data = (await response.json()) as Partial<DeviceAuthorizationResponse>;\n\tif (!data.device_code || !data.user_code || !data.verification_uri || !data.expires_in) {\n\t\tthrow new Error(\"Radius OAuth device authorization response is missing required fields\");\n\t}\n\n\treturn {\n\t\tdevice_code: data.device_code,\n\t\tuser_code: data.user_code,\n\t\tverification_uri: data.verification_uri,\n\t\texpires_in: data.expires_in,\n\t\tinterval: data.interval,\n\t};\n}\n\nasync function loginWithDeviceCode(gateway: string, interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\tconst device = await requestDeviceAuthorization(gateway, interaction.signal);\n\tinteraction.notify({\n\t\ttype: \"device_code\",\n\t\tuserCode: device.user_code,\n\t\tverificationUri: device.verification_uri,\n\t\tintervalSeconds: device.interval,\n\t\texpiresInSeconds: device.expires_in,\n\t});\n\n\treturn pollOAuthDeviceCodeFlow<OAuthCredential>({\n\t\tintervalSeconds: device.interval,\n\t\texpiresInSeconds: device.expires_in,\n\t\tsignal: interaction.signal,\n\t\tpoll: async () => {\n\t\t\ttry {\n\t\t\t\tconst credentials = await requestOAuthToken(\n\t\t\t\t\tgateway,\n\t\t\t\t\tnew URLSearchParams({\n\t\t\t\t\t\tgrant_type: OAUTH_DEVICE_CODE_GRANT_TYPE,\n\t\t\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\t\t\tdevice_code: device.device_code,\n\t\t\t\t\t}),\n\t\t\t\t\tinteraction.signal,\n\t\t\t\t);\n\t\t\t\treturn { status: \"complete\", value: credentials };\n\t\t\t} catch (error) {\n\t\t\t\tif (!(error instanceof OAuthResponseError)) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tswitch (error.oauthError) {\n\t\t\t\t\tcase \"authorization_pending\":\n\t\t\t\t\t\treturn { status: \"pending\" };\n\t\t\t\t\tcase \"slow_down\":\n\t\t\t\t\t\treturn { status: \"slow_down\" };\n\t\t\t\t\tcase \"expired_token\":\n\t\t\t\t\t\treturn { status: \"failed\", message: \"Device authorization expired.\" };\n\t\t\t\t\tcase \"access_denied\":\n\t\t\t\t\t\treturn { status: \"failed\", message: \"Device authorization was denied.\" };\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n}\n\nexport interface RadiusOAuthOptions {\n\tname: string;\n\tgateway: string;\n}\n\nexport function createRadiusOAuth(options: RadiusOAuthOptions): OAuthAuth {\n\tconst gateway = normalizeRadiusGatewayUrl(options.gateway);\n\n\treturn {\n\t\tname: options.name,\n\n\t\tasync login(interaction): Promise<OAuthCredential> {\n\t\t\tconst loginMethod = await interaction.prompt({\n\t\t\t\ttype: \"select\",\n\t\t\t\tmessage: `Sign in to ${options.name}:`,\n\t\t\t\toptions: [\n\t\t\t\t\t{ id: LOGIN_METHOD_BROWSER, label: \"Sign in with browser (recommended)\" },\n\t\t\t\t\t{\n\t\t\t\t\t\tid: LOGIN_METHOD_DEVICE_CODE,\n\t\t\t\t\t\tlabel: \"Sign in with device code (when signing in from another device)\",\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tif (loginMethod === LOGIN_METHOD_DEVICE_CODE) {\n\t\t\t\treturn loginWithDeviceCode(gateway, interaction);\n\t\t\t}\n\t\t\tif (loginMethod === LOGIN_METHOD_BROWSER) {\n\t\t\t\tconst discovery = await loadRadiusOAuthDiscovery(gateway, interaction.signal);\n\t\t\t\treturn loginWithBrowser(gateway, discovery.authorizationEndpoint, interaction);\n\t\t\t}\n\t\t\tthrow new Error(`Unknown ${options.name} sign-in method: ${loginMethod}`);\n\t\t},\n\n\t\tasync refresh(credential, signal): Promise<OAuthCredential> {\n\t\t\tconst refreshed = await requestOAuthToken(\n\t\t\t\tgateway,\n\t\t\t\tnew URLSearchParams({\n\t\t\t\t\tgrant_type: \"refresh_token\",\n\t\t\t\t\tclient_id: OAUTH_CLIENT_ID,\n\t\t\t\t\trefresh_token: credential.refresh,\n\t\t\t\t}),\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\treturn refreshed;\n\t\t},\n\n\t\tasync toAuth(credential) {\n\t\t\treturn { apiKey: credential.access };\n\t\t},\n\t};\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xai.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/xai.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,aAAa,CAAC;AAgOvF,eAAO,MAAM,QAAQ,EAAE,SAUtB,CAAC"
|
|
1
|
+
{"version":3,"file":"xai.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/xai.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,aAAa,CAAC;AAgOvF,eAAO,MAAM,QAAQ,EAAE,SAUtB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xai.js","sourceRoot":"","sources":["../../../src/auth/oauth/xai.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * xAI OAuth device-code flow.\n */\n\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\n\nconst XAI_CLIENT_ID = \"b1a00492-073a-47ea-816f-4c329264a828\";\nconst XAI_SCOPE = \"openid profile email offline_access grok-cli:access api:access\";\nconst XAI_DEVICE_CODE_URL = \"https://auth.x.ai/oauth2/device/code\";\nconst XAI_TOKEN_URL = \"https://auth.x.ai/oauth2/token\";\n// Refresh slightly before the reported expiry to avoid using a token that dies mid-request.\nconst REFRESH_SKEW_MS = 5 * 60 * 1000;\nconst DEFAULT_TOKEN_LIFETIME_SECONDS = 3600;\n\ntype JsonObject = Record<string, unknown>;\n\ntype OAuthHttpResponse = {\n\tok: boolean;\n\tstatus: number;\n\tbody: JsonObject;\n};\n\ntype XaiDeviceCode = {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUri: string;\n\tverificationUriComplete?: string;\n\tintervalSeconds?: number;\n\texpiresInSeconds: number;\n};\n\nfunction requiredString(body: JsonObject, field: string): string {\n\tconst value = body[field];\n\tif (typeof value !== \"string\" || value.length === 0) {\n\t\tthrow new Error(`Invalid xAI OAuth response field: ${field}`);\n\t}\n\treturn value;\n}\n\nfunction positiveNumber(body: JsonObject, field: string): number {\n\tconst value = body[field];\n\tif (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n\t\tthrow new Error(`Invalid xAI OAuth response field: ${field}`);\n\t}\n\treturn value;\n}\n\n// The verification URI is opened in the user's browser; force it to be an https URL\n// so a malicious response cannot make `open` launch something else.\nfunction validateVerificationUri(raw: string): string {\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(raw);\n\t} catch {\n\t\tthrow new Error(\"Untrusted verification URI in xAI OAuth response\");\n\t}\n\tif (url.protocol !== \"https:\") {\n\t\tthrow new Error(\"Untrusted verification URI in xAI OAuth response\");\n\t}\n\treturn url.href;\n}\n\nasync function postForm(url: string, fields: Record<string, string>, signal: AbortSignal): Promise<OAuthHttpResponse> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t},\n\t\t\tbody: new URLSearchParams(fields),\n\t\t\tsignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\t\tthrow error;\n\t}\n\n\tlet body: JsonObject;\n\ttry {\n\t\tconst parsed = (await response.json()) as unknown;\n\t\tbody = parsed && typeof parsed === \"object\" && !Array.isArray(parsed) ? (parsed as JsonObject) : {};\n\t} catch {\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\t\tthrow new Error(`xAI OAuth returned invalid JSON (HTTP ${response.status})`);\n\t}\n\treturn {\n\t\tok: response.ok,\n\t\tstatus: response.status,\n\t\tbody,\n\t};\n}\n\nfunction requestFailure(action: string, response: OAuthHttpResponse): Error {\n\tconst error = typeof response.body.error === \"string\" ? response.body.error : undefined;\n\tconst description =\n\t\ttypeof response.body.error_description === \"string\" ? response.body.error_description : undefined;\n\tconst detail = [error, description].filter(Boolean).join(\": \");\n\treturn new Error(`xAI OAuth ${action} failed (HTTP ${response.status})${detail ? `: ${detail}` : \"\"}`);\n}\n\nfunction parseDeviceCode(body: JsonObject): XaiDeviceCode {\n\t// RFC 8628 allows interval 0 (no minimum wait); fall back to the poller's\n\t// default instead of failing on non-positive or malformed values.\n\tconst interval = body.interval;\n\tconst intervalSeconds =\n\t\ttypeof interval === \"number\" && Number.isFinite(interval) && interval > 0 ? interval : undefined;\n\tconst verificationUriComplete =\n\t\ttypeof body.verification_uri_complete === \"string\" && body.verification_uri_complete.length > 0\n\t\t\t? validateVerificationUri(body.verification_uri_complete)\n\t\t\t: undefined;\n\treturn {\n\t\tdeviceCode: requiredString(body, \"device_code\"),\n\t\tuserCode: requiredString(body, \"user_code\"),\n\t\tverificationUri: validateVerificationUri(requiredString(body, \"verification_uri\")),\n\t\tverificationUriComplete,\n\t\tintervalSeconds,\n\t\texpiresInSeconds: positiveNumber(body, \"expires_in\"),\n\t};\n}\n\nfunction credentialsFromTokenResponse(body: JsonObject, previousRefreshToken?: string): OAuthCredential {\n\tconst access = requiredString(body, \"access_token\");\n\t// xAI may omit refresh_token on refresh when the token is not rotated.\n\tconst refresh =\n\t\tbody.refresh_token === undefined && previousRefreshToken\n\t\t\t? previousRefreshToken\n\t\t\t: requiredString(body, \"refresh_token\");\n\tconst expiresInSeconds =\n\t\tbody.expires_in === undefined ? DEFAULT_TOKEN_LIFETIME_SECONDS : positiveNumber(body, \"expires_in\");\n\treturn {\n\t\ttype: \"oauth\",\n\t\taccess,\n\t\trefresh,\n\t\texpires: Date.now() + expiresInSeconds * 1000 - REFRESH_SKEW_MS,\n\t};\n}\n\nasync function requestDeviceCode(signal: AbortSignal): Promise<XaiDeviceCode> {\n\tconst response = await postForm(\n\t\tXAI_DEVICE_CODE_URL,\n\t\t{\n\t\t\tclient_id: XAI_CLIENT_ID,\n\t\t\tscope: XAI_SCOPE,\n\t\t\treferrer: \"pi\",\n\t\t},\n\t\tsignal,\n\t);\n\tif (!response.ok) {\n\t\tthrow requestFailure(\"device authorization\", response);\n\t}\n\treturn parseDeviceCode(response.body);\n}\n\nasync function pollForTokens(device: XaiDeviceCode, signal: AbortSignal): Promise<OAuthCredential> {\n\treturn pollOAuthDeviceCodeFlow<OAuthCredential>({\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t\twaitBeforeFirstPoll: true,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst response = await postForm(\n\t\t\t\tXAI_TOKEN_URL,\n\t\t\t\t{\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t\tclient_id: XAI_CLIENT_ID,\n\t\t\t\t\tdevice_code: device.deviceCode,\n\t\t\t\t},\n\t\t\t\tsignal,\n\t\t\t);\n\n\t\t\tif (response.ok) {\n\t\t\t\treturn { status: \"complete\", value: credentialsFromTokenResponse(response.body) };\n\t\t\t}\n\n\t\t\tconst error = response.body.error;\n\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\treturn { status: \"pending\" };\n\t\t\t}\n\t\t\tif (error === \"slow_down\") {\n\t\t\t\tconst interval = response.body.interval;\n\t\t\t\treturn { status: \"slow_down\", intervalSeconds: typeof interval === \"number\" ? interval : undefined };\n\t\t\t}\n\t\t\tif (error === \"access_denied\" || error === \"authorization_denied\") {\n\t\t\t\treturn { status: \"failed\", message: \"xAI device authorization was denied\" };\n\t\t\t}\n\t\t\tif (error === \"expired_token\") {\n\t\t\t\treturn { status: \"failed\", message: \"xAI device code expired\" };\n\t\t\t}\n\t\t\treturn { status: \"failed\", message: requestFailure(\"device token polling\", response).message };\n\t\t},\n\t});\n}\n\nasync function loginXai(interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\tconst device = await requestDeviceCode(interaction.signal);\n\tinteraction.notify({\n\t\ttype: \"device_code\",\n\t\tuserCode: device.userCode,\n\t\tverificationUri: device.verificationUriComplete ?? device.verificationUri,\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t});\n\treturn pollForTokens(device, interaction.signal);\n}\n\nasync function refreshXaiToken(refreshToken: string, signal: AbortSignal): Promise<OAuthCredential> {\n\tconst response = await postForm(\n\t\tXAI_TOKEN_URL,\n\t\t{\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: XAI_CLIENT_ID,\n\t\t\trefresh_token: refreshToken,\n\t\t},\n\t\tsignal,\n\t);\n\tif (!response.ok) {\n\t\tthrow requestFailure(\"token refresh\", response);\n\t}\n\treturn credentialsFromTokenResponse(response.body, refreshToken);\n}\n\nexport const xaiOAuth: OAuthAuth = {\n\tname: \"xAI (Grok/X subscription)\",\n\tisSubscription: true,\n\tloginLabel: \"Sign in with SuperGrok or X Premium\",\n\tlogin: loginXai,\n\trefresh: (credential, signal) => refreshXaiToken(credential.refresh, signal),\n\n\tasync toAuth(credential) {\n\t\treturn { apiKey: credential.access };\n\t},\n};\n"]}
|
|
1
|
+
{"version":3,"file":"xai.js","sourceRoot":"","sources":["../../../src/auth/oauth/xai.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * xAI OAuth device-code flow.\n */\n\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\n\nconst XAI_CLIENT_ID = \"b1a00492-073a-47ea-816f-4c329264a828\";\nconst XAI_SCOPE = \"openid profile email offline_access grok-cli:access api:access\";\nconst XAI_DEVICE_CODE_URL = \"https://auth.x.ai/oauth2/device/code\";\nconst XAI_TOKEN_URL = \"https://auth.x.ai/oauth2/token\";\n// Refresh slightly before the reported expiry to avoid using a token that dies mid-request.\nconst REFRESH_SKEW_MS = 5 * 60 * 1000;\nconst DEFAULT_TOKEN_LIFETIME_SECONDS = 3600;\n\ntype JsonObject = Record<string, unknown>;\n\ntype OAuthHttpResponse = {\n\tok: boolean;\n\tstatus: number;\n\tbody: JsonObject;\n};\n\ntype XaiDeviceCode = {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUri: string;\n\tverificationUriComplete?: string;\n\tintervalSeconds?: number;\n\texpiresInSeconds: number;\n};\n\nfunction requiredString(body: JsonObject, field: string): string {\n\tconst value = body[field];\n\tif (typeof value !== \"string\" || value.length === 0) {\n\t\tthrow new Error(`Invalid xAI OAuth response field: ${field}`);\n\t}\n\treturn value;\n}\n\nfunction positiveNumber(body: JsonObject, field: string): number {\n\tconst value = body[field];\n\tif (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n\t\tthrow new Error(`Invalid xAI OAuth response field: ${field}`);\n\t}\n\treturn value;\n}\n\n// The verification URI is opened in the user's browser; force it to be an https URL\n// so a malicious response cannot make `open` launch something else.\nfunction validateVerificationUri(raw: string): string {\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(raw);\n\t} catch {\n\t\tthrow new Error(\"Untrusted verification URI in xAI OAuth response\");\n\t}\n\tif (url.protocol !== \"https:\") {\n\t\tthrow new Error(\"Untrusted verification URI in xAI OAuth response\");\n\t}\n\treturn url.href;\n}\n\nasync function postForm(url: string, fields: Record<string, string>, signal: AbortSignal): Promise<OAuthHttpResponse> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t},\n\t\t\tbody: new URLSearchParams(fields),\n\t\t\tsignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\t\tthrow error;\n\t}\n\n\tlet body: JsonObject;\n\ttry {\n\t\tconst parsed = (await response.json()) as unknown;\n\t\tbody = parsed && typeof parsed === \"object\" && !Array.isArray(parsed) ? (parsed as JsonObject) : {};\n\t} catch {\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\t\tthrow new Error(`xAI OAuth returned invalid JSON (HTTP ${response.status})`);\n\t}\n\treturn {\n\t\tok: response.ok,\n\t\tstatus: response.status,\n\t\tbody,\n\t};\n}\n\nfunction requestFailure(action: string, response: OAuthHttpResponse): Error {\n\tconst error = typeof response.body.error === \"string\" ? response.body.error : undefined;\n\tconst description =\n\t\ttypeof response.body.error_description === \"string\" ? response.body.error_description : undefined;\n\tconst detail = [error, description].filter(Boolean).join(\": \");\n\treturn new Error(`xAI OAuth ${action} failed (HTTP ${response.status})${detail ? `: ${detail}` : \"\"}`);\n}\n\nfunction parseDeviceCode(body: JsonObject): XaiDeviceCode {\n\t// RFC 8628 allows interval 0 (no minimum wait); fall back to the poller's\n\t// default instead of failing on non-positive or malformed values.\n\tconst interval = body.interval;\n\tconst intervalSeconds =\n\t\ttypeof interval === \"number\" && Number.isFinite(interval) && interval > 0 ? interval : undefined;\n\tconst verificationUriComplete =\n\t\ttypeof body.verification_uri_complete === \"string\" && body.verification_uri_complete.length > 0\n\t\t\t? validateVerificationUri(body.verification_uri_complete)\n\t\t\t: undefined;\n\treturn {\n\t\tdeviceCode: requiredString(body, \"device_code\"),\n\t\tuserCode: requiredString(body, \"user_code\"),\n\t\tverificationUri: validateVerificationUri(requiredString(body, \"verification_uri\")),\n\t\tverificationUriComplete,\n\t\tintervalSeconds,\n\t\texpiresInSeconds: positiveNumber(body, \"expires_in\"),\n\t};\n}\n\nfunction credentialsFromTokenResponse(body: JsonObject, previousRefreshToken?: string): OAuthCredential {\n\tconst access = requiredString(body, \"access_token\");\n\t// xAI may omit refresh_token on refresh when the token is not rotated.\n\tconst refresh =\n\t\tbody.refresh_token === undefined && previousRefreshToken\n\t\t\t? previousRefreshToken\n\t\t\t: requiredString(body, \"refresh_token\");\n\tconst expiresInSeconds =\n\t\tbody.expires_in === undefined ? DEFAULT_TOKEN_LIFETIME_SECONDS : positiveNumber(body, \"expires_in\");\n\treturn {\n\t\ttype: \"oauth\",\n\t\taccess,\n\t\trefresh,\n\t\texpires: Date.now() + expiresInSeconds * 1000 - REFRESH_SKEW_MS,\n\t};\n}\n\nasync function requestDeviceCode(signal: AbortSignal): Promise<XaiDeviceCode> {\n\tconst response = await postForm(\n\t\tXAI_DEVICE_CODE_URL,\n\t\t{\n\t\t\tclient_id: XAI_CLIENT_ID,\n\t\t\tscope: XAI_SCOPE,\n\t\t\treferrer: \"pi\",\n\t\t},\n\t\tsignal,\n\t);\n\tif (!response.ok) {\n\t\tthrow requestFailure(\"device authorization\", response);\n\t}\n\treturn parseDeviceCode(response.body);\n}\n\nasync function pollForTokens(device: XaiDeviceCode, signal: AbortSignal): Promise<OAuthCredential> {\n\treturn pollOAuthDeviceCodeFlow<OAuthCredential>({\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t\twaitBeforeFirstPoll: true,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst response = await postForm(\n\t\t\t\tXAI_TOKEN_URL,\n\t\t\t\t{\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t\tclient_id: XAI_CLIENT_ID,\n\t\t\t\t\tdevice_code: device.deviceCode,\n\t\t\t\t},\n\t\t\t\tsignal,\n\t\t\t);\n\n\t\t\tif (response.ok) {\n\t\t\t\treturn { status: \"complete\", value: credentialsFromTokenResponse(response.body) };\n\t\t\t}\n\n\t\t\tconst error = response.body.error;\n\t\t\tif (error === \"authorization_pending\") {\n\t\t\t\treturn { status: \"pending\" };\n\t\t\t}\n\t\t\tif (error === \"slow_down\") {\n\t\t\t\tconst interval = response.body.interval;\n\t\t\t\treturn { status: \"slow_down\", intervalSeconds: typeof interval === \"number\" ? interval : undefined };\n\t\t\t}\n\t\t\tif (error === \"access_denied\" || error === \"authorization_denied\") {\n\t\t\t\treturn { status: \"failed\", message: \"xAI device authorization was denied\" };\n\t\t\t}\n\t\t\tif (error === \"expired_token\") {\n\t\t\t\treturn { status: \"failed\", message: \"xAI device code expired\" };\n\t\t\t}\n\t\t\treturn { status: \"failed\", message: requestFailure(\"device token polling\", response).message };\n\t\t},\n\t});\n}\n\nasync function loginXai(interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\tconst device = await requestDeviceCode(interaction.signal);\n\tinteraction.notify({\n\t\ttype: \"device_code\",\n\t\tuserCode: device.userCode,\n\t\tverificationUri: device.verificationUriComplete ?? device.verificationUri,\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t});\n\treturn pollForTokens(device, interaction.signal);\n}\n\nasync function refreshXaiToken(refreshToken: string, signal: AbortSignal): Promise<OAuthCredential> {\n\tconst response = await postForm(\n\t\tXAI_TOKEN_URL,\n\t\t{\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: XAI_CLIENT_ID,\n\t\t\trefresh_token: refreshToken,\n\t\t},\n\t\tsignal,\n\t);\n\tif (!response.ok) {\n\t\tthrow requestFailure(\"token refresh\", response);\n\t}\n\treturn credentialsFromTokenResponse(response.body, refreshToken);\n}\n\nexport const xaiOAuth: OAuthAuth = {\n\tname: \"xAI (Grok/X subscription)\",\n\tisSubscription: true,\n\tloginLabel: \"Sign in with SuperGrok or X Premium\",\n\tlogin: loginXai,\n\trefresh: (credential, signal) => refreshXaiToken(credential.refresh, signal),\n\n\tasync toAuth(credential) {\n\t\treturn { apiKey: credential.access };\n\t},\n};\n"]}
|
package/dist/auth/resolve.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ProviderEnv } from "../types.ts";
|
|
2
|
+
export { ModelsError, type ModelsErrorCode } from "../utils/models-error.ts";
|
|
2
3
|
import type { AuthContext, AuthResult, CredentialStore, ProviderAuth } from "./types.ts";
|
|
3
|
-
export type ModelsErrorCode = "model_source" | "model_validation" | "provider" | "stream" | "auth" | "oauth";
|
|
4
4
|
export interface AuthResolutionOverrides {
|
|
5
5
|
apiKey?: string;
|
|
6
6
|
env?: ProviderEnv;
|
|
@@ -8,14 +8,8 @@ export interface AuthResolutionOverrides {
|
|
|
8
8
|
minOAuthValidityMs?: number;
|
|
9
9
|
signal?: AbortSignal;
|
|
10
10
|
}
|
|
11
|
-
export declare class ModelsError extends Error {
|
|
12
|
-
readonly code: ModelsErrorCode;
|
|
13
|
-
constructor(code: ModelsErrorCode, message: string, options?: {
|
|
14
|
-
cause?: unknown;
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
11
|
/**
|
|
18
|
-
* Auth resolution shared by
|
|
12
|
+
* Auth resolution shared by all operations in a `Models` collection.
|
|
19
13
|
* A stored credential owns the provider: ambient/env is consulted only when
|
|
20
14
|
* nothing is stored. No silent env fallback after a failed refresh or for a
|
|
21
15
|
* credential type without a matching handler.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/auth/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/auth/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/C,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE7E,OAAO,KAAK,EAGX,WAAW,EACX,UAAU,EAEV,eAAe,EAGf,YAAY,EACZ,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,uBAAuB;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,kFAAkF;IAClF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAClC,QAAQ,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE,EAC5C,WAAW,EAAE,eAAe,EAC5B,WAAW,EAAE,WAAW,EACxB,SAAS,CAAC,EAAE,uBAAuB,GACjC,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAMjC"}
|
package/dist/auth/resolve.js
CHANGED
|
@@ -1,24 +1,8 @@
|
|
|
1
1
|
import { operationSignal, raceWithAbortSignal } from "../utils/abort.js";
|
|
2
|
-
import {
|
|
3
|
-
export
|
|
4
|
-
code;
|
|
5
|
-
constructor(code, message, options) {
|
|
6
|
-
super(withCauseDetail(message, options?.cause), options);
|
|
7
|
-
this.name = "ModelsError";
|
|
8
|
-
this.code = code;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
/** Callers surface `error.message` only, so keep the underlying reason in it. */
|
|
12
|
-
function withCauseDetail(message, cause) {
|
|
13
|
-
if (cause === undefined || cause === null)
|
|
14
|
-
return message;
|
|
15
|
-
const detail = formatThrownValue(cause).trim();
|
|
16
|
-
if (!detail || message.includes(detail))
|
|
17
|
-
return message;
|
|
18
|
-
return `${message}: ${detail}`;
|
|
19
|
-
}
|
|
2
|
+
import { ModelsError } from "../utils/models-error.js";
|
|
3
|
+
export { ModelsError } from "../utils/models-error.js";
|
|
20
4
|
/**
|
|
21
|
-
* Auth resolution shared by
|
|
5
|
+
* Auth resolution shared by all operations in a `Models` collection.
|
|
22
6
|
* A stored credential owns the provider: ambient/env is consulted only when
|
|
23
7
|
* nothing is stored. No silent env fallback after a failed refresh or for a
|
|
24
8
|
* credential type without a matching handler.
|
package/dist/auth/resolve.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/auth/resolve.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProviderEnv } from \"../types.ts\";\nimport { operationSignal, raceWithAbortSignal } from \"../utils/abort.ts\";\nimport { formatThrownValue } from \"../utils/diagnostics.ts\";\nimport type {\n\tApiKeyAuth,\n\tApiKeyCredential,\n\tAuthContext,\n\tAuthResult,\n\tCredential,\n\tCredentialStore,\n\tOAuthAuth,\n\tOAuthCredential,\n\tProviderAuth,\n} from \"./types.ts\";\n\nexport type ModelsErrorCode = \"model_source\" | \"model_validation\" | \"provider\" | \"stream\" | \"auth\" | \"oauth\";\n\nexport interface AuthResolutionOverrides {\n\tapiKey?: string;\n\tenv?: ProviderEnv;\n\t/** Require this much remaining OAuth-token validity; defaults to five minutes. */\n\tminOAuthValidityMs?: number;\n\tsignal?: AbortSignal;\n}\n\nexport class ModelsError extends Error {\n\treadonly code: ModelsErrorCode;\n\n\tconstructor(code: ModelsErrorCode, message: string, options?: { cause?: unknown }) {\n\t\tsuper(withCauseDetail(message, options?.cause), options);\n\t\tthis.name = \"ModelsError\";\n\t\tthis.code = code;\n\t}\n}\n\n/** Callers surface `error.message` only, so keep the underlying reason in it. */\nfunction withCauseDetail(message: string, cause: unknown): string {\n\tif (cause === undefined || cause === null) return message;\n\tconst detail = formatThrownValue(cause).trim();\n\tif (!detail || message.includes(detail)) return message;\n\treturn `${message}: ${detail}`;\n}\n\n/**\n * Auth resolution shared by the `Models` and `ImagesModels` collections.\n * A stored credential owns the provider: ambient/env is consulted only when\n * nothing is stored. No silent env fallback after a failed refresh or for a\n * credential type without a matching handler.\n */\nexport function resolveProviderAuth(\n\tprovider: { id: string; auth: ProviderAuth },\n\tcredentials: CredentialStore,\n\tauthContext: AuthContext,\n\toverrides?: AuthResolutionOverrides,\n): Promise<AuthResult | undefined> {\n\tconst signal = operationSignal(overrides?.signal);\n\treturn raceWithAbortSignal(\n\t\tresolveProviderAuthWithSignal(provider, credentials, authContext, overrides, signal),\n\t\tsignal,\n\t);\n}\n\nasync function resolveProviderAuthWithSignal(\n\tprovider: { id: string; auth: ProviderAuth },\n\tcredentials: CredentialStore,\n\tauthContext: AuthContext,\n\toverrides: AuthResolutionOverrides | undefined,\n\tsignal: AbortSignal,\n): Promise<AuthResult | undefined> {\n\tsignal.throwIfAborted();\n\tconst requestAuthContext = overrides?.env ? overlayEnvAuthContext(authContext, overrides.env) : authContext;\n\n\tif (overrides?.apiKey !== undefined && provider.auth.apiKey) {\n\t\treturn resolveApiKey(\n\t\t\trequestAuthContext,\n\t\t\tprovider.auth.apiKey,\n\t\t\tprovider.id,\n\t\t\t{\n\t\t\t\ttype: \"api_key\",\n\t\t\t\tkey: overrides.apiKey,\n\t\t\t\tenv: overrides.env,\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tconst stored = await readCredential(credentials, provider.id, signal);\n\tif (stored) {\n\t\tif (stored.type === \"oauth\" && provider.auth.oauth) {\n\t\t\treturn resolveStoredOAuth(\n\t\t\t\tcredentials,\n\t\t\t\tprovider.id,\n\t\t\t\tprovider.auth.oauth,\n\t\t\t\tstored,\n\t\t\t\tsignal,\n\t\t\t\toverrides?.minOAuthValidityMs,\n\t\t\t);\n\t\t}\n\t\tif (stored.type === \"api_key\" && provider.auth.apiKey) {\n\t\t\tconst credential = overrides?.env ? { ...stored, env: { ...stored.env, ...overrides.env } } : stored;\n\t\t\treturn resolveApiKey(requestAuthContext, provider.auth.apiKey, provider.id, credential, signal);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t// Ambient (env vars, AWS profiles, ADC files).\n\treturn provider.auth.apiKey\n\t\t? resolveApiKey(requestAuthContext, provider.auth.apiKey, provider.id, undefined, signal)\n\t\t: undefined;\n}\n\nfunction overlayEnvAuthContext(base: AuthContext, env: ProviderEnv): AuthContext {\n\treturn {\n\t\tenv: async (name) => env[name] || (await base.env(name)),\n\t\tfileExists: (path) => base.fileExists(path),\n\t};\n}\n\nconst DEFAULT_OAUTH_MINIMUM_VALIDITY_MS = 5 * 60 * 1000;\nconst DEFAULT_OAUTH_REFRESH_TIMEOUT_MS = 15_000;\n\n/**\n * OAuth resolution with double-checked locking: tokens with less than five\n * minutes remaining lock, re-check expiry under the lock, refresh once\n * globally, and persist the rotated credential before release.\n */\nasync function resolveStoredOAuth(\n\tcredentials: CredentialStore,\n\tproviderId: string,\n\toauth: OAuthAuth,\n\tstored: OAuthCredential,\n\tsignal: AbortSignal,\n\tminOAuthValidityMs?: number,\n): Promise<AuthResult | undefined> {\n\tconst minimumValidityMs = Math.max(DEFAULT_OAUTH_MINIMUM_VALIDITY_MS, minOAuthValidityMs ?? 0);\n\tconst expiresSoon = (credential: OAuthCredential) => Date.now() + minimumValidityMs >= credential.expires;\n\tlet credential = stored;\n\n\tif (expiresSoon(credential)) {\n\t\t// Optimistic check said expired; the authoritative check runs under the lock.\n\t\tlet post: Credential | undefined;\n\t\ttry {\n\t\t\tpost = await credentials.modify(\n\t\t\t\tproviderId,\n\t\t\t\tasync (current) => {\n\t\t\t\t\tif (current?.type !== \"oauth\") return undefined; // logged out meanwhile\n\t\t\t\t\tif (!expiresSoon(current)) return undefined; // another process/request refreshed\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst refreshSignal = AbortSignal.any([\n\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t\tAbortSignal.timeout(DEFAULT_OAUTH_REFRESH_TIMEOUT_MS),\n\t\t\t\t\t\t]);\n\t\t\t\t\t\treturn await oauth.refresh(current, refreshSignal);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthrow new ModelsError(\"oauth\", `OAuth refresh failed for ${providerId}`, { cause: error });\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ signal },\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (error instanceof ModelsError) throw error;\n\t\t\tthrow new ModelsError(\"auth\", `Credential store modify failed for ${providerId}`, { cause: error });\n\t\t}\n\t\tif (post?.type !== \"oauth\") return undefined; // logged out meanwhile\n\t\tcredential = post;\n\t\t// The normal five-minute window triggers a refresh but does not impose a\n\t\t// provider contract. Explicit callers (such as bearer-token export) do\n\t\t// require the requested minimum after the refresh.\n\t\tif (minOAuthValidityMs !== undefined && expiresSoon(credential)) {\n\t\t\tthrow new ModelsError(\"oauth\", `OAuth refresh returned a token that expires too soon for ${providerId}`);\n\t\t}\n\t}\n\n\ttry {\n\t\treturn { auth: await oauth.toAuth(credential), source: \"OAuth\" };\n\t} catch (error) {\n\t\tthrow new ModelsError(\"oauth\", `OAuth auth derivation failed for ${providerId}`, { cause: error });\n\t}\n}\n\nasync function resolveApiKey(\n\tauthContext: AuthContext,\n\tapiKey: ApiKeyAuth,\n\tproviderId: string,\n\tcredential: ApiKeyCredential | undefined,\n\tsignal: AbortSignal,\n): Promise<AuthResult | undefined> {\n\ttry {\n\t\treturn await apiKey.resolve({ ctx: authContext, credential, signal });\n\t} catch (error) {\n\t\tthrow new ModelsError(\"auth\", `API key auth failed for provider ${providerId}`, { cause: error });\n\t}\n}\n\nasync function readCredential(\n\tcredentials: CredentialStore,\n\tproviderId: string,\n\tsignal: AbortSignal,\n): Promise<Credential | undefined> {\n\ttry {\n\t\treturn await credentials.read(providerId, { signal });\n\t} catch (error) {\n\t\tthrow new ModelsError(\"auth\", `Credential store read failed for ${providerId}`, { cause: error });\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/auth/resolve.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,WAAW,EAAwB,MAAM,0BAA0B,CAAC;AAsB7E;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAClC,QAA4C,EAC5C,WAA4B,EAC5B,WAAwB,EACxB,SAAmC;IAEnC,MAAM,MAAM,GAAG,eAAe,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAClD,OAAO,mBAAmB,CACzB,6BAA6B,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,CAAC,EACpF,MAAM,CACN,CAAC;AACH,CAAC;AAED,KAAK,UAAU,6BAA6B,CAC3C,QAA4C,EAC5C,WAA4B,EAC5B,WAAwB,EACxB,SAA8C,EAC9C,MAAmB;IAEnB,MAAM,CAAC,cAAc,EAAE,CAAC;IACxB,MAAM,kBAAkB,GAAG,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,qBAAqB,CAAC,WAAW,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IAE5G,IAAI,SAAS,EAAE,MAAM,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QAC7D,OAAO,aAAa,CACnB,kBAAkB,EAClB,QAAQ,CAAC,IAAI,CAAC,MAAM,EACpB,QAAQ,CAAC,EAAE,EACX;YACC,IAAI,EAAE,SAAS;YACf,GAAG,EAAE,SAAS,CAAC,MAAM;YACrB,GAAG,EAAE,SAAS,CAAC,GAAG;SAClB,EACD,MAAM,CACN,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACtE,IAAI,MAAM,EAAE,CAAC;QACZ,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YACpD,OAAO,kBAAkB,CACxB,WAAW,EACX,QAAQ,CAAC,EAAE,EACX,QAAQ,CAAC,IAAI,CAAC,KAAK,EACnB,MAAM,EACN,MAAM,EACN,SAAS,EAAE,kBAAkB,CAC7B,CAAC;QACH,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACvD,MAAM,UAAU,GAAG,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;YACrG,OAAO,aAAa,CAAC,kBAAkB,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QACjG,CAAC;QACD,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,+CAA+C;IAC/C,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM;QAC1B,CAAC,CAAC,aAAa,CAAC,kBAAkB,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC;QACzF,CAAC,CAAC,SAAS,CAAC;AACd,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAiB,EAAE,GAAgB;IACjE,OAAO;QACN,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxD,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;KAC3C,CAAC;AACH,CAAC;AAED,MAAM,iCAAiC,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AACxD,MAAM,gCAAgC,GAAG,MAAM,CAAC;AAEhD;;;;GAIG;AACH,KAAK,UAAU,kBAAkB,CAChC,WAA4B,EAC5B,UAAkB,EAClB,KAAgB,EAChB,MAAuB,EACvB,MAAmB,EACnB,kBAA2B;IAE3B,MAAM,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,iCAAiC,EAAE,kBAAkB,IAAI,CAAC,CAAC,CAAC;IAC/F,MAAM,WAAW,GAAG,CAAC,UAA2B,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,iBAAiB,IAAI,UAAU,CAAC,OAAO,CAAC;IAC1G,IAAI,UAAU,GAAG,MAAM,CAAC;IAExB,IAAI,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7B,8EAA8E;QAC9E,IAAI,IAA4B,CAAC;QACjC,IAAI,CAAC;YACJ,IAAI,GAAG,MAAM,WAAW,CAAC,MAAM,CAC9B,UAAU,EACV,KAAK,EAAE,OAAO,EAAE,EAAE;gBACjB,IAAI,OAAO,EAAE,IAAI,KAAK,OAAO;oBAAE,OAAO,SAAS,CAAC,CAAC,uBAAuB;gBACxE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;oBAAE,OAAO,SAAS,CAAC,CAAC,oCAAoC;gBACjF,IAAI,CAAC;oBACJ,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,CAAC;wBACrC,MAAM;wBACN,WAAW,CAAC,OAAO,CAAC,gCAAgC,CAAC;qBACrD,CAAC,CAAC;oBACH,OAAO,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;gBACpD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBAChB,MAAM,IAAI,WAAW,CAAC,OAAO,EAAE,4BAA4B,UAAU,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC5F,CAAC;YACF,CAAC,EACD,EAAE,MAAM,EAAE,CACV,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,KAAK,YAAY,WAAW;gBAAE,MAAM,KAAK,CAAC;YAC9C,MAAM,IAAI,WAAW,CAAC,MAAM,EAAE,sCAAsC,UAAU,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QACrG,CAAC;QACD,IAAI,IAAI,EAAE,IAAI,KAAK,OAAO;YAAE,OAAO,SAAS,CAAC,CAAC,uBAAuB;QACrE,UAAU,GAAG,IAAI,CAAC;QAClB,yEAAyE;QACzE,uEAAuE;QACvE,mDAAmD;QACnD,IAAI,kBAAkB,KAAK,SAAS,IAAI,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;YACjE,MAAM,IAAI,WAAW,CAAC,OAAO,EAAE,4DAA4D,UAAU,EAAE,CAAC,CAAC;QAC1G,CAAC;IACF,CAAC;IAED,IAAI,CAAC;QACJ,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IAClE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,WAAW,CAAC,OAAO,EAAE,oCAAoC,UAAU,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACpG,CAAC;AACF,CAAC;AAED,KAAK,UAAU,aAAa,CAC3B,WAAwB,EACxB,MAAkB,EAClB,UAAkB,EAClB,UAAwC,EACxC,MAAmB;IAEnB,IAAI,CAAC;QACJ,OAAO,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,WAAW,CAAC,MAAM,EAAE,oCAAoC,UAAU,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACnG,CAAC;AACF,CAAC;AAED,KAAK,UAAU,cAAc,CAC5B,WAA4B,EAC5B,UAAkB,EAClB,MAAmB;IAEnB,IAAI,CAAC;QACJ,OAAO,MAAM,WAAW,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,WAAW,CAAC,MAAM,EAAE,oCAAoC,UAAU,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACnG,CAAC;AACF,CAAC","sourcesContent":["import type { ProviderEnv } from \"../types.ts\";\nimport { operationSignal, raceWithAbortSignal } from \"../utils/abort.ts\";\nimport { ModelsError } from \"../utils/models-error.ts\";\n\nexport { ModelsError, type ModelsErrorCode } from \"../utils/models-error.ts\";\n\nimport type {\n\tApiKeyAuth,\n\tApiKeyCredential,\n\tAuthContext,\n\tAuthResult,\n\tCredential,\n\tCredentialStore,\n\tOAuthAuth,\n\tOAuthCredential,\n\tProviderAuth,\n} from \"./types.ts\";\n\nexport interface AuthResolutionOverrides {\n\tapiKey?: string;\n\tenv?: ProviderEnv;\n\t/** Require this much remaining OAuth-token validity; defaults to five minutes. */\n\tminOAuthValidityMs?: number;\n\tsignal?: AbortSignal;\n}\n\n/**\n * Auth resolution shared by all operations in a `Models` collection.\n * A stored credential owns the provider: ambient/env is consulted only when\n * nothing is stored. No silent env fallback after a failed refresh or for a\n * credential type without a matching handler.\n */\nexport function resolveProviderAuth(\n\tprovider: { id: string; auth: ProviderAuth },\n\tcredentials: CredentialStore,\n\tauthContext: AuthContext,\n\toverrides?: AuthResolutionOverrides,\n): Promise<AuthResult | undefined> {\n\tconst signal = operationSignal(overrides?.signal);\n\treturn raceWithAbortSignal(\n\t\tresolveProviderAuthWithSignal(provider, credentials, authContext, overrides, signal),\n\t\tsignal,\n\t);\n}\n\nasync function resolveProviderAuthWithSignal(\n\tprovider: { id: string; auth: ProviderAuth },\n\tcredentials: CredentialStore,\n\tauthContext: AuthContext,\n\toverrides: AuthResolutionOverrides | undefined,\n\tsignal: AbortSignal,\n): Promise<AuthResult | undefined> {\n\tsignal.throwIfAborted();\n\tconst requestAuthContext = overrides?.env ? overlayEnvAuthContext(authContext, overrides.env) : authContext;\n\n\tif (overrides?.apiKey !== undefined && provider.auth.apiKey) {\n\t\treturn resolveApiKey(\n\t\t\trequestAuthContext,\n\t\t\tprovider.auth.apiKey,\n\t\t\tprovider.id,\n\t\t\t{\n\t\t\t\ttype: \"api_key\",\n\t\t\t\tkey: overrides.apiKey,\n\t\t\t\tenv: overrides.env,\n\t\t\t},\n\t\t\tsignal,\n\t\t);\n\t}\n\n\tconst stored = await readCredential(credentials, provider.id, signal);\n\tif (stored) {\n\t\tif (stored.type === \"oauth\" && provider.auth.oauth) {\n\t\t\treturn resolveStoredOAuth(\n\t\t\t\tcredentials,\n\t\t\t\tprovider.id,\n\t\t\t\tprovider.auth.oauth,\n\t\t\t\tstored,\n\t\t\t\tsignal,\n\t\t\t\toverrides?.minOAuthValidityMs,\n\t\t\t);\n\t\t}\n\t\tif (stored.type === \"api_key\" && provider.auth.apiKey) {\n\t\t\tconst credential = overrides?.env ? { ...stored, env: { ...stored.env, ...overrides.env } } : stored;\n\t\t\treturn resolveApiKey(requestAuthContext, provider.auth.apiKey, provider.id, credential, signal);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t// Ambient (env vars, AWS profiles, ADC files).\n\treturn provider.auth.apiKey\n\t\t? resolveApiKey(requestAuthContext, provider.auth.apiKey, provider.id, undefined, signal)\n\t\t: undefined;\n}\n\nfunction overlayEnvAuthContext(base: AuthContext, env: ProviderEnv): AuthContext {\n\treturn {\n\t\tenv: async (name) => env[name] || (await base.env(name)),\n\t\tfileExists: (path) => base.fileExists(path),\n\t};\n}\n\nconst DEFAULT_OAUTH_MINIMUM_VALIDITY_MS = 5 * 60 * 1000;\nconst DEFAULT_OAUTH_REFRESH_TIMEOUT_MS = 15_000;\n\n/**\n * OAuth resolution with double-checked locking: tokens with less than five\n * minutes remaining lock, re-check expiry under the lock, refresh once\n * globally, and persist the rotated credential before release.\n */\nasync function resolveStoredOAuth(\n\tcredentials: CredentialStore,\n\tproviderId: string,\n\toauth: OAuthAuth,\n\tstored: OAuthCredential,\n\tsignal: AbortSignal,\n\tminOAuthValidityMs?: number,\n): Promise<AuthResult | undefined> {\n\tconst minimumValidityMs = Math.max(DEFAULT_OAUTH_MINIMUM_VALIDITY_MS, minOAuthValidityMs ?? 0);\n\tconst expiresSoon = (credential: OAuthCredential) => Date.now() + minimumValidityMs >= credential.expires;\n\tlet credential = stored;\n\n\tif (expiresSoon(credential)) {\n\t\t// Optimistic check said expired; the authoritative check runs under the lock.\n\t\tlet post: Credential | undefined;\n\t\ttry {\n\t\t\tpost = await credentials.modify(\n\t\t\t\tproviderId,\n\t\t\t\tasync (current) => {\n\t\t\t\t\tif (current?.type !== \"oauth\") return undefined; // logged out meanwhile\n\t\t\t\t\tif (!expiresSoon(current)) return undefined; // another process/request refreshed\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst refreshSignal = AbortSignal.any([\n\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t\tAbortSignal.timeout(DEFAULT_OAUTH_REFRESH_TIMEOUT_MS),\n\t\t\t\t\t\t]);\n\t\t\t\t\t\treturn await oauth.refresh(current, refreshSignal);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthrow new ModelsError(\"oauth\", `OAuth refresh failed for ${providerId}`, { cause: error });\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ signal },\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (error instanceof ModelsError) throw error;\n\t\t\tthrow new ModelsError(\"auth\", `Credential store modify failed for ${providerId}`, { cause: error });\n\t\t}\n\t\tif (post?.type !== \"oauth\") return undefined; // logged out meanwhile\n\t\tcredential = post;\n\t\t// The normal five-minute window triggers a refresh but does not impose a\n\t\t// provider contract. Explicit callers (such as bearer-token export) do\n\t\t// require the requested minimum after the refresh.\n\t\tif (minOAuthValidityMs !== undefined && expiresSoon(credential)) {\n\t\t\tthrow new ModelsError(\"oauth\", `OAuth refresh returned a token that expires too soon for ${providerId}`);\n\t\t}\n\t}\n\n\ttry {\n\t\treturn { auth: await oauth.toAuth(credential), source: \"OAuth\" };\n\t} catch (error) {\n\t\tthrow new ModelsError(\"oauth\", `OAuth auth derivation failed for ${providerId}`, { cause: error });\n\t}\n}\n\nasync function resolveApiKey(\n\tauthContext: AuthContext,\n\tapiKey: ApiKeyAuth,\n\tproviderId: string,\n\tcredential: ApiKeyCredential | undefined,\n\tsignal: AbortSignal,\n): Promise<AuthResult | undefined> {\n\ttry {\n\t\treturn await apiKey.resolve({ ctx: authContext, credential, signal });\n\t} catch (error) {\n\t\tthrow new ModelsError(\"auth\", `API key auth failed for provider ${providerId}`, { cause: error });\n\t}\n}\n\nasync function readCredential(\n\tcredentials: CredentialStore,\n\tproviderId: string,\n\tsignal: AbortSignal,\n): Promise<Credential | undefined> {\n\ttry {\n\t\treturn await credentials.read(providerId, { signal });\n\t} catch (error) {\n\t\tthrow new ModelsError(\"auth\", `Credential store read failed for ${providerId}`, { cause: error });\n\t}\n}\n"]}
|
package/dist/auth/types.d.ts
CHANGED
|
@@ -194,6 +194,15 @@ export interface ApiKeyAuth {
|
|
|
194
194
|
signal: AbortSignal;
|
|
195
195
|
}): Promise<AuthResult | undefined>;
|
|
196
196
|
}
|
|
197
|
+
/** App-supplied context for `Models.login`. */
|
|
198
|
+
export interface LoginOptions {
|
|
199
|
+
/**
|
|
200
|
+
* Returns the stable ID of this app installation, e.g. sent to OpenAI as its
|
|
201
|
+
* agent host ID. Called only by login flows that need it, so apps can create
|
|
202
|
+
* the ID on first use and must return the same ID on every later call.
|
|
203
|
+
*/
|
|
204
|
+
getDeviceId?: () => string;
|
|
205
|
+
}
|
|
197
206
|
/**
|
|
198
207
|
* OAuth auth. The `refresh`/`toAuth` split lets `Models` own the locked
|
|
199
208
|
* refresh pattern: `refresh` produces a credential, `toAuth` derives request
|
|
@@ -206,7 +215,7 @@ export interface OAuthAuth {
|
|
|
206
215
|
isSubscription?: boolean;
|
|
207
216
|
/** Selector label for the OAuth login option, e.g. "Sign in with SuperGrok or X Premium". */
|
|
208
217
|
loginLabel?: string;
|
|
209
|
-
login(interaction: ProviderAuthInteraction): Promise<OAuthCredential>;
|
|
218
|
+
login(interaction: ProviderAuthInteraction, options?: LoginOptions): Promise<OAuthCredential>;
|
|
210
219
|
/**
|
|
211
220
|
* Exchange the refresh token. Network call; throws on failure
|
|
212
221
|
* (invalid_grant etc.). `Models` runs this under the store lock.
|
package/dist/auth/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProviderEnv, ProviderHeaders } from \"../types.ts\";\n\n/**\n * Request auth for a single model request. If a value cannot be expressed as\n * `apiKey`, `headers`, or `baseUrl`, it is provider config, not auth.\n */\nexport interface ModelAuth {\n\tapiKey?: string;\n\theaders?: ProviderHeaders;\n\tbaseUrl?: string;\n}\n\n/**\n * Stored api-key credential. `env` holds provider-scoped environment/config\n * values such as Cloudflare account/gateway ids.\n */\nexport interface ApiKeyCredential {\n\ttype: \"api_key\";\n\tkey?: string;\n\tenv?: ProviderEnv;\n}\n\n/** OAuth token data returned by extension compatibility flows. */\nexport interface OAuthCredentials {\n\trefresh: string;\n\taccess: string;\n\texpires: number;\n\t[key: string]: unknown;\n}\n\n/** Stored canonical OAuth credential. */\nexport interface OAuthCredential extends OAuthCredentials {\n\ttype: \"oauth\";\n}\n\n/** One type-tagged credential per provider — the shape of today's auth.json. */\nexport type Credential = ApiKeyCredential | OAuthCredential;\n\n/** Non-secret credential metadata for account/status enumeration. */\nexport interface CredentialInfo {\n\tproviderId: string;\n\ttype: Credential[\"type\"];\n}\n\n/** Optional cancellation for public auth and credential operations. */\nexport interface AuthOperationOptions {\n\tsignal?: AbortSignal;\n}\n\n/**\n * App-owned credential storage, keyed by `Provider.id`, one credential per\n * provider. `modify` is the only write path, so every mutation is a\n * serialized read-modify-write; `Models.getAuth()` runs OAuth refresh inside\n * `modify` so concurrent requests cannot double-refresh a rotated token. The\n * app persists a credential after login via\n * `modify(provider.id, async () => credential)`. Login/logout orchestration\n * is app-owned.\n *\n * Error semantics: `read` resolves `undefined` for missing entries. Methods\n * reject only on storage failure; `Models` wraps such rejections in\n * `ModelsError` with code \"auth\". Best-effort stores that serve an in-memory\n * view and record persistence errors internally (like coding-agent's\n * AuthStorage) are valid implementations.\n */\nexport interface CredentialStore {\n\t/**\n\t * Read the stored credential, possibly expired. Display/status use;\n\t * resolved request auth comes from `Models.getAuth()`.\n\t */\n\tread(providerId: string, options?: AuthOperationOptions): Promise<Credential | undefined>;\n\n\t/**\n\t * List stored credential metadata without resolving or exposing secrets.\n\t * Implementations must not execute configured API-key commands while listing.\n\t */\n\tlist(options?: AuthOperationOptions): Promise<readonly CredentialInfo[]>;\n\n\t/**\n\t * Serialized write — the only write path. `fn` sees the current credential\n\t * because correct writes (refresh, login-during-refresh) depend on it;\n\t * return the new credential, or undefined to leave the entry unchanged.\n\t * Mutual exclusion per provider id, cross-process too where the backing\n\t * store supports it (e.g. a file lock). Resolves with the post-write\n\t * credential. Rejections from `fn` propagate.\n\t */\n\tmodify(\n\t\tproviderId: string,\n\t\tfn: (current: Credential | undefined) => Promise<Credential | undefined>,\n\t\toptions?: AuthOperationOptions,\n\t): Promise<Credential | undefined>;\n\n\t/** Remove a credential (logout). Implementations serialize this against `modify`. */\n\tdelete(providerId: string, options?: AuthOperationOptions): Promise<void>;\n}\n\n/** Environment access for auth resolution. Injectable for tests and browsers. */\nexport interface AuthContext {\n\tenv(name: string): Promise<string | undefined>;\n\t/** Check whether a file exists. Supports a leading `~`. Always false in browsers. */\n\tfileExists(path: string): Promise<boolean>;\n}\n\n/** Result of resolving auth for a model. */\nexport interface AuthResult {\n\tauth: ModelAuth;\n\t/** Provider-scoped environment/config values resolved from credentials and ambient context. */\n\tenv?: ProviderEnv;\n\t/** Human-readable label for status UI: \"ANTHROPIC_API_KEY\", \"OAuth\", \"~/.aws/credentials\". */\n\tsource?: string;\n}\n\nexport interface AuthCheck {\n\tsource?: string;\n\ttype: \"api_key\" | \"oauth\";\n}\n\nexport type AuthType = \"api_key\" | \"oauth\";\n\n/**\n * Prompt shown to the user during login. `signal` lets the flow cancel a\n * pending prompt when an out-of-band event resolves the step, e.g. a\n * `manual_code` prompt raced against a callback server, aborted when the\n * callback wins.\n */\nexport type AuthPrompt = { signal?: AbortSignal } & (\n\t| { type: \"text\"; message: string; placeholder?: string }\n\t| { type: \"secret\"; message: string; placeholder?: string }\n\t| { type: \"select\"; message: string; options: readonly { id: string; label: string; description?: string }[] }\n\t| { type: \"manual_code\"; message: string; placeholder?: string }\n);\n\nexport interface AuthInfoLink {\n\turl: string;\n\tlabel?: string;\n}\n\nexport type AuthEvent =\n\t| { type: \"info\"; message: string; links?: readonly AuthInfoLink[] }\n\t| { type: \"auth_url\"; url: string; instructions?: string }\n\t| {\n\t\t\ttype: \"device_code\";\n\t\t\tuserCode: string;\n\t\t\tverificationUri: string;\n\t\t\tintervalSeconds?: number;\n\t\t\texpiresInSeconds?: number;\n\t }\n\t| { type: \"progress\"; message: string };\n\n/**\n * Login interaction callbacks serving both api-key and OAuth flows.\n *\n * `prompt()` returns the entered/selected string (`select` returns the option\n * id). Rejects on cancel/abort. `signal` aborts the whole login flow;\n * per-prompt cancellation uses `AuthPrompt.signal`.\n */\nexport interface AuthInteraction {\n\tsignal?: AbortSignal;\n\n\tprompt(prompt: AuthPrompt): Promise<string>;\n\tnotify(event: AuthEvent): void;\n}\n\n/** Normalized interaction passed to provider login implementations. */\nexport type ProviderAuthInteraction = AuthInteraction & { signal: AbortSignal };\n\n/**\n * Api-key auth: stored key/provider env plus ambient sources (env vars, AWS\n * profiles, ADC files). Ambient-only providers omit `login`.\n */\nexport interface ApiKeyAuth {\n\t/** Display name, e.g. \"Anthropic API key\". */\n\tname: string;\n\n\t/** Interactive setup (prompt for key/provider env). Absent = ambient-only. */\n\tlogin?(interaction: ProviderAuthInteraction): Promise<ApiKeyCredential>;\n\n\t/**\n\t * Optional side-effect-free availability check. Use this when `resolve()` may\n\t * execute commands or perform other request-time work. Missing means Models\n\t * checks availability by resolving auth.\n\t */\n\tcheck?(input: {\n\t\tctx: AuthContext;\n\t\tcredential?: ApiKeyCredential;\n\t\tsignal: AbortSignal;\n\t}): Promise<AuthCheck | undefined>;\n\n\t/**\n\t * Resolve auth from the stored credential and/or ambient sources, merging\n\t * per field (`credential.key ?? env(\"...\")`, `credential.env?.NAME ?? env(\"...\")`).\n\t * undefined = not configured. Resolution is provider-scoped; model-specific\n\t * endpoint preparation happens after auth has been resolved.\n\t */\n\tresolve(input: {\n\t\tctx: AuthContext;\n\t\tcredential?: ApiKeyCredential;\n\t\tsignal: AbortSignal;\n\t}): Promise<AuthResult | undefined>;\n}\n\n/**\n * OAuth auth. The `refresh`/`toAuth` split lets `Models` own the locked\n * refresh pattern: `refresh` produces a credential, `toAuth` derives request\n * auth from whatever credential ends up stored.\n */\nexport interface OAuthAuth {\n\t/** Display name, e.g. \"Anthropic (Claude Pro/Max)\". */\n\tname: string;\n\n\t/** Whether access through this auth method is backed by a provider subscription. */\n\tisSubscription?: boolean;\n\n\t/** Selector label for the OAuth login option, e.g. \"Sign in with SuperGrok or X Premium\". */\n\tloginLabel?: string;\n\n\tlogin(interaction: ProviderAuthInteraction): Promise<OAuthCredential>;\n\n\t/**\n\t * Exchange the refresh token. Network call; throws on failure\n\t * (invalid_grant etc.). `Models` runs this under the store lock.\n\t */\n\trefresh(credential: OAuthCredential, signal: AbortSignal): Promise<OAuthCredential>;\n\n\t/**\n\t * Side-effect-free derivation of request auth from a valid credential.\n\t * Covers per-credential baseUrl (GitHub Copilot). Async so lazy wrappers\n\t * can load the implementation on first use.\n\t */\n\ttoAuth(credential: OAuthCredential): Promise<ModelAuth>;\n}\n\n/**\n * Provider auth. At least one of `apiKey`/`oauth` must be present: even\n * ambient-credential providers and keyless local servers provide `apiKey`\n * auth whose `resolve()` reports whether the provider is configured.\n */\nexport interface ProviderAuth {\n\tapiKey?: ApiKeyAuth;\n\toauth?: OAuthAuth;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ProviderEnv, ProviderHeaders } from \"../types.ts\";\n\n/**\n * Request auth for a single model request. If a value cannot be expressed as\n * `apiKey`, `headers`, or `baseUrl`, it is provider config, not auth.\n */\nexport interface ModelAuth {\n\tapiKey?: string;\n\theaders?: ProviderHeaders;\n\tbaseUrl?: string;\n}\n\n/**\n * Stored api-key credential. `env` holds provider-scoped environment/config\n * values such as Cloudflare account/gateway ids.\n */\nexport interface ApiKeyCredential {\n\ttype: \"api_key\";\n\tkey?: string;\n\tenv?: ProviderEnv;\n}\n\n/** OAuth token data returned by extension compatibility flows. */\nexport interface OAuthCredentials {\n\trefresh: string;\n\taccess: string;\n\texpires: number;\n\t[key: string]: unknown;\n}\n\n/** Stored canonical OAuth credential. */\nexport interface OAuthCredential extends OAuthCredentials {\n\ttype: \"oauth\";\n}\n\n/** One type-tagged credential per provider — the shape of today's auth.json. */\nexport type Credential = ApiKeyCredential | OAuthCredential;\n\n/** Non-secret credential metadata for account/status enumeration. */\nexport interface CredentialInfo {\n\tproviderId: string;\n\ttype: Credential[\"type\"];\n}\n\n/** Optional cancellation for public auth and credential operations. */\nexport interface AuthOperationOptions {\n\tsignal?: AbortSignal;\n}\n\n/**\n * App-owned credential storage, keyed by `Provider.id`, one credential per\n * provider. `modify` is the only write path, so every mutation is a\n * serialized read-modify-write; `Models.getAuth()` runs OAuth refresh inside\n * `modify` so concurrent requests cannot double-refresh a rotated token. The\n * app persists a credential after login via\n * `modify(provider.id, async () => credential)`. Login/logout orchestration\n * is app-owned.\n *\n * Error semantics: `read` resolves `undefined` for missing entries. Methods\n * reject only on storage failure; `Models` wraps such rejections in\n * `ModelsError` with code \"auth\". Best-effort stores that serve an in-memory\n * view and record persistence errors internally (like coding-agent's\n * AuthStorage) are valid implementations.\n */\nexport interface CredentialStore {\n\t/**\n\t * Read the stored credential, possibly expired. Display/status use;\n\t * resolved request auth comes from `Models.getAuth()`.\n\t */\n\tread(providerId: string, options?: AuthOperationOptions): Promise<Credential | undefined>;\n\n\t/**\n\t * List stored credential metadata without resolving or exposing secrets.\n\t * Implementations must not execute configured API-key commands while listing.\n\t */\n\tlist(options?: AuthOperationOptions): Promise<readonly CredentialInfo[]>;\n\n\t/**\n\t * Serialized write — the only write path. `fn` sees the current credential\n\t * because correct writes (refresh, login-during-refresh) depend on it;\n\t * return the new credential, or undefined to leave the entry unchanged.\n\t * Mutual exclusion per provider id, cross-process too where the backing\n\t * store supports it (e.g. a file lock). Resolves with the post-write\n\t * credential. Rejections from `fn` propagate.\n\t */\n\tmodify(\n\t\tproviderId: string,\n\t\tfn: (current: Credential | undefined) => Promise<Credential | undefined>,\n\t\toptions?: AuthOperationOptions,\n\t): Promise<Credential | undefined>;\n\n\t/** Remove a credential (logout). Implementations serialize this against `modify`. */\n\tdelete(providerId: string, options?: AuthOperationOptions): Promise<void>;\n}\n\n/** Environment access for auth resolution. Injectable for tests and browsers. */\nexport interface AuthContext {\n\tenv(name: string): Promise<string | undefined>;\n\t/** Check whether a file exists. Supports a leading `~`. Always false in browsers. */\n\tfileExists(path: string): Promise<boolean>;\n}\n\n/** Result of resolving auth for a model. */\nexport interface AuthResult {\n\tauth: ModelAuth;\n\t/** Provider-scoped environment/config values resolved from credentials and ambient context. */\n\tenv?: ProviderEnv;\n\t/** Human-readable label for status UI: \"ANTHROPIC_API_KEY\", \"OAuth\", \"~/.aws/credentials\". */\n\tsource?: string;\n}\n\nexport interface AuthCheck {\n\tsource?: string;\n\ttype: \"api_key\" | \"oauth\";\n}\n\nexport type AuthType = \"api_key\" | \"oauth\";\n\n/**\n * Prompt shown to the user during login. `signal` lets the flow cancel a\n * pending prompt when an out-of-band event resolves the step, e.g. a\n * `manual_code` prompt raced against a callback server, aborted when the\n * callback wins.\n */\nexport type AuthPrompt = { signal?: AbortSignal } & (\n\t| { type: \"text\"; message: string; placeholder?: string }\n\t| { type: \"secret\"; message: string; placeholder?: string }\n\t| { type: \"select\"; message: string; options: readonly { id: string; label: string; description?: string }[] }\n\t| { type: \"manual_code\"; message: string; placeholder?: string }\n);\n\nexport interface AuthInfoLink {\n\turl: string;\n\tlabel?: string;\n}\n\nexport type AuthEvent =\n\t| { type: \"info\"; message: string; links?: readonly AuthInfoLink[] }\n\t| { type: \"auth_url\"; url: string; instructions?: string }\n\t| {\n\t\t\ttype: \"device_code\";\n\t\t\tuserCode: string;\n\t\t\tverificationUri: string;\n\t\t\tintervalSeconds?: number;\n\t\t\texpiresInSeconds?: number;\n\t }\n\t| { type: \"progress\"; message: string };\n\n/**\n * Login interaction callbacks serving both api-key and OAuth flows.\n *\n * `prompt()` returns the entered/selected string (`select` returns the option\n * id). Rejects on cancel/abort. `signal` aborts the whole login flow;\n * per-prompt cancellation uses `AuthPrompt.signal`.\n */\nexport interface AuthInteraction {\n\tsignal?: AbortSignal;\n\n\tprompt(prompt: AuthPrompt): Promise<string>;\n\tnotify(event: AuthEvent): void;\n}\n\n/** Normalized interaction passed to provider login implementations. */\nexport type ProviderAuthInteraction = AuthInteraction & { signal: AbortSignal };\n\n/**\n * Api-key auth: stored key/provider env plus ambient sources (env vars, AWS\n * profiles, ADC files). Ambient-only providers omit `login`.\n */\nexport interface ApiKeyAuth {\n\t/** Display name, e.g. \"Anthropic API key\". */\n\tname: string;\n\n\t/** Interactive setup (prompt for key/provider env). Absent = ambient-only. */\n\tlogin?(interaction: ProviderAuthInteraction): Promise<ApiKeyCredential>;\n\n\t/**\n\t * Optional side-effect-free availability check. Use this when `resolve()` may\n\t * execute commands or perform other request-time work. Missing means Models\n\t * checks availability by resolving auth.\n\t */\n\tcheck?(input: {\n\t\tctx: AuthContext;\n\t\tcredential?: ApiKeyCredential;\n\t\tsignal: AbortSignal;\n\t}): Promise<AuthCheck | undefined>;\n\n\t/**\n\t * Resolve auth from the stored credential and/or ambient sources, merging\n\t * per field (`credential.key ?? env(\"...\")`, `credential.env?.NAME ?? env(\"...\")`).\n\t * undefined = not configured. Resolution is provider-scoped; model-specific\n\t * endpoint preparation happens after auth has been resolved.\n\t */\n\tresolve(input: {\n\t\tctx: AuthContext;\n\t\tcredential?: ApiKeyCredential;\n\t\tsignal: AbortSignal;\n\t}): Promise<AuthResult | undefined>;\n}\n\n/**\n * OAuth auth. The `refresh`/`toAuth` split lets `Models` own the locked\n * refresh pattern: `refresh` produces a credential, `toAuth` derives request\n * auth from whatever credential ends up stored.\n */\nexport interface OAuthAuth {\n\t/** Display name, e.g. \"Anthropic (Claude Pro/Max)\". */\n\tname: string;\n\n\t/** Whether access through this auth method is backed by a provider subscription. */\n\tisSubscription?: boolean;\n\n\t/** Selector label for the OAuth login option, e.g. \"Sign in with SuperGrok or X Premium\". */\n\tloginLabel?: string;\n\n\tlogin(interaction: ProviderAuthInteraction): Promise<OAuthCredential>;\n\n\t/**\n\t * Exchange the refresh token. Network call; throws on failure\n\t * (invalid_grant etc.). `Models` runs this under the store lock.\n\t */\n\trefresh(credential: OAuthCredential, signal: AbortSignal): Promise<OAuthCredential>;\n\n\t/**\n\t * Side-effect-free derivation of request auth from a valid credential.\n\t * Covers per-credential baseUrl (GitHub Copilot). Async so lazy wrappers\n\t * can load the implementation on first use.\n\t */\n\ttoAuth(credential: OAuthCredential): Promise<ModelAuth>;\n}\n\n/**\n * Provider auth. At least one of `apiKey`/`oauth` must be present: even\n * ambient-credential providers and keyless local servers provide `apiKey`\n * auth whose `resolve()` reports whether the provider is configured.\n */\nexport interface ProviderAuth {\n\tapiKey?: ApiKeyAuth;\n\toauth?: OAuthAuth;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/auth/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ProviderEnv, ProviderHeaders } from \"../types.ts\";\n\n/**\n * Request auth for a single model request. If a value cannot be expressed as\n * `apiKey`, `headers`, or `baseUrl`, it is provider config, not auth.\n */\nexport interface ModelAuth {\n\tapiKey?: string;\n\theaders?: ProviderHeaders;\n\tbaseUrl?: string;\n}\n\n/**\n * Stored api-key credential. `env` holds provider-scoped environment/config\n * values such as Cloudflare account/gateway ids.\n */\nexport interface ApiKeyCredential {\n\ttype: \"api_key\";\n\tkey?: string;\n\tenv?: ProviderEnv;\n}\n\n/** OAuth token data returned by extension compatibility flows. */\nexport interface OAuthCredentials {\n\trefresh: string;\n\taccess: string;\n\texpires: number;\n\t[key: string]: unknown;\n}\n\n/** Stored canonical OAuth credential. */\nexport interface OAuthCredential extends OAuthCredentials {\n\ttype: \"oauth\";\n}\n\n/** One type-tagged credential per provider — the shape of today's auth.json. */\nexport type Credential = ApiKeyCredential | OAuthCredential;\n\n/** Non-secret credential metadata for account/status enumeration. */\nexport interface CredentialInfo {\n\tproviderId: string;\n\ttype: Credential[\"type\"];\n}\n\n/** Optional cancellation for public auth and credential operations. */\nexport interface AuthOperationOptions {\n\tsignal?: AbortSignal;\n}\n\n/**\n * App-owned credential storage, keyed by `Provider.id`, one credential per\n * provider. `modify` is the only write path, so every mutation is a\n * serialized read-modify-write; `Models.getAuth()` runs OAuth refresh inside\n * `modify` so concurrent requests cannot double-refresh a rotated token. The\n * app persists a credential after login via\n * `modify(provider.id, async () => credential)`. Login/logout orchestration\n * is app-owned.\n *\n * Error semantics: `read` resolves `undefined` for missing entries. Methods\n * reject only on storage failure; `Models` wraps such rejections in\n * `ModelsError` with code \"auth\". Best-effort stores that serve an in-memory\n * view and record persistence errors internally (like coding-agent's\n * AuthStorage) are valid implementations.\n */\nexport interface CredentialStore {\n\t/**\n\t * Read the stored credential, possibly expired. Display/status use;\n\t * resolved request auth comes from `Models.getAuth()`.\n\t */\n\tread(providerId: string, options?: AuthOperationOptions): Promise<Credential | undefined>;\n\n\t/**\n\t * List stored credential metadata without resolving or exposing secrets.\n\t * Implementations must not execute configured API-key commands while listing.\n\t */\n\tlist(options?: AuthOperationOptions): Promise<readonly CredentialInfo[]>;\n\n\t/**\n\t * Serialized write — the only write path. `fn` sees the current credential\n\t * because correct writes (refresh, login-during-refresh) depend on it;\n\t * return the new credential, or undefined to leave the entry unchanged.\n\t * Mutual exclusion per provider id, cross-process too where the backing\n\t * store supports it (e.g. a file lock). Resolves with the post-write\n\t * credential. Rejections from `fn` propagate.\n\t */\n\tmodify(\n\t\tproviderId: string,\n\t\tfn: (current: Credential | undefined) => Promise<Credential | undefined>,\n\t\toptions?: AuthOperationOptions,\n\t): Promise<Credential | undefined>;\n\n\t/** Remove a credential (logout). Implementations serialize this against `modify`. */\n\tdelete(providerId: string, options?: AuthOperationOptions): Promise<void>;\n}\n\n/** Environment access for auth resolution. Injectable for tests and browsers. */\nexport interface AuthContext {\n\tenv(name: string): Promise<string | undefined>;\n\t/** Check whether a file exists. Supports a leading `~`. Always false in browsers. */\n\tfileExists(path: string): Promise<boolean>;\n}\n\n/** Result of resolving auth for a model. */\nexport interface AuthResult {\n\tauth: ModelAuth;\n\t/** Provider-scoped environment/config values resolved from credentials and ambient context. */\n\tenv?: ProviderEnv;\n\t/** Human-readable label for status UI: \"ANTHROPIC_API_KEY\", \"OAuth\", \"~/.aws/credentials\". */\n\tsource?: string;\n}\n\nexport interface AuthCheck {\n\tsource?: string;\n\ttype: \"api_key\" | \"oauth\";\n}\n\nexport type AuthType = \"api_key\" | \"oauth\";\n\n/**\n * Prompt shown to the user during login. `signal` lets the flow cancel a\n * pending prompt when an out-of-band event resolves the step, e.g. a\n * `manual_code` prompt raced against a callback server, aborted when the\n * callback wins.\n */\nexport type AuthPrompt = { signal?: AbortSignal } & (\n\t| { type: \"text\"; message: string; placeholder?: string }\n\t| { type: \"secret\"; message: string; placeholder?: string }\n\t| { type: \"select\"; message: string; options: readonly { id: string; label: string; description?: string }[] }\n\t| { type: \"manual_code\"; message: string; placeholder?: string }\n);\n\nexport interface AuthInfoLink {\n\turl: string;\n\tlabel?: string;\n}\n\nexport type AuthEvent =\n\t| { type: \"info\"; message: string; links?: readonly AuthInfoLink[] }\n\t| { type: \"auth_url\"; url: string; instructions?: string }\n\t| {\n\t\t\ttype: \"device_code\";\n\t\t\tuserCode: string;\n\t\t\tverificationUri: string;\n\t\t\tintervalSeconds?: number;\n\t\t\texpiresInSeconds?: number;\n\t }\n\t| { type: \"progress\"; message: string };\n\n/**\n * Login interaction callbacks serving both api-key and OAuth flows.\n *\n * `prompt()` returns the entered/selected string (`select` returns the option\n * id). Rejects on cancel/abort. `signal` aborts the whole login flow;\n * per-prompt cancellation uses `AuthPrompt.signal`.\n */\nexport interface AuthInteraction {\n\tsignal?: AbortSignal;\n\n\tprompt(prompt: AuthPrompt): Promise<string>;\n\tnotify(event: AuthEvent): void;\n}\n\n/** Normalized interaction passed to provider login implementations. */\nexport type ProviderAuthInteraction = AuthInteraction & { signal: AbortSignal };\n\n/**\n * Api-key auth: stored key/provider env plus ambient sources (env vars, AWS\n * profiles, ADC files). Ambient-only providers omit `login`.\n */\nexport interface ApiKeyAuth {\n\t/** Display name, e.g. \"Anthropic API key\". */\n\tname: string;\n\n\t/** Interactive setup (prompt for key/provider env). Absent = ambient-only. */\n\tlogin?(interaction: ProviderAuthInteraction): Promise<ApiKeyCredential>;\n\n\t/**\n\t * Optional side-effect-free availability check. Use this when `resolve()` may\n\t * execute commands or perform other request-time work. Missing means Models\n\t * checks availability by resolving auth.\n\t */\n\tcheck?(input: {\n\t\tctx: AuthContext;\n\t\tcredential?: ApiKeyCredential;\n\t\tsignal: AbortSignal;\n\t}): Promise<AuthCheck | undefined>;\n\n\t/**\n\t * Resolve auth from the stored credential and/or ambient sources, merging\n\t * per field (`credential.key ?? env(\"...\")`, `credential.env?.NAME ?? env(\"...\")`).\n\t * undefined = not configured. Resolution is provider-scoped; model-specific\n\t * endpoint preparation happens after auth has been resolved.\n\t */\n\tresolve(input: {\n\t\tctx: AuthContext;\n\t\tcredential?: ApiKeyCredential;\n\t\tsignal: AbortSignal;\n\t}): Promise<AuthResult | undefined>;\n}\n\n/** App-supplied context for `Models.login`. */\nexport interface LoginOptions {\n\t/**\n\t * Returns the stable ID of this app installation, e.g. sent to OpenAI as its\n\t * agent host ID. Called only by login flows that need it, so apps can create\n\t * the ID on first use and must return the same ID on every later call.\n\t */\n\tgetDeviceId?: () => string;\n}\n\n/**\n * OAuth auth. The `refresh`/`toAuth` split lets `Models` own the locked\n * refresh pattern: `refresh` produces a credential, `toAuth` derives request\n * auth from whatever credential ends up stored.\n */\nexport interface OAuthAuth {\n\t/** Display name, e.g. \"Anthropic (Claude Pro/Max)\". */\n\tname: string;\n\n\t/** Whether access through this auth method is backed by a provider subscription. */\n\tisSubscription?: boolean;\n\n\t/** Selector label for the OAuth login option, e.g. \"Sign in with SuperGrok or X Premium\". */\n\tloginLabel?: string;\n\n\tlogin(interaction: ProviderAuthInteraction, options?: LoginOptions): Promise<OAuthCredential>;\n\n\t/**\n\t * Exchange the refresh token. Network call; throws on failure\n\t * (invalid_grant etc.). `Models` runs this under the store lock.\n\t */\n\trefresh(credential: OAuthCredential, signal: AbortSignal): Promise<OAuthCredential>;\n\n\t/**\n\t * Side-effect-free derivation of request auth from a valid credential.\n\t * Covers per-credential baseUrl (GitHub Copilot). Async so lazy wrappers\n\t * can load the implementation on first use.\n\t */\n\ttoAuth(credential: OAuthCredential): Promise<ModelAuth>;\n}\n\n/**\n * Provider auth. At least one of `apiKey`/`oauth` must be present: even\n * ambient-credential providers and keyless local servers provide `apiKey`\n * auth whose `resolve()` reports whether the provider is configured.\n */\nexport interface ProviderAuth {\n\tapiKey?: ApiKeyAuth;\n\toauth?: OAuthAuth;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bedrock-provider.d.ts","sourceRoot":"","sources":["../src/bedrock-provider.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,qBAAqB;;;CAGjC,CAAC"
|
|
1
|
+
{"version":3,"file":"bedrock-provider.d.ts","sourceRoot":"","sources":["../src/bedrock-provider.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,qBAAqB;;;CAGjC,CAAC"}
|