useclaudeproxy 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +120 -0
- package/dist/app.d.ts +2 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +47 -0
- package/dist/app.js.map +1 -0
- package/dist/args.d.ts +17 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +37 -0
- package/dist/args.js.map +1 -0
- package/dist/config-yaml.d.ts +5 -0
- package/dist/config-yaml.d.ts.map +1 -0
- package/dist/config-yaml.js +26 -0
- package/dist/config-yaml.js.map +1 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +29 -0
- package/dist/config.js.map +1 -0
- package/dist/http-client.d.ts +10 -0
- package/dist/http-client.d.ts.map +1 -0
- package/dist/http-client.js +33 -0
- package/dist/http-client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/install-cli-proxy.d.ts +2 -0
- package/dist/install-cli-proxy.d.ts.map +1 -0
- package/dist/install-cli-proxy.js +140 -0
- package/dist/install-cli-proxy.js.map +1 -0
- package/dist/providers/hermes.d.ts +15 -0
- package/dist/providers/hermes.d.ts.map +1 -0
- package/dist/providers/hermes.js +210 -0
- package/dist/providers/hermes.js.map +1 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +11 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/types.d.ts +7 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/run-cli-proxy.d.ts +2 -0
- package/dist/run-cli-proxy.d.ts.map +1 -0
- package/dist/run-cli-proxy.js +22 -0
- package/dist/run-cli-proxy.js.map +1 -0
- package/dist/types.d.ts +31 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +23 -0
- package/dist/types.js.map +1 -0
- package/dist/yaml.example.d.ts +2 -0
- package/dist/yaml.example.d.ts.map +1 -0
- package/dist/yaml.example.js +141 -0
- package/dist/yaml.example.js.map +1 -0
- package/package.json +96 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Meisam Maani
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# useclaudeproxy
|
|
2
|
+
|
|
3
|
+
A TypeScript CLI (`useclaudeproxy`) that authenticates the **Hermes CLI** against
|
|
4
|
+
[Nous Research](https://nousresearch.com) via OAuth 2.0 Device Authorization
|
|
5
|
+
Grant, then downloads, configures, and runs
|
|
6
|
+
[`CLIProxyAPI`](https://github.com/router-for-me/CLIProxyAPI) — a local
|
|
7
|
+
OpenAI / Gemini / Claude / Codex compatible proxy — wired with the token it
|
|
8
|
+
just obtained.
|
|
9
|
+
|
|
10
|
+
In short: run one command, complete the device-flow login in your browser, and
|
|
11
|
+
you get a local proxy endpoint that Claude Code (or any OpenAI-compatible
|
|
12
|
+
client) can talk to.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Install as a CLI
|
|
17
|
+
|
|
18
|
+
This repo uses **pnpm**.
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
git clone https://github.com/maanimeisam/useclaudeproxy.git
|
|
22
|
+
cd useclaudeproxy
|
|
23
|
+
npm install
|
|
24
|
+
npm run build # tsc → dist/index.js (the useclaudeproxy bin)
|
|
25
|
+
npm link # exposes `useclaudeproxy` on your PATH
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
After linking you can run `useclaudeproxy` from anywhere.
|
|
29
|
+
|
|
30
|
+
## How it works
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
useclaudeproxy --model <model>
|
|
34
|
+
│
|
|
35
|
+
├─ 1. ensureCliProxy() download CLIProxyAPI (pinned v7.2.142) from GitHub → tools/
|
|
36
|
+
├─ 2. getValidToken() use stored token ──refresh──▶ run device flow
|
|
37
|
+
│ │ (portal.nousresearch.com)
|
|
38
|
+
│ ▼
|
|
39
|
+
├─ 3. getAccountInfo() verify the token, print account info
|
|
40
|
+
├─ 4. setProxyUrl() apply --proxy to tools/config.yaml
|
|
41
|
+
└─ 5. runCliProxy() spawn cli-proxy-api -config tools/config.yaml
|
|
42
|
+
+ watch loop transparently refresh the token while it runs
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Tokens are persisted at `data/tokens.json` (mode `0o600`). On every refresh the
|
|
46
|
+
provider token is re-injected into `tools/config.yaml` so the proxy keeps
|
|
47
|
+
working without manual re-entry.
|
|
48
|
+
|
|
49
|
+
## Requirements
|
|
50
|
+
|
|
51
|
+
- **Node.js** ≥ 18
|
|
52
|
+
- **npm** (package manager)
|
|
53
|
+
- One of: Linux (`amd64` / `aarch64`), macOS, Windows, FreeBSD (the binary is
|
|
54
|
+
fetched per-platform from the CLIProxyAPI release)
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
The only required flag is `--model` — the upstream model name you want to
|
|
59
|
+
expose through the proxy.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Run the device flow, start the proxy, and keep the token fresh.
|
|
63
|
+
useclaudeproxy --model stealth/ox-alpha
|
|
64
|
+
|
|
65
|
+
# Same thing, routing the proxy's own upstream traffic through a proxy:
|
|
66
|
+
useclaudeproxy --proxy http://127.0.0.1:2080 --model stealth/ox-alpha
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
On success the CLI prints the env vars to point Claude Code at the local proxy:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
export ANTHROPIC_MODEL=claude-opus-5
|
|
73
|
+
export ANTHROPIC_BASE_URL=http://127.0.0.1:8317
|
|
74
|
+
export ANTHROPIC_AUTH_TOKEN=456789
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Global flags
|
|
78
|
+
|
|
79
|
+
These work in **any position** — before or after the command.
|
|
80
|
+
|
|
81
|
+
| Flag | Default | Notes |
|
|
82
|
+
| ------------------- | ------------------ | ------------------------------------------------------------- |
|
|
83
|
+
| `--model <model>` | _(required)_ | Model name to expose in OpenAI compatibility. |
|
|
84
|
+
| `--provider <name>` | `hermes` | OAuth provider to use (hermes only, for now). |
|
|
85
|
+
| `--node-env <env>` | `development` | `development` \| `production`. |
|
|
86
|
+
| `--debug <ns>` | `useclaudeproxy:*` | `debug` namespaces, e.g. `useclaudeproxy:oauth`. |
|
|
87
|
+
| `--data-dir <dir>` | `data` | Token storage directory. |
|
|
88
|
+
| `--proxy <url>` | `""` | CLIProxyAPI outbound proxy (`""`\|`direct`\|`none` to clear). |
|
|
89
|
+
| `--force` | `false` | Re-download the binary even if already installed. |
|
|
90
|
+
| `--renew` | `false` | Re-extract from the kept archive and re-run the device flow. |
|
|
91
|
+
|
|
92
|
+
Example with position-independent flags:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
useclaudeproxy --data-dir ~/.useclaudeproxy --debug useclaudeproxy:oauth --model stealth/ox-alpha
|
|
96
|
+
# is equivalent to
|
|
97
|
+
useclaudeproxy --model stealth/ox-alpha --data-dir ~/.useclaudeproxy --debug useclaudeproxy:oauth
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Notes
|
|
101
|
+
|
|
102
|
+
- This repo contains the **TS orchestration app** (`src/`). The actual proxy is
|
|
103
|
+
the third-party `cli-proxy-api` binary fetched from the
|
|
104
|
+
[CLIProxyAPI releases](https://github.com/router-for-me/CLIProxyAPI/releases)
|
|
105
|
+
— it is not part of the TS build.
|
|
106
|
+
- Two independent "proxy" concepts: the TS app's OAuth calls can use an outbound
|
|
107
|
+
proxy (`--proxy`), and the binary has its own separate `proxy-url` for upstream
|
|
108
|
+
provider traffic. They do not affect each other.
|
|
109
|
+
- Providers are pluggable. `hermes` is registered in `src/providers/index.ts`;
|
|
110
|
+
add another by implementing the `Provider` interface in `src/providers/types.ts`.
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT — see [LICENSE](LICENSE).
|
|
115
|
+
|
|
116
|
+
## Acknowledgements
|
|
117
|
+
|
|
118
|
+
- [**router-for-me/CLIProxyAPI**](https://github.com/router-for-me/CLIProxyAPI)
|
|
119
|
+
— the local OpenAI/Gemini/Claude/Codex-compatible proxy binary this tool
|
|
120
|
+
downloads, configures, and runs. Licensed MIT.
|
package/dist/app.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAwBA,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAiCzC"}
|
package/dist/app.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import Debug from "debug";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { args } from "./args.js";
|
|
4
|
+
import { setProxyUrl } from "./config-yaml.js";
|
|
5
|
+
import { TOKENS_PATH, WATCH_INTERVAL_MS } from "./config.js";
|
|
6
|
+
import { ensureCliProxy } from "./install-cli-proxy.js";
|
|
7
|
+
import { getProvider } from "./providers/index.js";
|
|
8
|
+
import { runCliProxy } from "./run-cli-proxy.js";
|
|
9
|
+
const log = Debug("useclaudeproxy:oauth");
|
|
10
|
+
const errorLog = Debug("useclaudeproxy:oauth:error");
|
|
11
|
+
function sleep(ms) {
|
|
12
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
13
|
+
}
|
|
14
|
+
// Clear the stored token so the next getValidToken() re-runs the device flow.
|
|
15
|
+
function clearStoredToken() {
|
|
16
|
+
if (fs.existsSync(TOKENS_PATH)) {
|
|
17
|
+
fs.rmSync(TOKENS_PATH, { force: true });
|
|
18
|
+
log("--renew: cleared stored token");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export async function app() {
|
|
22
|
+
const provider = getProvider(args.activeProvider);
|
|
23
|
+
log("Starting %s OAuth Device Flow", provider.name);
|
|
24
|
+
await ensureCliProxy();
|
|
25
|
+
// if (args.renew) clearStoredToken();
|
|
26
|
+
const token = await provider.getValidToken();
|
|
27
|
+
const account = await provider.getAccountInfo(token.access_token);
|
|
28
|
+
log("Account Information:\n" + JSON.stringify(account, null, 2));
|
|
29
|
+
setProxyUrl(args.proxy);
|
|
30
|
+
runCliProxy()
|
|
31
|
+
.then((code) => process.exit(code))
|
|
32
|
+
.catch((err) => {
|
|
33
|
+
errorLog("Failed to run CLIProxyAPI: %o", err);
|
|
34
|
+
console.error(err);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
});
|
|
37
|
+
log("Watching token every %dms", WATCH_INTERVAL_MS);
|
|
38
|
+
let current = token.access_token;
|
|
39
|
+
while (true) {
|
|
40
|
+
await sleep(WATCH_INTERVAL_MS);
|
|
41
|
+
const refreshed = await provider.getValidToken();
|
|
42
|
+
const renewed = refreshed.access_token !== current;
|
|
43
|
+
current = refreshed.access_token;
|
|
44
|
+
log(`Token ${renewed ? "RENEWED" : "valid"} (expires_in=${refreshed.expires_in})`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=app.js.map
|
package/dist/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAiB,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,GAAG,GAAG,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAC1C,MAAM,QAAQ,GAAG,KAAK,CAAC,4BAA4B,CAAC,CAAC;AAErD,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,8EAA8E;AAC9E,SAAS,gBAAgB;IACvB,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/B,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG;IACvB,MAAM,QAAQ,GAAa,WAAW,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC5D,GAAG,CAAC,+BAA+B,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IAEpD,MAAM,cAAc,EAAE,CAAC;IAEvB,sCAAsC;IAEtC,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,CAAC;IAE7C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAClE,GAAG,CAAC,wBAAwB,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAEjE,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxB,WAAW,EAAE;SACV,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SAClC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACb,QAAQ,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAC;QAC/C,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEL,GAAG,CAAC,2BAA2B,EAAE,iBAAiB,CAAC,CAAC;IACpD,IAAI,OAAO,GAAG,KAAK,CAAC,YAAY,CAAC;IACjC,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAC/B,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,CAAC;QACjD,MAAM,OAAO,GAAG,SAAS,CAAC,YAAY,KAAK,OAAO,CAAC;QACnD,OAAO,GAAG,SAAS,CAAC,YAAY,CAAC;QACjC,GAAG,CACD,SAAS,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,gBAAgB,SAAS,CAAC,UAAU,GAAG,CAC9E,CAAC;IACJ,CAAC;AACH,CAAC"}
|
package/dist/args.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const PROVIDERS: string[];
|
|
2
|
+
interface CliArgs {
|
|
3
|
+
force: boolean;
|
|
4
|
+
nodeEnv: string;
|
|
5
|
+
debug: string;
|
|
6
|
+
dataDir: string;
|
|
7
|
+
proxy: string;
|
|
8
|
+
renew: boolean;
|
|
9
|
+
activeProvider: string;
|
|
10
|
+
provider?: string;
|
|
11
|
+
token?: string;
|
|
12
|
+
proxyUrl?: string;
|
|
13
|
+
model: string;
|
|
14
|
+
}
|
|
15
|
+
export declare const args: CliArgs;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=args.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS,UAAgC,CAAC;AAEvD,UAAU,OAAO;IACf,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAiED,eAAO,MAAM,IAAI,SAAM,CAAC"}
|
package/dist/args.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
export const PROVIDERS = ["claude", "gemini", "codex"];
|
|
3
|
+
const program = new Command();
|
|
4
|
+
program
|
|
5
|
+
.name("useclaudeproxy")
|
|
6
|
+
.description("Hermes OAuth Device Flow")
|
|
7
|
+
.option("--node-env <env>", "development | production", "development")
|
|
8
|
+
.option("--debug <ns>", 'debug namespaces, e.g. "useclaudeproxy:*"', "useclaudeproxy:*")
|
|
9
|
+
.option("--data-dir <dir>", "token storage directory", "data")
|
|
10
|
+
.requiredOption("--model <model>", "model name to expose in openai-compatibility")
|
|
11
|
+
.option("--proxy <url>", 'CLIProxyAPI outbound proxy (omit for "", or ""|direct|none to clear)')
|
|
12
|
+
.option("--provider <name>", "OAuth provider to use (default: hermes)", "hermes")
|
|
13
|
+
.option("--force", "re-download CLIProxyAPI even if already installed")
|
|
14
|
+
.option("--renew", "re-extract from the kept archive and re-run device flow")
|
|
15
|
+
.parse();
|
|
16
|
+
const cli = {
|
|
17
|
+
force: false,
|
|
18
|
+
nodeEnv: "development",
|
|
19
|
+
debug: "useclaudeproxy:*",
|
|
20
|
+
dataDir: "data",
|
|
21
|
+
proxy: "",
|
|
22
|
+
renew: false,
|
|
23
|
+
activeProvider: "hermes",
|
|
24
|
+
model: "",
|
|
25
|
+
};
|
|
26
|
+
const opts = program.opts();
|
|
27
|
+
process.env.DEBUG = opts.debug;
|
|
28
|
+
cli.nodeEnv = opts.nodeEnv;
|
|
29
|
+
cli.debug = opts.debug;
|
|
30
|
+
cli.dataDir = opts.dataDir;
|
|
31
|
+
cli.proxy = opts.proxy ?? "";
|
|
32
|
+
cli.model = opts.model;
|
|
33
|
+
cli.force = opts.force;
|
|
34
|
+
cli.renew = opts.renew;
|
|
35
|
+
cli.activeProvider = opts.provider;
|
|
36
|
+
export const args = cli;
|
|
37
|
+
//# sourceMappingURL=args.js.map
|
package/dist/args.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAgBvD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,gBAAgB,CAAC;KACtB,WAAW,CAAC,0BAA0B,CAAC;KACvC,MAAM,CAAC,kBAAkB,EAAE,0BAA0B,EAAE,aAAa,CAAC;KACrE,MAAM,CACL,cAAc,EACd,2CAA2C,EAC3C,kBAAkB,CACnB;KACA,MAAM,CAAC,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,CAAC;KAC7D,cAAc,CACb,iBAAiB,EACjB,8CAA8C,CAC/C;KACA,MAAM,CACL,eAAe,EACf,sEAAsE,CACvE;KACA,MAAM,CACL,mBAAmB,EACnB,yCAAyC,EACzC,QAAQ,CACT;KACA,MAAM,CAAC,SAAS,EAAE,mDAAmD,CAAC;KACtE,MAAM,CAAC,SAAS,EAAE,yDAAyD,CAAC;KAC5E,KAAK,EAAE,CAAC;AAEX,MAAM,GAAG,GAAY;IACnB,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE,aAAa;IACtB,KAAK,EAAE,kBAAkB;IACzB,OAAO,EAAE,MAAM;IACf,KAAK,EAAE,EAAE;IACT,KAAK,EAAE,KAAK;IACZ,cAAc,EAAE,QAAQ;IACxB,KAAK,EAAE,EAAE;CACV,CAAC;AAEF,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAWxB,CAAC;AAEF,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;AAC/B,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;AAC3B,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;AACvB,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;AAC3B,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;AAC7B,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;AACvB,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;AACvB,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;AACvB,GAAG,CAAC,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC;AAEnC,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const CONFIG_PATH: string;
|
|
2
|
+
export declare function readConfig(filePath?: string): Record<string, any>;
|
|
3
|
+
export declare function writeConfig(config: Record<string, any>, filePath?: string): void;
|
|
4
|
+
export declare function setProxyUrl(proxyUrl: string): void;
|
|
5
|
+
//# sourceMappingURL=config-yaml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-yaml.d.ts","sourceRoot":"","sources":["../src/config-yaml.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,WAAW,QAKvB,CAAC;AAEF,wBAAgB,UAAU,CACxB,QAAQ,GAAE,MAAoB,GAC7B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAQrB;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,QAAQ,GAAE,MAAoB,GAC7B,IAAI,CAGN;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAalD"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import YAML from "yaml";
|
|
4
|
+
let cache;
|
|
5
|
+
export const CONFIG_PATH = path.join(import.meta.dirname, "..", "tools", "config.yaml");
|
|
6
|
+
export function readConfig(filePath = CONFIG_PATH) {
|
|
7
|
+
if (!cache) {
|
|
8
|
+
cache = (YAML.parse(fs.readFileSync(filePath, "utf8")) ?? {});
|
|
9
|
+
}
|
|
10
|
+
return cache;
|
|
11
|
+
}
|
|
12
|
+
export function writeConfig(config, filePath = CONFIG_PATH) {
|
|
13
|
+
fs.writeFileSync(filePath, YAML.stringify(config), "utf8");
|
|
14
|
+
cache = config;
|
|
15
|
+
}
|
|
16
|
+
export function setProxyUrl(proxyUrl) {
|
|
17
|
+
const url = proxyUrl.trim();
|
|
18
|
+
const PROXY_RE = /^(socks5|http|https):\/\//i;
|
|
19
|
+
if (url !== "" && !/^(direct|none)$/i.test(url) && !PROXY_RE.test(url)) {
|
|
20
|
+
throw new Error(`Invalid proxy-url: ${url} (use http/https/socks5://..., "direct", "none", or "")`);
|
|
21
|
+
}
|
|
22
|
+
const config = readConfig();
|
|
23
|
+
config["proxy-url"] = url;
|
|
24
|
+
writeConfig(config);
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=config-yaml.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-yaml.js","sourceRoot":"","sources":["../src/config-yaml.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,IAAI,KAAsC,CAAC;AAC3C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAClC,OAAO,IAAI,CAAC,OAAO,EACnB,IAAI,EACJ,OAAO,EACP,aAAa,CACd,CAAC;AAEF,MAAM,UAAU,UAAU,CACxB,QAAQ,GAAW,WAAW;IAE9B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAG3D,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,MAA2B,EAC3B,QAAQ,GAAW,WAAW;IAE9B,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IAC3D,KAAK,GAAG,MAAM,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC5B,MAAM,QAAQ,GAAG,4BAA4B,CAAC;IAE9C,IAAI,GAAG,KAAK,EAAE,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACvE,MAAM,IAAI,KAAK,CACb,sBAAsB,GAAG,yDAAyD,CACnF,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,CAAC,WAAW,CAAC,GAAG,GAAG,CAAC;IAC1B,WAAW,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const config: Readonly<{
|
|
2
|
+
NODE_ENV: "development" | "production";
|
|
3
|
+
DATA_DIR: string;
|
|
4
|
+
DEBUG?: string | undefined;
|
|
5
|
+
}>;
|
|
6
|
+
export type Config = typeof config;
|
|
7
|
+
export declare const TOKENS_PATH: string;
|
|
8
|
+
export declare const WATCH_INTERVAL_MS = 7000;
|
|
9
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AA0BA,eAAO,MAAM,MAAM;;;;EAAgC,CAAC;AACpD,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC;AAKnC,eAAO,MAAM,WAAW,QAA4C,CAAC;AACrE,eAAO,MAAM,iBAAiB,OAAO,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { args } from "./args.js";
|
|
5
|
+
// All config is supplied via CLI flags (see args.ts). Validated with zod and
|
|
6
|
+
// frozen. Importing this module also creates DATA_DIR.
|
|
7
|
+
const envSchema = z.object({
|
|
8
|
+
NODE_ENV: z.enum(["development", "production"]).default("development"),
|
|
9
|
+
DATA_DIR: z.string().default("data"),
|
|
10
|
+
DEBUG: z.string().optional(),
|
|
11
|
+
// Proxy
|
|
12
|
+
});
|
|
13
|
+
const parsedEnv = envSchema.safeParse({
|
|
14
|
+
NODE_ENV: args.nodeEnv,
|
|
15
|
+
DATA_DIR: args.dataDir,
|
|
16
|
+
DEBUG: args.debug,
|
|
17
|
+
});
|
|
18
|
+
if (!parsedEnv.success) {
|
|
19
|
+
console.error("❌ Invalid arguments:");
|
|
20
|
+
console.error(z.prettifyError(parsedEnv.error));
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
export const config = Object.freeze(parsedEnv.data);
|
|
24
|
+
fs.mkdirSync(config.DATA_DIR, { recursive: true });
|
|
25
|
+
// Shared token-storage path. Which provider wrote it is the provider's concern;
|
|
26
|
+
// where it lives on disk is core infra.
|
|
27
|
+
export const TOKENS_PATH = path.join(config.DATA_DIR, "tokens.json");
|
|
28
|
+
export const WATCH_INTERVAL_MS = 7000;
|
|
29
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,6EAA6E;AAC7E,uDAAuD;AACvD,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;IACtE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;IACpC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAE5B,QAAQ;CACT,CAAC,CAAC;AAEH,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC;IACpC,QAAQ,EAAE,IAAI,CAAC,OAAO;IACtB,QAAQ,EAAE,IAAI,CAAC,OAAO;IACtB,KAAK,EAAE,IAAI,CAAC,KAAK;CAClB,CAAC,CAAC;AACH,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;IACvB,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACtC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;AAEpD,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAEnD,gFAAgF;AAChF,wCAAwC;AACxC,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;AACrE,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Got } from "got";
|
|
2
|
+
/**
|
|
3
|
+
* Builds a `got` instance configured for the upstream OAuth provider,
|
|
4
|
+
* optionally routed through the configured HTTP(S) proxy.
|
|
5
|
+
*
|
|
6
|
+
* This module has one job: produce a correctly-configured HTTP client.
|
|
7
|
+
* It knows nothing about OAuth flows, device codes, or polling.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createOAuthHttpClient(): Got;
|
|
10
|
+
//# sourceMappingURL=http-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"AACA,OAAY,EAAsB,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAOxD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,IAAI,GAAG,CAa3C"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import Debug from "debug";
|
|
2
|
+
import got from "got";
|
|
3
|
+
import { HttpProxyAgent } from "http-proxy-agent";
|
|
4
|
+
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
5
|
+
import { args } from "./args.js";
|
|
6
|
+
const log = Debug("app:proxy:upstream-client");
|
|
7
|
+
/**
|
|
8
|
+
* Builds a `got` instance configured for the upstream OAuth provider,
|
|
9
|
+
* optionally routed through the configured HTTP(S) proxy.
|
|
10
|
+
*
|
|
11
|
+
* This module has one job: produce a correctly-configured HTTP client.
|
|
12
|
+
* It knows nothing about OAuth flows, device codes, or polling.
|
|
13
|
+
*/
|
|
14
|
+
export function createOAuthHttpClient() {
|
|
15
|
+
log("Proxy=%s", args.proxy);
|
|
16
|
+
const options = {
|
|
17
|
+
https: { rejectUnauthorized: false },
|
|
18
|
+
headers: { "Content-Type": "application/json" },
|
|
19
|
+
retry: { limit: 0 },
|
|
20
|
+
throwHttpErrors: false,
|
|
21
|
+
timeout: { request: undefined },
|
|
22
|
+
...(args.proxy ? { agent: buildProxyAgents() } : {}),
|
|
23
|
+
};
|
|
24
|
+
return got.extend(options);
|
|
25
|
+
}
|
|
26
|
+
function buildProxyAgents() {
|
|
27
|
+
const agentOptions = { keepAlive: true, keepAliveMsecs: 30_000 };
|
|
28
|
+
return {
|
|
29
|
+
http: new HttpProxyAgent(args.proxy, agentOptions),
|
|
30
|
+
https: new HttpsProxyAgent(args.proxy, agentOptions),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=http-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAqC,MAAM,KAAK,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,GAAG,GAAG,KAAK,CAAC,2BAA2B,CAAC,CAAC;AAE/C;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB;IACnC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAE5B,MAAM,OAAO,GAAkB;QAC7B,KAAK,EAAE,EAAE,kBAAkB,EAAE,KAAK,EAAE;QACpC,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE;QACnB,eAAe,EAAE,KAAK;QACtB,OAAO,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE;QAC/B,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrD,CAAC;IAEF,OAAO,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,gBAAgB;IACvB,MAAM,YAAY,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC;IAEjE,OAAO;QACL,IAAI,EAAE,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC;QAClD,KAAK,EAAE,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC;KACrD,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import Debug from "debug";
|
|
3
|
+
import { app } from "./app.js";
|
|
4
|
+
import { config } from "./config.js";
|
|
5
|
+
import { AccessDeniedError, DeviceCodeExpiredError, OAuthHttpError, } from "./types.js";
|
|
6
|
+
const log = Debug("useclaudeproxy:oauth");
|
|
7
|
+
const errorLog = Debug("useclaudeproxy:oauth:error");
|
|
8
|
+
log("Enviroment: %s", config.NODE_ENV);
|
|
9
|
+
if (config.NODE_ENV === "development" && config.DEBUG)
|
|
10
|
+
Debug.enable(config.DEBUG);
|
|
11
|
+
app().catch((err) => {
|
|
12
|
+
if (err instanceof DeviceCodeExpiredError ||
|
|
13
|
+
err instanceof AccessDeniedError) {
|
|
14
|
+
errorLog(err.message);
|
|
15
|
+
console.error(err.message);
|
|
16
|
+
}
|
|
17
|
+
else if (err instanceof OAuthHttpError) {
|
|
18
|
+
errorLog("OAuth request failed: %s (status=%d) body=%o", err.message, err.statusCode, err.body);
|
|
19
|
+
console.error(err.message);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
errorLog("Fatal error: %o", err);
|
|
23
|
+
console.error(err);
|
|
24
|
+
}
|
|
25
|
+
process.exit(1);
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB,MAAM,GAAG,GAAG,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAC1C,MAAM,QAAQ,GAAG,KAAK,CAAC,4BAA4B,CAAC,CAAC;AAErD,GAAG,CAAC,gBAAgB,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;AACvC,IAAI,MAAM,CAAC,QAAQ,KAAK,aAAa,IAAI,MAAM,CAAC,KAAK;IACnD,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAE7B,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAClB,IACE,GAAG,YAAY,sBAAsB;QACrC,GAAG,YAAY,iBAAiB,EAChC,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;SAAM,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;QACzC,QAAQ,CACN,8CAA8C,EAC9C,GAAG,CAAC,OAAO,EACX,GAAG,CAAC,UAAU,EACd,GAAG,CAAC,IAAI,CACT,CAAC;QACF,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;SAAM,CAAC;QACN,QAAQ,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;QACjC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-cli-proxy.d.ts","sourceRoot":"","sources":["../src/install-cli-proxy.ts"],"names":[],"mappings":"AA8EA,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CA0CpD"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import Debug from "debug";
|
|
2
|
+
import got from "got";
|
|
3
|
+
import cp from "node:child_process";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { pipeline } from "node:stream/promises";
|
|
8
|
+
import { args } from "./args.js";
|
|
9
|
+
import { CONFIG_PATH } from "./config-yaml.js";
|
|
10
|
+
import { TOKENS_PATH } from "./config.js";
|
|
11
|
+
const log = Debug("app:install");
|
|
12
|
+
const VERSION = "7.2.142";
|
|
13
|
+
const RELEASE_BASE = `https://github.com/router-for-me/CLIProxyAPI/releases/download/v${VERSION}`;
|
|
14
|
+
const TOOLS_DIR = path.join(import.meta.dirname, "..", "tools");
|
|
15
|
+
function pickAsset() {
|
|
16
|
+
const p = os.platform();
|
|
17
|
+
const a = os.arch();
|
|
18
|
+
let platform;
|
|
19
|
+
let ext;
|
|
20
|
+
switch (p) {
|
|
21
|
+
case "win32":
|
|
22
|
+
platform = "windows";
|
|
23
|
+
ext = "zip";
|
|
24
|
+
break;
|
|
25
|
+
case "darwin":
|
|
26
|
+
platform = "darwin";
|
|
27
|
+
ext = "tar.gz";
|
|
28
|
+
break;
|
|
29
|
+
case "freebsd":
|
|
30
|
+
platform = "freebsd";
|
|
31
|
+
ext = "tar.gz";
|
|
32
|
+
break;
|
|
33
|
+
case "linux":
|
|
34
|
+
platform = "linux";
|
|
35
|
+
ext = "tar.gz";
|
|
36
|
+
break;
|
|
37
|
+
default:
|
|
38
|
+
throw new Error(`Unsupported platform: ${p}`);
|
|
39
|
+
}
|
|
40
|
+
let arch;
|
|
41
|
+
switch (a) {
|
|
42
|
+
case "x64":
|
|
43
|
+
arch = "amd64";
|
|
44
|
+
break;
|
|
45
|
+
case "arm64":
|
|
46
|
+
arch = "aarch64";
|
|
47
|
+
break;
|
|
48
|
+
default:
|
|
49
|
+
throw new Error(`Unsupported architecture: ${a}`);
|
|
50
|
+
}
|
|
51
|
+
return `CLIProxyAPI_${VERSION}_${platform}_${arch}.${ext}`;
|
|
52
|
+
}
|
|
53
|
+
async function download(url, dest) {
|
|
54
|
+
const stream = got.stream(url);
|
|
55
|
+
stream.on("downloadProgress", ({ transferred, total, percent }) => {
|
|
56
|
+
const t = (transferred / 1e6).toFixed(1);
|
|
57
|
+
const totalStr = total ? `/${(total / 1e6).toFixed(1)}` : "";
|
|
58
|
+
const pct = total ? ` (${(percent * 100).toFixed(0)}%)` : "";
|
|
59
|
+
process.stderr.write(`\r⬇️ ${t}MB${totalStr}${pct}`);
|
|
60
|
+
});
|
|
61
|
+
try {
|
|
62
|
+
await pipeline(stream, fs.createWriteStream(dest));
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
process.stderr.write("\n");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function extract(archivePath, destDir) {
|
|
69
|
+
const flag = archivePath.endsWith(".zip") ? "-xf" : "-xzf";
|
|
70
|
+
cp.execFileSync("tar", [flag, archivePath, "-C", destDir], {
|
|
71
|
+
stdio: "inherit",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
export async function ensureCliProxy() {
|
|
75
|
+
const asset = pickAsset();
|
|
76
|
+
const url = `${RELEASE_BASE}/${asset}`;
|
|
77
|
+
const archivePath = path.join(TOOLS_DIR, asset);
|
|
78
|
+
// --renew: re-extract from the kept archive, then app.ts re-runs the device flow.
|
|
79
|
+
if (args.renew) {
|
|
80
|
+
if (fs.existsSync(TOKENS_PATH)) {
|
|
81
|
+
fs.rmSync(TOKENS_PATH, { force: true });
|
|
82
|
+
log("--renew: cleared stored token, will re-run device flow");
|
|
83
|
+
}
|
|
84
|
+
renewFromArchive(archivePath);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (fs.existsSync(TOOLS_DIR) &&
|
|
88
|
+
fs.readdirSync(TOOLS_DIR).length > 0 &&
|
|
89
|
+
!args.force) {
|
|
90
|
+
log("CLIProxyAPI already present at %s, skipping download", TOOLS_DIR);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (args.force) {
|
|
94
|
+
console.warn(`⚠️ --force set: re-downloading archive and overwriting extracted files in ${TOOLS_DIR}`);
|
|
95
|
+
}
|
|
96
|
+
fs.mkdirSync(TOOLS_DIR, { recursive: true });
|
|
97
|
+
// Keep the archive alongside the extracted files (no .tmp- + rm).
|
|
98
|
+
if (!fs.existsSync(archivePath)) {
|
|
99
|
+
console.error(`⬇️ Downloading from ${url}`);
|
|
100
|
+
log("Downloading %s", url);
|
|
101
|
+
await download(url, archivePath);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
log("Archive already present, skipping download: %s", archivePath);
|
|
105
|
+
}
|
|
106
|
+
extract(archivePath, TOOLS_DIR);
|
|
107
|
+
log("Installed CLIProxyAPI to %s", TOOLS_DIR);
|
|
108
|
+
createConfig();
|
|
109
|
+
}
|
|
110
|
+
function renewFromArchive(archivePath) {
|
|
111
|
+
if (!fs.existsSync(archivePath)) {
|
|
112
|
+
console.error("❌ No archive at " +
|
|
113
|
+
archivePath +
|
|
114
|
+
" to renew from — run once without --renew to fetch it.");
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
const keep = new Set([path.basename(archivePath)]);
|
|
118
|
+
for (const name of fs.readdirSync(TOOLS_DIR)) {
|
|
119
|
+
if (keep.has(name))
|
|
120
|
+
continue;
|
|
121
|
+
fs.rmSync(path.join(TOOLS_DIR, name), { recursive: true, force: true });
|
|
122
|
+
}
|
|
123
|
+
extract(archivePath, TOOLS_DIR);
|
|
124
|
+
log("Renewed CLIProxyAPI from %s", archivePath);
|
|
125
|
+
createConfig();
|
|
126
|
+
args.renew = false;
|
|
127
|
+
}
|
|
128
|
+
// ponytail: only seeds when live config absent — never clobbers an edited one
|
|
129
|
+
function createConfig() {
|
|
130
|
+
const example = path.join(TOOLS_DIR, "config.example.yaml");
|
|
131
|
+
if (!fs.existsSync(example)) {
|
|
132
|
+
console.error(`❌ Missing template: ${example}`);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
if (fs.existsSync(CONFIG_PATH))
|
|
136
|
+
return;
|
|
137
|
+
fs.copyFileSync(example, CONFIG_PATH);
|
|
138
|
+
log("Seeded %s from %s", CONFIG_PATH, example);
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=install-cli-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-cli-proxy.js","sourceRoot":"","sources":["../src/install-cli-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type TokenResponse } from "../types.ts";
|
|
2
|
+
import type { Provider } from "./types.ts";
|
|
3
|
+
export declare class HermesProvider implements Provider {
|
|
4
|
+
readonly name = "hermes";
|
|
5
|
+
private readonly client;
|
|
6
|
+
getValidToken(): Promise<TokenResponse>;
|
|
7
|
+
getAccountInfo(accessToken: string): Promise<Record<string, unknown>>;
|
|
8
|
+
private runDeviceFlow;
|
|
9
|
+
private readStoredToken;
|
|
10
|
+
private saveTokens;
|
|
11
|
+
private initConfig;
|
|
12
|
+
private setApiKey;
|
|
13
|
+
}
|
|
14
|
+
export declare const hermesProvider: HermesProvider;
|
|
15
|
+
//# sourceMappingURL=hermes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes.d.ts","sourceRoot":"","sources":["../../src/providers/hermes.ts"],"names":[],"mappings":"AAOA,OAAO,EAOL,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AA8H3C,qBAAa,cAAe,YAAW,QAAQ;IAC7C,QAAQ,CAAC,IAAI,YAAY;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgC;IAEjD,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC,CAwB5C;IAEK,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAE1E;YAEa,aAAa;IAoB3B,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,UAAU;IAiDlB,OAAO,CAAC,SAAS;CASlB;AAED,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
|