dsh-codex-subscription 1.7.2 → 1.7.4
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/AGENTS.md +4 -4
- package/THIRD_PARTY_NOTICES.md +1 -0
- package/lib/client.js +3 -0
- package/lib/index.js +183 -8
- package/package.json +4 -1
package/AGENTS.md
CHANGED
|
@@ -6,7 +6,7 @@ Use this guide when a user asks an Agent to install, update, verify, or remove
|
|
|
6
6
|
## Safety
|
|
7
7
|
|
|
8
8
|
- Confirm the target DSH installation and profile. Use `web` only when it is the user's target.
|
|
9
|
-
- Use the exact `1.7.
|
|
9
|
+
- Use the exact `1.7.4` package below; do not install a moving branch.
|
|
10
10
|
- Never print OAuth credentials, account IDs, authorization callbacks, or credential-store contents.
|
|
11
11
|
- Preserve the DSH profile, unrelated plugins, sessions, and saved sign-in.
|
|
12
12
|
- Do not start, stop, or restart DSH without explicit permission.
|
|
@@ -34,13 +34,13 @@ For an official DSH installation run through npm, keep the complete `npx` prefix
|
|
|
34
34
|
run command does not create a global `dsh` command:
|
|
35
35
|
|
|
36
36
|
```sh
|
|
37
|
-
npx -y @deepseek-ai/dsh@0.1.1-rc.2 plugin --profile web add dsh-codex-subscription@1.7.
|
|
37
|
+
npx -y @deepseek-ai/dsh@0.1.1-rc.2 plugin --profile web add dsh-codex-subscription@1.7.4
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
With an existing global `dsh` command:
|
|
41
41
|
|
|
42
42
|
```sh
|
|
43
|
-
dsh plugin --profile web add dsh-codex-subscription@1.7.
|
|
43
|
+
dsh plugin --profile web add dsh-codex-subscription@1.7.4
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
Use the same `add` command to update or repair. This is the complete package-changing operation.
|
|
@@ -58,7 +58,7 @@ dsh --profile web --dump-config
|
|
|
58
58
|
|
|
59
59
|
For the official npm route, run the same checks with `npx -y @deepseek-ai/dsh@0.1.1-rc.2` in place of `dsh`.
|
|
60
60
|
|
|
61
|
-
1. `dsh-codex-subscription` version `1.7.
|
|
61
|
+
1. `dsh-codex-subscription` version `1.7.4` appears exactly once.
|
|
62
62
|
2. `codex-subscription` appears exactly once in the composed config.
|
|
63
63
|
3. No unrelated plugin or profile was changed and DSH was not restarted.
|
|
64
64
|
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -8,6 +8,7 @@ This project depends on software distributed under its own terms. The dependency
|
|
|
8
8
|
| `@earendil-works/pi-ai` 0.82.1 | OpenAI Codex OAuth, model catalog, Responses transport, and WebSocket continuation | MIT | https://github.com/earendil-works/pi |
|
|
9
9
|
| React | DSH settings component runtime | MIT | https://github.com/facebook/react |
|
|
10
10
|
| Heroicons | Composer speed icon | MIT | https://github.com/tailwindlabs/heroicons |
|
|
11
|
+
| `https-proxy-agent` 7.0.6 | HTTPS proxy transport for Codex OAuth token requests | MIT | https://github.com/TooTallNate/proxy-agents |
|
|
11
12
|
| tsdown | Development-time bundler | MIT | https://github.com/rolldown/tsdown |
|
|
12
13
|
|
|
13
14
|
No third-party project endorses this community plugin. See each installed package for its complete license text and transitive dependency notices.
|
package/lib/client.js
CHANGED
|
@@ -436,6 +436,7 @@ window.__ModuleLoader__.load({
|
|
|
436
436
|
.codexSubscriptionCreditSection{display:flex;flex-direction:column;gap:7px}.codexSubscriptionCreditNote{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionCreditRows{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px}.codexSubscriptionCreditBalance,.codexSubscriptionSpendLimit{min-width:0;border-radius:10px;padding:12px 14px;background:var(--dsw-alias-bg-module-platform)}
|
|
437
437
|
.codexSubscriptionCreditBalance{display:flex;flex-direction:column;gap:6px}.codexSubscriptionCreditBalance span,.codexSubscriptionCreditLabel{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}.codexSubscriptionCreditBalance strong{font:600 18px/24px ui-monospace,SFMono-Regular,Consolas,monospace;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
|
|
438
438
|
.codexSubscriptionResetSummary{display:flex;align-items:center;justify-content:space-between;gap:10px}.codexSubscriptionResetMeta{display:flex;min-width:0;flex-direction:column;gap:1px}.codexSubscriptionResetBalance{display:flex;flex-direction:column;gap:8px}.codexSubscriptionResetBalance .codexSubscriptionActions{justify-content:flex-start}.codexSubscriptionResetFlow{display:flex;flex-direction:column;gap:10px;border-top:1px solid var(--dsw-alias-border-l2);padding-top:10px}.codexSubscriptionResetFlow h4{margin:0;font-size:13px;line-height:20px;font-weight:500}.codexSubscriptionResetWarning{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}.codexSubscriptionResetExpiry{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionResetCheck{display:flex;align-items:flex-start;gap:8px;padding:9px 10px;border-radius:8px;background:var(--dsw-alias-bg-module-platform);font-size:12px;line-height:18px;color:var(--dsw-alias-label-primary);cursor:pointer}.codexSubscriptionResetCheck input{margin:3px 0 0;accent-color:var(--dsw-alias-label-primary)}.codexSubscriptionResetFinal{border-color:var(--dsw-alias-state-error-primary)!important;color:var(--dsw-alias-state-error-primary)!important}.codexSubscriptionResetResult{font-size:12px;line-height:18px;color:var(--dsw-alias-state-success-primary)}
|
|
439
|
+
.codexSubscriptionResetUse:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.codexSubscriptionResetUse:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:1px}
|
|
439
440
|
.codexSubscriptionSpendLimit{display:flex;flex-direction:column;gap:8px}.codexSubscriptionSpendTop{display:flex;align-items:baseline;justify-content:space-between;gap:12px}.codexSubscriptionSpendTop strong{font:600 16px/22px ui-monospace,SFMono-Regular,Consolas,monospace;font-variant-numeric:tabular-nums}.codexSubscriptionSpendLimit progress{width:100%;height:6px;border:0;border-radius:999px;overflow:hidden;background:var(--dsw-alias-border-l3);accent-color:var(--dsw-alias-brand-primary,#3964fe);-webkit-appearance:none;appearance:none}.codexSubscriptionSpendLimit progress::-webkit-progress-bar{background:var(--dsw-alias-border-l3);border-radius:999px}.codexSubscriptionSpendLimit progress::-webkit-progress-value{background:var(--dsw-alias-brand-primary,#3964fe);border-radius:999px}.codexSubscriptionSpendLimit progress::-moz-progress-bar{background:var(--dsw-alias-brand-primary,#3964fe);border-radius:999px}
|
|
440
441
|
.codexComposerQuota{display:inline-flex;align-items:center;flex:0 0 auto;height:28px;box-sizing:border-box;padding:0;color:var(--dsw-alias-label-secondary);font-family:inherit;font-size:12px;line-height:20px;font-weight:500;font-variant-numeric:tabular-nums;white-space:nowrap;user-select:none}.codexComposerQuotaBar{display:block;width:40px;height:4px;border:0;border-radius:999px;overflow:hidden;background:var(--dsw-alias-border-l3);accent-color:var(--dsw-alias-label-secondary);-webkit-appearance:none;appearance:none}.codexComposerQuotaBar::-webkit-progress-bar{background:var(--dsw-alias-border-l3);border-radius:999px}.codexComposerQuotaBar::-webkit-progress-value{background:var(--dsw-alias-label-secondary);border-radius:999px}.codexComposerQuotaBar::-moz-progress-bar{background:var(--dsw-alias-label-secondary);border-radius:999px}
|
|
441
442
|
.codexModelSelect{position:relative;min-width:0}.codexModelSelectTrigger{display:flex;align-items:center;gap:4px;min-width:0;max-width:min(360px,45cqw);height:28px;padding:0 4px 0 8px;border:0;border-radius:24px;outline:0;background:transparent;color:var(--dsw-alias-label-secondary);font-size:13px;font-weight:500;line-height:20px;cursor:pointer}.codexModelSelectTrigger:hover:not(:disabled),.codexModelSelectTrigger[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover)}.codexModelSelectTrigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.codexModelSelectTrigger:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.codexModelSelectBolt{display:block;flex:none;width:14px;height:14px;color:var(--dsw-alias-label-primary)}.codexModelSelectLabel{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.codexModelSelectEffort{flex:none;color:var(--dsw-alias-label-caption)}.codexModelSelectChevron{flex:none;color:var(--dsw-alias-label-caption);transition:transform 120ms}.codexModelSelectTrigger[aria-expanded=true] .codexModelSelectChevron{transform:rotate(180deg)}
|
|
@@ -1385,6 +1386,7 @@ window.__ModuleLoader__.load({
|
|
|
1385
1386
|
return () => window.clearInterval(timer);
|
|
1386
1387
|
}, [flow?.id, flow?.phase]);
|
|
1387
1388
|
const begin = (method) => {
|
|
1389
|
+
setFlow(void 0);
|
|
1388
1390
|
setBusy(true);
|
|
1389
1391
|
setError(void 0);
|
|
1390
1392
|
call("login/start", {
|
|
@@ -1744,6 +1746,7 @@ window.__ModuleLoader__.load({
|
|
|
1744
1746
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1745
1747
|
className: "codexSubscriptionActions",
|
|
1746
1748
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1749
|
+
className: "codexSubscriptionResetUse",
|
|
1747
1750
|
type: "button",
|
|
1748
1751
|
variant: "outline",
|
|
1749
1752
|
disabled: resetBusy,
|
package/lib/index.js
CHANGED
|
@@ -3,7 +3,10 @@ import { LlmError, createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
|
3
3
|
import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
|
|
4
4
|
import { settingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
5
5
|
import z from "@deepseek-ai/schemastery";
|
|
6
|
-
import { spawn } from "node:child_process";
|
|
6
|
+
import { execFile, spawn } from "node:child_process";
|
|
7
|
+
import { request } from "node:https";
|
|
8
|
+
import { promisify } from "node:util";
|
|
9
|
+
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
7
10
|
import { openaiCodexProvider as createOpenAICodexProvider } from "@earendil-works/pi-ai/providers/openai-codex";
|
|
8
11
|
import { createModels } from "@earendil-works/pi-ai";
|
|
9
12
|
import { randomUUID } from "node:crypto";
|
|
@@ -104,7 +107,8 @@ var DshOAuthCredentialStore = class {
|
|
|
104
107
|
}
|
|
105
108
|
};
|
|
106
109
|
/** Return only account state that is safe to expose to the browser client. */
|
|
107
|
-
function createCodexAuthService(models, store) {
|
|
110
|
+
function createCodexAuthService(models, store, options = {}) {
|
|
111
|
+
const runLogin = options.runLogin ?? ((run) => run());
|
|
108
112
|
return Object.freeze({
|
|
109
113
|
async status(options) {
|
|
110
114
|
const current = await store.read(PROVIDER$1, options);
|
|
@@ -120,7 +124,7 @@ function createCodexAuthService(models, store) {
|
|
|
120
124
|
};
|
|
121
125
|
},
|
|
122
126
|
login(interaction) {
|
|
123
|
-
return models.login(PROVIDER$1, "oauth", interaction);
|
|
127
|
+
return runLogin(() => models.login(PROVIDER$1, "oauth", interaction));
|
|
124
128
|
},
|
|
125
129
|
logout(options) {
|
|
126
130
|
return models.logout(PROVIDER$1, options);
|
|
@@ -218,6 +222,15 @@ const publicPrompt = (prompt) => ({
|
|
|
218
222
|
message: String(prompt.message ?? ""),
|
|
219
223
|
...typeof prompt.placeholder === "string" ? { placeholder: prompt.placeholder } : {}
|
|
220
224
|
});
|
|
225
|
+
function classifyLoginFailure(error) {
|
|
226
|
+
const message = error instanceof Error ? error.message : "";
|
|
227
|
+
if (/token exchange failed/iu.test(message)) return "token-exchange";
|
|
228
|
+
if (/fetch failed|\b(?:ECONN|ENOTFOUND|ETIMEDOUT|CERT_|socket|network)\b/iu.test(message)) return "network";
|
|
229
|
+
if (/extract accountId|account[_ -]?id/iu.test(message)) return "account-claim";
|
|
230
|
+
if (/credential|credentials-local|OAuth JSON/iu.test(message)) return "credential-store";
|
|
231
|
+
if (/Missing authorization code|State mismatch|callback/iu.test(message)) return "callback";
|
|
232
|
+
return "provider";
|
|
233
|
+
}
|
|
221
234
|
/** Own one host-side login without exposing tokens to the browser client. */
|
|
222
235
|
var CodexLoginCoordinator = class {
|
|
223
236
|
#sessions = /* @__PURE__ */ new Map();
|
|
@@ -234,13 +247,23 @@ var CodexLoginCoordinator = class {
|
|
|
234
247
|
if (active === void 0) return { phase: "idle" };
|
|
235
248
|
return {
|
|
236
249
|
method: active.view.method,
|
|
237
|
-
phase: active.view.phase
|
|
250
|
+
phase: active.view.phase,
|
|
251
|
+
...active.view.phase === "failed" ? { failure: classifyLoginFailure(active.hostError) } : {}
|
|
238
252
|
};
|
|
239
253
|
}
|
|
240
254
|
async start({ method }) {
|
|
241
255
|
if (!LOGIN_METHODS.has(method)) throw new Error(`unsupported Codex login method: ${String(method)}`);
|
|
242
256
|
const active = this.#activeId === void 0 ? void 0 : this.#sessions.get(this.#activeId);
|
|
243
|
-
if (active !== void 0 && !TERMINAL_PHASES.has(active.view.phase))
|
|
257
|
+
if (active !== void 0 && !TERMINAL_PHASES.has(active.view.phase)) {
|
|
258
|
+
active.view = {
|
|
259
|
+
id: active.view.id,
|
|
260
|
+
provider: "openai-codex",
|
|
261
|
+
method: active.view.method,
|
|
262
|
+
phase: "cancelled",
|
|
263
|
+
authenticated: false
|
|
264
|
+
};
|
|
265
|
+
active.controller.abort(/* @__PURE__ */ new Error("Codex login replaced by a new attempt"));
|
|
266
|
+
}
|
|
244
267
|
if (active !== void 0) this.#sessions.delete(active.view.id);
|
|
245
268
|
const id = this.createId();
|
|
246
269
|
const ready = deferred();
|
|
@@ -259,7 +282,7 @@ var CodexLoginCoordinator = class {
|
|
|
259
282
|
};
|
|
260
283
|
this.#sessions.set(id, session);
|
|
261
284
|
this.#activeId = id;
|
|
262
|
-
const publishReady = () => ready.resolve(
|
|
285
|
+
const publishReady = () => ready.resolve(publicClone(session.view));
|
|
263
286
|
const interaction = {
|
|
264
287
|
signal: controller.signal,
|
|
265
288
|
prompt: async (prompt) => {
|
|
@@ -451,6 +474,158 @@ function createCodexRpcHandler(coordinator, options = {}) {
|
|
|
451
474
|
};
|
|
452
475
|
}
|
|
453
476
|
//#endregion
|
|
477
|
+
//#region src/oauth-network.js
|
|
478
|
+
const execFileAsync = promisify(execFile);
|
|
479
|
+
const CODEX_AUTH_HOST = "auth.openai.com";
|
|
480
|
+
const MAX_RESPONSE_BYTES = 2 * 1024 * 1024;
|
|
481
|
+
let patchQueue = Promise.resolve();
|
|
482
|
+
function normalizeProxy(raw) {
|
|
483
|
+
if (typeof raw !== "string" || raw.trim() === "") return void 0;
|
|
484
|
+
const value = raw.trim().includes("://") ? raw.trim() : `http://${raw.trim()}`;
|
|
485
|
+
try {
|
|
486
|
+
const url = new URL(value);
|
|
487
|
+
if (!["http:", "https:"].includes(url.protocol) || url.hostname === "") return void 0;
|
|
488
|
+
return url.toString();
|
|
489
|
+
} catch {
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
function bypassesProxy(hostname, port, rawNoProxy) {
|
|
494
|
+
if (typeof rawNoProxy !== "string" || rawNoProxy.trim() === "") return false;
|
|
495
|
+
return rawNoProxy.split(/[\s,]+/u).some((raw) => {
|
|
496
|
+
const entry = raw.trim().toLowerCase();
|
|
497
|
+
if (entry === "*") return true;
|
|
498
|
+
if (entry === "") return false;
|
|
499
|
+
const match = /^(.*?)(?::(\d+))?$/u.exec(entry);
|
|
500
|
+
const host = match?.[1]?.replace(/^\./u, "");
|
|
501
|
+
const entryPort = match?.[2];
|
|
502
|
+
if (!host || entryPort && entryPort !== port) return false;
|
|
503
|
+
return hostname === host || hostname.endsWith(`.${host}`);
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
function proxyFromEnvironment(env = process.env, target = new URL(`https://${CODEX_AUTH_HOST}/`)) {
|
|
507
|
+
if (bypassesProxy(target.hostname.toLowerCase(), target.port || "443", env.NO_PROXY ?? env.no_proxy)) return void 0;
|
|
508
|
+
return normalizeProxy(env.HTTPS_PROXY ?? env.https_proxy ?? env.ALL_PROXY ?? env.all_proxy);
|
|
509
|
+
}
|
|
510
|
+
function selectWindowsProxy(value) {
|
|
511
|
+
if (typeof value !== "string") return void 0;
|
|
512
|
+
const entries = value.split(";").map((item) => item.trim()).filter(Boolean);
|
|
513
|
+
const https = entries.find((item) => /^https=/iu.test(item));
|
|
514
|
+
const http = entries.find((item) => /^http=/iu.test(item));
|
|
515
|
+
const selected = (https ?? http ?? entries.find((item) => !item.includes("=")))?.replace(/^[^=]+=/u, "");
|
|
516
|
+
return normalizeProxy(selected);
|
|
517
|
+
}
|
|
518
|
+
async function windowsSystemProxy(options = {}) {
|
|
519
|
+
const run = options.execFile ?? execFileAsync;
|
|
520
|
+
const reg = `${process.env.SystemRoot ?? "C:\\Windows"}\\System32\\reg.exe`;
|
|
521
|
+
const key = "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
|
|
522
|
+
try {
|
|
523
|
+
const enabled = await run(reg, [
|
|
524
|
+
"query",
|
|
525
|
+
key,
|
|
526
|
+
"/v",
|
|
527
|
+
"ProxyEnable"
|
|
528
|
+
], {
|
|
529
|
+
windowsHide: true,
|
|
530
|
+
encoding: "utf8"
|
|
531
|
+
});
|
|
532
|
+
if (!/REG_DWORD\s+0x1\b/iu.test(enabled.stdout)) return void 0;
|
|
533
|
+
const configured = await run(reg, [
|
|
534
|
+
"query",
|
|
535
|
+
key,
|
|
536
|
+
"/v",
|
|
537
|
+
"ProxyServer"
|
|
538
|
+
], {
|
|
539
|
+
windowsHide: true,
|
|
540
|
+
encoding: "utf8"
|
|
541
|
+
});
|
|
542
|
+
return selectWindowsProxy(/^\s*ProxyServer\s+REG_\w+\s+(.+)$/imu.exec(configured.stdout)?.[1]);
|
|
543
|
+
} catch {
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
async function macSystemProxy(options = {}) {
|
|
548
|
+
const run = options.execFile ?? execFileAsync;
|
|
549
|
+
try {
|
|
550
|
+
const result = await run("/usr/sbin/scutil", ["--proxy"], { encoding: "utf8" });
|
|
551
|
+
if (!/^\s*HTTPSEnable\s*:\s*1\s*$/imu.test(result.stdout)) return void 0;
|
|
552
|
+
const host = /^\s*HTTPSProxy\s*:\s*(\S+)\s*$/imu.exec(result.stdout)?.[1];
|
|
553
|
+
const port = /^\s*HTTPSPort\s*:\s*(\d+)\s*$/imu.exec(result.stdout)?.[1];
|
|
554
|
+
return normalizeProxy(host && port ? `${host}:${port}` : void 0);
|
|
555
|
+
} catch {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
async function resolveCodexOAuthProxy(options = {}) {
|
|
560
|
+
const envProxy = proxyFromEnvironment(options.env);
|
|
561
|
+
if (envProxy) return envProxy;
|
|
562
|
+
const platform = options.platform ?? process.platform;
|
|
563
|
+
if (platform === "win32") return windowsSystemProxy(options);
|
|
564
|
+
if (platform === "darwin") return macSystemProxy(options);
|
|
565
|
+
}
|
|
566
|
+
function bodyBytes(body) {
|
|
567
|
+
if (body === void 0 || body === null) return void 0;
|
|
568
|
+
if (typeof body === "string") return Buffer.from(body);
|
|
569
|
+
if (body instanceof URLSearchParams) return Buffer.from(body.toString());
|
|
570
|
+
if (body instanceof Uint8Array) return Buffer.from(body);
|
|
571
|
+
throw new TypeError("Unsupported Codex OAuth request body");
|
|
572
|
+
}
|
|
573
|
+
function fetchThroughProxy(input, init, proxyUrl) {
|
|
574
|
+
const target = new URL(typeof input === "string" || input instanceof URL ? input : input.url);
|
|
575
|
+
const body = bodyBytes(init?.body);
|
|
576
|
+
const headers = new Headers(init?.headers);
|
|
577
|
+
if (body && !headers.has("content-length")) headers.set("content-length", String(body.byteLength));
|
|
578
|
+
return new Promise((resolve, reject) => {
|
|
579
|
+
const request$1 = request(target, {
|
|
580
|
+
method: init?.method ?? "GET",
|
|
581
|
+
headers: Object.fromEntries(headers.entries()),
|
|
582
|
+
agent: new HttpsProxyAgent(proxyUrl),
|
|
583
|
+
signal: init?.signal
|
|
584
|
+
}, (response) => {
|
|
585
|
+
const chunks = [];
|
|
586
|
+
let total = 0;
|
|
587
|
+
response.on("data", (chunk) => {
|
|
588
|
+
total += chunk.length;
|
|
589
|
+
if (total > MAX_RESPONSE_BYTES) {
|
|
590
|
+
request$1.destroy(/* @__PURE__ */ new Error("Codex OAuth response exceeded the safety limit"));
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
chunks.push(chunk);
|
|
594
|
+
});
|
|
595
|
+
response.on("end", () => resolve(new Response(Buffer.concat(chunks), {
|
|
596
|
+
status: response.statusCode ?? 500,
|
|
597
|
+
statusText: response.statusMessage,
|
|
598
|
+
headers: response.headers
|
|
599
|
+
})));
|
|
600
|
+
});
|
|
601
|
+
request$1.on("error", reject);
|
|
602
|
+
if (body) request$1.write(body);
|
|
603
|
+
request$1.end();
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
async function withCodexOAuthNetwork(run, options = {}) {
|
|
607
|
+
const previous = patchQueue;
|
|
608
|
+
let release;
|
|
609
|
+
patchQueue = new Promise((resolve) => {
|
|
610
|
+
release = resolve;
|
|
611
|
+
});
|
|
612
|
+
await previous;
|
|
613
|
+
const proxyUrl = await resolveCodexOAuthProxy(options);
|
|
614
|
+
const original = globalThis.fetch;
|
|
615
|
+
const proxyFetch = options.fetchThroughProxy ?? fetchThroughProxy;
|
|
616
|
+
const wrapper = proxyUrl ? (input, init) => {
|
|
617
|
+
const target = new URL(typeof input === "string" || input instanceof URL ? input : input.url);
|
|
618
|
+
return target.protocol === "https:" && target.hostname === CODEX_AUTH_HOST ? proxyFetch(input, init, proxyUrl) : original(input, init);
|
|
619
|
+
} : original;
|
|
620
|
+
globalThis.fetch = wrapper;
|
|
621
|
+
try {
|
|
622
|
+
return await run();
|
|
623
|
+
} finally {
|
|
624
|
+
if (globalThis.fetch === wrapper) globalThis.fetch = original;
|
|
625
|
+
release();
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
//#endregion
|
|
454
629
|
//#region src/settings-contract.js
|
|
455
630
|
const SETTINGS_NAMESPACE = "codex-subscription";
|
|
456
631
|
const QUICK_QUOTA_MODE_FIELD = "quickQuotaMode";
|
|
@@ -526,7 +701,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0 } = {
|
|
|
526
701
|
}
|
|
527
702
|
//#endregion
|
|
528
703
|
//#region src/version.js
|
|
529
|
-
const PACKAGE_VERSION = "1.7.
|
|
704
|
+
const PACKAGE_VERSION = "1.7.4";
|
|
530
705
|
const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
|
|
531
706
|
//#endregion
|
|
532
707
|
//#region src/codex-search.js
|
|
@@ -1567,7 +1742,7 @@ function apply(ctx) {
|
|
|
1567
1742
|
select(settings.get());
|
|
1568
1743
|
return settings.watch(select);
|
|
1569
1744
|
}, "codex-subscription: search provider selection");
|
|
1570
|
-
const auth = createCodexAuthService(authModels, store);
|
|
1745
|
+
const auth = createCodexAuthService(authModels, store, { runLogin: withCodexOAuthNetwork });
|
|
1571
1746
|
const coordinator = new CodexLoginCoordinator(auth);
|
|
1572
1747
|
const usageReader = createCodexUsageReader({
|
|
1573
1748
|
getAuth: resolveAuth,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-codex-subscription",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.4",
|
|
4
4
|
"description": "Use ChatGPT and Codex subscriptions in DeepSeek Harness with OAuth, quota, safe resets, web search, images, and Fast mode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -122,6 +122,9 @@
|
|
|
122
122
|
"react-dom": "18.3.1",
|
|
123
123
|
"tsdown": "0.22.2"
|
|
124
124
|
},
|
|
125
|
+
"dependencies": {
|
|
126
|
+
"https-proxy-agent": "7.0.6"
|
|
127
|
+
},
|
|
125
128
|
"scripts": {
|
|
126
129
|
"build": "tsdown --config tsdown.config.mjs",
|
|
127
130
|
"test": "node --test tests/*.test.mjs",
|