@code-yeongyu/senpi 2026.9.21-2 → 2026.9.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/bundle/chunks/{anthropic-messages-C3ZY2ANT.js → anthropic-messages-2P7APOOQ.js} +1 -1
- package/dist/bundle/chunks/{app-server-command-HSX5RFAP.js → app-server-command-DLBXJ5K5.js} +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-7TAGS2VU.js → azure-openai-responses-3AH7MJWF.js} +1 -1
- package/dist/bundle/chunks/{chunk-3SLCHXZO.js → chunk-4AXZDO3E.js} +2 -2
- package/dist/bundle/chunks/{chunk-Z3KQB2R3.js → chunk-7ICH7UFW.js} +12 -12
- package/dist/bundle/chunks/{chunk-KNM6SRPE.js → chunk-AAVNXTGQ.js} +1 -1
- package/dist/bundle/chunks/{chunk-IDTLJYJ5.js → chunk-AY37SZJZ.js} +4 -4
- package/dist/bundle/chunks/{chunk-XHMOFY4T.js → chunk-BUPX33Q4.js} +3 -3
- package/dist/bundle/chunks/{chunk-GLKVDRNP.js → chunk-CWCY7LXK.js} +1 -1
- package/dist/bundle/chunks/{chunk-POMPEGWQ.js → chunk-F3DXL5MX.js} +1 -1
- package/dist/bundle/chunks/{chunk-GVI2HP7N.js → chunk-I2HIIJPI.js} +1 -1
- package/dist/bundle/chunks/{chunk-T6XA2IZR.js → chunk-JR4X6ECO.js} +1 -1
- package/dist/bundle/chunks/{chunk-M2XAY6I7.js → chunk-M2HSO7MH.js} +1 -1
- package/dist/bundle/chunks/{chunk-MIVOQT3Q.js → chunk-N5AQJAQ2.js} +1 -1
- package/dist/bundle/chunks/{chunk-UYVPLEOL.js → chunk-NK2RNX25.js} +1 -1
- package/dist/bundle/chunks/chunk-NMB4C6ZZ.js +2 -0
- package/dist/bundle/chunks/{chunk-B7W62BM7.js → chunk-P4OHEJ7P.js} +1 -1
- package/dist/bundle/chunks/{chunk-I425CMTO.js → chunk-VBNHBSBD.js} +1 -1
- package/dist/bundle/chunks/{chunk-B2IM56LB.js → chunk-VYIJQQ5I.js} +1 -1
- package/dist/bundle/chunks/chunk-XRHUMMIW.js +8 -0
- package/dist/bundle/chunks/{chunk-47GF6XYZ.js → chunk-YT2ZSZOY.js} +1 -1
- package/dist/bundle/chunks/{chunk-OSDJ2SYO.js → chunk-ZCBX2K34.js} +1 -1
- package/dist/bundle/chunks/{chunk-D5CL7PPD.js → chunk-ZMVXBX33.js} +2 -2
- package/dist/bundle/chunks/{cli-main-GQTEEZ2V.js → cli-main-D2VPNIQ3.js} +1 -1
- package/dist/bundle/chunks/{google-generative-ai-JWIH75VF.js → google-generative-ai-Y2IYMUVC.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-IRGAY5XR.js → google-vertex-TKBBMPHV.js} +1 -1
- package/dist/bundle/chunks/{host-command-KOEKIHIZ.js → host-command-IFIIOX5S.js} +1 -1
- package/dist/bundle/chunks/host-lifecycle-3OJZA4QQ.js +3 -0
- package/dist/bundle/chunks/host-lifecycle.js +3 -3
- package/dist/bundle/chunks/{interactive-host-runtime-2KTFEW7O.js → interactive-host-runtime-V7PBDIOJ.js} +1 -1
- package/dist/bundle/chunks/{interactive-mode-I3ILWXQB.js → interactive-mode-RFMMGQCT.js} +1 -1
- package/dist/bundle/chunks/kimi-coding.js +2 -2
- package/dist/bundle/chunks/{mistral-conversations-VOBYATVJ.js → mistral-conversations-ZYDVFRYF.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-S5FWCIWE.js → multi-session-host-45YMCQIH.js} +8 -7
- package/dist/bundle/chunks/openai-codex-responses-MEIUNROM.js +10 -0
- package/dist/bundle/chunks/{openai-completions-YK6QTYOH.js → openai-completions-4V76L5ZJ.js} +1 -1
- package/dist/bundle/chunks/openai-responses-YR7WRBG3.js +2 -0
- package/dist/bundle/chunks/{package-manager-cli-HOL6CAI6.js → package-manager-cli-7DQKRSI5.js} +1 -1
- package/dist/bundle/chunks/rotation-stream-YPZP3VJS.js +2 -0
- package/dist/bundle/chunks/{rpc-mode-L3DSGTVM.js → rpc-mode-4GWZCJKI.js} +1 -1
- package/dist/bundle/chunks/{session-picker-L3FYEQBL.js → session-picker-ZKRYWZGC.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +38 -37
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/agent-session.d.ts +6 -4
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +9 -7
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/credential-pool/classify.d.ts.map +1 -1
- package/dist/core/credential-pool/classify.js +12 -0
- package/dist/core/credential-pool/classify.js.map +1 -1
- package/dist/core/credential-pool/failover.d.ts +37 -5
- package/dist/core/credential-pool/failover.d.ts.map +1 -1
- package/dist/core/credential-pool/failover.js +60 -24
- package/dist/core/credential-pool/failover.js.map +1 -1
- package/dist/core/credential-pool/rotation-events.d.ts +5 -0
- package/dist/core/credential-pool/rotation-events.d.ts.map +1 -0
- package/dist/core/credential-pool/rotation-events.js +25 -0
- package/dist/core/credential-pool/rotation-events.js.map +1 -0
- package/dist/core/credential-pool/rotation-stream.d.ts +4 -3
- package/dist/core/credential-pool/rotation-stream.d.ts.map +1 -1
- package/dist/core/credential-pool/rotation-stream.js +8 -11
- package/dist/core/credential-pool/rotation-stream.js.map +1 -1
- package/dist/core/extensions/builtin/ask-user/schema.d.ts +2 -25
- package/dist/core/extensions/builtin/ask-user/schema.d.ts.map +1 -1
- package/dist/core/extensions/builtin/ask-user/schema.js.map +1 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts +2 -7
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts.map +1 -1
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.js +2 -8
- package/dist/core/extensions/builtin/compaction/deterministic-fallback.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/naming.d.ts +0 -1
- package/dist/core/extensions/builtin/mcp/expose/naming.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/naming.js +0 -3
- package/dist/core/extensions/builtin/mcp/expose/naming.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/register.d.ts +1 -2
- package/dist/core/extensions/builtin/mcp/expose/register.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/register.js +0 -21
- package/dist/core/extensions/builtin/mcp/expose/register.js.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/schema-compat.d.ts +2 -2
- package/dist/core/extensions/builtin/mcp/expose/schema-compat.d.ts.map +1 -1
- package/dist/core/extensions/builtin/mcp/expose/schema-compat.js +2 -2
- package/dist/core/extensions/builtin/mcp/expose/schema-compat.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts +29 -0
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +30 -3
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/modes/interactive/components/assistant-render-descriptors.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-render-descriptors.js +8 -7
- package/dist/modes/interactive/components/assistant-render-descriptors.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +7 -5
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/handoff-activity.d.ts +4 -0
- package/dist/modes/rpc/handoff-activity.d.ts.map +1 -0
- package/dist/modes/rpc/handoff-activity.js +6 -0
- package/dist/modes/rpc/handoff-activity.js.map +1 -0
- package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
- package/dist/modes/rpc/host-ensure.js +60 -17
- package/dist/modes/rpc/host-ensure.js.map +1 -1
- package/dist/modes/rpc/host-lifecycle.d.ts +3 -0
- package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
- package/dist/modes/rpc/host-lifecycle.js +25 -5
- package/dist/modes/rpc/host-lifecycle.js.map +1 -1
- package/dist/modes/rpc/multi-session-host.d.ts +1 -0
- package/dist/modes/rpc/multi-session-host.d.ts.map +1 -1
- package/dist/modes/rpc/multi-session-host.js +40 -7
- package/dist/modes/rpc/multi-session-host.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +13 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/modes/rpc/session-command-router.d.ts +10 -4
- package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
- package/dist/modes/rpc/session-command-router.js +90 -18
- package/dist/modes/rpc/session-command-router.js.map +1 -1
- package/dist/modes/rpc/session-event-writer.d.ts +5 -3
- package/dist/modes/rpc/session-event-writer.d.ts.map +1 -1
- package/dist/modes/rpc/session-event-writer.js +21 -2
- package/dist/modes/rpc/session-event-writer.js.map +1 -1
- package/dist/modes/rpc/session-worker-client.d.ts +1 -0
- package/dist/modes/rpc/session-worker-client.d.ts.map +1 -1
- package/dist/modes/rpc/session-worker-client.js +3 -0
- package/dist/modes/rpc/session-worker-client.js.map +1 -1
- package/dist/modes/rpc/session-worker-protocol.d.ts +3 -1
- package/dist/modes/rpc/session-worker-protocol.d.ts.map +1 -1
- package/dist/modes/rpc/session-worker-protocol.js.map +1 -1
- package/dist/modes/rpc/session-worker.js +7 -1
- package/dist/modes/rpc/session-worker.js.map +1 -1
- package/docs/providers.md +9 -1
- package/docs/rpc.md +58 -8
- package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +15 -0
- package/node_modules/@code-yeongyu/senpi-codemode/README.md +51 -13
- package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/agent-bridge.ts +53 -9
- package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/reserved-dispatch.ts +1 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/config/settings.ts +18 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/extension/eval-status.ts +9 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +3 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/AGENTS.md +2 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/prelude.jl +10 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/context-manager.ts +18 -6
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-contract.ts +2 -6
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/prelude.ts +1 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/run-queue.ts +17 -7
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-runtime.js +6 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/kernel-contract.ts +2 -5
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/kernel.ts +37 -5
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py +11 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/prelude.rb +6 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-contract.ts +2 -5
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-kernel.ts +14 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-queue.ts +18 -5
- package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt-template.ts +3 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +4 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/timeouts/idle-timeout.ts +9 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/AGENTS.md +2 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-execution.ts +19 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-runtime.ts +11 -3
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-contract.ts +6 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-manager.ts +72 -20
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-snapshot.ts +28 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-state.ts +5 -4
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-status.ts +5 -2
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-eval-result.ts +76 -25
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-execution-event.ts +4 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-kernel-reset-refused-error.ts +12 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-request.ts +2 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool-options.ts +3 -1
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool.ts +58 -37
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/managed-cell.ts +15 -8
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +20 -6
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/run-eval-cell.ts +89 -25
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/terminal-snapshot-store.ts +4 -0
- package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +51 -10
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/README.md +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +14 -56
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +18 -27
- package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/api/websocket-transport-failure.d.ts +40 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/websocket-transport-failure.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/websocket-transport-failure.js +102 -0
- package/node_modules/@earendil-works/pi-ai/dist/api/websocket-transport-failure.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.d.ts +4 -3
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js +28 -14
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-region.d.ts +44 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-region.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-region.js +120 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-region.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.d.ts +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.js +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.d.ts +3 -0
- package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.js +21 -15
- package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-workers-ai.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/huggingface.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding-auth.d.ts +9 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding-auth.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding-auth.js +43 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding-auth.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.js +3 -2
- package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/provider-failure-description.d.ts +19 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/provider-failure-description.d.ts.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/provider-failure-description.js +63 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/provider-failure-description.js.map +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-pty/package.json +1 -1
- package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
- package/dist/bundle/chunks/chunk-5J5R5AMP.js +0 -8
- package/dist/bundle/chunks/chunk-I3F6VZZF.js +0 -2
- package/dist/bundle/chunks/host-lifecycle-DGZJTBDJ.js +0 -3
- package/dist/bundle/chunks/openai-codex-responses-L2PO2D6F.js +0 -10
- package/dist/bundle/chunks/openai-responses-YDUBVF4S.js +0 -2
- package/dist/bundle/chunks/rotation-stream-Y4YU6HV4.js +0 -2
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Kimi Code (subscription) OAuth flow
|
|
3
3
|
*
|
|
4
|
-
* RFC 8628 device authorization grant against
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* RFC 8628 device authorization grant against the region's auth host
|
|
5
|
+
* (https://auth.kimi.com or https://auth.kimi.ai) with JSON responses. The
|
|
6
|
+
* access token authenticates requests to that region's coding API as an
|
|
7
|
+
* `Authorization: Bearer` header; see kimi-region.ts for the host table.
|
|
7
8
|
*/
|
|
8
|
-
import { getProviderEnvValue } from "../../utils/provider-env.js";
|
|
9
9
|
import { sleep } from "../../utils/sleep.js";
|
|
10
10
|
import { pollOAuthDeviceCodeFlow } from "./device-code.js";
|
|
11
11
|
import { kimiCodeIdentityHeaders } from "./kimi-identity.js";
|
|
12
|
+
import { chooseKimiCodeLoginEndpoints, kimiCodeCredentialEnv, kimiCodeEndpointsForCredential } from "./kimi-region.js";
|
|
12
13
|
const CLIENT_ID = "17e5f671-d194-4dfb-9706-5516cb48c098";
|
|
13
|
-
const DEFAULT_OAUTH_HOST = "https://auth.kimi.com";
|
|
14
14
|
const DEVICE_CODE_TIMEOUT_SECONDS = 15 * 60;
|
|
15
15
|
const DEFAULT_POLL_INTERVAL_SECONDS = 5;
|
|
16
16
|
const REQUEST_TIMEOUT_MS = 30 * 1000;
|
|
17
17
|
const REFRESH_MAX_RETRIES = 3;
|
|
18
|
-
function getOauthHost() {
|
|
19
|
-
const override = getProviderEnvValue("KIMI_CODE_OAUTH_HOST") || getProviderEnvValue("KIMI_OAUTH_HOST");
|
|
20
|
-
return (override || DEFAULT_OAUTH_HOST).replace(/\/+$/, "");
|
|
21
|
-
}
|
|
22
18
|
function requestSignal(signal) {
|
|
23
19
|
return AbortSignal.any([AbortSignal.timeout(REQUEST_TIMEOUT_MS), signal]);
|
|
24
20
|
}
|
|
@@ -224,7 +220,8 @@ async function refreshToken(oauthHost, refreshTokenValue, signal) {
|
|
|
224
220
|
throw lastError ?? new Error("Kimi Code token refresh failed");
|
|
225
221
|
}
|
|
226
222
|
async function loginKimiCoding(interaction) {
|
|
227
|
-
const
|
|
223
|
+
const endpoints = await chooseKimiCodeLoginEndpoints(interaction);
|
|
224
|
+
const oauthHost = endpoints.oauthHost;
|
|
228
225
|
const device = await startDeviceAuthorization(oauthHost, interaction.signal);
|
|
229
226
|
interaction.notify({
|
|
230
227
|
type: "device_code",
|
|
@@ -234,7 +231,13 @@ async function loginKimiCoding(interaction) {
|
|
|
234
231
|
expiresInSeconds: device.expiresInSeconds,
|
|
235
232
|
});
|
|
236
233
|
const token = await pollForToken(oauthHost, device, interaction.signal);
|
|
237
|
-
return {
|
|
234
|
+
return {
|
|
235
|
+
type: "oauth",
|
|
236
|
+
access: token.access,
|
|
237
|
+
refresh: token.refresh,
|
|
238
|
+
expires: token.expires,
|
|
239
|
+
...(endpoints.env ? { env: endpoints.env } : {}),
|
|
240
|
+
};
|
|
238
241
|
}
|
|
239
242
|
export const kimiCodingOAuth = {
|
|
240
243
|
name: "Kimi Code (subscription)",
|
|
@@ -242,11 +245,22 @@ export const kimiCodingOAuth = {
|
|
|
242
245
|
loginLabel: "Sign in with Kimi Code",
|
|
243
246
|
login: loginKimiCoding,
|
|
244
247
|
refresh: async (credential, signal) => {
|
|
245
|
-
const
|
|
246
|
-
|
|
248
|
+
const env = kimiCodeCredentialEnv(credential);
|
|
249
|
+
const token = await refreshToken(kimiCodeEndpointsForCredential(credential).oauthHost, credential.refresh, signal);
|
|
250
|
+
return {
|
|
251
|
+
type: "oauth",
|
|
252
|
+
access: token.access,
|
|
253
|
+
refresh: token.refresh,
|
|
254
|
+
expires: token.expires,
|
|
255
|
+
...(env ? { env } : {}),
|
|
256
|
+
};
|
|
247
257
|
},
|
|
248
258
|
async toAuth(credential) {
|
|
249
|
-
|
|
259
|
+
const { apiBaseUrl } = kimiCodeEndpointsForCredential(credential);
|
|
260
|
+
return {
|
|
261
|
+
headers: { ...kimiCodeIdentityHeaders(), Authorization: `Bearer ${credential.access}` },
|
|
262
|
+
...(apiBaseUrl ? { baseUrl: apiBaseUrl } : {}),
|
|
263
|
+
};
|
|
250
264
|
},
|
|
251
265
|
};
|
|
252
266
|
//# sourceMappingURL=kimi-coding.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kimi-coding.js","sourceRoot":"","sources":["../../../src/auth/oauth/kimi-coding.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Kimi Code (subscription) OAuth flow\n *\n * RFC 8628 device authorization grant against https://auth.kimi.com with JSON\n * responses. The access token authenticates requests to\n * https://api.kimi.com/coding as an `Authorization: Bearer` header.\n */\n\nimport { getProviderEnvValue } from \"../../utils/provider-env.ts\";\nimport { sleep } from \"../../utils/sleep.ts\";\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\nimport { kimiCodeIdentityHeaders } from \"./kimi-identity.ts\";\n\nconst CLIENT_ID = \"17e5f671-d194-4dfb-9706-5516cb48c098\";\nconst DEFAULT_OAUTH_HOST = \"https://auth.kimi.com\";\nconst DEVICE_CODE_TIMEOUT_SECONDS = 15 * 60;\nconst DEFAULT_POLL_INTERVAL_SECONDS = 5;\nconst REQUEST_TIMEOUT_MS = 30 * 1000;\nconst REFRESH_MAX_RETRIES = 3;\n\ntype DeviceAuthorization = {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUri: string;\n\tverificationUriComplete: string;\n\tintervalSeconds: number;\n\texpiresInSeconds: number;\n};\n\ntype TokenResponse = {\n\taccess: string;\n\trefresh: string;\n\texpires: number;\n};\n\nfunction getOauthHost(): string {\n\tconst override = getProviderEnvValue(\"KIMI_CODE_OAUTH_HOST\") || getProviderEnvValue(\"KIMI_OAUTH_HOST\");\n\treturn (override || DEFAULT_OAUTH_HOST).replace(/\\/+$/, \"\");\n}\n\nfunction requestSignal(signal: AbortSignal): AbortSignal {\n\treturn AbortSignal.any([AbortSignal.timeout(REQUEST_TIMEOUT_MS), signal]);\n}\n\nfunction formUrlEncode(fields: Record<string, string>): string {\n\treturn new URLSearchParams(fields).toString();\n}\n\nasync function readJson(response: Response): Promise<Record<string, unknown> | null> {\n\ttry {\n\t\tconst json = await response.json();\n\t\treturn json && typeof json === \"object\" ? (json as Record<string, unknown>) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** The verification URI is opened in the user's browser; only http(s) URLs are trusted. */\nfunction trustedHttpUrl(value: unknown): string | null {\n\tif (typeof value !== \"string\" || !value) return null;\n\ttry {\n\t\tconst url = new URL(value);\n\t\tif (url.protocol !== \"https:\" && url.protocol !== \"http:\") return null;\n\t\treturn url.href;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function startDeviceAuthorization(oauthHost: string, signal: AbortSignal): Promise<DeviceAuthorization> {\n\tconst response = await fetch(`${oauthHost}/api/oauth/device_authorization`, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t...kimiCodeIdentityHeaders(),\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: formUrlEncode({ client_id: CLIENT_ID }),\n\t\tsignal: requestSignal(signal),\n\t});\n\n\tif (!response.ok) {\n\t\tconst text = await response.text().catch(() => \"\");\n\t\tthrow new Error(`Kimi Code device authorization failed with status ${response.status}${text ? `: ${text}` : \"\"}`);\n\t}\n\n\tconst json = await readJson(response);\n\tconst deviceCode = json?.device_code;\n\tconst userCode = json?.user_code;\n\tconst verificationUri = json?.verification_uri;\n\tconst verificationUriComplete = json?.verification_uri_complete;\n\tif (\n\t\ttypeof deviceCode !== \"string\" ||\n\t\ttypeof userCode !== \"string\" ||\n\t\ttypeof verificationUri !== \"string\" ||\n\t\ttypeof verificationUriComplete !== \"string\" ||\n\t\t!trustedHttpUrl(verificationUriComplete) ||\n\t\t!trustedHttpUrl(verificationUri)\n\t) {\n\t\tthrow new Error(`Invalid Kimi Code device authorization response: ${JSON.stringify(json)}`);\n\t}\n\n\tconst interval = json?.interval;\n\tconst expiresIn = json?.expires_in;\n\treturn {\n\t\tdeviceCode,\n\t\tuserCode,\n\t\tverificationUri,\n\t\tverificationUriComplete,\n\t\tintervalSeconds:\n\t\t\ttypeof interval === \"number\" && Number.isFinite(interval) && interval > 0\n\t\t\t\t? interval\n\t\t\t\t: DEFAULT_POLL_INTERVAL_SECONDS,\n\t\texpiresInSeconds:\n\t\t\ttypeof expiresIn === \"number\" && Number.isFinite(expiresIn) && expiresIn > 0\n\t\t\t\t? expiresIn\n\t\t\t\t: DEVICE_CODE_TIMEOUT_SECONDS,\n\t};\n}\n\nfunction parseTokenResponse(json: Record<string, unknown> | null, operation: string): TokenResponse {\n\tconst accessToken = json?.access_token;\n\tconst refreshToken = json?.refresh_token;\n\tconst expiresIn = json?.expires_in;\n\tif (\n\t\ttypeof accessToken !== \"string\" ||\n\t\t!accessToken ||\n\t\ttypeof refreshToken !== \"string\" ||\n\t\t!refreshToken ||\n\t\ttypeof expiresIn !== \"number\" ||\n\t\t!Number.isFinite(expiresIn) ||\n\t\texpiresIn <= 0\n\t) {\n\t\tthrow new Error(`Kimi Code token ${operation} response missing fields: ${JSON.stringify(json)}`);\n\t}\n\treturn {\n\t\taccess: accessToken,\n\t\trefresh: refreshToken,\n\t\texpires: Date.now() + expiresIn * 1000,\n\t};\n}\n\nasync function pollForToken(\n\toauthHost: string,\n\tdevice: DeviceAuthorization,\n\tsignal: AbortSignal,\n): Promise<TokenResponse> {\n\treturn pollOAuthDeviceCodeFlow<TokenResponse>({\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 fetch(`${oauthHost}/api/oauth/token`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t...kimiCodeIdentityHeaders(),\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: formUrlEncode({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tdevice_code: device.deviceCode,\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t}),\n\t\t\t\tsignal: requestSignal(signal),\n\t\t\t});\n\n\t\t\tif (response.status >= 500) {\n\t\t\t\tconst text = await response.text().catch(() => \"\");\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\tmessage: `Kimi Code device token request failed with status ${response.status}${text ? `: ${text}` : \"\"}`,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst json = await readJson(response);\n\t\t\tif (response.ok && typeof json?.access_token === \"string\") {\n\t\t\t\ttry {\n\t\t\t\t\treturn { status: \"complete\", value: parseTokenResponse(json, \"poll\") };\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn { status: \"failed\", message: error instanceof Error ? error.message : String(error) };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst error = json?.error;\n\t\t\tconst description = typeof json?.error_description === \"string\" ? `: ${json.error_description}` : \"\";\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 = json?.interval;\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"slow_down\",\n\t\t\t\t\tintervalSeconds: typeof interval === \"number\" && interval > 0 ? interval : undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (error === \"expired_token\") {\n\t\t\t\treturn { status: \"failed\", message: \"Kimi Code device authorization expired. Please restart login.\" };\n\t\t\t}\n\t\t\tif (error === \"access_denied\") {\n\t\t\t\treturn { status: \"failed\", message: \"Kimi Code login was denied.\" };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tmessage: `Kimi Code device token request failed (status ${response.status})${typeof error === \"string\" ? `: ${error}${description}` : \"\"}`,\n\t\t\t};\n\t\t},\n\t});\n}\n\nfunction isRetryableRefreshFailure(response: Response): boolean {\n\treturn response.status === 429 || response.status >= 500;\n}\n\nasync function refreshToken(oauthHost: string, refreshTokenValue: string, signal: AbortSignal): Promise<TokenResponse> {\n\tlet lastError: Error | undefined;\n\tfor (let attempt = 0; attempt <= REFRESH_MAX_RETRIES; attempt++) {\n\t\tif (attempt > 0) {\n\t\t\tawait sleep(1000 * 2 ** (attempt - 1), signal);\n\t\t}\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Kimi Code token refresh aborted\");\n\t\t}\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await fetch(`${oauthHost}/api/oauth/token`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t...kimiCodeIdentityHeaders(),\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: formUrlEncode({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tgrant_type: \"refresh_token\",\n\t\t\t\t\trefresh_token: refreshTokenValue,\n\t\t\t\t}),\n\t\t\t\tsignal: requestSignal(signal),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error));\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst json = await readJson(response);\n\t\tif (response.ok) {\n\t\t\treturn parseTokenResponse(json, \"refresh\");\n\t\t}\n\n\t\t// Unauthorized: the stored credential is dead; Models clears it and prompts re-login.\n\t\tif (response.status === 401 || response.status === 403 || json?.error === \"invalid_grant\") {\n\t\t\tconst description = typeof json?.error_description === \"string\" ? `: ${json.error_description}` : \"\";\n\t\t\tthrow new Error(`Kimi Code token refresh unauthorized (status ${response.status})${description}`);\n\t\t}\n\n\t\tif (isRetryableRefreshFailure(response) && attempt < REFRESH_MAX_RETRIES) {\n\t\t\tlastError = new Error(`Kimi Code token refresh failed with status ${response.status}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst text = JSON.stringify(json);\n\t\tthrow new Error(`Kimi Code token refresh failed with status ${response.status}${text ? `: ${text}` : \"\"}`);\n\t}\n\n\tthrow lastError ?? new Error(\"Kimi Code token refresh failed\");\n}\n\nasync function loginKimiCoding(interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\tconst oauthHost = getOauthHost();\n\tconst device = await startDeviceAuthorization(oauthHost, interaction.signal);\n\tinteraction.notify({\n\t\ttype: \"device_code\",\n\t\tuserCode: device.userCode,\n\t\tverificationUri: device.verificationUriComplete,\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t});\n\tconst token = await pollForToken(oauthHost, device, interaction.signal);\n\treturn { type: \"oauth\", access: token.access, refresh: token.refresh, expires: token.expires };\n}\n\nexport const kimiCodingOAuth: OAuthAuth = {\n\tname: \"Kimi Code (subscription)\",\n\tisSubscription: true,\n\tloginLabel: \"Sign in with Kimi Code\",\n\n\tlogin: loginKimiCoding,\n\n\trefresh: async (credential, signal) => {\n\t\tconst token = await refreshToken(getOauthHost(), credential.refresh, signal);\n\t\treturn { type: \"oauth\", access: token.access, refresh: token.refresh, expires: token.expires };\n\t},\n\n\tasync toAuth(credential) {\n\t\treturn { headers: { ...kimiCodeIdentityHeaders(), Authorization: `Bearer ${credential.access}` } };\n\t},\n};\n"]}
|
|
1
|
+
{"version":3,"file":"kimi-coding.js","sourceRoot":"","sources":["../../../src/auth/oauth/kimi-coding.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Kimi Code (subscription) OAuth flow\n *\n * RFC 8628 device authorization grant against the region's auth host\n * (https://auth.kimi.com or https://auth.kimi.ai) with JSON responses. The\n * access token authenticates requests to that region's coding API as an\n * `Authorization: Bearer` header; see kimi-region.ts for the host table.\n */\n\nimport { sleep } from \"../../utils/sleep.ts\";\nimport type { OAuthAuth, OAuthCredential, ProviderAuthInteraction } from \"../types.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\nimport { kimiCodeIdentityHeaders } from \"./kimi-identity.ts\";\nimport { chooseKimiCodeLoginEndpoints, kimiCodeCredentialEnv, kimiCodeEndpointsForCredential } from \"./kimi-region.ts\";\n\nconst CLIENT_ID = \"17e5f671-d194-4dfb-9706-5516cb48c098\";\nconst DEVICE_CODE_TIMEOUT_SECONDS = 15 * 60;\nconst DEFAULT_POLL_INTERVAL_SECONDS = 5;\nconst REQUEST_TIMEOUT_MS = 30 * 1000;\nconst REFRESH_MAX_RETRIES = 3;\n\ntype DeviceAuthorization = {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUri: string;\n\tverificationUriComplete: string;\n\tintervalSeconds: number;\n\texpiresInSeconds: number;\n};\n\ntype TokenResponse = {\n\taccess: string;\n\trefresh: string;\n\texpires: number;\n};\n\nfunction requestSignal(signal: AbortSignal): AbortSignal {\n\treturn AbortSignal.any([AbortSignal.timeout(REQUEST_TIMEOUT_MS), signal]);\n}\n\nfunction formUrlEncode(fields: Record<string, string>): string {\n\treturn new URLSearchParams(fields).toString();\n}\n\nasync function readJson(response: Response): Promise<Record<string, unknown> | null> {\n\ttry {\n\t\tconst json = await response.json();\n\t\treturn json && typeof json === \"object\" ? (json as Record<string, unknown>) : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** The verification URI is opened in the user's browser; only http(s) URLs are trusted. */\nfunction trustedHttpUrl(value: unknown): string | null {\n\tif (typeof value !== \"string\" || !value) return null;\n\ttry {\n\t\tconst url = new URL(value);\n\t\tif (url.protocol !== \"https:\" && url.protocol !== \"http:\") return null;\n\t\treturn url.href;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function startDeviceAuthorization(oauthHost: string, signal: AbortSignal): Promise<DeviceAuthorization> {\n\tconst response = await fetch(`${oauthHost}/api/oauth/device_authorization`, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t...kimiCodeIdentityHeaders(),\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: formUrlEncode({ client_id: CLIENT_ID }),\n\t\tsignal: requestSignal(signal),\n\t});\n\n\tif (!response.ok) {\n\t\tconst text = await response.text().catch(() => \"\");\n\t\tthrow new Error(`Kimi Code device authorization failed with status ${response.status}${text ? `: ${text}` : \"\"}`);\n\t}\n\n\tconst json = await readJson(response);\n\tconst deviceCode = json?.device_code;\n\tconst userCode = json?.user_code;\n\tconst verificationUri = json?.verification_uri;\n\tconst verificationUriComplete = json?.verification_uri_complete;\n\tif (\n\t\ttypeof deviceCode !== \"string\" ||\n\t\ttypeof userCode !== \"string\" ||\n\t\ttypeof verificationUri !== \"string\" ||\n\t\ttypeof verificationUriComplete !== \"string\" ||\n\t\t!trustedHttpUrl(verificationUriComplete) ||\n\t\t!trustedHttpUrl(verificationUri)\n\t) {\n\t\tthrow new Error(`Invalid Kimi Code device authorization response: ${JSON.stringify(json)}`);\n\t}\n\n\tconst interval = json?.interval;\n\tconst expiresIn = json?.expires_in;\n\treturn {\n\t\tdeviceCode,\n\t\tuserCode,\n\t\tverificationUri,\n\t\tverificationUriComplete,\n\t\tintervalSeconds:\n\t\t\ttypeof interval === \"number\" && Number.isFinite(interval) && interval > 0\n\t\t\t\t? interval\n\t\t\t\t: DEFAULT_POLL_INTERVAL_SECONDS,\n\t\texpiresInSeconds:\n\t\t\ttypeof expiresIn === \"number\" && Number.isFinite(expiresIn) && expiresIn > 0\n\t\t\t\t? expiresIn\n\t\t\t\t: DEVICE_CODE_TIMEOUT_SECONDS,\n\t};\n}\n\nfunction parseTokenResponse(json: Record<string, unknown> | null, operation: string): TokenResponse {\n\tconst accessToken = json?.access_token;\n\tconst refreshToken = json?.refresh_token;\n\tconst expiresIn = json?.expires_in;\n\tif (\n\t\ttypeof accessToken !== \"string\" ||\n\t\t!accessToken ||\n\t\ttypeof refreshToken !== \"string\" ||\n\t\t!refreshToken ||\n\t\ttypeof expiresIn !== \"number\" ||\n\t\t!Number.isFinite(expiresIn) ||\n\t\texpiresIn <= 0\n\t) {\n\t\tthrow new Error(`Kimi Code token ${operation} response missing fields: ${JSON.stringify(json)}`);\n\t}\n\treturn {\n\t\taccess: accessToken,\n\t\trefresh: refreshToken,\n\t\texpires: Date.now() + expiresIn * 1000,\n\t};\n}\n\nasync function pollForToken(\n\toauthHost: string,\n\tdevice: DeviceAuthorization,\n\tsignal: AbortSignal,\n): Promise<TokenResponse> {\n\treturn pollOAuthDeviceCodeFlow<TokenResponse>({\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 fetch(`${oauthHost}/api/oauth/token`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t...kimiCodeIdentityHeaders(),\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: formUrlEncode({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tdevice_code: device.deviceCode,\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t}),\n\t\t\t\tsignal: requestSignal(signal),\n\t\t\t});\n\n\t\t\tif (response.status >= 500) {\n\t\t\t\tconst text = await response.text().catch(() => \"\");\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\tmessage: `Kimi Code device token request failed with status ${response.status}${text ? `: ${text}` : \"\"}`,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst json = await readJson(response);\n\t\t\tif (response.ok && typeof json?.access_token === \"string\") {\n\t\t\t\ttry {\n\t\t\t\t\treturn { status: \"complete\", value: parseTokenResponse(json, \"poll\") };\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn { status: \"failed\", message: error instanceof Error ? error.message : String(error) };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst error = json?.error;\n\t\t\tconst description = typeof json?.error_description === \"string\" ? `: ${json.error_description}` : \"\";\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 = json?.interval;\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"slow_down\",\n\t\t\t\t\tintervalSeconds: typeof interval === \"number\" && interval > 0 ? interval : undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (error === \"expired_token\") {\n\t\t\t\treturn { status: \"failed\", message: \"Kimi Code device authorization expired. Please restart login.\" };\n\t\t\t}\n\t\t\tif (error === \"access_denied\") {\n\t\t\t\treturn { status: \"failed\", message: \"Kimi Code login was denied.\" };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tmessage: `Kimi Code device token request failed (status ${response.status})${typeof error === \"string\" ? `: ${error}${description}` : \"\"}`,\n\t\t\t};\n\t\t},\n\t});\n}\n\nfunction isRetryableRefreshFailure(response: Response): boolean {\n\treturn response.status === 429 || response.status >= 500;\n}\n\nasync function refreshToken(oauthHost: string, refreshTokenValue: string, signal: AbortSignal): Promise<TokenResponse> {\n\tlet lastError: Error | undefined;\n\tfor (let attempt = 0; attempt <= REFRESH_MAX_RETRIES; attempt++) {\n\t\tif (attempt > 0) {\n\t\t\tawait sleep(1000 * 2 ** (attempt - 1), signal);\n\t\t}\n\t\tif (signal.aborted) {\n\t\t\tthrow new Error(\"Kimi Code token refresh aborted\");\n\t\t}\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await fetch(`${oauthHost}/api/oauth/token`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t...kimiCodeIdentityHeaders(),\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: formUrlEncode({\n\t\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t\t\tgrant_type: \"refresh_token\",\n\t\t\t\t\trefresh_token: refreshTokenValue,\n\t\t\t\t}),\n\t\t\t\tsignal: requestSignal(signal),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tlastError = error instanceof Error ? error : new Error(String(error));\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst json = await readJson(response);\n\t\tif (response.ok) {\n\t\t\treturn parseTokenResponse(json, \"refresh\");\n\t\t}\n\n\t\t// Unauthorized: the stored credential is dead; Models clears it and prompts re-login.\n\t\tif (response.status === 401 || response.status === 403 || json?.error === \"invalid_grant\") {\n\t\t\tconst description = typeof json?.error_description === \"string\" ? `: ${json.error_description}` : \"\";\n\t\t\tthrow new Error(`Kimi Code token refresh unauthorized (status ${response.status})${description}`);\n\t\t}\n\n\t\tif (isRetryableRefreshFailure(response) && attempt < REFRESH_MAX_RETRIES) {\n\t\t\tlastError = new Error(`Kimi Code token refresh failed with status ${response.status}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst text = JSON.stringify(json);\n\t\tthrow new Error(`Kimi Code token refresh failed with status ${response.status}${text ? `: ${text}` : \"\"}`);\n\t}\n\n\tthrow lastError ?? new Error(\"Kimi Code token refresh failed\");\n}\n\nasync function loginKimiCoding(interaction: ProviderAuthInteraction): Promise<OAuthCredential> {\n\tconst endpoints = await chooseKimiCodeLoginEndpoints(interaction);\n\tconst oauthHost = endpoints.oauthHost;\n\tconst device = await startDeviceAuthorization(oauthHost, interaction.signal);\n\tinteraction.notify({\n\t\ttype: \"device_code\",\n\t\tuserCode: device.userCode,\n\t\tverificationUri: device.verificationUriComplete,\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t});\n\tconst token = await pollForToken(oauthHost, device, interaction.signal);\n\treturn {\n\t\ttype: \"oauth\",\n\t\taccess: token.access,\n\t\trefresh: token.refresh,\n\t\texpires: token.expires,\n\t\t...(endpoints.env ? { env: endpoints.env } : {}),\n\t};\n}\n\nexport const kimiCodingOAuth: OAuthAuth = {\n\tname: \"Kimi Code (subscription)\",\n\tisSubscription: true,\n\tloginLabel: \"Sign in with Kimi Code\",\n\n\tlogin: loginKimiCoding,\n\n\trefresh: async (credential, signal) => {\n\t\tconst env = kimiCodeCredentialEnv(credential);\n\t\tconst token = await refreshToken(\n\t\t\tkimiCodeEndpointsForCredential(credential).oauthHost,\n\t\t\tcredential.refresh,\n\t\t\tsignal,\n\t\t);\n\t\treturn {\n\t\t\ttype: \"oauth\",\n\t\t\taccess: token.access,\n\t\t\trefresh: token.refresh,\n\t\t\texpires: token.expires,\n\t\t\t...(env ? { env } : {}),\n\t\t};\n\t},\n\n\tasync toAuth(credential) {\n\t\tconst { apiBaseUrl } = kimiCodeEndpointsForCredential(credential);\n\t\treturn {\n\t\t\theaders: { ...kimiCodeIdentityHeaders(), Authorization: `Bearer ${credential.access}` },\n\t\t\t...(apiBaseUrl ? { baseUrl: apiBaseUrl } : {}),\n\t\t};\n\t},\n};\n"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ProviderEnv } from "../../types.ts";
|
|
2
|
+
import type { AuthPrompt, ProviderAuthInteraction } from "../types.ts";
|
|
3
|
+
/** Region ids match the official Kimi Code CLI's `kimi login --region` values. */
|
|
4
|
+
export type KimiCodeRegion = "mainland-cn" | "global";
|
|
5
|
+
export declare const KIMI_CODE_REGION_ENV = "KIMI_CODE_REGION";
|
|
6
|
+
export declare const KIMI_CODE_OAUTH_HOST_ENV = "KIMI_CODE_OAUTH_HOST";
|
|
7
|
+
export declare const KIMI_OAUTH_HOST_ENV = "KIMI_OAUTH_HOST";
|
|
8
|
+
export declare const DEFAULT_KIMI_CODE_REGION: KimiCodeRegion;
|
|
9
|
+
export interface KimiCodeRegionProfile {
|
|
10
|
+
readonly id: KimiCodeRegion;
|
|
11
|
+
readonly label: string;
|
|
12
|
+
readonly description: string;
|
|
13
|
+
readonly oauthHost: string;
|
|
14
|
+
readonly apiBaseUrl: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const KIMI_CODE_REGION_PROFILES: Readonly<Record<KimiCodeRegion, KimiCodeRegionProfile>>;
|
|
17
|
+
export interface KimiCodeEndpoints {
|
|
18
|
+
readonly region: KimiCodeRegion | undefined;
|
|
19
|
+
readonly oauthHost: string;
|
|
20
|
+
/** Set only when the region moves inference off the provider's catalog base. */
|
|
21
|
+
readonly apiBaseUrl: string | undefined;
|
|
22
|
+
/** Credential metadata that makes refresh and inference follow this choice. */
|
|
23
|
+
readonly env: ProviderEnv | undefined;
|
|
24
|
+
}
|
|
25
|
+
export interface KimiCodeEndpointInput {
|
|
26
|
+
readonly storedRegion?: unknown;
|
|
27
|
+
readonly storedOauthHost?: unknown;
|
|
28
|
+
readonly envOauthHost?: string | undefined;
|
|
29
|
+
readonly envRegion?: string | undefined;
|
|
30
|
+
}
|
|
31
|
+
export declare function isKimiCodeRegion(value: unknown): value is KimiCodeRegion;
|
|
32
|
+
export declare function kimiCodeRegionForOauthHost(host: string): KimiCodeRegion | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* A credential's stored host or region owns its refresh and inference routing;
|
|
35
|
+
* the process env only decides for credentials that predate regions and for
|
|
36
|
+
* new logins.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveKimiCodeEndpoints(input: KimiCodeEndpointInput): KimiCodeEndpoints;
|
|
39
|
+
export declare function kimiCodeCredentialEnv(credential: Readonly<Record<string, unknown>>): ProviderEnv | undefined;
|
|
40
|
+
export declare function kimiCodeEndpointsForCredential(credential: Readonly<Record<string, unknown>>): KimiCodeEndpoints;
|
|
41
|
+
export declare function kimiCodeRegionPrompt(): AuthPrompt;
|
|
42
|
+
/** An explicit host or region in the env skips the prompt so headless logins keep working. */
|
|
43
|
+
export declare function chooseKimiCodeLoginEndpoints(interaction: ProviderAuthInteraction): Promise<KimiCodeEndpoints>;
|
|
44
|
+
//# sourceMappingURL=kimi-region.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kimi-region.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/kimi-region.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,KAAK,EAAE,UAAU,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAEvE,kFAAkF;AAClF,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,QAAQ,CAAC;AAEtD,eAAO,MAAM,oBAAoB,qBAAqB,CAAC;AACvD,eAAO,MAAM,wBAAwB,yBAAyB,CAAC;AAC/D,eAAO,MAAM,mBAAmB,oBAAoB,CAAC;AACrD,eAAO,MAAM,wBAAwB,EAAE,cAA8B,CAAC;AAEtE,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAe7F,CAAC;AAEF,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,gFAAgF;IAChF,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,+EAA+E;IAC/E,QAAQ,CAAC,GAAG,EAAE,WAAW,GAAG,SAAS,CAAC;CACtC;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAExE;AAMD,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAMnF;AAuBD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,qBAAqB,GAAG,iBAAiB,CAQxF;AAED,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,WAAW,GAAG,SAAS,CAQ5G;AAED,wBAAgB,8BAA8B,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,iBAAiB,CAQ/G;AAED,wBAAgB,oBAAoB,IAAI,UAAU,CAUjD;AAED,8FAA8F;AAC9F,wBAAsB,4BAA4B,CAAC,WAAW,EAAE,uBAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAanH"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { getProviderEnvValue } from "../../utils/provider-env.js";
|
|
2
|
+
export const KIMI_CODE_REGION_ENV = "KIMI_CODE_REGION";
|
|
3
|
+
export const KIMI_CODE_OAUTH_HOST_ENV = "KIMI_CODE_OAUTH_HOST";
|
|
4
|
+
export const KIMI_OAUTH_HOST_ENV = "KIMI_OAUTH_HOST";
|
|
5
|
+
export const DEFAULT_KIMI_CODE_REGION = "mainland-cn";
|
|
6
|
+
export const KIMI_CODE_REGION_PROFILES = {
|
|
7
|
+
"mainland-cn": {
|
|
8
|
+
id: "mainland-cn",
|
|
9
|
+
label: "Mainland China (kimi.com)",
|
|
10
|
+
description: "Accounts created on kimi.com",
|
|
11
|
+
oauthHost: "https://auth.kimi.com",
|
|
12
|
+
apiBaseUrl: "https://api.kimi.com/coding",
|
|
13
|
+
},
|
|
14
|
+
global: {
|
|
15
|
+
id: "global",
|
|
16
|
+
label: "Outside mainland China (kimi.ai)",
|
|
17
|
+
description: "Accounts created on kimi.ai",
|
|
18
|
+
oauthHost: "https://auth.kimi.ai",
|
|
19
|
+
apiBaseUrl: "https://api.kimi.ai/coding",
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
export function isKimiCodeRegion(value) {
|
|
23
|
+
return value === "mainland-cn" || value === "global";
|
|
24
|
+
}
|
|
25
|
+
function normalizeHost(host) {
|
|
26
|
+
return host.trim().replace(/\/+$/, "");
|
|
27
|
+
}
|
|
28
|
+
export function kimiCodeRegionForOauthHost(host) {
|
|
29
|
+
const normalized = normalizeHost(host);
|
|
30
|
+
for (const profile of Object.values(KIMI_CODE_REGION_PROFILES)) {
|
|
31
|
+
if (profile.oauthHost === normalized)
|
|
32
|
+
return profile.id;
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
function endpointsForRegion(region) {
|
|
37
|
+
const profile = KIMI_CODE_REGION_PROFILES[region];
|
|
38
|
+
return {
|
|
39
|
+
region,
|
|
40
|
+
oauthHost: profile.oauthHost,
|
|
41
|
+
apiBaseUrl: region === DEFAULT_KIMI_CODE_REGION ? undefined : profile.apiBaseUrl,
|
|
42
|
+
env: { [KIMI_CODE_REGION_ENV]: region },
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function endpointsForHost(host) {
|
|
46
|
+
const region = kimiCodeRegionForOauthHost(host);
|
|
47
|
+
if (region !== undefined)
|
|
48
|
+
return endpointsForRegion(region);
|
|
49
|
+
return {
|
|
50
|
+
region: undefined,
|
|
51
|
+
oauthHost: normalizeHost(host),
|
|
52
|
+
apiBaseUrl: undefined,
|
|
53
|
+
env: { [KIMI_CODE_OAUTH_HOST_ENV]: normalizeHost(host) },
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A credential's stored host or region owns its refresh and inference routing;
|
|
58
|
+
* the process env only decides for credentials that predate regions and for
|
|
59
|
+
* new logins.
|
|
60
|
+
*/
|
|
61
|
+
export function resolveKimiCodeEndpoints(input) {
|
|
62
|
+
if (typeof input.storedOauthHost === "string" && input.storedOauthHost.trim()) {
|
|
63
|
+
return endpointsForHost(input.storedOauthHost);
|
|
64
|
+
}
|
|
65
|
+
if (isKimiCodeRegion(input.storedRegion))
|
|
66
|
+
return endpointsForRegion(input.storedRegion);
|
|
67
|
+
if (input.envOauthHost?.trim())
|
|
68
|
+
return endpointsForHost(input.envOauthHost);
|
|
69
|
+
if (isKimiCodeRegion(input.envRegion))
|
|
70
|
+
return endpointsForRegion(input.envRegion);
|
|
71
|
+
return { ...endpointsForRegion(DEFAULT_KIMI_CODE_REGION), env: undefined };
|
|
72
|
+
}
|
|
73
|
+
export function kimiCodeCredentialEnv(credential) {
|
|
74
|
+
const value = credential.env;
|
|
75
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
76
|
+
return undefined;
|
|
77
|
+
const env = {};
|
|
78
|
+
for (const [name, entry] of Object.entries(value)) {
|
|
79
|
+
if (typeof entry === "string")
|
|
80
|
+
env[name] = entry;
|
|
81
|
+
}
|
|
82
|
+
return env;
|
|
83
|
+
}
|
|
84
|
+
export function kimiCodeEndpointsForCredential(credential) {
|
|
85
|
+
const env = kimiCodeCredentialEnv(credential);
|
|
86
|
+
return resolveKimiCodeEndpoints({
|
|
87
|
+
storedRegion: env?.[KIMI_CODE_REGION_ENV],
|
|
88
|
+
storedOauthHost: env?.[KIMI_CODE_OAUTH_HOST_ENV],
|
|
89
|
+
envOauthHost: getProviderEnvValue(KIMI_CODE_OAUTH_HOST_ENV) || getProviderEnvValue(KIMI_OAUTH_HOST_ENV),
|
|
90
|
+
envRegion: getProviderEnvValue(KIMI_CODE_REGION_ENV),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
export function kimiCodeRegionPrompt() {
|
|
94
|
+
return {
|
|
95
|
+
type: "select",
|
|
96
|
+
message: "Which Kimi service hosts your account?",
|
|
97
|
+
options: Object.values(KIMI_CODE_REGION_PROFILES).map((profile) => ({
|
|
98
|
+
id: profile.id,
|
|
99
|
+
label: profile.label,
|
|
100
|
+
description: profile.description,
|
|
101
|
+
})),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** An explicit host or region in the env skips the prompt so headless logins keep working. */
|
|
105
|
+
export async function chooseKimiCodeLoginEndpoints(interaction) {
|
|
106
|
+
const fromEnv = resolveKimiCodeEndpoints({
|
|
107
|
+
envOauthHost: getProviderEnvValue(KIMI_CODE_OAUTH_HOST_ENV) || getProviderEnvValue(KIMI_OAUTH_HOST_ENV),
|
|
108
|
+
envRegion: getProviderEnvValue(KIMI_CODE_REGION_ENV),
|
|
109
|
+
});
|
|
110
|
+
if (fromEnv.env !== undefined)
|
|
111
|
+
return fromEnv;
|
|
112
|
+
interaction.signal.throwIfAborted();
|
|
113
|
+
const answer = await interaction.prompt(kimiCodeRegionPrompt());
|
|
114
|
+
interaction.signal.throwIfAborted();
|
|
115
|
+
if (!isKimiCodeRegion(answer)) {
|
|
116
|
+
throw new Error(`Unknown Kimi Code region: ${answer}`);
|
|
117
|
+
}
|
|
118
|
+
return endpointsForRegion(answer);
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=kimi-region.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kimi-region.js","sourceRoot":"","sources":["../../../src/auth/oauth/kimi-region.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProviderEnv } from \"../../types.ts\";\nimport { getProviderEnvValue } from \"../../utils/provider-env.ts\";\nimport type { AuthPrompt, ProviderAuthInteraction } from \"../types.ts\";\n\n/** Region ids match the official Kimi Code CLI's `kimi login --region` values. */\nexport type KimiCodeRegion = \"mainland-cn\" | \"global\";\n\nexport const KIMI_CODE_REGION_ENV = \"KIMI_CODE_REGION\";\nexport const KIMI_CODE_OAUTH_HOST_ENV = \"KIMI_CODE_OAUTH_HOST\";\nexport const KIMI_OAUTH_HOST_ENV = \"KIMI_OAUTH_HOST\";\nexport const DEFAULT_KIMI_CODE_REGION: KimiCodeRegion = \"mainland-cn\";\n\nexport interface KimiCodeRegionProfile {\n\treadonly id: KimiCodeRegion;\n\treadonly label: string;\n\treadonly description: string;\n\treadonly oauthHost: string;\n\treadonly apiBaseUrl: string;\n}\n\nexport const KIMI_CODE_REGION_PROFILES: Readonly<Record<KimiCodeRegion, KimiCodeRegionProfile>> = {\n\t\"mainland-cn\": {\n\t\tid: \"mainland-cn\",\n\t\tlabel: \"Mainland China (kimi.com)\",\n\t\tdescription: \"Accounts created on kimi.com\",\n\t\toauthHost: \"https://auth.kimi.com\",\n\t\tapiBaseUrl: \"https://api.kimi.com/coding\",\n\t},\n\tglobal: {\n\t\tid: \"global\",\n\t\tlabel: \"Outside mainland China (kimi.ai)\",\n\t\tdescription: \"Accounts created on kimi.ai\",\n\t\toauthHost: \"https://auth.kimi.ai\",\n\t\tapiBaseUrl: \"https://api.kimi.ai/coding\",\n\t},\n};\n\nexport interface KimiCodeEndpoints {\n\treadonly region: KimiCodeRegion | undefined;\n\treadonly oauthHost: string;\n\t/** Set only when the region moves inference off the provider's catalog base. */\n\treadonly apiBaseUrl: string | undefined;\n\t/** Credential metadata that makes refresh and inference follow this choice. */\n\treadonly env: ProviderEnv | undefined;\n}\n\nexport interface KimiCodeEndpointInput {\n\treadonly storedRegion?: unknown;\n\treadonly storedOauthHost?: unknown;\n\treadonly envOauthHost?: string | undefined;\n\treadonly envRegion?: string | undefined;\n}\n\nexport function isKimiCodeRegion(value: unknown): value is KimiCodeRegion {\n\treturn value === \"mainland-cn\" || value === \"global\";\n}\n\nfunction normalizeHost(host: string): string {\n\treturn host.trim().replace(/\\/+$/, \"\");\n}\n\nexport function kimiCodeRegionForOauthHost(host: string): KimiCodeRegion | undefined {\n\tconst normalized = normalizeHost(host);\n\tfor (const profile of Object.values(KIMI_CODE_REGION_PROFILES)) {\n\t\tif (profile.oauthHost === normalized) return profile.id;\n\t}\n\treturn undefined;\n}\n\nfunction endpointsForRegion(region: KimiCodeRegion): KimiCodeEndpoints {\n\tconst profile = KIMI_CODE_REGION_PROFILES[region];\n\treturn {\n\t\tregion,\n\t\toauthHost: profile.oauthHost,\n\t\tapiBaseUrl: region === DEFAULT_KIMI_CODE_REGION ? undefined : profile.apiBaseUrl,\n\t\tenv: { [KIMI_CODE_REGION_ENV]: region },\n\t};\n}\n\nfunction endpointsForHost(host: string): KimiCodeEndpoints {\n\tconst region = kimiCodeRegionForOauthHost(host);\n\tif (region !== undefined) return endpointsForRegion(region);\n\treturn {\n\t\tregion: undefined,\n\t\toauthHost: normalizeHost(host),\n\t\tapiBaseUrl: undefined,\n\t\tenv: { [KIMI_CODE_OAUTH_HOST_ENV]: normalizeHost(host) },\n\t};\n}\n\n/**\n * A credential's stored host or region owns its refresh and inference routing;\n * the process env only decides for credentials that predate regions and for\n * new logins.\n */\nexport function resolveKimiCodeEndpoints(input: KimiCodeEndpointInput): KimiCodeEndpoints {\n\tif (typeof input.storedOauthHost === \"string\" && input.storedOauthHost.trim()) {\n\t\treturn endpointsForHost(input.storedOauthHost);\n\t}\n\tif (isKimiCodeRegion(input.storedRegion)) return endpointsForRegion(input.storedRegion);\n\tif (input.envOauthHost?.trim()) return endpointsForHost(input.envOauthHost);\n\tif (isKimiCodeRegion(input.envRegion)) return endpointsForRegion(input.envRegion);\n\treturn { ...endpointsForRegion(DEFAULT_KIMI_CODE_REGION), env: undefined };\n}\n\nexport function kimiCodeCredentialEnv(credential: Readonly<Record<string, unknown>>): ProviderEnv | undefined {\n\tconst value = credential.env;\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return undefined;\n\tconst env: ProviderEnv = {};\n\tfor (const [name, entry] of Object.entries(value)) {\n\t\tif (typeof entry === \"string\") env[name] = entry;\n\t}\n\treturn env;\n}\n\nexport function kimiCodeEndpointsForCredential(credential: Readonly<Record<string, unknown>>): KimiCodeEndpoints {\n\tconst env = kimiCodeCredentialEnv(credential);\n\treturn resolveKimiCodeEndpoints({\n\t\tstoredRegion: env?.[KIMI_CODE_REGION_ENV],\n\t\tstoredOauthHost: env?.[KIMI_CODE_OAUTH_HOST_ENV],\n\t\tenvOauthHost: getProviderEnvValue(KIMI_CODE_OAUTH_HOST_ENV) || getProviderEnvValue(KIMI_OAUTH_HOST_ENV),\n\t\tenvRegion: getProviderEnvValue(KIMI_CODE_REGION_ENV),\n\t});\n}\n\nexport function kimiCodeRegionPrompt(): AuthPrompt {\n\treturn {\n\t\ttype: \"select\",\n\t\tmessage: \"Which Kimi service hosts your account?\",\n\t\toptions: Object.values(KIMI_CODE_REGION_PROFILES).map((profile) => ({\n\t\t\tid: profile.id,\n\t\t\tlabel: profile.label,\n\t\t\tdescription: profile.description,\n\t\t})),\n\t};\n}\n\n/** An explicit host or region in the env skips the prompt so headless logins keep working. */\nexport async function chooseKimiCodeLoginEndpoints(interaction: ProviderAuthInteraction): Promise<KimiCodeEndpoints> {\n\tconst fromEnv = resolveKimiCodeEndpoints({\n\t\tenvOauthHost: getProviderEnvValue(KIMI_CODE_OAUTH_HOST_ENV) || getProviderEnvValue(KIMI_OAUTH_HOST_ENV),\n\t\tenvRegion: getProviderEnvValue(KIMI_CODE_REGION_ENV),\n\t});\n\tif (fromEnv.env !== undefined) return fromEnv;\n\tinteraction.signal.throwIfAborted();\n\tconst answer = await interaction.prompt(kimiCodeRegionPrompt());\n\tinteraction.signal.throwIfAborted();\n\tif (!isKimiCodeRegion(answer)) {\n\t\tthrow new Error(`Unknown Kimi Code region: ${answer}`);\n\t}\n\treturn endpointsForRegion(answer);\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { TURN_RETRY_SUPPRESSION_PREFIX } from "../../utils/provider-failure-description.ts";
|
|
1
2
|
import { type PoolFailureClassification } from "./classify.ts";
|
|
2
3
|
import type { SelectableSlot } from "./select.ts";
|
|
3
|
-
|
|
4
|
-
export declare const TURN_RETRY_SUPPRESSION_PREFIX = "senpi:no-turn-retry:";
|
|
4
|
+
export { TURN_RETRY_SUPPRESSION_PREFIX };
|
|
5
5
|
export declare const DEFAULT_SLOT_BLOCK_MS = 60000;
|
|
6
6
|
export declare const MAX_SLOT_BLOCK_MS: number;
|
|
7
7
|
export type PoolFailoverEvent<TSlot extends SelectableSlot> = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"failover.d.ts","sourceRoot":"","sources":["../../../src/auth/pool/failover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,yBAAyB,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,
|
|
1
|
+
{"version":3,"file":"failover.d.ts","sourceRoot":"","sources":["../../../src/auth/pool/failover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,6CAA6C,CAAC;AAC5F,OAAO,EAAuB,KAAK,yBAAyB,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,6BAA6B,EAAE,CAAC;AACzC,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAC5C,eAAO,MAAM,iBAAiB,QAAuB,CAAC;AAEtD,MAAM,MAAM,iBAAiB,CAAC,KAAK,SAAS,cAAc,IAAI;IAC7D,IAAI,EAAE,KAAK,CAAC;IACZ,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,cAAc,EAAE,yBAAyB,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,mBAAmB,CAAC,MAAM,EAAE,KAAK,SAAS,cAAc,IAAI;IACvE,KAAK,EAAE,SAAS,KAAK,EAAE,CAAC;IACxB,MAAM,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,EAAE,KAAK,KAAK,CAAC;IAC3C,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IACpF,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,yBAAyB,CAAC;IACzD;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAC/C,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,KAAK,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,qBAAa,iBAAkB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,cAAc,EAAE,yBAAyB,CAAC;IACnD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IAEpC,YAAY,cAAc,EAAE,yBAAyB,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAOnG;CACD;AAoBD;;;;;;GAMG;AACH,wBAAuB,eAAe,CAAC,MAAM,EAAE,KAAK,SAAS,cAAc,EAC1E,OAAO,EAAE,mBAAmB,CAAC,MAAM,EAAE,KAAK,CAAC,GACzC,cAAc,CAAC,MAAM,CAAC,CA4CxB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { TURN_RETRY_SUPPRESSION_PREFIX } from "../../utils/provider-failure-description.js";
|
|
1
2
|
import { classifyPoolFailure } from "./classify.js";
|
|
2
|
-
|
|
3
|
-
export const TURN_RETRY_SUPPRESSION_PREFIX = "senpi:no-turn-retry:";
|
|
3
|
+
export { TURN_RETRY_SUPPRESSION_PREFIX };
|
|
4
4
|
export const DEFAULT_SLOT_BLOCK_MS = 60_000;
|
|
5
5
|
export const MAX_SLOT_BLOCK_MS = 48 * 60 * 60 * 1_000;
|
|
6
6
|
export class PoolFailoverError extends Error {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"failover.js","sourceRoot":"","sources":["../../../src/auth/pool/failover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAkC,MAAM,eAAe,CAAC;AAGpF,
|
|
1
|
+
{"version":3,"file":"failover.js","sourceRoot":"","sources":["../../../src/auth/pool/failover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,6CAA6C,CAAC;AAC5F,OAAO,EAAE,mBAAmB,EAAkC,MAAM,eAAe,CAAC;AAGpF,OAAO,EAAE,6BAA6B,EAAE,CAAC;AACzC,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAC5C,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;AA4BtD,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAK3C,YAAY,cAAyC,EAAE,QAAiB,EAAE,iBAA0B;QACnG,MAAM,MAAM,GAAG,QAAQ,YAAY,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC/E,KAAK,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;QAC5E,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;IAC5C,CAAC;CACD;AAED,SAAS,WAAW,CACnB,IAAW,EACX,cAAyC,EACzC,GAAW,EACX,OAAe,EACf,WAAmB;IAEnB,IAAI,cAAc,CAAC,WAAW,KAAK,YAAY,EAAE,CAAC;QACjD,kEAAkE;QAClE,MAAM,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;QACpD,OAAO,IAAI,CAAC,YAAY,CAAC;QACzB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,WAAW,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC;IACzE,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,cAAc,CAAC,YAAY,IAAI,QAAQ,CAAC,CAAC;IACtF,OAAO,EAAE,GAAG,IAAI,EAAE,YAAY,EAAE,GAAG,GAAG,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;AAC7E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,eAAe,CACrC,OAA2C;IAE3C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACpC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,mBAAmB,CAAC;IACzD,MAAM,SAAS,GAAG,OAAO,CAAC,iBAAiB,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC5D,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,qBAAqB,CAAC;IACjE,IAAI,KAAK,GAAG,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,SAAwC,CAAC;IAE7C,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC;QACjE,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,eAAe,GAAG,KAAK,CAAC;QAC5B,IAAI,CAAC;YACJ,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YACrD,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;gBACzC,eAAe,KAAK,SAAS,CAAC,KAAK,CAAC,CAAC;gBACrC,MAAM,KAAK,CAAC;YACb,CAAC;YACD,OAAO;QACR,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,cAAc,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;YACvC,MAAM,OAAO,GAAG,IAAI,iBAAiB,CAAC,cAAc,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC;YAC9E,SAAS,GAAG,OAAO,CAAC;YACpB,IAAI,cAAc,CAAC,MAAM,KAAK,QAAQ;gBAAE,MAAM,OAAO,CAAC;YAEtD,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;YAC/E,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;YAC1F,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC,OAAO,CAAC,CAAC;YACtC,MAAM,QAAQ,GAA6B;gBAC1C,IAAI,EAAE,OAAO;gBACb,cAAc;gBACd,OAAO,EAAE,OAAO,GAAG,CAAC;gBACpB,eAAe;aACf,CAAC;YACF,IAAI,CAAC;gBACJ,IAAI,CAAC,eAAe,IAAI,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;oBACpD,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC3C,CAAC;YACF,CAAC;oBAAS,CAAC;gBACV,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC;YACpC,CAAC;YACD,IAAI,eAAe;gBAAE,MAAM,OAAO,CAAC;QACpC,CAAC;IACF,CAAC;IACD,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;AACvF,CAAC","sourcesContent":["import { TURN_RETRY_SUPPRESSION_PREFIX } from \"../../utils/provider-failure-description.ts\";\nimport { classifyPoolFailure, type PoolFailureClassification } from \"./classify.ts\";\nimport type { SelectableSlot } from \"./select.ts\";\n\nexport { TURN_RETRY_SUPPRESSION_PREFIX };\nexport const DEFAULT_SLOT_BLOCK_MS = 60_000;\nexport const MAX_SLOT_BLOCK_MS = 48 * 60 * 60 * 1_000;\n\nexport type PoolFailoverEvent<TSlot extends SelectableSlot> = {\n\tslot: TSlot;\n\tnextSlot?: TSlot;\n\tclassification: PoolFailureClassification;\n\tattempt: number;\n\tcommittedOutput: boolean;\n};\n\nexport type PoolFailoverOptions<TEvent, TSlot extends SelectableSlot> = {\n\tslots: readonly TSlot[];\n\tselect: (slots: readonly TSlot[]) => TSlot;\n\trunAttempt: (slot: TSlot) => AsyncIterable<TEvent> | Promise<AsyncIterable<TEvent>>;\n\tclassify?: (error: unknown) => PoolFailureClassification;\n\t/**\n\t * Rotation is transparent only before committed output. Absent, every yielded\n\t * event counts as committed (default-DENY), so silent mid-stream rotation\n\t * requires an explicit opt-in from a caller that knows which events are\n\t * bookkeeping rather than user-visible output.\n\t */\n\tisCommittedOutput?: (event: TEvent) => boolean;\n\tpersistBlock?: (slot: TSlot) => void | Promise<void>;\n\tonRotate?: (event: PoolFailoverEvent<TSlot>) => void | Promise<void>;\n\tnow?: () => number;\n\tbaseBlockMs?: number;\n};\n\nexport class PoolFailoverError extends Error {\n\treadonly classification: PoolFailureClassification;\n\treadonly original: unknown;\n\treadonly suppressTurnRetry: boolean;\n\n\tconstructor(classification: PoolFailureClassification, original: unknown, suppressTurnRetry: boolean) {\n\t\tconst detail = original instanceof Error ? original.message : String(original);\n\t\tsuper(`${suppressTurnRetry ? TURN_RETRY_SUPPRESSION_PREFIX : \"\"}${detail}`);\n\t\tthis.name = \"PoolFailoverError\";\n\t\tthis.classification = classification;\n\t\tthis.original = original;\n\t\tthis.suppressTurnRetry = suppressTurnRetry;\n\t}\n}\n\nfunction blockedSlot<TSlot extends SelectableSlot>(\n\tslot: TSlot,\n\tclassification: PoolFailureClassification,\n\tnow: number,\n\tattempt: number,\n\tbaseBlockMs: number,\n): TSlot {\n\tif (classification.blockReason === \"auth_error\") {\n\t\t// An auth block has no expiry: only a re-login rewrites the slot.\n\t\tconst next = { ...slot, blockReason: \"auth_error\" };\n\t\tdelete next.blockedUntil;\n\t\treturn next;\n\t}\n\tconst fallback = Math.min(MAX_SLOT_BLOCK_MS, baseBlockMs * 2 ** attempt);\n\tconst duration = Math.min(MAX_SLOT_BLOCK_MS, classification.retryAfterMs ?? fallback);\n\treturn { ...slot, blockedUntil: now + duration, blockReason: \"rate_limit\" };\n}\n\n/**\n * Runs at most one attempt per slot. A rotation is transparent only while no\n * committed output has reached the caller; afterwards the classified error is\n * thrown with the turn-retry suppression marker so the session layer never\n * replays a partially delivered turn. Non-rotate classes throw immediately and\n * compose with the retry/model-fallback machinery above this engine.\n */\nexport async function* runSlotFailover<TEvent, TSlot extends SelectableSlot>(\n\toptions: PoolFailoverOptions<TEvent, TSlot>,\n): AsyncGenerator<TEvent> {\n\tconst now = options.now ?? Date.now;\n\tconst classify = options.classify ?? classifyPoolFailure;\n\tconst committed = options.isCommittedOutput ?? (() => true);\n\tconst baseBlockMs = options.baseBlockMs ?? DEFAULT_SLOT_BLOCK_MS;\n\tlet slots = [...options.slots];\n\tlet lastError: PoolFailoverError | undefined;\n\n\tfor (let attempt = 0; attempt < options.slots.length; attempt++) {\n\t\tconst slot = options.select(slots);\n\t\tlet committedOutput = false;\n\t\ttry {\n\t\t\tconst attemptStream = await options.runAttempt(slot);\n\t\t\tfor await (const event of attemptStream) {\n\t\t\t\tcommittedOutput ||= committed(event);\n\t\t\t\tyield event;\n\t\t\t}\n\t\t\treturn;\n\t\t} catch (error) {\n\t\t\tconst classification = classify(error);\n\t\t\tconst failure = new PoolFailoverError(classification, error, committedOutput);\n\t\t\tlastError = failure;\n\t\t\tif (classification.action !== \"rotate\") throw failure;\n\n\t\t\tconst blocked = blockedSlot(slot, classification, now(), attempt, baseBlockMs);\n\t\t\tslots = slots.map((candidate) => (candidate.name === blocked.name ? blocked : candidate));\n\t\t\tawait options.persistBlock?.(blocked);\n\t\t\tconst rotation: PoolFailoverEvent<TSlot> = {\n\t\t\t\tslot: blocked,\n\t\t\t\tclassification,\n\t\t\t\tattempt: attempt + 1,\n\t\t\t\tcommittedOutput,\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tif (!committedOutput && attempt + 1 < slots.length) {\n\t\t\t\t\trotation.nextSlot = options.select(slots);\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tawait options.onRotate?.(rotation);\n\t\t\t}\n\t\t\tif (committedOutput) throw failure;\n\t\t}\n\t}\n\tthrow lastError ?? new Error(\"Credential pool failover exhausted without an attempt\");\n}\n"]}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ProviderEnv } from "../../types.ts";
|
|
1
2
|
import type { Credential } from "../types.ts";
|
|
2
3
|
export type { Credential };
|
|
3
4
|
export declare const DEFAULT_SLOT_NAME = "default";
|
|
@@ -12,6 +13,8 @@ export type CredentialSlot = {
|
|
|
12
13
|
access?: string;
|
|
13
14
|
refresh?: string;
|
|
14
15
|
expires?: number;
|
|
16
|
+
/** Provider-scoped values this account carries (a Kimi region, a Cloudflare account id). */
|
|
17
|
+
env?: ProviderEnv;
|
|
15
18
|
};
|
|
16
19
|
export type PooledCredential = Credential & {
|
|
17
20
|
accounts?: CredentialSlot[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../../src/auth/pool/slots.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B,eAAO,MAAM,iBAAiB,YAAY,CAAC;AAE3C,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE9D,MAAM,MAAM,cAAc,GAAG;IAC5B,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"slots.d.ts","sourceRoot":"","sources":["../../../src/auth/pool/slots.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B,eAAO,MAAM,iBAAiB,YAAY,CAAC;AAE3C,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE9D,MAAM,MAAM,cAAc,GAAG;IAC5B,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4FAA4F;IAC5F,GAAG,CAAC,EAAE,WAAW,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG;IAC3C,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAIF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMtD;AAID;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAiC3C,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUxD;AAoBD,gEAAgE;AAChE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CASrE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAGpF;AAED,yFAAyF;AACzF,wBAAgB,qBAAqB,CACpC,UAAU,EAAE,gBAAgB,EAC5B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GAAG,IAAI,GAClB,gBAAgB,CA8BlB;AAqBD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,gBAAgB,GAAG,SAAS,GAAG,cAAc,EAAE,CAIpF;AAED,wBAAgB,QAAQ,CAAC,UAAU,EAAE,gBAAgB,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAE3G;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,gBAAgB,GAAG,SAAS,EAAE,IAAI,EAAE,cAAc,GAAG,gBAAgB,CAc3G;AAkBD;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,gBAAgB,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAW/G;AAED,wBAAgB,OAAO,CAAC,UAAU,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAGpF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,gBAAgB,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAW1G;AAgDD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAC9B,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,IAAI,EAAE,UAAU,EAChB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,UAAU,KAAK,IAAI,GACpE,UAAU,CA2BZ;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAGvF;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,gBAAgB,GAAG,SAAS,CAQnH;AAED;;;;;GAKG;AACH;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,UAAU,CAS7G;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,UAAU,GAAG,UAAU,CAe3F"}
|
|
@@ -119,17 +119,20 @@ export function renameSlotDisplayName(credential, name, value) {
|
|
|
119
119
|
function storedSlots(credential) {
|
|
120
120
|
return Array.isArray(credential.accounts) ? credential.accounts : [];
|
|
121
121
|
}
|
|
122
|
-
function
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
122
|
+
function credentialSlotEnv(credential) {
|
|
123
|
+
const value = credential.env;
|
|
124
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
125
|
+
return {};
|
|
126
|
+
const env = {};
|
|
127
|
+
for (const [name, entry] of Object.entries(value)) {
|
|
128
|
+
if (typeof entry !== "string")
|
|
129
|
+
return {};
|
|
130
|
+
env[name] = entry;
|
|
131
131
|
}
|
|
132
|
-
return {
|
|
132
|
+
return { env };
|
|
133
|
+
}
|
|
134
|
+
function slotFromFlatCredential(credential) {
|
|
135
|
+
return slotFromFlatCredentialNamed(credential, DEFAULT_SLOT_NAME);
|
|
133
136
|
}
|
|
134
137
|
/**
|
|
135
138
|
* A flat credential written by a build predating pools is read as a one-slot pool
|
|
@@ -170,12 +173,13 @@ function slotMirrorsFlat(credential, slot) {
|
|
|
170
173
|
}
|
|
171
174
|
/** Rewrites the flat top-level projection to carry the given slot's material. */
|
|
172
175
|
function projectFlatFields(credential, slot) {
|
|
176
|
+
const env = slot.env === undefined ? {} : { env: slot.env };
|
|
173
177
|
if (credential.type === "oauth") {
|
|
174
178
|
if (slot.access === undefined || slot.refresh === undefined || slot.expires === undefined)
|
|
175
179
|
return credential;
|
|
176
|
-
return { ...credential, access: slot.access, refresh: slot.refresh, expires: slot.expires };
|
|
180
|
+
return { ...credential, access: slot.access, refresh: slot.refresh, expires: slot.expires, ...env };
|
|
177
181
|
}
|
|
178
|
-
return { ...credential, key: slot.key };
|
|
182
|
+
return { ...credential, key: slot.key, ...env };
|
|
179
183
|
}
|
|
180
184
|
/**
|
|
181
185
|
* Removes one slot. The credential is dropped entirely once its last slot is gone,
|
|
@@ -219,12 +223,13 @@ export function projectSlot(credential, name) {
|
|
|
219
223
|
if (!slot)
|
|
220
224
|
return undefined;
|
|
221
225
|
const { accounts: _accounts, pinned: _pinned, ...flat } = credential;
|
|
226
|
+
const env = slot.env === undefined ? {} : { env: slot.env };
|
|
222
227
|
if (flat.type === "oauth") {
|
|
223
228
|
if (slot.access === undefined || slot.refresh === undefined || slot.expires === undefined)
|
|
224
229
|
return undefined;
|
|
225
|
-
return { ...flat, access: slot.access, refresh: slot.refresh, expires: slot.expires };
|
|
230
|
+
return { ...flat, access: slot.access, refresh: slot.refresh, expires: slot.expires, ...env };
|
|
226
231
|
}
|
|
227
|
-
return { ...flat, key: slot.key };
|
|
232
|
+
return { ...flat, key: slot.key, ...env };
|
|
228
233
|
}
|
|
229
234
|
function slotFromFlatCredentialNamed(credential, name) {
|
|
230
235
|
if (credential.type === "oauth") {
|
|
@@ -234,9 +239,10 @@ function slotFromFlatCredentialNamed(credential, name) {
|
|
|
234
239
|
access: credential.access,
|
|
235
240
|
refresh: credential.refresh,
|
|
236
241
|
expires: credential.expires,
|
|
242
|
+
...credentialSlotEnv(credential),
|
|
237
243
|
};
|
|
238
244
|
}
|
|
239
|
-
return { name, source: "login", key: credential.key };
|
|
245
|
+
return { name, source: "login", key: credential.key, ...credentialSlotEnv(credential) };
|
|
240
246
|
}
|
|
241
247
|
function nextLoginSlotName(credential) {
|
|
242
248
|
const taken = new Set(listSlots(credential).map((slot) => slot.name));
|