pi-provider-qoder-cn 0.2.22 → 0.2.24

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.
Files changed (3) hide show
  1. package/README.md +4 -0
  2. package/dist/index.js +45 -37
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -144,6 +144,10 @@ Notes:
144
144
  latest grant`, and an account that has never claimed prints no expiry line at
145
145
  all, because with no grant there is nothing to date from, and inventing one
146
146
  would show dates the API never sent.
147
+ - `Enterprise` is the org-wide pool. It names its allowance `cap` and sends no
148
+ `total`, so the row is keyed on any of `cap`, `used` or `remaining` carrying a
149
+ value: a freshly refreshed cycle reports `used: 0`, and that used to drop the
150
+ whole row and leave the view saying `Buckets none returned`.
147
151
  - `Expires never` means the API reported the year-9999 sentinel, i.e. the
148
152
  allowance has no expiry date.
149
153
  - `Note plan quota is prorated` appears after a mid-cycle plan change.
package/dist/index.js CHANGED
@@ -1791,29 +1791,36 @@ var init_oauth = __esm({
1791
1791
  // src/index.ts
1792
1792
  init_oauth();
1793
1793
 
1794
- // src/auth/usage.ts
1795
- init_region();
1796
- function num(value) {
1794
+ // src/quota.ts
1795
+ function quotaNumber(value) {
1797
1796
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
1798
1797
  }
1799
- function round2(value) {
1800
- return Math.round(value * 100) / 100;
1798
+ function bucketLimit(bucket) {
1799
+ return quotaNumber(bucket.total ?? bucket.cap);
1801
1800
  }
1802
1801
  function hasAllowance(bucket) {
1803
1802
  if (!bucket) return false;
1804
- return num(bucket.total ?? bucket.cap) > 0 || num(bucket.used) > 0 || num(bucket.remaining) > 0;
1803
+ return bucketLimit(bucket) > 0 || quotaNumber(bucket.used) > 0 || quotaNumber(bucket.remaining) > 0;
1804
+ }
1805
+ function pickBucket(raw, camel) {
1806
+ if (!raw) return void 0;
1807
+ const source = raw;
1808
+ const snake = camel.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
1809
+ return source[snake] ?? source[camel];
1810
+ }
1811
+
1812
+ // src/auth/usage.ts
1813
+ init_region();
1814
+ function round2(value) {
1815
+ return Math.round(value * 100) / 100;
1805
1816
  }
1806
1817
  function resetTimestamp(expiresAt) {
1807
- const ms = num(expiresAt);
1818
+ const ms = quotaNumber(expiresAt);
1808
1819
  if (ms <= 0) return void 0;
1809
1820
  const timestamp = ms < 1e12 ? ms * 1e3 : ms;
1810
1821
  if (new Date(timestamp).getUTCFullYear() >= 9999) return void 0;
1811
1822
  return new Date(timestamp).toISOString();
1812
1823
  }
1813
- function pickBucket(raw, camel) {
1814
- const snake = camel.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
1815
- return raw[snake] ?? raw[camel];
1816
- }
1817
1824
  async function fetchQoderUsageForMode(credentials, mode) {
1818
1825
  const region = getQoderRegionConfig(mode);
1819
1826
  const response = await fetch(getQoderUsageURL(mode), {
@@ -1838,12 +1845,12 @@ async function fetchQoderUsageForMode(credentials, mode) {
1838
1845
  const usageBuckets = buckets.map(({ id, label, quota }) => ({
1839
1846
  id,
1840
1847
  label,
1841
- usedDisplay: round2(num(quota?.used)).toFixed(2),
1842
- limitDisplay: round2(num(quota?.total ?? quota?.cap)).toFixed(2),
1848
+ usedDisplay: round2(quotaNumber(quota?.used)).toFixed(2),
1849
+ limitDisplay: round2(quotaNumber(quota?.total ?? quota?.cap)).toFixed(2),
1843
1850
  unit: quota?.unit || "credits",
1844
1851
  resetAt
1845
1852
  }));
1846
- const remaining = buckets.reduce((sum, { quota }) => sum + Math.max(0, num(quota?.remaining)), 0);
1853
+ const remaining = buckets.reduce((sum, { quota }) => sum + Math.max(0, quotaNumber(quota?.remaining)), 0);
1847
1854
  const unit = buckets[0]?.quota?.unit || "credits";
1848
1855
  return {
1849
1856
  summary: buckets.length > 0 ? `${round2(remaining)} ${unit} remaining` : "",
@@ -2448,6 +2455,11 @@ function getBeijingDailyResetCountdown(now = Date.now()) {
2448
2455
  const minutes = totalMinutes % 60;
2449
2456
  return hours > 0 ? `${hours}\u5C0F\u65F6${minutes}\u5206\u949F` : `${minutes}\u5206\u949F`;
2450
2457
  }
2458
+ var CREDENTIAL_EXPIRED_CODES = /* @__PURE__ */ new Set(["105", "TOKEN_EXPIRE", "TOKEN_EXPIRED"]);
2459
+ var CREDENTIAL_EXPIRED_MESSAGE = /token expired|login expired|token is not active|token has expired/i;
2460
+ function isCredentialExpiredVerdict(code, message) {
2461
+ return code !== void 0 && CREDENTIAL_EXPIRED_CODES.has(code) || CREDENTIAL_EXPIRED_MESSAGE.test(message);
2462
+ }
2451
2463
  function formatQoderStreamError(statusCode, rawBody, now = Date.now(), mode = "cn") {
2452
2464
  const parsed = parseQoderErrorPayload(rawBody);
2453
2465
  const code = parsed?.code;
@@ -2527,7 +2539,7 @@ function formatQoderStreamError(statusCode, rawBody, now = Date.now(), mode = "c
2527
2539
  `- Fix: purchase a credit pack at ${store}, or wait for the next billing cycle.`
2528
2540
  ].join("\n");
2529
2541
  }
2530
- if (code === "105" || /token expired/i.test(message) || /login expired/i.test(message)) {
2542
+ if (isCredentialExpiredVerdict(code, message)) {
2531
2543
  if (isCn) {
2532
2544
  return [
2533
2545
  `[Qoder CN \u51ED\u8BC1\u5931\u6548] \u767B\u5F55\u6001\u5DF2\u8FC7\u671F\u6216 Token \u5931\u6548 (\u9519\u8BEF\u7801 105)`,
@@ -2591,7 +2603,8 @@ function formatQoderStreamError(statusCode, rawBody, now = Date.now(), mode = "c
2591
2603
  }
2592
2604
  function isCredentialExpiredError(error) {
2593
2605
  const message = error instanceof Error ? error.message : String(error ?? "");
2594
- return message.includes("\u9519\u8BEF\u7801 105") || message.includes("\u51ED\u8BC1\u5931\u6548") || /token expired|login expired/i.test(message);
2606
+ if (message.includes("\u9519\u8BEF\u7801 105") || message.includes("\u51ED\u8BC1\u5931\u6548")) return true;
2607
+ return isCredentialExpiredVerdict(void 0, message) || /TOKEN_EXPIRED?/i.test(message);
2595
2608
  }
2596
2609
 
2597
2610
  // src/commands/usage.ts
@@ -2744,33 +2757,28 @@ function bucketRow(label, bucket, danger) {
2744
2757
  danger
2745
2758
  };
2746
2759
  }
2747
- function hasBucket(bucket) {
2748
- if (!bucket) return false;
2749
- return (bucket.total ?? 0) > 0 || (bucket.used ?? 0) > 0;
2750
- }
2751
- function pickBucket2(raw, camel) {
2752
- if (!raw) return void 0;
2753
- const snake = camel.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`);
2754
- return raw[snake] ?? raw[camel];
2755
- }
2756
2760
  function formatQoderUsage(raw, mode, now = Date.now(), options = {}) {
2757
2761
  const color = options.color ?? false;
2758
2762
  const region = getQoderRegionConfig(mode);
2759
2763
  const danger = Boolean(raw?.isQuotaExceeded);
2760
2764
  const userType = raw?.userType ? ` (${raw.userType})` : "";
2761
- const showUserQuota = hasBucket(pickBucket2(raw, "userQuota"));
2762
- const showAddOnQuota = hasBucket(pickBucket2(raw, "addOnQuota"));
2763
- const org = pickBucket2(raw, "orgResourcePackage") ?? pickBucket2(raw, "sharedQuota");
2764
- const showOrg = hasBucket(org);
2765
- const orgPercent = typeof org?.used === "number" && typeof org?.cap === "number" && org.cap > 0 ? formatPercent(org.used / org.cap * 100) : void 0;
2765
+ const showUserQuota = hasAllowance(pickBucket(raw, "userQuota"));
2766
+ const showAddOnQuota = hasAllowance(pickBucket(raw, "addOnQuota"));
2767
+ const org = pickBucket(raw, "orgResourcePackage") ?? pickBucket(raw, "sharedQuota");
2768
+ const showOrg = hasAllowance(org);
2769
+ const orgLimit = org ? bucketLimit(org) : 0;
2770
+ const orgPercent = org && orgLimit > 0 ? formatPercent(quotaNumber(org.used) / orgLimit * 100) : void 0;
2766
2771
  const overallPercent = formatPercent(
2767
- showOrg ? normalizePercent(raw?.totalUsagePercentage) || orgPercent : normalizePercent(raw?.totalUsagePercentage)
2772
+ showOrg ? orgPercent ?? normalizePercent(raw?.totalUsagePercentage) : normalizePercent(raw?.totalUsagePercentage)
2768
2773
  );
2769
2774
  const rows = [{ label: "Overall", percent: overallPercent, tail: "used", danger }];
2770
- if (showUserQuota) rows.push(bucketRow("Plan quota", pickBucket2(raw, "userQuota"), danger));
2771
- if (showAddOnQuota) rows.push(bucketRow("Add-on", pickBucket2(raw, "addOnQuota"), danger));
2772
- if (showOrg && org)
2773
- rows.push(bucketRow("Enterprise", { ...org, percentage: void 0, total: org.cap ?? org.total }, danger));
2775
+ if (showUserQuota) rows.push(bucketRow("Plan quota", pickBucket(raw, "userQuota"), danger));
2776
+ if (showAddOnQuota) rows.push(bucketRow("Add-on", pickBucket(raw, "addOnQuota"), danger));
2777
+ if (showOrg && org) {
2778
+ rows.push(
2779
+ bucketRow("Enterprise", { ...org, percentage: void 0, total: orgLimit, used: quotaNumber(org.used) }, danger)
2780
+ );
2781
+ }
2774
2782
  const isPersonalStandard = raw?.userType === "personal_standard" || raw?.userType === "free";
2775
2783
  const notes = [];
2776
2784
  if (danger) {
@@ -2808,7 +2816,7 @@ function formatQoderUsage(raw, mode, now = Date.now(), options = {}) {
2808
2816
  });
2809
2817
  }
2810
2818
  }
2811
- const addOn = pickBucket2(raw, "addOnQuota");
2819
+ const addOn = pickBucket(raw, "addOnQuota");
2812
2820
  if (showAddOnQuota && (addOn?.remaining ?? 0) > 0 && checkin) {
2813
2821
  const expiryMs = checkin.expiresAt ? Date.parse(checkin.expiresAt) : void 0;
2814
2822
  const grant = { expiryMs, amount: checkin.amount, validityDays: checkin.validityDays };
@@ -3518,7 +3526,7 @@ async function peekCredentialExpired(reader, decoder) {
3518
3526
  if (typeof envelope.statusCodeValue === "number" && envelope.statusCodeValue !== 200) {
3519
3527
  const parsed = parseQoderErrorPayload(envelope.body);
3520
3528
  const message = parsed?.message ?? (typeof envelope.body === "string" ? envelope.body : "");
3521
- return parsed?.code === "105" || /token expired|login expired/i.test(message);
3529
+ return isCredentialExpiredVerdict(parsed?.code, message);
3522
3530
  }
3523
3531
  return false;
3524
3532
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-provider-qoder-cn",
3
- "version": "0.2.22",
3
+ "version": "0.2.24",
4
4
  "description": "Pi extension for Qoder CN — PAT/OAuth auth, /qoder-cn.usage quota command, and enterprise VPC endpoint support",
5
5
  "type": "module",
6
6
  "license": "MIT",