@moxxy/plugin-provider-claude-code 0.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/constants.d.ts +41 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +41 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/login.d.ts +49 -0
- package/dist/login.d.ts.map +1 -0
- package/dist/login.js +342 -0
- package/dist/login.js.map +1 -0
- package/dist/provider.d.ts +24 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +22 -0
- package/dist/provider.js.map +1 -0
- package/package.json +66 -0
- package/src/constants.ts +46 -0
- package/src/index.ts +47 -0
- package/src/login.test.ts +441 -0
- package/src/login.ts +426 -0
- package/src/provider.test.ts +36 -0
- package/src/provider.ts +34 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Moxxy (moxxy.ai)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for the Claude subscription (Pro/Max) provider.
|
|
3
|
+
*
|
|
4
|
+
* These are the public Claude Code OAuth client parameters — the same values
|
|
5
|
+
* the `claude` CLI uses — so a token minted here interoperates with one from
|
|
6
|
+
* `claude setup-token`, and vice-versa. We never embed a client secret; the
|
|
7
|
+
* flow is PKCE + an out-of-band (manual paste) authorization code.
|
|
8
|
+
*/
|
|
9
|
+
/** Provider name in the registry / `/model` picker / `provider.name` config. */
|
|
10
|
+
export declare const CLAUDE_CODE_PROVIDER_ID = "claude-code";
|
|
11
|
+
/** Human-readable upstream service, shown in `moxxy login` and the init wizard. */
|
|
12
|
+
export declare const CLAUDE_CODE_SERVICE_NAME = "Claude (Pro/Max subscription)";
|
|
13
|
+
export declare const CLAUDE_AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
14
|
+
export declare const CLAUDE_TOKEN_URL = "https://console.anthropic.com/v1/oauth/token";
|
|
15
|
+
export declare const CLAUDE_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
16
|
+
/**
|
|
17
|
+
* Out-of-band redirect: after consent, Anthropic shows the user a
|
|
18
|
+
* `code#state` string to paste back into the terminal (no loopback server).
|
|
19
|
+
*/
|
|
20
|
+
export declare const CLAUDE_REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback";
|
|
21
|
+
export declare const CLAUDE_SCOPES: readonly ["org:create_api_key", "user:profile", "user:inference"];
|
|
22
|
+
/**
|
|
23
|
+
* `anthropic-beta` values sent with every request. `oauth-2025-04-20` is the
|
|
24
|
+
* flag that makes the Messages API accept a subscription bearer token at all;
|
|
25
|
+
* `claude-code-20250219` matches what the real CLI sends. Sent comma-joined.
|
|
26
|
+
*/
|
|
27
|
+
export declare const CLAUDE_OAUTH_BETA: readonly ["oauth-2025-04-20", "claude-code-20250219"];
|
|
28
|
+
/**
|
|
29
|
+
* Required first system block. Claude rejects a subscription token unless the
|
|
30
|
+
* system prompt leads with this exact identity line; moxxy's real system
|
|
31
|
+
* prompt is appended as the following block. (Verified against the working
|
|
32
|
+
* opencode / claude-code-router behaviour.)
|
|
33
|
+
*/
|
|
34
|
+
export declare const CLAUDE_CODE_SYSTEM = "You are Claude Code, Anthropic's official CLI for Claude.";
|
|
35
|
+
/**
|
|
36
|
+
* Env vars a pasted/CI token can arrive through. `CLAUDE_CODE_OAUTH_TOKEN` is
|
|
37
|
+
* what `claude setup-token` documents; `ANTHROPIC_AUTH_TOKEN` is the
|
|
38
|
+
* SDK-native bearer var. Checked in this order.
|
|
39
|
+
*/
|
|
40
|
+
export declare const CLAUDE_TOKEN_ENV_VARS: readonly ["CLAUDE_CODE_OAUTH_TOKEN", "ANTHROPIC_AUTH_TOKEN"];
|
|
41
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,gFAAgF;AAChF,eAAO,MAAM,uBAAuB,gBAAgB,CAAC;AAErD,mFAAmF;AACnF,eAAO,MAAM,wBAAwB,kCAAkC,CAAC;AAExE,eAAO,MAAM,oBAAoB,sCAAsC,CAAC;AACxE,eAAO,MAAM,gBAAgB,iDAAiD,CAAC;AAC/E,eAAO,MAAM,gBAAgB,yCAAyC,CAAC;AACvE;;;GAGG;AACH,eAAO,MAAM,mBAAmB,sDAAsD,CAAC;AACvF,eAAO,MAAM,aAAa,mEAAoE,CAAC;AAE/F;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,uDAAwD,CAAC;AAEvF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,8DAA8D,CAAC;AAE9F;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,8DAA+D,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constants for the Claude subscription (Pro/Max) provider.
|
|
3
|
+
*
|
|
4
|
+
* These are the public Claude Code OAuth client parameters — the same values
|
|
5
|
+
* the `claude` CLI uses — so a token minted here interoperates with one from
|
|
6
|
+
* `claude setup-token`, and vice-versa. We never embed a client secret; the
|
|
7
|
+
* flow is PKCE + an out-of-band (manual paste) authorization code.
|
|
8
|
+
*/
|
|
9
|
+
/** Provider name in the registry / `/model` picker / `provider.name` config. */
|
|
10
|
+
export const CLAUDE_CODE_PROVIDER_ID = 'claude-code';
|
|
11
|
+
/** Human-readable upstream service, shown in `moxxy login` and the init wizard. */
|
|
12
|
+
export const CLAUDE_CODE_SERVICE_NAME = 'Claude (Pro/Max subscription)';
|
|
13
|
+
export const CLAUDE_AUTHORIZE_URL = 'https://claude.ai/oauth/authorize';
|
|
14
|
+
export const CLAUDE_TOKEN_URL = 'https://console.anthropic.com/v1/oauth/token';
|
|
15
|
+
export const CLAUDE_CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e';
|
|
16
|
+
/**
|
|
17
|
+
* Out-of-band redirect: after consent, Anthropic shows the user a
|
|
18
|
+
* `code#state` string to paste back into the terminal (no loopback server).
|
|
19
|
+
*/
|
|
20
|
+
export const CLAUDE_REDIRECT_URI = 'https://console.anthropic.com/oauth/code/callback';
|
|
21
|
+
export const CLAUDE_SCOPES = ['org:create_api_key', 'user:profile', 'user:inference'];
|
|
22
|
+
/**
|
|
23
|
+
* `anthropic-beta` values sent with every request. `oauth-2025-04-20` is the
|
|
24
|
+
* flag that makes the Messages API accept a subscription bearer token at all;
|
|
25
|
+
* `claude-code-20250219` matches what the real CLI sends. Sent comma-joined.
|
|
26
|
+
*/
|
|
27
|
+
export const CLAUDE_OAUTH_BETA = ['oauth-2025-04-20', 'claude-code-20250219'];
|
|
28
|
+
/**
|
|
29
|
+
* Required first system block. Claude rejects a subscription token unless the
|
|
30
|
+
* system prompt leads with this exact identity line; moxxy's real system
|
|
31
|
+
* prompt is appended as the following block. (Verified against the working
|
|
32
|
+
* opencode / claude-code-router behaviour.)
|
|
33
|
+
*/
|
|
34
|
+
export const CLAUDE_CODE_SYSTEM = "You are Claude Code, Anthropic's official CLI for Claude.";
|
|
35
|
+
/**
|
|
36
|
+
* Env vars a pasted/CI token can arrive through. `CLAUDE_CODE_OAUTH_TOKEN` is
|
|
37
|
+
* what `claude setup-token` documents; `ANTHROPIC_AUTH_TOKEN` is the
|
|
38
|
+
* SDK-native bearer var. Checked in this order.
|
|
39
|
+
*/
|
|
40
|
+
export const CLAUDE_TOKEN_ENV_VARS = ['CLAUDE_CODE_OAUTH_TOKEN', 'ANTHROPIC_AUTH_TOKEN'];
|
|
41
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,gFAAgF;AAChF,MAAM,CAAC,MAAM,uBAAuB,GAAG,aAAa,CAAC;AAErD,mFAAmF;AACnF,MAAM,CAAC,MAAM,wBAAwB,GAAG,+BAA+B,CAAC;AAExE,MAAM,CAAC,MAAM,oBAAoB,GAAG,mCAAmC,CAAC;AACxE,MAAM,CAAC,MAAM,gBAAgB,GAAG,8CAA8C,CAAC;AAC/E,MAAM,CAAC,MAAM,gBAAgB,GAAG,sCAAsC,CAAC;AACvE;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,mDAAmD,CAAC;AACvF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,oBAAoB,EAAE,cAAc,EAAE,gBAAgB,CAAU,CAAC;AAE/F;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,kBAAkB,EAAE,sBAAsB,CAAU,CAAC;AAEvF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,2DAA2D,CAAC;AAE9F;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,yBAAyB,EAAE,sBAAsB,CAAU,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const claudeCodeProviderDef: import("@moxxy/sdk").ProviderDef;
|
|
2
|
+
export declare const claudeCodePlugin: import("@moxxy/sdk").Plugin;
|
|
3
|
+
export default claudeCodePlugin;
|
|
4
|
+
export { CLAUDE_CODE_PROVIDER_ID, CLAUDE_CODE_SERVICE_NAME, CLAUDE_CODE_SYSTEM, CLAUDE_OAUTH_BETA, CLAUDE_TOKEN_ENV_VARS, } from './constants.js';
|
|
5
|
+
export { claudeLogin, claudeLogout, claudeStatus, ensureFreshClaudeTokens, refreshClaudeAccessToken, type FreshClaudeTokens, } from './login.js';
|
|
6
|
+
export { createClaudeCodeClient, type ClaudeCodeProviderConfig } from './provider.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,qBAAqB,kCAehC,CAAC;AAEH,eAAO,MAAM,gBAAgB,6BAI3B,CAAC;AAEH,eAAe,gBAAgB,CAAC;AAEhC,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,uBAAuB,EACvB,wBAAwB,EACxB,KAAK,iBAAiB,GACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,sBAAsB,EAAE,KAAK,wBAAwB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { defineProvider, definePlugin } from '@moxxy/sdk';
|
|
2
|
+
import { anthropicModels } from '@moxxy/plugin-provider-anthropic';
|
|
3
|
+
import { CLAUDE_CODE_PROVIDER_ID, CLAUDE_CODE_SERVICE_NAME } from './constants.js';
|
|
4
|
+
import { createClaudeCodeClient } from './provider.js';
|
|
5
|
+
import { claudeLogin, claudeLogout, claudeStatus } from './login.js';
|
|
6
|
+
export const claudeCodeProviderDef = defineProvider({
|
|
7
|
+
name: CLAUDE_CODE_PROVIDER_ID,
|
|
8
|
+
// Same Claude models as the API-key `anthropic` provider — it's the same
|
|
9
|
+
// Messages API, only the credential differs.
|
|
10
|
+
models: [...anthropicModels],
|
|
11
|
+
createClient: (config) => createClaudeCodeClient(config),
|
|
12
|
+
// No validateKey: an OAuth bearer is validated by the request itself, and
|
|
13
|
+
// an interactive paste/sign-in already proves the token round-trips.
|
|
14
|
+
auth: {
|
|
15
|
+
kind: 'oauth',
|
|
16
|
+
serviceName: CLAUDE_CODE_SERVICE_NAME,
|
|
17
|
+
login: claudeLogin,
|
|
18
|
+
logout: claudeLogout,
|
|
19
|
+
status: claudeStatus,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
export const claudeCodePlugin = definePlugin({
|
|
23
|
+
name: '@moxxy/plugin-provider-claude-code',
|
|
24
|
+
version: '0.0.0',
|
|
25
|
+
providers: [claudeCodeProviderDef],
|
|
26
|
+
});
|
|
27
|
+
export default claudeCodePlugin;
|
|
28
|
+
export { CLAUDE_CODE_PROVIDER_ID, CLAUDE_CODE_SERVICE_NAME, CLAUDE_CODE_SYSTEM, CLAUDE_OAUTH_BETA, CLAUDE_TOKEN_ENV_VARS, } from './constants.js';
|
|
29
|
+
export { claudeLogin, claudeLogout, claudeStatus, ensureFreshClaudeTokens, refreshClaudeAccessToken, } from './login.js';
|
|
30
|
+
export { createClaudeCodeClient } from './provider.js';
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAiC,MAAM,eAAe,CAAC;AACtF,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,CAAC,MAAM,qBAAqB,GAAG,cAAc,CAAC;IAClD,IAAI,EAAE,uBAAuB;IAC7B,yEAAyE;IACzE,6CAA6C;IAC7C,MAAM,EAAE,CAAC,GAAG,eAAe,CAAC;IAC5B,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,sBAAsB,CAAC,MAAkC,CAAC;IACpF,0EAA0E;IAC1E,qEAAqE;IACrE,IAAI,EAAE;QACJ,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,wBAAwB;QACrC,KAAK,EAAE,WAAW;QAClB,MAAM,EAAE,YAAY;QACpB,MAAM,EAAE,YAAY;KACrB;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC;IAC3C,IAAI,EAAE,oCAAoC;IAC1C,OAAO,EAAE,OAAO;IAChB,SAAS,EAAE,CAAC,qBAAqB,CAAC;CACnC,CAAC,CAAC;AAEH,eAAe,gBAAgB,CAAC;AAEhC,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,uBAAuB,EACvB,wBAAwB,GAEzB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,sBAAsB,EAAiC,MAAM,eAAe,CAAC"}
|
package/dist/login.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude subscription login + token lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* Claude's OAuth is an out-of-band (manual code-paste) authorization-code +
|
|
5
|
+
* PKCE flow whose token endpoint speaks JSON (not the form-encoded dialect
|
|
6
|
+
* the framework's `exchangeCodeForToken` / `refreshAccessToken` assume), so
|
|
7
|
+
* the HTTP exchange + refresh are implemented here. Everything else is reused
|
|
8
|
+
* from `@moxxy/plugin-oauth`: PKCE, the auth-URL builder, the browser opener,
|
|
9
|
+
* vault storage layout, and `parseTokenResponse`.
|
|
10
|
+
*/
|
|
11
|
+
import { type OAuthVault } from '@moxxy/plugin-oauth';
|
|
12
|
+
import type { ProviderAuthContext, ProviderOAuthResult, ProviderOAuthStatus } from '@moxxy/sdk';
|
|
13
|
+
/**
|
|
14
|
+
* Drive an interactive Claude sign-in. Two ways in, both through one command:
|
|
15
|
+
* 1. paste an existing `claude setup-token` token (stored verbatim), or
|
|
16
|
+
* 2. press Enter to run the browser out-of-band authorization-code flow.
|
|
17
|
+
* Needs `ctx.prompt` (a TTY); headless callers use `CLAUDE_CODE_OAUTH_TOKEN`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function claudeLogin(ctx: ProviderAuthContext): Promise<ProviderOAuthResult>;
|
|
20
|
+
export declare function claudeLogout(ctx: ProviderAuthContext): Promise<boolean>;
|
|
21
|
+
export declare function claudeStatus(ctx: ProviderAuthContext): Promise<ProviderOAuthStatus | null>;
|
|
22
|
+
export interface FreshClaudeTokens {
|
|
23
|
+
readonly accessToken: string;
|
|
24
|
+
readonly expiresAt?: number;
|
|
25
|
+
/** True when a refresh_token is stored, so a 401 can be recovered. */
|
|
26
|
+
readonly canRefresh: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Read the stored Claude creds, refreshing first if the access token is near
|
|
30
|
+
* expiry and a refresh_token is available. Returns null when nothing is
|
|
31
|
+
* stored. Persists rotated tokens BEFORE returning so a crash can't strand a
|
|
32
|
+
* single-use refresh_token. The refresh itself is serialized per credential
|
|
33
|
+
* (in-process + cross-process) and coalesces with concurrent refreshers.
|
|
34
|
+
*/
|
|
35
|
+
export declare function ensureFreshClaudeTokens(vault: OAuthVault): Promise<FreshClaudeTokens | null>;
|
|
36
|
+
/**
|
|
37
|
+
* Force a refresh of the stored Claude tokens and persist the rotated bundle.
|
|
38
|
+
* Used as the provider's reactive 401 recovery. Throws if no refresh_token is
|
|
39
|
+
* stored (e.g. a pasted `setup-token`).
|
|
40
|
+
*/
|
|
41
|
+
export declare function refreshClaudeAccessToken(vault: OAuthVault): Promise<{
|
|
42
|
+
token: string;
|
|
43
|
+
expiresAt?: number;
|
|
44
|
+
}>;
|
|
45
|
+
export declare function __setClaudeFetch(f: typeof fetch): void;
|
|
46
|
+
export declare function __setClaudeOpenBrowser(f: (url: string) => Promise<void>): void;
|
|
47
|
+
export declare function __setClaudeSleep(f: (ms: number) => Promise<void>): void;
|
|
48
|
+
export declare function __setClaudeTimeoutMs(ms: number): void;
|
|
49
|
+
//# sourceMappingURL=login.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAaL,KAAK,UAAU,EAGhB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAepB;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAuFxF;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAM7E;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAUhG;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,sEAAsE;IACtE,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAalG;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAYhD;AA4ED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,KAAK,GAAG,IAAI,CAEtD;AAID,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAE9E;AAID,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAEvE;AAID,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAErD"}
|
package/dist/login.js
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude subscription login + token lifecycle.
|
|
3
|
+
*
|
|
4
|
+
* Claude's OAuth is an out-of-band (manual code-paste) authorization-code +
|
|
5
|
+
* PKCE flow whose token endpoint speaks JSON (not the form-encoded dialect
|
|
6
|
+
* the framework's `exchangeCodeForToken` / `refreshAccessToken` assume), so
|
|
7
|
+
* the HTTP exchange + refresh are implemented here. Everything else is reused
|
|
8
|
+
* from `@moxxy/plugin-oauth`: PKCE, the auth-URL builder, the browser opener,
|
|
9
|
+
* vault storage layout, and `parseTokenResponse`.
|
|
10
|
+
*/
|
|
11
|
+
import { buildAuthUrl, clearStoredCreds, computeCodeChallenge, generateCodeVerifier, generateState, isAuthRejection, isExpired, openInBrowser, parseTokenResponse, readStoredCreds, storeTokenSet, withCredentialLock, } from '@moxxy/plugin-oauth';
|
|
12
|
+
import { MoxxyError } from '@moxxy/sdk';
|
|
13
|
+
import { CLAUDE_AUTHORIZE_URL, CLAUDE_CLIENT_ID, CLAUDE_CODE_PROVIDER_ID, CLAUDE_CODE_SERVICE_NAME, CLAUDE_REDIRECT_URI, CLAUDE_SCOPES, CLAUDE_TOKEN_URL, } from './constants.js';
|
|
14
|
+
const PASTE_PROMPT = 'Paste a token from `claude setup-token` (or press Enter to sign in via browser): ';
|
|
15
|
+
const CODE_PROMPT = 'Paste the authorization code shown after you approve: ';
|
|
16
|
+
/**
|
|
17
|
+
* Drive an interactive Claude sign-in. Two ways in, both through one command:
|
|
18
|
+
* 1. paste an existing `claude setup-token` token (stored verbatim), or
|
|
19
|
+
* 2. press Enter to run the browser out-of-band authorization-code flow.
|
|
20
|
+
* Needs `ctx.prompt` (a TTY); headless callers use `CLAUDE_CODE_OAUTH_TOKEN`.
|
|
21
|
+
*/
|
|
22
|
+
export async function claudeLogin(ctx) {
|
|
23
|
+
if (!ctx.prompt) {
|
|
24
|
+
throw new MoxxyError({
|
|
25
|
+
code: 'OAUTH_FLOW_NOT_SUPPORTED',
|
|
26
|
+
message: 'Claude sign-in needs an interactive terminal.',
|
|
27
|
+
hint: 'Run `claude setup-token` and set CLAUDE_CODE_OAUTH_TOKEN, or run ' +
|
|
28
|
+
'`moxxy login claude-code` in a terminal.',
|
|
29
|
+
context: { provider: CLAUDE_CODE_PROVIDER_ID },
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const pasted = (await ctx.prompt(PASTE_PROMPT, { mask: true })).trim();
|
|
33
|
+
if (pasted) {
|
|
34
|
+
// A `setup-token` is a long-lived bearer with no refresh token; store it
|
|
35
|
+
// as-is. `isExpired` treats a missing expiry as non-expiring.
|
|
36
|
+
await storeTokenSet(ctx.vault, CLAUDE_CODE_PROVIDER_ID, { accessToken: pasted, tokenType: 'Bearer' }, { clientId: CLAUDE_CLIENT_ID, tokenUrl: CLAUDE_TOKEN_URL });
|
|
37
|
+
ctx.write('\nStored your Claude token.\n');
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
const verifier = generateCodeVerifier();
|
|
41
|
+
const challenge = computeCodeChallenge(verifier);
|
|
42
|
+
const state = generateState();
|
|
43
|
+
const authUrl = buildAuthUrl({
|
|
44
|
+
authUrl: CLAUDE_AUTHORIZE_URL,
|
|
45
|
+
clientId: CLAUDE_CLIENT_ID,
|
|
46
|
+
redirectUri: CLAUDE_REDIRECT_URI,
|
|
47
|
+
scopes: [...CLAUDE_SCOPES],
|
|
48
|
+
codeChallenge: challenge,
|
|
49
|
+
state,
|
|
50
|
+
extraAuthParams: { code: 'true' },
|
|
51
|
+
});
|
|
52
|
+
ctx.write(`\nSign in to ${CLAUDE_CODE_SERVICE_NAME} to authorize moxxy.\n\n` +
|
|
53
|
+
`If your browser doesn't open automatically, paste this URL:\n\n ${authUrl}\n\n` +
|
|
54
|
+
`After approving, copy the authorization code shown and paste it back here.\n` +
|
|
55
|
+
`(Anthropic's sign-in page sometimes shows "Internal server error" on the\n` +
|
|
56
|
+
` first attempt — just click "Try again" and it goes through.)\n\n`);
|
|
57
|
+
try {
|
|
58
|
+
await openBrowserImpl(authUrl);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Non-fatal — the user can open the URL surfaced above by hand.
|
|
62
|
+
}
|
|
63
|
+
// The authorization code is a single-use, exchangeable credential — mask it
|
|
64
|
+
// so it doesn't echo into scrollback / screen-share, matching the token paste.
|
|
65
|
+
const entered = (await ctx.prompt(CODE_PROMPT, { mask: true })).trim();
|
|
66
|
+
if (!entered) {
|
|
67
|
+
throw new MoxxyError({
|
|
68
|
+
code: 'AUTH_DENIED',
|
|
69
|
+
message: 'No authorization code entered — sign-in cancelled.',
|
|
70
|
+
context: { provider: CLAUDE_CODE_PROVIDER_ID },
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
// Anthropic returns `code#state`, but often shows just the bare code, so the
|
|
74
|
+
// state check below is best-effort: it only fires when a state was pasted.
|
|
75
|
+
// The real CSRF/code-injection defense is PKCE — the `code_verifier` binds
|
|
76
|
+
// the code to this client session, so a foreign code fails the exchange.
|
|
77
|
+
const hash = entered.indexOf('#');
|
|
78
|
+
const code = hash >= 0 ? entered.slice(0, hash) : entered;
|
|
79
|
+
const returnedState = hash >= 0 ? entered.slice(hash + 1) : '';
|
|
80
|
+
if (returnedState && returnedState !== state) {
|
|
81
|
+
throw new MoxxyError({
|
|
82
|
+
code: 'AUTH_INVALID',
|
|
83
|
+
message: 'Authorization state mismatch — please run sign-in again.',
|
|
84
|
+
context: { provider: CLAUDE_CODE_PROVIDER_ID },
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
const { tokenSet, accountEmail } = await exchangeClaudeCode(code, returnedState || state, verifier);
|
|
88
|
+
await persistClaudeTokens(ctx.vault, tokenSet, accountEmail);
|
|
89
|
+
ctx.write(`\nSigned in to Claude${accountEmail ? ` as ${accountEmail}` : ''}.\n`);
|
|
90
|
+
// Omit `expiresAt` when the credential never expires (setup-token paste, or a
|
|
91
|
+
// token response without `expires_in`). Surfacing `0` would read as "epoch =
|
|
92
|
+
// already expired" to the CLI status renderer, which only checks `!== undefined`.
|
|
93
|
+
return {
|
|
94
|
+
...(accountEmail ? { accountId: accountEmail } : {}),
|
|
95
|
+
...(tokenSet.expiresAt !== undefined ? { expiresAt: tokenSet.expiresAt } : {}),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export async function claudeLogout(ctx) {
|
|
99
|
+
try {
|
|
100
|
+
return (await clearStoredCreds(ctx.vault, CLAUDE_CODE_PROVIDER_ID)) > 0;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export async function claudeStatus(ctx) {
|
|
107
|
+
const stored = await readStoredCreds(ctx.vault, CLAUDE_CODE_PROVIDER_ID);
|
|
108
|
+
if (!stored)
|
|
109
|
+
return null;
|
|
110
|
+
return {
|
|
111
|
+
accountId: stored.extras.account_email ?? null,
|
|
112
|
+
// Omit when absent — a stored setup-token has no expiry, and `0` would be
|
|
113
|
+
// mis-rendered as "expired" (the CLI only treats `!== undefined` as set).
|
|
114
|
+
...(stored.tokenSet.expiresAt !== undefined ? { expiresAt: stored.tokenSet.expiresAt } : {}),
|
|
115
|
+
vaultKey: `oauth/${CLAUDE_CODE_PROVIDER_ID}/*`,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Read the stored Claude creds, refreshing first if the access token is near
|
|
120
|
+
* expiry and a refresh_token is available. Returns null when nothing is
|
|
121
|
+
* stored. Persists rotated tokens BEFORE returning so a crash can't strand a
|
|
122
|
+
* single-use refresh_token. The refresh itself is serialized per credential
|
|
123
|
+
* (in-process + cross-process) and coalesces with concurrent refreshers.
|
|
124
|
+
*/
|
|
125
|
+
export async function ensureFreshClaudeTokens(vault) {
|
|
126
|
+
const stored = await readStoredCreds(vault, CLAUDE_CODE_PROVIDER_ID);
|
|
127
|
+
if (!stored)
|
|
128
|
+
return null;
|
|
129
|
+
const { tokenSet } = stored;
|
|
130
|
+
if (tokenSet.refreshToken && isExpired(tokenSet)) {
|
|
131
|
+
const refreshed = await refreshClaudeUnderLock(vault, stored);
|
|
132
|
+
return { accessToken: refreshed.accessToken, ...(refreshed.expiresAt !== undefined ? { expiresAt: refreshed.expiresAt } : {}), canRefresh: true };
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
accessToken: tokenSet.accessToken,
|
|
136
|
+
...(tokenSet.expiresAt !== undefined ? { expiresAt: tokenSet.expiresAt } : {}),
|
|
137
|
+
canRefresh: tokenSet.refreshToken !== undefined,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Force a refresh of the stored Claude tokens and persist the rotated bundle.
|
|
142
|
+
* Used as the provider's reactive 401 recovery. Throws if no refresh_token is
|
|
143
|
+
* stored (e.g. a pasted `setup-token`).
|
|
144
|
+
*/
|
|
145
|
+
export async function refreshClaudeAccessToken(vault) {
|
|
146
|
+
const stored = await readStoredCreds(vault, CLAUDE_CODE_PROVIDER_ID);
|
|
147
|
+
if (!stored?.tokenSet.refreshToken) {
|
|
148
|
+
throw new MoxxyError({
|
|
149
|
+
code: 'AUTH_EXPIRED',
|
|
150
|
+
message: 'Claude token expired and no refresh_token is stored.',
|
|
151
|
+
hint: 'Run `moxxy login claude-code` again, or refresh `CLAUDE_CODE_OAUTH_TOKEN` via `claude setup-token`.',
|
|
152
|
+
context: { provider: CLAUDE_CODE_PROVIDER_ID },
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
const refreshed = await refreshClaudeUnderLock(vault, stored);
|
|
156
|
+
return { token: refreshed.accessToken, ...(refreshed.expiresAt !== undefined ? { expiresAt: refreshed.expiresAt } : {}) };
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Refresh + persist under the per-credential lock. Anthropic ROTATES the
|
|
160
|
+
* refresh_token on every refresh and invalidates the previous one, so two
|
|
161
|
+
* concurrent refreshes (a second consumer in this process, or another moxxy
|
|
162
|
+
* process — TUI alongside a desktop runner) must not both burn the same
|
|
163
|
+
* stored token. Under the lock we:
|
|
164
|
+
* 1. re-read the vault — if someone else already rotated and the new access
|
|
165
|
+
* token is still fresh, reuse it (coalesce; no IdP call at all);
|
|
166
|
+
* 2. otherwise refresh with the freshest stored refresh_token;
|
|
167
|
+
* 3. on an invalid_grant-style rejection, re-read once more — if the
|
|
168
|
+
* on-disk refresh_token changed under us (another process won a race we
|
|
169
|
+
* couldn't see), retry ONCE with the fresher token before declaring
|
|
170
|
+
* re-auth necessary.
|
|
171
|
+
*/
|
|
172
|
+
async function refreshClaudeUnderLock(vault, baseline) {
|
|
173
|
+
return withCredentialLock(`oauth-${CLAUDE_CODE_PROVIDER_ID}`, async () => {
|
|
174
|
+
const current = (await readStoredCreds(vault, CLAUDE_CODE_PROVIDER_ID)) ?? baseline;
|
|
175
|
+
if (current.tokenSet.accessToken !== baseline.tokenSet.accessToken && !isExpired(current.tokenSet)) {
|
|
176
|
+
return current.tokenSet;
|
|
177
|
+
}
|
|
178
|
+
const refreshToken = current.tokenSet.refreshToken ?? baseline.tokenSet.refreshToken;
|
|
179
|
+
if (!refreshToken) {
|
|
180
|
+
throw new MoxxyError({
|
|
181
|
+
code: 'AUTH_EXPIRED',
|
|
182
|
+
message: 'Claude token expired and no refresh_token is stored.',
|
|
183
|
+
hint: 'Run `moxxy login claude-code` again, or refresh `CLAUDE_CODE_OAUTH_TOKEN` via `claude setup-token`.',
|
|
184
|
+
context: { provider: CLAUDE_CODE_PROVIDER_ID },
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
const email = current.extras.account_email ?? baseline.extras.account_email;
|
|
188
|
+
try {
|
|
189
|
+
return await refreshAndPersist(vault, refreshToken, email);
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
if (isAuthRejection(err)) {
|
|
193
|
+
const latest = await readStoredCreds(vault, CLAUDE_CODE_PROVIDER_ID);
|
|
194
|
+
const latestRefresh = latest?.tokenSet.refreshToken;
|
|
195
|
+
if (latestRefresh && latestRefresh !== refreshToken) {
|
|
196
|
+
return refreshAndPersist(vault, latestRefresh, latest.extras.account_email ?? email);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
throw err;
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Anthropic's OAuth endpoints (both `claude.ai/oauth/authorize` and the token
|
|
205
|
+
* endpoint) intermittently return a transient HTTP 500 — the *same* request
|
|
206
|
+
* then succeeds on retry. So retry 5xx/429/network failures with a short
|
|
207
|
+
* backoff before giving up. 4xx (bad/expired/already-used code, invalid_grant)
|
|
208
|
+
* is deterministic and surfaced immediately, never retried.
|
|
209
|
+
*/
|
|
210
|
+
const TOKEN_POST_MAX_ATTEMPTS = 3;
|
|
211
|
+
const TOKEN_POST_BACKOFF_MS = [600, 1800];
|
|
212
|
+
/**
|
|
213
|
+
* Per-attempt deadline on the token POST. Node's `fetch` has NO default
|
|
214
|
+
* timeout, so a half-open TCP socket (server accepts but never responds — a
|
|
215
|
+
* stalled edge node, a black-holing proxy, a captive portal that keeps the
|
|
216
|
+
* connection alive) would hang the whole login/refresh indefinitely. Bound
|
|
217
|
+
* each attempt; a timeout aborts the request and is classed as a transient
|
|
218
|
+
* network error, so the retry loop tries again and ultimately surfaces the
|
|
219
|
+
* "endpoint kept failing" hint instead of wedging forever.
|
|
220
|
+
*/
|
|
221
|
+
const TOKEN_POST_TIMEOUT_MS = 30_000;
|
|
222
|
+
/** Test seam so the exchange/refresh can run against a fake fetch. */
|
|
223
|
+
let fetchImpl = fetch;
|
|
224
|
+
export function __setClaudeFetch(f) {
|
|
225
|
+
fetchImpl = f;
|
|
226
|
+
}
|
|
227
|
+
/** Test seam so the OOB login can run without launching a real browser. */
|
|
228
|
+
let openBrowserImpl = openInBrowser;
|
|
229
|
+
export function __setClaudeOpenBrowser(f) {
|
|
230
|
+
openBrowserImpl = f;
|
|
231
|
+
}
|
|
232
|
+
/** Test seam so the retry backoff doesn't actually sleep under test. */
|
|
233
|
+
let sleepImpl = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
234
|
+
export function __setClaudeSleep(f) {
|
|
235
|
+
sleepImpl = f;
|
|
236
|
+
}
|
|
237
|
+
/** Test seam to shrink the per-attempt network deadline (default {@link TOKEN_POST_TIMEOUT_MS}). */
|
|
238
|
+
let timeoutMs = TOKEN_POST_TIMEOUT_MS;
|
|
239
|
+
export function __setClaudeTimeoutMs(ms) {
|
|
240
|
+
timeoutMs = ms;
|
|
241
|
+
}
|
|
242
|
+
async function exchangeClaudeCode(code, state, verifier) {
|
|
243
|
+
return postClaudeToken({
|
|
244
|
+
grant_type: 'authorization_code',
|
|
245
|
+
code,
|
|
246
|
+
state,
|
|
247
|
+
client_id: CLAUDE_CLIENT_ID,
|
|
248
|
+
redirect_uri: CLAUDE_REDIRECT_URI,
|
|
249
|
+
code_verifier: verifier,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
async function refreshAndPersist(vault, refreshToken, priorEmail) {
|
|
253
|
+
const { tokenSet, accountEmail } = await postClaudeToken({
|
|
254
|
+
grant_type: 'refresh_token',
|
|
255
|
+
refresh_token: refreshToken,
|
|
256
|
+
client_id: CLAUDE_CLIENT_ID,
|
|
257
|
+
});
|
|
258
|
+
// Claude rotates the refresh_token on every refresh; if a response ever
|
|
259
|
+
// omits one, keep the prior so we don't lock ourselves out.
|
|
260
|
+
const merged = tokenSet.refreshToken
|
|
261
|
+
? tokenSet
|
|
262
|
+
: { ...tokenSet, refreshToken };
|
|
263
|
+
await persistClaudeTokens(vault, merged, accountEmail ?? priorEmail);
|
|
264
|
+
return merged;
|
|
265
|
+
}
|
|
266
|
+
async function persistClaudeTokens(vault, tokenSet, accountEmail) {
|
|
267
|
+
await storeTokenSet(vault, CLAUDE_CODE_PROVIDER_ID, tokenSet, {
|
|
268
|
+
clientId: CLAUDE_CLIENT_ID,
|
|
269
|
+
tokenUrl: CLAUDE_TOKEN_URL,
|
|
270
|
+
...(accountEmail ? { extras: { account_email: accountEmail } } : {}),
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
async function postClaudeToken(body) {
|
|
274
|
+
let transient = '';
|
|
275
|
+
for (let attempt = 1; attempt <= TOKEN_POST_MAX_ATTEMPTS; attempt++) {
|
|
276
|
+
if (attempt > 1)
|
|
277
|
+
await sleepImpl(TOKEN_POST_BACKOFF_MS[attempt - 2] ?? 1800);
|
|
278
|
+
let res;
|
|
279
|
+
try {
|
|
280
|
+
res = await fetchImpl(CLAUDE_TOKEN_URL, {
|
|
281
|
+
method: 'POST',
|
|
282
|
+
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
|
283
|
+
body: JSON.stringify(body),
|
|
284
|
+
// Bound a hung connection so it surfaces as a retryable network error
|
|
285
|
+
// (TimeoutError) rather than blocking the login/refresh forever.
|
|
286
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
transient = `network error (${err instanceof Error ? err.message : String(err)})`;
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (res.ok) {
|
|
294
|
+
// A captive portal / proxy / misbehaving edge can return 200 with an HTML
|
|
295
|
+
// or empty body, or a JSON primitive/array. Treat any of these as a
|
|
296
|
+
// transient and retry rather than letting a raw SyntaxError escape the
|
|
297
|
+
// retry/classify path.
|
|
298
|
+
let parsed;
|
|
299
|
+
try {
|
|
300
|
+
parsed = await res.json();
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
transient = 'HTTP 200 with non-JSON body';
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
307
|
+
transient = 'HTTP 200 with malformed token response';
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
const json = parsed;
|
|
311
|
+
return { tokenSet: parseTokenResponse(json), ...extractAccountEmail(json) };
|
|
312
|
+
}
|
|
313
|
+
const text = await res.text().catch(() => '');
|
|
314
|
+
// Deterministic client errors: surface immediately, don't burn retries.
|
|
315
|
+
if (res.status < 500 && res.status !== 429) {
|
|
316
|
+
throw new MoxxyError({
|
|
317
|
+
code: res.status === 401 || res.status === 403 ? 'AUTH_DENIED' : 'AUTH_INVALID',
|
|
318
|
+
message: `Claude token endpoint returned HTTP ${res.status}: ${text.slice(0, 300)}`,
|
|
319
|
+
context: { provider: CLAUDE_CODE_PROVIDER_ID, status: res.status },
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
// 5xx / 429 — Anthropic-side flake; loop and try the same request again.
|
|
323
|
+
transient = `HTTP ${res.status}: ${text.slice(0, 200)}`;
|
|
324
|
+
}
|
|
325
|
+
throw new MoxxyError({
|
|
326
|
+
code: 'AUTH_INVALID',
|
|
327
|
+
message: `Claude token endpoint kept failing after ${TOKEN_POST_MAX_ATTEMPTS} attempts (last: ${transient}).`,
|
|
328
|
+
hint: "Anthropic's OAuth endpoint is returning transient errors right now — " +
|
|
329
|
+
'wait a few seconds and run `moxxy login claude-code` again.',
|
|
330
|
+
context: { provider: CLAUDE_CODE_PROVIDER_ID },
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
function extractAccountEmail(json) {
|
|
334
|
+
const account = json.account;
|
|
335
|
+
if (account && typeof account === 'object') {
|
|
336
|
+
const email = account.email_address;
|
|
337
|
+
if (typeof email === 'string' && email)
|
|
338
|
+
return { accountEmail: email };
|
|
339
|
+
}
|
|
340
|
+
return {};
|
|
341
|
+
}
|
|
342
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Claude subscription provider is the standard Anthropic Messages API
|
|
3
|
+
* with a bearer (OAuth) credential instead of an API key, so it reuses
|
|
4
|
+
* `AnthropicProvider` in OAuth mode rather than duplicating the streaming /
|
|
5
|
+
* tool-call event handling. This module just stamps in the Claude-specific
|
|
6
|
+
* constants (beta headers + the required identity preamble) and forwards the
|
|
7
|
+
* resolved token + refresh callback.
|
|
8
|
+
*/
|
|
9
|
+
import { AnthropicProvider } from '@moxxy/plugin-provider-anthropic';
|
|
10
|
+
export interface ClaudeCodeProviderConfig {
|
|
11
|
+
/** Claude Code OAuth access token (bearer). Resolved by the host. */
|
|
12
|
+
readonly oauthToken?: string;
|
|
13
|
+
/** Epoch-ms expiry of `oauthToken`, when known (drives proactive refresh). */
|
|
14
|
+
readonly oauthExpiresAt?: number;
|
|
15
|
+
/** Refresh callback wired by the host; omitted for non-refreshable tokens. */
|
|
16
|
+
readonly oauthRefresh?: () => Promise<{
|
|
17
|
+
readonly token: string;
|
|
18
|
+
readonly expiresAt?: number;
|
|
19
|
+
}>;
|
|
20
|
+
/** Optional default model override. */
|
|
21
|
+
readonly defaultModel?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function createClaudeCodeClient(config?: ClaudeCodeProviderConfig): AnthropicProvider;
|
|
24
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAGrE,MAAM,WAAW,wBAAwB;IACvC,qEAAqE;IACrE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/F,uCAAuC;IACvC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,wBAAgB,sBAAsB,CAAC,MAAM,GAAE,wBAA6B,GAAG,iBAAiB,CAU/F"}
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Claude subscription provider is the standard Anthropic Messages API
|
|
3
|
+
* with a bearer (OAuth) credential instead of an API key, so it reuses
|
|
4
|
+
* `AnthropicProvider` in OAuth mode rather than duplicating the streaming /
|
|
5
|
+
* tool-call event handling. This module just stamps in the Claude-specific
|
|
6
|
+
* constants (beta headers + the required identity preamble) and forwards the
|
|
7
|
+
* resolved token + refresh callback.
|
|
8
|
+
*/
|
|
9
|
+
import { AnthropicProvider } from '@moxxy/plugin-provider-anthropic';
|
|
10
|
+
import { CLAUDE_CODE_PROVIDER_ID, CLAUDE_CODE_SYSTEM, CLAUDE_OAUTH_BETA } from './constants.js';
|
|
11
|
+
export function createClaudeCodeClient(config = {}) {
|
|
12
|
+
return new AnthropicProvider({
|
|
13
|
+
name: CLAUDE_CODE_PROVIDER_ID,
|
|
14
|
+
oauthBeta: [...CLAUDE_OAUTH_BETA],
|
|
15
|
+
systemPreamble: CLAUDE_CODE_SYSTEM,
|
|
16
|
+
...(config.oauthToken ? { oauthToken: config.oauthToken } : {}),
|
|
17
|
+
...(config.oauthExpiresAt !== undefined ? { oauthExpiresAt: config.oauthExpiresAt } : {}),
|
|
18
|
+
...(config.oauthRefresh ? { oauthRefresh: config.oauthRefresh } : {}),
|
|
19
|
+
...(config.defaultModel ? { defaultModel: config.defaultModel } : {}),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAahG,MAAM,UAAU,sBAAsB,CAAC,SAAmC,EAAE;IAC1E,OAAO,IAAI,iBAAiB,CAAC;QAC3B,IAAI,EAAE,uBAAuB;QAC7B,SAAS,EAAE,CAAC,GAAG,iBAAiB,CAAC;QACjC,cAAc,EAAE,kBAAkB;QAClC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,GAAG,CAAC,MAAM,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzF,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtE,CAAC,CAAC;AACL,CAAC"}
|