dsh-codex-subscription 1.11.3 → 1.11.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 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.11.3` package below; do not install a moving branch.
9
+ - Use the exact `1.11.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.11.3
37
+ npx -y @deepseek-ai/dsh@0.1.1-rc.2 plugin --profile web add dsh-codex-subscription@1.11.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.11.3
43
+ dsh plugin --profile web add dsh-codex-subscription@1.11.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.11.3` appears exactly once.
61
+ 1. `dsh-codex-subscription` version `1.11.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
 
@@ -8,6 +8,7 @@
8
8
  "0.1.1-rc.2"
9
9
  ],
10
10
  "previews": [
11
- "0.1.2-alpha.2"
11
+ "0.1.2-alpha.2",
12
+ "0.1.2-alpha.3"
12
13
  ]
13
14
  }
package/lib/index.js CHANGED
@@ -44,11 +44,14 @@ function parseOAuthCredential(value) {
44
44
  */
45
45
  var DshOAuthCredentialStore = class {
46
46
  #chains = /* @__PURE__ */ new Map();
47
- constructor(credentials, ref, legacyRefs = []) {
47
+ constructor(credentials, ref, legacyRefs = [], options = {}) {
48
48
  if (credentials === void 0 || credentials === null) throw new Error("Codex OAuth requires the DSH credentials service");
49
+ const expirySkewMs = options.expirySkewMs ?? 0;
50
+ if (!Number.isFinite(expirySkewMs) || expirySkewMs < 0) throw new Error("Codex OAuth expiry skew must be a non-negative finite number");
49
51
  this.credentials = credentials;
50
52
  this.ref = ref;
51
53
  this.legacyRefs = Object.freeze([...legacyRefs]);
54
+ this.expirySkewMs = expirySkewMs;
52
55
  }
53
56
  #enqueue(providerId, operation, options) {
54
57
  assertProvider(providerId);
@@ -78,7 +81,11 @@ var DshOAuthCredentialStore = class {
78
81
  }
79
82
  abortIfNeeded(options);
80
83
  if (hit?.value === void 0 || hit.value === "") return void 0;
81
- return parseOAuthCredential(hit.value);
84
+ const credential = parseOAuthCredential(hit.value);
85
+ return this.expirySkewMs === 0 ? credential : {
86
+ ...credential,
87
+ expires: credential.expires - this.expirySkewMs
88
+ };
82
89
  }
83
90
  read(providerId, options) {
84
91
  return this.#enqueue(providerId, () => this.#read(providerId, options), options);
@@ -935,7 +942,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
935
942
  }
936
943
  //#endregion
937
944
  //#region src/version.js
938
- const PACKAGE_VERSION = "1.11.3";
945
+ const PACKAGE_VERSION = "1.11.4";
939
946
  const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
940
947
  //#endregion
941
948
  //#region src/model-catalog.js
@@ -1836,6 +1843,8 @@ async function createSubscriptionDiagnostics({ auth, preferences, login = { phas
1836
1843
  const CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
1837
1844
  const DEFAULT_TTL_MS = 6e4;
1838
1845
  const DEFAULT_TIMEOUT_MS$1 = 15e3;
1846
+ const DEFAULT_FAILURE_TTL_MS = 5e3;
1847
+ const DEFAULT_MAX_RETRY_AFTER_MS = 5 * 6e4;
1839
1848
  const record$1 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1840
1849
  function windowOf(value) {
1841
1850
  if (value === void 0 || value === null) return void 0;
@@ -1951,6 +1960,15 @@ const requestSignal$1 = (signal, timeoutMs) => {
1951
1960
  const timeout = AbortSignal.timeout(timeoutMs);
1952
1961
  return signal === void 0 ? timeout : AbortSignal.any([signal, timeout]);
1953
1962
  };
1963
+ function retryAfterMs(response, now, maximum) {
1964
+ if (response.status !== 429) return void 0;
1965
+ const raw = response.headers?.get?.("retry-after")?.trim();
1966
+ if (!raw) return void 0;
1967
+ const seconds = Number(raw);
1968
+ const delay = Number.isFinite(seconds) && seconds >= 0 ? seconds * 1e3 : Date.parse(raw) - now();
1969
+ if (!Number.isFinite(delay) || delay < 0) return void 0;
1970
+ return Math.min(delay, maximum);
1971
+ }
1954
1972
  /**
1955
1973
  * Read quota through the same refreshable OAuth lifecycle used by model turns.
1956
1974
  * The browser receives only a parsed quota projection; bearer and account id
@@ -1963,7 +1981,10 @@ function createCodexUsageReader(options) {
1963
1981
  const now = options.now ?? Date.now;
1964
1982
  const ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
1965
1983
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS$1;
1984
+ const failureTtlMs = options.failureTtlMs ?? DEFAULT_FAILURE_TTL_MS;
1985
+ const maxRetryAfterMs = options.maxRetryAfterMs ?? DEFAULT_MAX_RETRY_AFTER_MS;
1966
1986
  let cached;
1987
+ let failed;
1967
1988
  let inFlight;
1968
1989
  let generation = 0;
1969
1990
  const load = async (signal) => {
@@ -1984,7 +2005,11 @@ function createCodexUsageReader(options) {
1984
2005
  },
1985
2006
  signal: requestSignal$1(signal, timeoutMs)
1986
2007
  });
1987
- if (!response.ok) throw new Error(response.status === 401 || response.status === 403 ? "ChatGPT sign-in needs to be renewed" : `ChatGPT usage request failed (HTTP ${response.status})`);
2008
+ if (!response.ok) {
2009
+ const error = /* @__PURE__ */ new Error(response.status === 401 || response.status === 403 ? "ChatGPT sign-in needs to be renewed" : `ChatGPT usage request failed (HTTP ${response.status})`);
2010
+ Object.defineProperty(error, "retryAfterMs", { value: retryAfterMs(response, now, maxRetryAfterMs) });
2011
+ throw error;
2012
+ }
1988
2013
  let value;
1989
2014
  try {
1990
2015
  value = await response.json();
@@ -1998,12 +2023,25 @@ function createCodexUsageReader(options) {
1998
2023
  };
1999
2024
  return Object.freeze({
2000
2025
  read({ force = false, signal } = {}) {
2026
+ if (failed !== void 0 && now() < failed.retryAt) return Promise.reject(new Error(failed.message));
2001
2027
  if (!force && cached !== void 0 && now() - cached.fetchedAt < ttlMs) return Promise.resolve(structuredClone(cached));
2002
2028
  if (inFlight !== void 0) return inFlight.then(structuredClone);
2003
2029
  const currentGeneration = generation;
2004
2030
  const current = load(signal).then((value) => {
2005
- if (generation === currentGeneration) cached = structuredClone(value);
2031
+ if (generation === currentGeneration) {
2032
+ cached = structuredClone(value);
2033
+ failed = void 0;
2034
+ }
2006
2035
  return structuredClone(value);
2036
+ }).catch((error) => {
2037
+ if (generation === currentGeneration && error?.name !== "AbortError") {
2038
+ const delay = Number.isFinite(error?.retryAfterMs) ? error.retryAfterMs : failureTtlMs;
2039
+ failed = {
2040
+ message: error instanceof Error ? error.message : "ChatGPT usage request failed",
2041
+ retryAt: now() + delay
2042
+ };
2043
+ }
2044
+ throw error;
2007
2045
  }).finally(() => {
2008
2046
  if (inFlight === current) inFlight = void 0;
2009
2047
  });
@@ -2013,6 +2051,7 @@ function createCodexUsageReader(options) {
2013
2051
  clear() {
2014
2052
  generation += 1;
2015
2053
  cached = void 0;
2054
+ failed = void 0;
2016
2055
  inFlight = void 0;
2017
2056
  }
2018
2057
  });
@@ -2404,6 +2443,7 @@ const inject = [
2404
2443
  "attachments"
2405
2444
  ];
2406
2445
  const PROVIDER = "openai-codex";
2446
+ const OAUTH_EXPIRY_SKEW_MS = 6e4;
2407
2447
  const CREDENTIAL_REF = credentialRef("OPENAI_CODEX_SUBSCRIPTION_OAUTH");
2408
2448
  const LEGACY_CREDENTIAL_REF = credentialRef("WSL043_OPENAI_CODEX_OAUTH");
2409
2449
  const CHANNEL = "/codex-subscription";
@@ -2616,7 +2656,7 @@ function apply(ctx) {
2616
2656
  const searchProvider = createSearchProviderSwitcher(ctx.loader);
2617
2657
  const network = createCodexNetworkTransport();
2618
2658
  const originalImages = new OriginalImageStore();
2619
- const store = new DshOAuthCredentialStore(ctx.credentials, CREDENTIAL_REF, [LEGACY_CREDENTIAL_REF]);
2659
+ const store = new DshOAuthCredentialStore(ctx.credentials, CREDENTIAL_REF, [LEGACY_CREDENTIAL_REF], { expirySkewMs: OAUTH_EXPIRY_SKEW_MS });
2620
2660
  const baseProvider = createOpenAICodexProvider();
2621
2661
  let resolveAuth = async () => void 0;
2622
2662
  const modelCatalog = createOfficialModelCatalog({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-codex-subscription",
3
- "version": "1.11.3",
3
+ "version": "1.11.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",
@@ -77,22 +77,22 @@
77
77
  },
78
78
  "peerDependencies": {
79
79
  "@deepseek-ai/cordis": "4.0.1 || 4.0.2",
80
- "@deepseek-ai/dsh-api-remotes": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
81
- "@deepseek-ai/dsh-client-connection": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
82
- "@deepseek-ai/dsh-client-locale": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
83
- "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
84
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
85
- "@deepseek-ai/dsh-client-ui-model-selection": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
86
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
87
- "@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
88
- "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
89
- "@deepseek-ai/dsh-client-ui-tool": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
90
- "@deepseek-ai/dsh-credentials": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
91
- "@deepseek-ai/dsh-llm": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
92
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
93
- "@deepseek-ai/dsh-settings": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
94
- "@deepseek-ai/dsh-tools": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
95
- "@deepseek-ai/dsh-web": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2",
80
+ "@deepseek-ai/dsh-api-remotes": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
81
+ "@deepseek-ai/dsh-client-connection": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
82
+ "@deepseek-ai/dsh-client-locale": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
83
+ "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
84
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
85
+ "@deepseek-ai/dsh-client-ui-model-selection": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
86
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
87
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
88
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
89
+ "@deepseek-ai/dsh-client-ui-tool": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
90
+ "@deepseek-ai/dsh-credentials": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
91
+ "@deepseek-ai/dsh-llm": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
92
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
93
+ "@deepseek-ai/dsh-settings": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
94
+ "@deepseek-ai/dsh-tools": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
95
+ "@deepseek-ai/dsh-web": "0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-alpha.2 || 0.1.2-alpha.3",
96
96
  "@deepseek-ai/schemastery": "3.18.1",
97
97
  "@earendil-works/pi-ai": "0.82.1",
98
98
  "react": "^18.2.0",