@leo000001/opencode-quota-sidebar 3.0.1 → 3.0.2

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 (41) hide show
  1. package/CHANGELOG.md +14 -2
  2. package/CONTRIBUTING.md +4 -1
  3. package/README.md +210 -514
  4. package/README.zh-CN.md +337 -0
  5. package/SECURITY.md +2 -2
  6. package/assets/OpenCode-Quota-Sidebar.png +0 -0
  7. package/dist/cost.d.ts +3 -3
  8. package/dist/cost.js +258 -169
  9. package/dist/format.js +10 -3
  10. package/dist/providers/common.d.ts +6 -0
  11. package/dist/providers/common.js +32 -12
  12. package/dist/providers/core/anthropic.d.ts +1 -1
  13. package/dist/providers/core/anthropic.js +43 -39
  14. package/dist/providers/core/kimi_for_coding.d.ts +1 -1
  15. package/dist/providers/core/kimi_for_coding.js +44 -64
  16. package/dist/providers/core/minimax_cn_coding_plan.d.ts +2 -0
  17. package/dist/providers/core/minimax_cn_coding_plan.js +214 -0
  18. package/dist/providers/core/zhipu_coding_plan.d.ts +1 -1
  19. package/dist/providers/core/zhipu_coding_plan.js +41 -61
  20. package/dist/providers/index.d.ts +3 -3
  21. package/dist/providers/index.js +5 -5
  22. package/dist/providers/third_party/rightcode.d.ts +1 -1
  23. package/dist/providers/third_party/rightcode.js +41 -61
  24. package/dist/providers/third_party/xyai.d.ts +2 -0
  25. package/dist/providers/third_party/{xyai_vibe.js → xyai.js} +113 -79
  26. package/dist/quota.d.ts +2 -2
  27. package/dist/quota.js +24 -18
  28. package/dist/quota_render.d.ts +1 -1
  29. package/dist/quota_render.js +23 -17
  30. package/dist/storage_parse.js +1 -0
  31. package/dist/title.js +7 -7
  32. package/dist/title_apply.js +18 -1
  33. package/dist/tui.tsx +2 -1
  34. package/dist/tui_helpers.d.ts +2 -1
  35. package/dist/tui_helpers.js +6 -1
  36. package/dist/types.d.ts +2 -0
  37. package/package.json +9 -2
  38. package/quota-sidebar.config.example.json +45 -45
  39. package/dist/providers/third_party/buzz.d.ts +0 -2
  40. package/dist/providers/third_party/buzz.js +0 -156
  41. package/dist/providers/third_party/xyai_vibe.d.ts +0 -2
@@ -1,39 +1,19 @@
1
- import { isRecord, swallow } from '../../helpers.js';
2
- import { asNumber, basePathPrefixes, configuredProviderEnabled, fetchWithTimeout, sanitizeBaseURL, toIso, } from '../common.js';
1
+ import { isRecord, swallow } from "../../helpers.js";
2
+ import { asNumber, basePathPrefixes, configuredProviderEnabled, fetchWithTimeout, resolveApiKey, sanitizeBaseURL, toIso, } from "../common.js";
3
3
  function isRightCodeBaseURL(value) {
4
4
  const normalized = sanitizeBaseURL(value);
5
5
  if (!normalized)
6
6
  return false;
7
7
  try {
8
8
  const parsed = new URL(normalized);
9
- if (parsed.protocol !== 'https:')
9
+ if (parsed.protocol !== "https:")
10
10
  return false;
11
- return parsed.host === 'www.right.codes' || parsed.host === 'right.codes';
11
+ return parsed.host === "www.right.codes" || parsed.host === "right.codes";
12
12
  }
13
13
  catch {
14
14
  return false;
15
15
  }
16
16
  }
17
- function resolveApiKey(auth, providerOptions) {
18
- const optionKey = providerOptions?.apiKey;
19
- if (typeof optionKey === 'string' && optionKey)
20
- return optionKey;
21
- if (!auth)
22
- return undefined;
23
- if (auth.type === 'api' && typeof auth.key === 'string' && auth.key) {
24
- return auth.key;
25
- }
26
- if (auth.type === 'wellknown') {
27
- if (typeof auth.key === 'string' && auth.key)
28
- return auth.key;
29
- if (typeof auth.token === 'string' && auth.token)
30
- return auth.token;
31
- }
32
- if (auth.type === 'oauth' && typeof auth.access === 'string' && auth.access) {
33
- return auth.access;
34
- }
35
- return undefined;
36
- }
37
17
  function matchesSubscriptionPrefix(providerPrefixes, availablePrefixes) {
38
18
  if (providerPrefixes.length === 0 || availablePrefixes.length === 0) {
39
19
  return false;
@@ -50,10 +30,10 @@ function matchesSubscriptionPrefix(providerPrefixes, availablePrefixes) {
50
30
  }
51
31
  function formatQuotaValue(value) {
52
32
  if (!Number.isFinite(value))
53
- return '0';
33
+ return "0";
54
34
  if (Math.abs(value) >= 10) {
55
35
  const one = value.toFixed(1);
56
- return one.endsWith('.0') ? one.slice(0, -2) : one;
36
+ return one.endsWith(".0") ? one.slice(0, -2) : one;
57
37
  }
58
38
  return value.toFixed(2);
59
39
  }
@@ -72,7 +52,7 @@ function parseSubscription(value) {
72
52
  // Intentionally not using normalizePercent(): daily ratio can exceed 100%.
73
53
  const remainingPercent = (dailyRemaining / total) * 100;
74
54
  return {
75
- name: typeof value.name === 'string' ? value.name : 'Subscription',
55
+ name: typeof value.name === "string" ? value.name : "Subscription",
76
56
  dailyTotal: total,
77
57
  dailyRemaining,
78
58
  remainingPercent,
@@ -83,20 +63,20 @@ function extractPrefixes(value) {
83
63
  const raw = value.available_prefixes;
84
64
  if (!Array.isArray(raw))
85
65
  return [];
86
- return raw.filter((item) => typeof item === 'string' && !!item);
66
+ return raw.filter((item) => typeof item === "string" && !!item);
87
67
  }
88
68
  async function fetchRightCodeQuota(ctx) {
89
69
  const checkedAt = Date.now();
90
- const sourceProviderID = typeof ctx.sourceProviderID === 'string' && ctx.sourceProviderID
70
+ const sourceProviderID = typeof ctx.sourceProviderID === "string" && ctx.sourceProviderID
91
71
  ? ctx.sourceProviderID
92
72
  : ctx.providerID;
93
- const shortLabel = sourceProviderID.startsWith('rightcode-')
94
- ? `RC-${sourceProviderID.slice('rightcode-'.length)}`
95
- : 'RC';
73
+ const shortLabel = sourceProviderID.startsWith("rightcode-")
74
+ ? `RC-${sourceProviderID.slice("rightcode-".length)}`
75
+ : "RC";
96
76
  const base = {
97
77
  providerID: sourceProviderID,
98
- adapterID: 'rightcode',
99
- label: 'RightCode',
78
+ adapterID: "rightcode",
79
+ label: "RightCode",
100
80
  shortLabel,
101
81
  sortOrder: 5,
102
82
  };
@@ -104,43 +84,43 @@ async function fetchRightCodeQuota(ctx) {
104
84
  if (!apiKey) {
105
85
  return {
106
86
  ...base,
107
- status: 'unavailable',
87
+ status: "unavailable",
108
88
  checkedAt,
109
- note: 'missing api key',
89
+ note: "missing api key",
110
90
  };
111
91
  }
112
- const response = await fetchWithTimeout('https://www.right.codes/account/summary', {
92
+ const response = await fetchWithTimeout("https://www.right.codes/account/summary", {
113
93
  headers: {
114
- Accept: 'application/json',
94
+ Accept: "application/json",
115
95
  Authorization: `Bearer ${apiKey}`,
116
- 'User-Agent': 'opencode-quota-sidebar',
96
+ "User-Agent": "opencode-quota-sidebar",
117
97
  },
118
- }, ctx.config.quota.requestTimeoutMs).catch(swallow('fetchRightCodeQuota'));
98
+ }, ctx.config.quota.requestTimeoutMs).catch(swallow("fetchRightCodeQuota"));
119
99
  if (!response) {
120
100
  return {
121
101
  ...base,
122
- status: 'error',
102
+ status: "error",
123
103
  checkedAt,
124
- note: 'network request failed',
104
+ note: "network request failed",
125
105
  };
126
106
  }
127
107
  if (!response.ok) {
128
108
  return {
129
109
  ...base,
130
- status: 'error',
110
+ status: "error",
131
111
  checkedAt,
132
112
  note: `http ${response.status}`,
133
113
  };
134
114
  }
135
115
  const payload = await response
136
116
  .json()
137
- .catch(swallow('fetchRightCodeQuota:json'));
117
+ .catch(swallow("fetchRightCodeQuota:json"));
138
118
  if (!isRecord(payload)) {
139
119
  return {
140
120
  ...base,
141
- status: 'error',
121
+ status: "error",
142
122
  checkedAt,
143
- note: 'invalid response',
123
+ note: "invalid response",
144
124
  };
145
125
  }
146
126
  const balance = asNumber(payload.balance);
@@ -164,7 +144,7 @@ async function fetchRightCodeQuota(ctx) {
164
144
  const dailyPercent = dailyTotal > 0 ? (dailyRemaining / dailyTotal) * 100 : undefined;
165
145
  const parsedExpiries = matched
166
146
  .map((subscription) => subscription.expiresAt)
167
- .filter((iso) => typeof iso === 'string' && !!iso)
147
+ .filter((iso) => typeof iso === "string" && !!iso)
168
148
  .map((iso) => ({ iso, ts: Date.parse(iso) }))
169
149
  .filter((item) => !Number.isNaN(item.ts));
170
150
  const uniqueExpiryTimestamps = new Set(parsedExpiries.map((e) => e.ts));
@@ -184,10 +164,10 @@ async function fetchRightCodeQuota(ctx) {
184
164
  remainingPercent: dailyPercent,
185
165
  },
186
166
  ];
187
- const names = matched.map((subscription) => subscription.name).join(', ');
167
+ const names = matched.map((subscription) => subscription.name).join(", ");
188
168
  return {
189
169
  ...base,
190
- status: dailyPercent === undefined ? 'error' : 'ok',
170
+ status: dailyPercent === undefined ? "error" : "ok",
191
171
  checkedAt,
192
172
  remainingPercent: dailyPercent,
193
173
  expiresAt: expiry,
@@ -195,39 +175,39 @@ async function fetchRightCodeQuota(ctx) {
195
175
  ? undefined
196
176
  : {
197
177
  amount: balance,
198
- currency: '$',
178
+ currency: "$",
199
179
  },
200
180
  windows,
201
181
  note: dailyPercent === undefined
202
- ? 'matched subscription has no daily quota fields'
203
- : `subscription daily quota: ${names}${expiry ? ` | exp ${expiry.slice(5, 10)}` : ''}${hasMultipleExpiries ? '+' : ''}`,
182
+ ? "matched subscription has no daily quota fields"
183
+ : `subscription daily quota: ${names}${expiry ? ` | exp ${expiry.slice(5, 10)}` : ""}${hasMultipleExpiries ? "+" : ""}`,
204
184
  };
205
185
  }
206
186
  if (balance !== undefined) {
207
187
  return {
208
188
  ...base,
209
- status: 'ok',
189
+ status: "ok",
210
190
  checkedAt,
211
191
  balance: {
212
192
  amount: balance,
213
- currency: '$',
193
+ currency: "$",
214
194
  },
215
- note: 'no matching subscription for provider prefix',
195
+ note: "no matching subscription for provider prefix",
216
196
  };
217
197
  }
218
198
  return {
219
199
  ...base,
220
- status: 'error',
200
+ status: "error",
221
201
  checkedAt,
222
- note: 'missing balance and subscription fields',
202
+ note: "missing balance and subscription fields",
223
203
  };
224
204
  }
225
205
  export const rightCodeAdapter = {
226
- id: 'rightcode',
227
- label: 'RightCode',
228
- shortLabel: 'RC',
206
+ id: "rightcode",
207
+ label: "RightCode",
208
+ shortLabel: "RC",
229
209
  sortOrder: 5,
230
210
  matchScore: ({ providerOptions }) => isRightCodeBaseURL(providerOptions?.baseURL) ? 100 : 0,
231
- isEnabled: (config) => configuredProviderEnabled(config.quota, 'rightcode', true),
211
+ isEnabled: (config) => configuredProviderEnabled(config.quota, "rightcode", true),
232
212
  fetch: fetchRightCodeQuota,
233
213
  };
@@ -0,0 +1,2 @@
1
+ import type { QuotaProviderAdapter } from "../types.js";
2
+ export declare const xyaiAdapter: QuotaProviderAdapter;
@@ -1,6 +1,6 @@
1
- import { debugError, isRecord, swallow } from '../../helpers.js';
2
- import { asNumber, configuredProviderEnabled, fetchWithTimeout, sanitizeBaseURL, toIso, } from '../common.js';
3
- const XYAI_BASE_URL = 'https://new.xychatai.com';
1
+ import { debugError, isRecord, swallow } from "../../helpers.js";
2
+ import { asNumber, configuredProviderEnabled, fetchWithTimeout, sanitizeBaseURL, toIso, } from "../common.js";
3
+ const XYAI_BASE_URL = "https://new.xychatai.com";
4
4
  function resolveSiteOrigin(value) {
5
5
  const normalized = sanitizeBaseURL(value);
6
6
  if (!normalized)
@@ -18,7 +18,7 @@ function isXyaiBaseURL(value) {
18
18
  return false;
19
19
  try {
20
20
  const parsed = new URL(normalized);
21
- return parsed.protocol === 'https:' && parsed.host === 'new.xychatai.com';
21
+ return parsed.protocol === "https:" && parsed.host === "new.xychatai.com";
22
22
  }
23
23
  catch {
24
24
  return false;
@@ -29,45 +29,62 @@ function providerConfigFor(config, providerIDs) {
29
29
  if (!providerID)
30
30
  continue;
31
31
  const value = config.quota.providers?.[providerID];
32
- if (value && typeof value === 'object' && !Array.isArray(value)) {
32
+ if (value && typeof value === "object" && !Array.isArray(value)) {
33
33
  return value;
34
34
  }
35
35
  }
36
36
  return undefined;
37
37
  }
38
+ function xyaiConfigCandidates(runtimeProviderID, providerID) {
39
+ const candidates = [];
40
+ const push = (value) => {
41
+ if (!value)
42
+ return;
43
+ if (!candidates.includes(value))
44
+ candidates.push(value);
45
+ };
46
+ if (runtimeProviderID === "xyai" || runtimeProviderID === "xyai-vibe") {
47
+ push("xyai");
48
+ }
49
+ push(runtimeProviderID);
50
+ push(providerID);
51
+ push("xyai");
52
+ push("xyai-vibe");
53
+ return candidates;
54
+ }
38
55
  function resolveSessionCookie(auth, providerConfig) {
39
- if (typeof providerConfig?.sessionCookie === 'string' &&
56
+ if (typeof providerConfig?.sessionCookie === "string" &&
40
57
  providerConfig.sessionCookie) {
41
58
  return providerConfig.sessionCookie;
42
59
  }
43
60
  if (!auth)
44
61
  return undefined;
45
- if (auth.type === 'wellknown') {
46
- if (typeof auth.token === 'string' && auth.token)
62
+ if (auth.type === "wellknown") {
63
+ if (typeof auth.token === "string" && auth.token)
47
64
  return auth.token;
48
65
  }
49
66
  return undefined;
50
67
  }
51
68
  function resolveServiceType(providerConfig) {
52
- return providerConfig?.serviceType === 'claudecode' ? 'claudecode' : 'codex';
69
+ return providerConfig?.serviceType === "claudecode" ? "claudecode" : "codex";
53
70
  }
54
71
  function resolveLogin(providerConfig) {
55
72
  const login = providerConfig?.login;
56
- if (!login || typeof login !== 'object' || Array.isArray(login)) {
73
+ if (!login || typeof login !== "object" || Array.isArray(login)) {
57
74
  return undefined;
58
75
  }
59
- const username = typeof login.username === 'string' ? login.username.trim() : '';
60
- const password = typeof login.password === 'string' ? login.password : '';
76
+ const username = typeof login.username === "string" ? login.username.trim() : "";
77
+ const password = typeof login.password === "string" ? login.password : "";
61
78
  if (!username || !password)
62
79
  return undefined;
63
80
  return { username, password };
64
81
  }
65
82
  function headerCookies(response) {
66
83
  const headers = response.headers;
67
- if (typeof headers.getSetCookie === 'function') {
84
+ if (typeof headers.getSetCookie === "function") {
68
85
  return headers.getSetCookie().filter(Boolean);
69
86
  }
70
- const joined = response.headers.get('set-cookie');
87
+ const joined = response.headers.get("set-cookie");
71
88
  return joined ? [joined] : [];
72
89
  }
73
90
  function extractShareSession(response) {
@@ -80,45 +97,49 @@ function extractShareSession(response) {
80
97
  }
81
98
  async function loginAndPersistSession(siteOrigin, login, providerID, updateAuth, timeoutMs) {
82
99
  const response = await fetchWithTimeout(`${siteOrigin}/frontend-api/login`, {
83
- method: 'POST',
100
+ method: "POST",
84
101
  headers: {
85
- Accept: 'application/json',
86
- 'Content-Type': 'application/json',
87
- 'User-Agent': 'opencode-quota-sidebar',
102
+ Accept: "application/json",
103
+ "Content-Type": "application/json",
104
+ "User-Agent": "opencode-quota-sidebar",
88
105
  },
89
106
  body: JSON.stringify({
90
107
  userToken: login.username,
91
108
  password: login.password,
92
- token: '',
109
+ token: "",
93
110
  }),
94
- }, timeoutMs).catch(swallow('fetchXyaiVibeQuota:login'));
111
+ }, timeoutMs).catch(swallow("fetchXyaiQuota:login"));
95
112
  if (!response) {
96
- return { error: 'login request failed' };
113
+ return { error: "login request failed" };
97
114
  }
98
115
  if (!response.ok) {
99
116
  return { error: `login http ${response.status}` };
100
117
  }
101
- const payload = await response.json().catch(swallow('fetchXyaiVibeQuota:loginJson'));
118
+ const payload = await response
119
+ .json()
120
+ .catch(swallow("fetchXyaiQuota:loginJson"));
102
121
  if (!isRecord(payload)) {
103
- return { error: 'invalid login response' };
122
+ return { error: "invalid login response" };
104
123
  }
105
124
  if (payload.code !== 1) {
106
- const msg = typeof payload.msg === 'string' && payload.msg ? payload.msg : 'login failed';
125
+ const msg = typeof payload.msg === "string" && payload.msg
126
+ ? payload.msg
127
+ : "login failed";
107
128
  return { error: msg };
108
129
  }
109
130
  const session = extractShareSession(response);
110
131
  if (!session) {
111
- return { error: 'missing share-session cookie' };
132
+ return { error: "missing share-session cookie" };
112
133
  }
113
134
  if (updateAuth) {
114
135
  try {
115
- await updateAuth(providerID, { type: 'wellknown', token: session });
136
+ await updateAuth(providerID, { type: "wellknown", token: session });
116
137
  }
117
138
  catch (error) {
118
- debugError('updateAuth:xyai-vibe', error);
139
+ debugError("updateAuth:xyai", error);
119
140
  return {
120
141
  session,
121
- warning: 'session refreshed but failed to persist; using in-memory session',
142
+ warning: "session refreshed but failed to persist; using in-memory session",
122
143
  };
123
144
  }
124
145
  }
@@ -127,35 +148,39 @@ async function loginAndPersistSession(siteOrigin, login, providerID, updateAuth,
127
148
  async function fetchQuotaPayload(siteOrigin, session, timeoutMs) {
128
149
  const response = await fetchWithTimeout(`${siteOrigin}/frontend-api/vibe-code/quota`, {
129
150
  headers: {
130
- Accept: 'application/json',
151
+ Accept: "application/json",
131
152
  Cookie: `share-session=${session}`,
132
- 'User-Agent': 'opencode-quota-sidebar',
153
+ "User-Agent": "opencode-quota-sidebar",
133
154
  },
134
- }, timeoutMs).catch(swallow('fetchXyaiVibeQuota:quota'));
155
+ }, timeoutMs).catch(swallow("fetchXyaiQuota:quota"));
135
156
  if (!response)
136
- return { error: 'network request failed' };
157
+ return { error: "network request failed" };
137
158
  if (!response.ok)
138
159
  return { error: `http ${response.status}` };
139
- const payload = await response.json().catch(swallow('fetchXyaiVibeQuota:quotaJson'));
160
+ const payload = await response
161
+ .json()
162
+ .catch(swallow("fetchXyaiQuota:quotaJson"));
140
163
  if (!isRecord(payload))
141
- return { error: 'invalid response' };
164
+ return { error: "invalid response" };
142
165
  return { payload };
143
166
  }
144
167
  function isAuthFailure(payload) {
145
- return payload.code === -1 || payload.msg === '认证失败,请重新登录';
168
+ return payload.code === -1 || payload.msg === "认证失败,请重新登录";
146
169
  }
147
170
  function formatAmount(value) {
148
171
  if (!Number.isFinite(value))
149
- return '0';
172
+ return "0";
150
173
  if (Math.abs(value) >= 10) {
151
174
  const one = value.toFixed(1);
152
- return one.endsWith('.0') ? one.slice(0, -2) : one;
175
+ return one.endsWith(".0") ? one.slice(0, -2) : one;
153
176
  }
154
177
  return value.toFixed(2);
155
178
  }
156
179
  function pickServicePayload(payload, preferred) {
157
180
  const source = isRecord(payload.data) ? payload.data : payload;
158
- const ordered = preferred === 'claudecode' ? ['claudecode', 'codex'] : ['codex', 'claudecode'];
181
+ const ordered = preferred === "claudecode"
182
+ ? ["claudecode", "codex"]
183
+ : ["codex", "claudecode"];
159
184
  for (const key of ordered) {
160
185
  const value = source[key];
161
186
  if (isRecord(value))
@@ -166,15 +191,17 @@ function pickServicePayload(payload, preferred) {
166
191
  function parseQuotaSnapshot(args) {
167
192
  const base = {
168
193
  providerID: args.providerID,
169
- adapterID: 'xyai-vibe',
170
- label: 'XYAI Vibe',
171
- shortLabel: 'XYAI',
194
+ adapterID: "xyai",
195
+ label: "XYAI",
196
+ shortLabel: "XYAI",
172
197
  sortOrder: 7,
173
198
  };
174
199
  const subscriptions = isRecord(args.payload.subscriptions)
175
200
  ? args.payload.subscriptions
176
201
  : undefined;
177
- const usage = isRecord(args.payload.currentUsage) ? args.payload.currentUsage : undefined;
202
+ const usage = isRecord(args.payload.currentUsage)
203
+ ? args.payload.currentUsage
204
+ : undefined;
178
205
  const amountLimit = asNumber(subscriptions?.amountLimit);
179
206
  const remainingAmount = asNumber(subscriptions?.remainingAmount);
180
207
  const periodResetTime = toIso(subscriptions?.periodResetTime);
@@ -182,54 +209,52 @@ function parseQuotaSnapshot(args) {
182
209
  if (amountLimit === undefined || remainingAmount === undefined) {
183
210
  return {
184
211
  ...base,
185
- status: 'error',
212
+ status: "error",
186
213
  checkedAt: args.checkedAt,
187
- note: 'missing quota fields',
214
+ note: "missing quota fields",
188
215
  };
189
216
  }
190
- const remainingPercent = amountLimit > 0 ? Math.max(0, Math.min(100, (remainingAmount / amountLimit) * 100)) : undefined;
217
+ const remainingPercent = amountLimit > 0
218
+ ? Math.max(0, Math.min(100, (remainingAmount / amountLimit) * 100))
219
+ : undefined;
191
220
  const windows = [
192
221
  {
193
222
  label: `Daily $${formatAmount(remainingAmount)}/$${formatAmount(amountLimit)}`,
194
223
  showPercent: false,
195
224
  remainingPercent,
196
225
  resetAt: periodResetTime,
197
- resetLabel: 'Rst',
226
+ resetLabel: "Rst",
198
227
  },
199
228
  ];
200
229
  const noteParts = [
201
230
  expireTime ? `exp ${expireTime.slice(5, 10)}` : undefined,
202
- args.serviceType === 'claudecode' ? 'service=claudecode' : undefined,
231
+ args.serviceType === "claudecode" ? "service=claudecode" : undefined,
203
232
  args.warning,
204
233
  ].filter((value) => Boolean(value));
205
234
  return {
206
235
  ...base,
207
- status: 'ok',
236
+ status: "ok",
208
237
  checkedAt: args.checkedAt,
209
238
  remainingPercent,
210
239
  resetAt: periodResetTime,
211
240
  expiresAt: expireTime,
212
- note: noteParts.join(' | ') || undefined,
241
+ note: noteParts.join(" | ") || undefined,
213
242
  windows,
214
243
  };
215
244
  }
216
- async function fetchXyaiVibeQuota(ctx) {
245
+ async function fetchXyaiQuota(ctx) {
217
246
  const checkedAt = Date.now();
218
- const runtimeProviderID = typeof ctx.sourceProviderID === 'string' && ctx.sourceProviderID
247
+ const runtimeProviderID = typeof ctx.sourceProviderID === "string" && ctx.sourceProviderID
219
248
  ? ctx.sourceProviderID
220
249
  : ctx.providerID;
221
- const providerConfig = providerConfigFor(ctx.config, [
222
- runtimeProviderID,
223
- ctx.providerID,
224
- 'xyai-vibe',
225
- ]);
250
+ const providerConfig = providerConfigFor(ctx.config, xyaiConfigCandidates(runtimeProviderID, ctx.providerID));
226
251
  const siteOrigin = resolveSiteOrigin(providerConfig?.baseURL ?? ctx.providerOptions?.baseURL);
227
252
  const serviceType = resolveServiceType(providerConfig);
228
253
  const base = {
229
254
  providerID: runtimeProviderID,
230
- adapterID: 'xyai-vibe',
231
- label: 'XYAI Vibe',
232
- shortLabel: 'XYAI',
255
+ adapterID: "xyai",
256
+ label: "XYAI",
257
+ shortLabel: "XYAI",
233
258
  sortOrder: 7,
234
259
  };
235
260
  let session = resolveSessionCookie(ctx.auth, providerConfig);
@@ -237,10 +262,10 @@ async function fetchXyaiVibeQuota(ctx) {
237
262
  let warning;
238
263
  if (!session && login) {
239
264
  const loginResult = await loginAndPersistSession(siteOrigin, login, ctx.providerID, ctx.updateAuth, ctx.config.quota.requestTimeoutMs);
240
- if ('error' in loginResult) {
265
+ if ("error" in loginResult) {
241
266
  return {
242
267
  ...base,
243
- status: 'unavailable',
268
+ status: "unavailable",
244
269
  checkedAt,
245
270
  note: loginResult.error,
246
271
  };
@@ -251,24 +276,26 @@ async function fetchXyaiVibeQuota(ctx) {
251
276
  if (!session) {
252
277
  return {
253
278
  ...base,
254
- status: 'unavailable',
279
+ status: "unavailable",
255
280
  checkedAt,
256
- note: 'missing share-session or login credentials',
281
+ note: "missing share-session or login credentials",
257
282
  };
258
283
  }
259
284
  let quotaResult = await fetchQuotaPayload(siteOrigin, session, ctx.config.quota.requestTimeoutMs);
260
- if (!('error' in quotaResult) && isAuthFailure(quotaResult.payload) && login) {
285
+ if (!("error" in quotaResult) &&
286
+ isAuthFailure(quotaResult.payload) &&
287
+ login) {
261
288
  const loginResult = await loginAndPersistSession(siteOrigin, login, ctx.providerID, ctx.updateAuth, ctx.config.quota.requestTimeoutMs);
262
- if (!('error' in loginResult)) {
289
+ if (!("error" in loginResult)) {
263
290
  session = loginResult.session;
264
291
  warning = loginResult.warning ?? warning;
265
292
  quotaResult = await fetchQuotaPayload(siteOrigin, session, ctx.config.quota.requestTimeoutMs);
266
293
  }
267
294
  }
268
- if ('error' in quotaResult) {
295
+ if ("error" in quotaResult) {
269
296
  return {
270
297
  ...base,
271
- status: 'error',
298
+ status: "error",
272
299
  checkedAt,
273
300
  note: quotaResult.error,
274
301
  };
@@ -276,18 +303,18 @@ async function fetchXyaiVibeQuota(ctx) {
276
303
  if (isAuthFailure(quotaResult.payload)) {
277
304
  return {
278
305
  ...base,
279
- status: 'unavailable',
306
+ status: "unavailable",
280
307
  checkedAt,
281
- note: 'auth expired',
308
+ note: "auth expired",
282
309
  };
283
310
  }
284
311
  const service = pickServicePayload(quotaResult.payload, serviceType);
285
312
  if (!service) {
286
313
  return {
287
314
  ...base,
288
- status: 'error',
315
+ status: "error",
289
316
  checkedAt,
290
- note: 'missing service payload',
317
+ note: "missing service payload",
291
318
  };
292
319
  }
293
320
  return parseQuotaSnapshot({
@@ -298,17 +325,24 @@ async function fetchXyaiVibeQuota(ctx) {
298
325
  warning,
299
326
  });
300
327
  }
301
- export const xyaiVibeAdapter = {
302
- id: 'xyai-vibe',
303
- label: 'XYAI Vibe',
304
- shortLabel: 'XYAI',
328
+ export const xyaiAdapter = {
329
+ id: "xyai",
330
+ label: "XYAI",
331
+ shortLabel: "XYAI",
305
332
  sortOrder: 7,
306
- normalizeID: (providerID) => (providerID === 'xyai-vibe' ? 'xyai-vibe' : undefined),
333
+ normalizeID: (providerID) => providerID === "xyai" || providerID === "xyai-vibe" ? "xyai" : undefined,
307
334
  matchScore: ({ providerID, providerOptions }) => {
308
- if (providerID === 'xyai-vibe')
335
+ if (providerID === "xyai")
309
336
  return 100;
337
+ if (providerID === "xyai-vibe")
338
+ return 99;
310
339
  return isXyaiBaseURL(providerOptions?.baseURL) ? 95 : 0;
311
340
  },
312
- isEnabled: (config) => configuredProviderEnabled(config.quota, 'xyai-vibe', false),
313
- fetch: fetchXyaiVibeQuota,
341
+ isEnabled: (config) => {
342
+ const renamed = config.quota.providers?.xyai?.enabled;
343
+ if (typeof renamed === "boolean")
344
+ return renamed;
345
+ return configuredProviderEnabled(config.quota, "xyai-vibe", false);
346
+ },
347
+ fetch: fetchXyaiQuota,
314
348
  };
package/dist/quota.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { AuthUpdate, AuthValue } from './providers/types.js';
2
- import type { QuotaSidebarConfig, QuotaSnapshot } from './types.js';
1
+ import type { AuthUpdate, AuthValue } from "./providers/types.js";
2
+ import type { QuotaSidebarConfig, QuotaSnapshot } from "./types.js";
3
3
  export declare function quotaSort(left: QuotaSnapshot, right: QuotaSnapshot): number;
4
4
  export declare function listDefaultQuotaProviderIDs(): string[];
5
5
  export declare function createQuotaRuntime(): {