dsh-codex-subscription 2.5.0 → 2.5.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/README.en.md CHANGED
@@ -105,7 +105,7 @@ This plugin supports the latest DeepSeek Harness release recorded in its package
105
105
  2. Paste this package name, with its version, into the **Package name or address** field:
106
106
 
107
107
  ```text
108
- dsh-codex-subscription@2.5.0
108
+ dsh-codex-subscription@2.5.1
109
109
  ```
110
110
 
111
111
  3. Click **Install** and wait for completion. Follow the page instructions; save your work before restarting if requested.
package/README.md CHANGED
@@ -105,7 +105,7 @@
105
105
  2. 在 **包名或地址** 输入框中粘贴下面的包名(已带版本号):
106
106
 
107
107
  ```text
108
- dsh-codex-subscription@2.5.0
108
+ dsh-codex-subscription@2.5.1
109
109
  ```
110
110
 
111
111
  3. 点击 **安装**,等待安装完成;按页面提示操作,需要重启时先保存工作。
package/lib/client.js CHANGED
@@ -5967,6 +5967,12 @@ window.__ModuleLoader__.load({
5967
5967
  resetAccountChanged: "登录账号已变更,请重新开始。",
5968
5968
  resetUncertain: "服务端返回结果不确定。请再次确认,插件会复用同一个请求,不会另外发起一次重置。",
5969
5969
  creditsNote: "额外 Credits、消费上限、重置次数分别显示。",
5970
+ creditsExpires: "预计 {date} 到期,还剩 {days} 天",
5971
+ creditsExpiredToday: "今天 {date} 到期",
5972
+ creditsExpiryEstimate: "(估计:官方公布的 Pro 200 补偿 Credits 到期日,接口未返回,以 ChatGPT 使用情况页为准)",
5973
+ creditsAfterAllowance: "Credits 要等套餐额度用完后才会开始消耗,官方没有“先用 Credits”的开关。",
5974
+ creditsMessages: "约可发 {local} 条本地消息 / {cloud} 条云端消息",
5975
+ chatPass: "ChatPass 每周额度",
5970
5976
  creditsUsed: "已用 {used} / {limit} credits",
5971
5977
  spendReached: "Credits 月度消费上限已用尽。",
5972
5978
  unavailable: "暂无数据",
@@ -6528,6 +6534,12 @@ window.__ModuleLoader__.load({
6528
6534
  resetAccountChanged: "The signed-in account changed. Start again.",
6529
6535
  resetUncertain: "The server result is uncertain. Confirm again to check the same request; the plugin will not start a separate reset.",
6530
6536
  creditsNote: "Extra Credits, spending caps, and resets are separate items.",
6537
+ creditsExpires: "Expires {date} ({days} days left)",
6538
+ creditsExpiredToday: "Expires today ({date})",
6539
+ creditsExpiryEstimate: "(Estimate: the published expiry of the Pro 200 compensation Credits; the API does not report it, so check ChatGPT usage settings)",
6540
+ creditsAfterAllowance: "Credits are only drawn once the plan allowance runs out; there is no official switch to spend them first.",
6541
+ creditsMessages: "Roughly {local} local / {cloud} cloud messages",
6542
+ chatPass: "ChatPass weekly",
6531
6543
  creditsUsed: "{used} / {limit} credits used",
6532
6544
  spendReached: "The monthly Credits spending cap has been reached.",
6533
6545
  unavailable: "No data yet",
@@ -6770,6 +6782,7 @@ window.__ModuleLoader__.load({
6770
6782
  .codexSubscriptionSearchOptions[open]>summary{margin-bottom:8px}
6771
6783
  .codexSubscriptionCreditSection{display:flex;flex-direction:column;gap:7px}
6772
6784
  .codexSubscriptionCreditNote{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
6785
+ .codexSubscriptionCreditExpiry{display:grid;gap:2px;font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionCreditExpiry p{margin:0}.codexSubscriptionCreditExpiry[data-soon=true]{color:var(--dsw-alias-label-secondary);font-weight:600}
6773
6786
  .codexSubscriptionCreditRows{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px}
6774
6787
  .codexSubscriptionCreditBalance,.codexSubscriptionSpendLimit{min-width:0;border-radius:10px;padding:12px 14px;background:var(--dsw-alias-bg-module-platform)}
6775
6788
  .codexSubscriptionCreditBalance{display:flex;flex-direction:column;gap:6px}
@@ -8672,7 +8685,7 @@ window.__ModuleLoader__.load({
8672
8685
  }
8673
8686
  //#endregion
8674
8687
  //#region src/version.js
8675
- const PACKAGE_VERSION = "2.5.0";
8688
+ const PACKAGE_VERSION = "2.5.1";
8676
8689
  //#endregion
8677
8690
  //#region src/client-recovery.js
8678
8691
  async function recoveryCall(rpc, endpoint, payload = {}, timeoutMs = 1e4) {
@@ -11296,8 +11309,38 @@ window.__ModuleLoader__.load({
11296
11309
  ]
11297
11310
  });
11298
11311
  }
11312
+ Object.freeze({
11313
+ credits: 62500,
11314
+ expiresAt: Date.UTC(2026, 11, 31, 12)
11315
+ });
11316
+ const DAY_MS = 864e5;
11317
+ /** Whole days left, and whether the expiry is close enough to call out. */
11318
+ function creditExpiryStatus(expiry, now = Date.now()) {
11319
+ if (expiry === void 0) return void 0;
11320
+ const daysLeft = Math.max(0, Math.ceil((expiry.expiresAt - now) / DAY_MS));
11321
+ return {
11322
+ daysLeft,
11323
+ soon: daysLeft <= 30
11324
+ };
11325
+ }
11299
11326
  //#endregion
11300
11327
  //#region src/client-usage.jsx
11328
+ const count = (value) => Number(value).toLocaleString();
11329
+ function CreditExpiry({ credits, t }) {
11330
+ const date = validDate(credits.expiresAt);
11331
+ if (date === void 0 || credits.unlimited) return null;
11332
+ const status = creditExpiryStatus({ expiresAt: credits.expiresAt });
11333
+ const estimate = credits.expirySource === "estimate";
11334
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
11335
+ className: "codexSubscriptionCreditExpiry",
11336
+ "data-soon": status.soon,
11337
+ role: "status",
11338
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [fill(t(status.daysLeft === 0 ? "creditsExpiredToday" : "creditsExpires"), {
11339
+ date: date.toLocaleDateString(),
11340
+ days: status.daysLeft
11341
+ }), estimate ? ` ${t("creditsExpiryEstimate")}` : ""] })
11342
+ });
11343
+ }
11301
11344
  function ResetTime({ resetsAt, t }) {
11302
11345
  const date = Number.isSafeInteger(resetsAt) ? validDate(resetsAt * 1e3) : void 0;
11303
11346
  if (date === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetUnknown") });
@@ -11559,7 +11602,7 @@ window.__ModuleLoader__.load({
11559
11602
  const visibleUsage = signedIn ? usage : void 0;
11560
11603
  const limits = visibleUsage?.rateLimits ?? [];
11561
11604
  const exhausted = limits.some((limit) => limit.id !== "code_review" && limit.windows.some((window) => window.usedPercent >= 100));
11562
- const hasUsageDetails = limits.length > 0 || visibleUsage?.credits !== void 0 || visibleUsage?.individualLimit !== void 0 || visibleUsage?.resetCredits?.availableCount > 0;
11605
+ const hasUsageDetails = limits.length > 0 || visibleUsage?.chatPass !== void 0 || visibleUsage?.credits !== void 0 || visibleUsage?.individualLimit !== void 0 || visibleUsage?.resetCredits?.availableCount > 0;
11563
11606
  const fetchedAt = typeof visibleUsage?.fetchedAt === "number" ? validDate(visibleUsage.fetchedAt) : void 0;
11564
11607
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11565
11608
  className: "codexSubscriptionCard codexSubscriptionUsageCard",
@@ -11642,6 +11685,36 @@ window.__ModuleLoader__.load({
11642
11685
  ]
11643
11686
  }, `${limit.id}-${window.windowSeconds}-${index}`)))
11644
11687
  }),
11688
+ visibleUsage?.chatPass === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
11689
+ className: "codexSubscriptionLimits",
11690
+ children: visibleUsage.chatPass.windows.map((window, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11691
+ className: "codexSubscriptionLimit",
11692
+ children: [
11693
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11694
+ className: "codexSubscriptionLimitTop",
11695
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
11696
+ className: "codexSubscriptionLimitLabel",
11697
+ children: t("chatPass")
11698
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: [percent(window.remainingPercent), "%"] })]
11699
+ }),
11700
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("progress", {
11701
+ max: "100",
11702
+ value: window.remainingPercent,
11703
+ "aria-label": `${t("chatPass")} ${fill(t("remaining"), { value: percent(window.remainingPercent) })}`
11704
+ }),
11705
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11706
+ className: "codexSubscriptionLimitMeta",
11707
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
11708
+ className: "codexSubscriptionLimitPeriod",
11709
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: windowLabel(window.windowSeconds, t) })
11710
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetTime, {
11711
+ resetsAt: window.resetsAt,
11712
+ t
11713
+ })]
11714
+ })
11715
+ ]
11716
+ }, `chatpass-${window.windowSeconds}-${index}`))
11717
+ }),
11645
11718
  visibleUsage?.credits === void 0 && visibleUsage?.individualLimit === void 0 && !(visibleUsage?.resetCredits?.availableCount > 0) ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
11646
11719
  className: "codexSubscriptionCreditSection",
11647
11720
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -11654,6 +11727,21 @@ window.__ModuleLoader__.load({
11654
11727
  className: "codexSubscriptionCreditBalance",
11655
11728
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("creditsBalance") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: visibleUsage.credits.unlimited ? t("unlimited") : `${visibleUsage.credits.balance ?? t("unavailable")} ${t("creditsUnit")}` })]
11656
11729
  }) : null,
11730
+ visibleUsage?.credits ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CreditExpiry, {
11731
+ credits: visibleUsage.credits,
11732
+ t
11733
+ }) : null,
11734
+ visibleUsage?.credits && !visibleUsage.credits.unlimited ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
11735
+ className: "codexSubscriptionCreditNote",
11736
+ children: t("creditsAfterAllowance")
11737
+ }) : null,
11738
+ visibleUsage?.credits?.approxLocalMessages ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
11739
+ className: "codexSubscriptionCreditNote",
11740
+ children: fill(t("creditsMessages"), {
11741
+ local: `${count(visibleUsage.credits.approxLocalMessages[0])}–${count(visibleUsage.credits.approxLocalMessages[1])}`,
11742
+ cloud: visibleUsage.credits.approxCloudMessages ? `${count(visibleUsage.credits.approxCloudMessages[0])}–${count(visibleUsage.credits.approxCloudMessages[1])}` : t("unavailable")
11743
+ })
11744
+ }) : null,
11657
11745
  visibleUsage?.resetCredits?.availableCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
11658
11746
  className: "codexSubscriptionCreditBalance codexSubscriptionResetDisclosure",
11659
11747
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: fill(t("resetCreditsAvailable"), { count: visibleUsage.resetCredits.availableCount }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditList, {
package/lib/index.js CHANGED
@@ -2043,7 +2043,7 @@ function inheritedOriginalImageRef(session, assetId) {
2043
2043
  }
2044
2044
  //#endregion
2045
2045
  //#region src/version.js
2046
- const PACKAGE_VERSION = "2.5.0";
2046
+ const PACKAGE_VERSION = "2.5.1";
2047
2047
  const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
2048
2048
  //#endregion
2049
2049
  //#region src/codex-images.js
@@ -4824,6 +4824,24 @@ function safeCounters(source, keys) {
4824
4824
  return Object.fromEntries(keys.filter((key) => Number.isSafeInteger(values?.[key]) && values[key] >= 0).map((key) => [key, values[key]]));
4825
4825
  }
4826
4826
  //#endregion
4827
+ //#region src/credit-expiry.js
4828
+ const PRO_200_COMPENSATION = Object.freeze({
4829
+ credits: 62500,
4830
+ expiresAt: Date.UTC(2026, 11, 31, 12)
4831
+ });
4832
+ /** Expiry of the balance: the API's own value when it has one, otherwise the known grant. */
4833
+ function creditExpiry({ planType, balance, apiExpiresAt }, now = Date.now()) {
4834
+ if (Number.isFinite(apiExpiresAt) && apiExpiresAt > now) return {
4835
+ expiresAt: apiExpiresAt,
4836
+ source: "api"
4837
+ };
4838
+ const amount = Number(balance);
4839
+ if (planType === "pro" && Number.isFinite(amount) && amount >= PRO_200_COMPENSATION.credits && now < PRO_200_COMPENSATION.expiresAt) return {
4840
+ expiresAt: PRO_200_COMPENSATION.expiresAt,
4841
+ source: "estimate"
4842
+ };
4843
+ }
4844
+ //#endregion
4827
4845
  //#region src/usage.js
4828
4846
  const CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
4829
4847
  const DEFAULT_TTL_MS = 6e4;
@@ -4865,15 +4883,44 @@ function epochSeconds(value, label) {
4865
4883
  if (!Number.isSafeInteger(value) || value < 0) throw new Error(`Codex returned an invalid ${label}`);
4866
4884
  return value;
4867
4885
  }
4868
- function creditsOf(value) {
4886
+ function messageRange(value) {
4887
+ return Array.isArray(value) && value.length === 2 && value.every((item) => Number.isSafeInteger(item) && item >= 0) ? [value[0], value[1]] : void 0;
4888
+ }
4889
+ function expiryOf(value) {
4890
+ const raw = value?.expires_at;
4891
+ if (Number.isSafeInteger(raw) && raw > 0) return raw * 1e3;
4892
+ if (typeof raw === "string" && raw.length <= 64) {
4893
+ const parsed = Date.parse(raw);
4894
+ if (Number.isFinite(parsed) && parsed > 0) return parsed;
4895
+ }
4896
+ }
4897
+ function creditsOf(value, planType) {
4869
4898
  if (value === void 0 || value === null) return void 0;
4870
4899
  if (!record$1(value) || typeof value.has_credits !== "boolean" || typeof value.unlimited !== "boolean") throw new Error("Codex returned malformed credit details");
4871
4900
  if (!value.has_credits) return void 0;
4901
+ const balance = value.balance === void 0 || value.balance === null ? void 0 : decimal(value.balance, "credit balance");
4902
+ const expiry = value.unlimited ? void 0 : creditExpiry({
4903
+ planType,
4904
+ balance,
4905
+ apiExpiresAt: expiryOf(value)
4906
+ });
4907
+ const local = messageRange(value.approx_local_messages), cloud = messageRange(value.approx_cloud_messages);
4872
4908
  return {
4873
4909
  unlimited: value.unlimited,
4874
- ...value.balance === void 0 || value.balance === null ? {} : { balance: decimal(value.balance, "credit balance") }
4910
+ ...balance === void 0 ? {} : { balance },
4911
+ ...expiry === void 0 ? {} : {
4912
+ expiresAt: expiry.expiresAt,
4913
+ expirySource: expiry.source
4914
+ },
4915
+ ...local === void 0 ? {} : { approxLocalMessages: local },
4916
+ ...cloud === void 0 ? {} : { approxCloudMessages: cloud }
4875
4917
  };
4876
4918
  }
4919
+ function chatPassOf(value) {
4920
+ if (!record$1(value) || !Array.isArray(value.windows)) return void 0;
4921
+ const windows = value.windows.map(windowOf).filter(Boolean);
4922
+ return windows.length === 0 ? void 0 : { windows };
4923
+ }
4877
4924
  function individualOf(value) {
4878
4925
  if (value === void 0 || value === null) return void 0;
4879
4926
  if (!record$1(value)) throw new Error("Codex returned malformed spend control");
@@ -4937,12 +4984,14 @@ function parseCodexUsage(value) {
4937
4984
  addLimit(limitOf(entry.metered_feature, entry.limit_name || void 0, entry.rate_limit));
4938
4985
  }
4939
4986
  addLimit(limitOf("code_review", "Code review", value.code_review_rate_limit));
4940
- const credits = creditsOf(value.credits);
4987
+ const chatPass = chatPassOf(value.chatpass);
4988
+ const credits = creditsOf(value.credits, typeof value.plan_type === "string" ? value.plan_type : void 0);
4941
4989
  const individualLimit = individualOf(value.spend_control);
4942
4990
  const spendControlReached = spendControlReachedOf(value.spend_control);
4943
4991
  const resetCredits = resetCreditsOf(value.rate_limit_reset_credits);
4944
4992
  return {
4945
4993
  rateLimits,
4994
+ ...chatPass === void 0 ? {} : { chatPass },
4946
4995
  ...credits === void 0 ? {} : { credits },
4947
4996
  ...individualLimit === void 0 ? {} : { individualLimit },
4948
4997
  ...spendControlReached === void 0 ? {} : { spendControlReached },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-codex-subscription",
3
- "version": "2.5.0",
3
+ "version": "2.5.1",
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",