dsh-codex-subscription 1.12.2 → 1.13.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/AGENTS.md +4 -4
- package/README.en.md +4 -4
- package/README.md +4 -4
- package/lib/client.js +295 -236
- package/lib/index.js +120 -30
- package/package.json +1 -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.
|
|
9
|
+
- Use the exact `1.13.1` 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.2-rc.1 plugin --profile web add dsh-codex-subscription@1.
|
|
37
|
+
npx -y @deepseek-ai/dsh@0.1.2-rc.1 plugin --profile web add dsh-codex-subscription@1.13.1
|
|
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.
|
|
43
|
+
dsh plugin --profile web add dsh-codex-subscription@1.13.1
|
|
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.2-rc.1` in place of `dsh`.
|
|
60
60
|
|
|
61
|
-
1. `dsh-codex-subscription` version `1.
|
|
61
|
+
1. `dsh-codex-subscription` version `1.13.1` 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/README.en.md
CHANGED
|
@@ -43,7 +43,7 @@ DSH-Portable exposes the same standard plugin command, so the command above also
|
|
|
43
43
|
| **Recoverable and diagnosable** | Sign-in state reconciles automatically; Settings can create a support report without credentials or account identifiers |
|
|
44
44
|
| **Visible quota** | Keep backend-provided standard Codex, Spark, and other limits separate |
|
|
45
45
|
| **Composer quota** | Choose a compact percentage, progress bar, or no inline quota display |
|
|
46
|
-
| **Safe quota reset** | See
|
|
46
|
+
| **Safe quota reset** | See each reset credit separately and deliberately try one with a cooldown and acknowledgement |
|
|
47
47
|
| **Subscription search** | Explicitly route search globally through DSH default search or the signed-in Codex subscription |
|
|
48
48
|
| **Codex image generation and editing (Beta)** | Generate without references, or explicitly edit one selected image; preview, zoom, annotate regions, download the original, and continue in the same composer |
|
|
49
49
|
| **Fast mode** | Switch between Standard and Fast directly in the composer |
|
|
@@ -133,12 +133,12 @@ Restart DSH manually after installation, then:
|
|
|
133
133
|
|
|
134
134
|
## Features
|
|
135
135
|
|
|
136
|
-
- ChatGPT OAuth sign-in with credentials kept on the host; manually
|
|
136
|
+
- ChatGPT OAuth sign-in with credentials kept on the host; accounts are identified by a privacy-masked email that can be clicked to reveal, and can be manually added, switched, or removed without automatic rotation or quota pooling;
|
|
137
137
|
- Codex models and Beta image generation/editing directly inside DSH conversations;
|
|
138
138
|
- A clear global choice between DSH default search and Codex subscription search; it applies to every model and session rather than following the selected model;
|
|
139
139
|
- Actual backend-provided quota, reset time, and freshness;
|
|
140
140
|
- Separate standard Codex, Codex-Spark, Credits, and other independent limits;
|
|
141
|
-
-
|
|
141
|
+
- One row per available quota reset with its disclosed name and expiry, plus deliberate early redemption, layered confirmation, and no automatic retry;
|
|
142
142
|
- Optional percentage, progress bar, or Beta runway estimate for the selected Codex model (off by default);
|
|
143
143
|
- Standard or Fast mode for supported Codex models directly in the composer;
|
|
144
144
|
- Standard, Extended, and per-model Custom context windows; Custom accepts a full numeric token count, stays within each audited model capacity, and feeds DSH's native agent compaction policy;
|
|
@@ -159,7 +159,7 @@ Standard Codex uses the lowest remaining window returned by the service; Spark u
|
|
|
159
159
|
|
|
160
160
|
### Safe quota reset
|
|
161
161
|
|
|
162
|
-
If ChatGPT reports
|
|
162
|
+
If ChatGPT reports available quota resets, Settings shows each one in its own compact row with its disclosed name and expiry.
|
|
163
163
|
You may deliberately try it before a quota reaches 100%, which is useful for a reset nearing expiry. ChatGPT still
|
|
164
164
|
decides whether a window needs resetting and may return **nothing to reset** without spending the reset. The final
|
|
165
165
|
action requires an acknowledgement checkbox and five-second cooldown. Cancel never consumes a reset, rapid repeated
|
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ DSH-Portable 也提供相同的标准插件命令,因此同样使用上面的
|
|
|
44
44
|
| **可恢复、可诊断** | 登录状态会自动对账;设置页可生成不含凭据和账号标识的支持报告 |
|
|
45
45
|
| **额度可见** | 普通 Codex、Spark 等服务端实际返回的额度分开显示 |
|
|
46
46
|
| **输入框额度** | 可选择紧凑百分比、进度条或完全关闭输入框额度显示 |
|
|
47
|
-
| **安全额度重置** |
|
|
47
|
+
| **安全额度重置** | 每张重置卡单独显示,并通过冷静期和知情确认主动尝试重置 |
|
|
48
48
|
| **订阅搜索** | 可将全部模型的搜索明确路由到 DSH 默认搜索或已登录的 Codex 订阅 |
|
|
49
49
|
| **Codex 图片生成与编辑(Beta)** | 可无参考图全新生成,也可明确选择会话图片继续编辑;支持预览、缩放、区域备注、下载原图并衔接回当前输入框 |
|
|
50
50
|
| **高速模式** | 直接在输入框切换标准或高速,无需离开当前会话 |
|
|
@@ -134,12 +134,12 @@ dsh --profile web --dump-config
|
|
|
134
134
|
|
|
135
135
|
## 功能
|
|
136
136
|
|
|
137
|
-
- ChatGPT OAuth
|
|
137
|
+
- ChatGPT OAuth 登录,凭据保留在本机;账号以默认隐藏部分字符的邮箱区分,点击可切换完整显示;可手动添加、切换和移除多个账号,不会自动轮换或合并额度;
|
|
138
138
|
- Codex 模型和 Beta 图片生成与编辑直接出现在 DSH 会话中;
|
|
139
139
|
- 搜索来源是全局设置,可在 DSH 默认搜索与 Codex 订阅搜索之间切换;它对所有模型和会话生效,不会随当前模型自动切换;
|
|
140
140
|
- 设置页显示服务端返回的额度、重置时间和更新时间;
|
|
141
141
|
- 普通 Codex、Codex-Spark、Credits 等独立额度分开显示;
|
|
142
|
-
-
|
|
142
|
+
- 每张可用重置卡单独显示名称和到期时间,也允许在额度未完全用尽时主动尝试,并经过分层确认且不会自动重试;
|
|
143
143
|
- 输入框可用百分比、进度条或可选的 Beta 续航预测显示当前 Codex 模型的剩余额度(默认关闭);
|
|
144
144
|
- 输入框可为支持的 Codex 模型切换标准或高速模式;
|
|
145
145
|
- 上下文窗口提供标准、扩展和逐模型自定义;自定义直接填写完整 Token 数值,并在已审核的模型容量内交给 DSH 原生 Agent 压缩策略处理;
|
|
@@ -159,7 +159,7 @@ Spark 使用独立额度。插件不会写死“5 小时 + 每周”,也不会
|
|
|
159
159
|
|
|
160
160
|
### 安全使用额度重置
|
|
161
161
|
|
|
162
|
-
ChatGPT
|
|
162
|
+
ChatGPT 返回可用重置卡时,设置页会把每张卡分别显示为紧凑的一行,并展示服务端提供的名称和到期时间。即使额度尚未到 100%,
|
|
163
163
|
也可以主动尝试使用,适合重置卡即将过期的情况;是否需要重置仍由 ChatGPT 判断,服务端可能返回“当前无需重置”且不扣次数。
|
|
164
164
|
最终操作需要勾选知情确认并等待 5 秒。取消不会消耗,快速连续点击只允许一次请求,网络结果不确定时也不会自动重试。
|
|
165
165
|
|
package/lib/client.js
CHANGED
|
@@ -220,6 +220,148 @@ window.__ModuleLoader__.load({
|
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
222
|
//#endregion
|
|
223
|
+
//#region src/preference-controller.js
|
|
224
|
+
const CHANNEL$1 = "/codex-subscription";
|
|
225
|
+
const unwrap$1 = (response) => {
|
|
226
|
+
if (!response?.ok) throw new Error(response?.error?.message ?? "Codex RPC failed");
|
|
227
|
+
return response.value;
|
|
228
|
+
};
|
|
229
|
+
function createPreferenceController(scope, rpc) {
|
|
230
|
+
let updating = false;
|
|
231
|
+
let error = false;
|
|
232
|
+
let fallbackStatus = "loading";
|
|
233
|
+
let fallback;
|
|
234
|
+
let pendingPatch;
|
|
235
|
+
let failedPatch;
|
|
236
|
+
let generation = 0;
|
|
237
|
+
let contextModels = [];
|
|
238
|
+
let verbosityModels = [];
|
|
239
|
+
const nativeSnapshot = () => scope.getSnapshot();
|
|
240
|
+
const read = () => {
|
|
241
|
+
const native = nativeSnapshot();
|
|
242
|
+
const current = native.status === "ready" ? native : fallbackStatus === "ready" ? fallback : native;
|
|
243
|
+
const value = pendingPatch === void 0 ? current.value : {
|
|
244
|
+
...current.value,
|
|
245
|
+
...pendingPatch
|
|
246
|
+
};
|
|
247
|
+
return Object.freeze({
|
|
248
|
+
status: current.status,
|
|
249
|
+
quickQuotaMode: normalizeQuickQuotaMode(value?.[QUICK_QUOTA_MODE_FIELD], value?.[LEGACY_QUICK_QUOTA_FIELD]),
|
|
250
|
+
searchProvider: normalizeSearchProvider(value?.[SEARCH_PROVIDER_FIELD]),
|
|
251
|
+
speedMode: normalizeSpeedMode(value?.[SPEED_MODE_FIELD]),
|
|
252
|
+
outputVerbosity: normalizeOutputVerbosity(value?.[OUTPUT_VERBOSITY_FIELD]),
|
|
253
|
+
contextMode: normalizeContextMode(value?.[CONTEXT_MODE_FIELD]),
|
|
254
|
+
customContextWindow: normalizeCustomContextWindow(value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
|
|
255
|
+
customContextWindows: Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [modelKey, normalizeCustomContextWindow(value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])])),
|
|
256
|
+
contextModels,
|
|
257
|
+
verbosityModels,
|
|
258
|
+
writable: !updating && current.status === "ready" && current.writable === true,
|
|
259
|
+
saving: updating,
|
|
260
|
+
error
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
let snapshot = read();
|
|
264
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
265
|
+
const publish = () => {
|
|
266
|
+
snapshot = read();
|
|
267
|
+
for (const listener of listeners) listener();
|
|
268
|
+
};
|
|
269
|
+
const disposeScope = scope.subscribe(() => {
|
|
270
|
+
error = false;
|
|
271
|
+
if (!updating) failedPatch = void 0;
|
|
272
|
+
publish();
|
|
273
|
+
});
|
|
274
|
+
const acceptFallback = (value) => {
|
|
275
|
+
contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
|
|
276
|
+
verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
277
|
+
fallbackStatus = "ready";
|
|
278
|
+
fallback = {
|
|
279
|
+
status: "ready",
|
|
280
|
+
value: {
|
|
281
|
+
[QUICK_QUOTA_MODE_FIELD]: normalizeQuickQuotaMode(value?.[QUICK_QUOTA_MODE_FIELD], value?.[LEGACY_QUICK_QUOTA_FIELD]),
|
|
282
|
+
[SEARCH_PROVIDER_FIELD]: normalizeSearchProvider(value?.[SEARCH_PROVIDER_FIELD]),
|
|
283
|
+
[SPEED_MODE_FIELD]: normalizeSpeedMode(value?.[SPEED_MODE_FIELD]),
|
|
284
|
+
[OUTPUT_VERBOSITY_FIELD]: normalizeOutputVerbosity(value?.[OUTPUT_VERBOSITY_FIELD]),
|
|
285
|
+
[CONTEXT_MODE_FIELD]: normalizeContextMode(value?.[CONTEXT_MODE_FIELD]),
|
|
286
|
+
[CUSTOM_CONTEXT_WINDOW_FIELD]: normalizeCustomContextWindow(value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
|
|
287
|
+
...Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [field, normalizeCustomContextWindow(value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])]))
|
|
288
|
+
},
|
|
289
|
+
writable: value?.writable === true
|
|
290
|
+
};
|
|
291
|
+
};
|
|
292
|
+
const load = async () => {
|
|
293
|
+
const current = ++generation;
|
|
294
|
+
updating = false;
|
|
295
|
+
pendingPatch = void 0;
|
|
296
|
+
fallbackStatus = "loading";
|
|
297
|
+
fallback = void 0;
|
|
298
|
+
error = false;
|
|
299
|
+
publish();
|
|
300
|
+
try {
|
|
301
|
+
const value = unwrap$1(await rpc.call(CHANNEL$1, "preferences/status", {}));
|
|
302
|
+
if (current !== generation) return;
|
|
303
|
+
if (nativeSnapshot().status === "ready") {
|
|
304
|
+
contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
|
|
305
|
+
verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
306
|
+
} else acceptFallback(value);
|
|
307
|
+
publish();
|
|
308
|
+
} catch {
|
|
309
|
+
if (current !== generation || nativeSnapshot().status === "ready") return;
|
|
310
|
+
fallbackStatus = "unavailable";
|
|
311
|
+
publish();
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
const set = async (patch) => {
|
|
315
|
+
if (snapshot.status !== "ready" || snapshot.writable !== true) return;
|
|
316
|
+
const current = ++generation;
|
|
317
|
+
const entries = Object.entries(patch);
|
|
318
|
+
updating = true;
|
|
319
|
+
pendingPatch = patch;
|
|
320
|
+
error = false;
|
|
321
|
+
failedPatch = void 0;
|
|
322
|
+
publish();
|
|
323
|
+
try {
|
|
324
|
+
if (nativeSnapshot().status === "ready") {
|
|
325
|
+
for (const [field, value] of entries) {
|
|
326
|
+
if (current !== generation) return;
|
|
327
|
+
await scope.set(field, value);
|
|
328
|
+
}
|
|
329
|
+
if (current !== generation) return;
|
|
330
|
+
const accepted = nativeSnapshot().value;
|
|
331
|
+
error = entries.some(([field, value]) => accepted?.[field] !== value);
|
|
332
|
+
pendingPatch = void 0;
|
|
333
|
+
} else {
|
|
334
|
+
const value = unwrap$1(await rpc.call(CHANNEL$1, "preferences/update", patch));
|
|
335
|
+
if (current !== generation) return;
|
|
336
|
+
acceptFallback(value);
|
|
337
|
+
pendingPatch = void 0;
|
|
338
|
+
}
|
|
339
|
+
} catch {
|
|
340
|
+
if (current === generation) {
|
|
341
|
+
pendingPatch = void 0;
|
|
342
|
+
error = true;
|
|
343
|
+
failedPatch = patch;
|
|
344
|
+
}
|
|
345
|
+
} finally {
|
|
346
|
+
if (current === generation) {
|
|
347
|
+
updating = false;
|
|
348
|
+
publish();
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
return {
|
|
353
|
+
getSnapshot: () => snapshot,
|
|
354
|
+
subscribe: (listener) => {
|
|
355
|
+
listeners.add(listener);
|
|
356
|
+
return () => listeners.delete(listener);
|
|
357
|
+
},
|
|
358
|
+
load,
|
|
359
|
+
set,
|
|
360
|
+
retry: () => failedPatch === void 0 ? load() : set(failedPatch),
|
|
361
|
+
dispose: disposeScope
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
//#endregion
|
|
223
365
|
//#region src/client.jsx
|
|
224
366
|
const inject = [
|
|
225
367
|
"slots",
|
|
@@ -246,7 +388,6 @@ window.__ModuleLoader__.load({
|
|
|
246
388
|
deviceLogin: "设备代码登录",
|
|
247
389
|
logout: "退出登录",
|
|
248
390
|
addAccount: "添加账号",
|
|
249
|
-
accountLabel: "账号名称",
|
|
250
391
|
switchAccount: "切换",
|
|
251
392
|
removeAccount: "移除",
|
|
252
393
|
removeConfirm: "确认移除",
|
|
@@ -262,12 +403,15 @@ window.__ModuleLoader__.load({
|
|
|
262
403
|
loadFailed: "无法读取账户状态。",
|
|
263
404
|
accountRetry: "重试",
|
|
264
405
|
diagnostics: "支持诊断",
|
|
265
|
-
diagnosticsHint: "生成不含凭据、账号标识和授权时间的诊断信息。",
|
|
266
406
|
diagnosticsLoad: "生成诊断",
|
|
407
|
+
diagnosticsLoading: "生成中…",
|
|
267
408
|
diagnosticsCopy: "复制诊断",
|
|
268
409
|
diagnosticsCopied: "已复制",
|
|
269
410
|
diagnosticsFailed: "无法生成诊断信息。",
|
|
270
411
|
feedbackOpen: "反馈问题",
|
|
412
|
+
showEmail: "显示完整邮箱",
|
|
413
|
+
hideEmail: "隐藏邮箱",
|
|
414
|
+
emailUnavailable: "邮箱不可用",
|
|
271
415
|
searchTitle: "搜索来源",
|
|
272
416
|
searchScope: "自动按当前会话模型分流;手动选择会覆盖所有模型和会话。",
|
|
273
417
|
searchAuto: "自动",
|
|
@@ -299,21 +443,21 @@ window.__ModuleLoader__.load({
|
|
|
299
443
|
creditsUnit: "credits",
|
|
300
444
|
unlimited: "不限额",
|
|
301
445
|
monthlyCreditLimit: "Credits 月度消费上限",
|
|
302
|
-
resetCredits: "
|
|
303
|
-
|
|
304
|
-
resetUse: "
|
|
305
|
-
resetPreparing: "
|
|
446
|
+
resetCredits: "额度重置",
|
|
447
|
+
resetCreditDefaultName: "额度重置",
|
|
448
|
+
resetUse: "使用",
|
|
449
|
+
resetPreparing: "准备中…",
|
|
306
450
|
resetConfirmTitle: "确认使用额度重置",
|
|
307
|
-
resetWarning: "
|
|
308
|
-
resetEarlyWarning: "
|
|
451
|
+
resetWarning: "执行后会消耗 1 次,且无法撤销。",
|
|
452
|
+
resetEarlyWarning: "当前额度未用尽,服务可能不执行重置。",
|
|
309
453
|
resetAcknowledge: "我知道这次操作可能立即消耗 1 次重置",
|
|
310
454
|
resetCreditExpires: "到期:{value}",
|
|
311
455
|
resetCreditExpiryUnknown: "到期时间未提供",
|
|
312
456
|
resetCreditExpiryLoading: "正在读取到期时间…",
|
|
313
457
|
resetCreditExpiryFailed: "无法读取到期时间",
|
|
314
|
-
resetWait: "
|
|
315
|
-
resetFinal: "
|
|
316
|
-
resetUsing: "
|
|
458
|
+
resetWait: "请等待 {count} 秒",
|
|
459
|
+
resetFinal: "确认使用",
|
|
460
|
+
resetUsing: "使用中…",
|
|
317
461
|
resetSuccess: "额度重置已完成。",
|
|
318
462
|
resetNothing: "当前没有可重置的额度,未消耗新的重置次数。",
|
|
319
463
|
resetNoCredit: "没有可用的额度重置。",
|
|
@@ -326,7 +470,7 @@ window.__ModuleLoader__.load({
|
|
|
326
470
|
resetAcknowledgeRequired: "请先确认已了解这次操作可能消耗重置次数。",
|
|
327
471
|
resetAccountChanged: "登录账号已变更,请重新开始。",
|
|
328
472
|
resetUncertain: "服务端返回结果不确定。请再次确认,插件会复用同一个请求,不会另外发起一次重置。",
|
|
329
|
-
creditsNote: "
|
|
473
|
+
creditsNote: "额外 Credits、消费上限、重置次数分别显示。",
|
|
330
474
|
creditsUsed: "已用 {used} / {limit} credits",
|
|
331
475
|
spendReached: "Credits 月度消费上限已用尽。",
|
|
332
476
|
unavailable: "暂无数据",
|
|
@@ -429,7 +573,6 @@ window.__ModuleLoader__.load({
|
|
|
429
573
|
deviceLogin: "Device-code sign-in",
|
|
430
574
|
logout: "Sign out",
|
|
431
575
|
addAccount: "Add account",
|
|
432
|
-
accountLabel: "Account name",
|
|
433
576
|
switchAccount: "Switch",
|
|
434
577
|
removeAccount: "Remove",
|
|
435
578
|
removeConfirm: "Confirm remove",
|
|
@@ -445,12 +588,15 @@ window.__ModuleLoader__.load({
|
|
|
445
588
|
loadFailed: "Could not read account status.",
|
|
446
589
|
accountRetry: "Retry",
|
|
447
590
|
diagnostics: "Support diagnostics",
|
|
448
|
-
diagnosticsHint: "Create a report without credentials, account identifiers, or authorization timestamps.",
|
|
449
591
|
diagnosticsLoad: "Create report",
|
|
592
|
+
diagnosticsLoading: "Creating…",
|
|
450
593
|
diagnosticsCopy: "Copy report",
|
|
451
594
|
diagnosticsCopied: "Copied",
|
|
452
595
|
diagnosticsFailed: "Could not create diagnostics.",
|
|
453
596
|
feedbackOpen: "Report a problem",
|
|
597
|
+
showEmail: "Show full email",
|
|
598
|
+
hideEmail: "Hide email",
|
|
599
|
+
emailUnavailable: "Email unavailable",
|
|
454
600
|
searchTitle: "Search source",
|
|
455
601
|
searchScope: "Auto follows the current session model; an explicit choice overrides every model and session.",
|
|
456
602
|
searchAuto: "Auto",
|
|
@@ -482,21 +628,21 @@ window.__ModuleLoader__.load({
|
|
|
482
628
|
creditsUnit: "credits",
|
|
483
629
|
unlimited: "Unlimited",
|
|
484
630
|
monthlyCreditLimit: "Monthly Credits spending cap",
|
|
485
|
-
resetCredits: "
|
|
486
|
-
|
|
487
|
-
resetUse: "Use
|
|
488
|
-
resetPreparing: "
|
|
631
|
+
resetCredits: "Quota resets",
|
|
632
|
+
resetCreditDefaultName: "Quota reset",
|
|
633
|
+
resetUse: "Use",
|
|
634
|
+
resetPreparing: "Preparing…",
|
|
489
635
|
resetConfirmTitle: "Confirm quota reset",
|
|
490
|
-
resetWarning: "
|
|
491
|
-
resetEarlyWarning: "
|
|
636
|
+
resetWarning: "This consumes one reset and cannot be undone.",
|
|
637
|
+
resetEarlyWarning: "Quota remains. The service may decline the reset.",
|
|
492
638
|
resetAcknowledge: "I understand this may consume one reset now",
|
|
493
639
|
resetCreditExpires: "Expires {value}",
|
|
494
640
|
resetCreditExpiryUnknown: "Expiration time not provided",
|
|
495
641
|
resetCreditExpiryLoading: "Reading expiration…",
|
|
496
642
|
resetCreditExpiryFailed: "Could not read expiration",
|
|
497
|
-
resetWait: "Wait {count}
|
|
498
|
-
resetFinal: "
|
|
499
|
-
resetUsing: "
|
|
643
|
+
resetWait: "Wait {count} seconds",
|
|
644
|
+
resetFinal: "Confirm use",
|
|
645
|
+
resetUsing: "Using…",
|
|
500
646
|
resetSuccess: "Quota reset completed.",
|
|
501
647
|
resetNothing: "There is currently nothing to reset; no new reset was consumed.",
|
|
502
648
|
resetNoCredit: "No quota reset is available.",
|
|
@@ -509,7 +655,7 @@ window.__ModuleLoader__.load({
|
|
|
509
655
|
resetAcknowledgeRequired: "Confirm that you understand this may consume a reset.",
|
|
510
656
|
resetAccountChanged: "The signed-in account changed. Start again.",
|
|
511
657
|
resetUncertain: "The server result is uncertain. Confirm again to check the same request; the plugin will not start a separate reset.",
|
|
512
|
-
creditsNote: "
|
|
658
|
+
creditsNote: "Extra Credits, spending caps, and resets are separate items.",
|
|
513
659
|
creditsUsed: "{used} / {limit} credits used",
|
|
514
660
|
spendReached: "The monthly Credits spending cap has been reached.",
|
|
515
661
|
unavailable: "No data yet",
|
|
@@ -615,14 +761,15 @@ window.__ModuleLoader__.load({
|
|
|
615
761
|
.codexSubscriptionContext{display:flex;flex-direction:column;gap:8px}.codexSubscriptionContextHead{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.codexSubscriptionContextCopy{display:flex;min-width:0;flex:1;flex-direction:column;gap:2px}.codexSubscriptionContextHint{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionContextTrigger{height:32px;min-width:108px;display:inline-flex;align-items:center;justify-content:space-between;gap:10px;padding:0 10px 0 12px;border:0;border-radius:999px;outline:0;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;cursor:pointer}.codexSubscriptionContextTrigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.codexSubscriptionContextTrigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.codexSubscriptionContextTrigger:disabled{color:var(--dsw-alias-label-dimmed);cursor:not-allowed}.codexSubscriptionContextTrigger svg{color:var(--dsw-alias-label-tertiary);transition:transform 120ms var(--ds-ease-in-out)}.codexSubscriptionContextTrigger[aria-expanded=true] svg{transform:rotate(180deg)}.codexSubscriptionContextModels{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.codexSubscriptionContextModel{min-height:42px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-bottom:1px solid var(--dsw-alias-border-l2)}.codexSubscriptionContextModel:last-child{border-bottom:0}.codexSubscriptionContextModelCopy{display:flex;min-width:0;flex-direction:column}.codexSubscriptionContextModelCopy strong{font-size:12px;line-height:18px;font-weight:500}.codexSubscriptionContextModelCopy span{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionContextInput{width:116px}
|
|
616
762
|
.codexSubscriptionSwitch{position:relative;flex:0 0 auto;width:32px;height:18px;padding:0;border:1px solid var(--dsw-alias-border-l3);border-radius:999px;background:var(--dsw-alias-bg-module-platform);cursor:pointer}.codexSubscriptionSwitch:disabled{cursor:not-allowed;opacity:.5}.codexSubscriptionSwitch[aria-checked=true]{background:var(--dsw-alias-label-secondary);border-color:var(--dsw-alias-label-secondary)}.codexSubscriptionSwitchKnob{position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:var(--dsw-alias-bg-layer-1);transition:transform 120ms var(--ds-ease-in-out)}.codexSubscriptionSwitch[aria-checked=true] .codexSubscriptionSwitchKnob{transform:translateX(14px)}
|
|
617
763
|
.codexSubscriptionSearch{display:flex;flex-direction:column;gap:7px}.codexSubscriptionSearchChoices{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:6px}.codexSubscriptionSearchChoice{display:grid;grid-template-columns:14px minmax(0,1fr);align-items:center;column-gap:8px;min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);padding:9px 10px;text-align:left;cursor:pointer}.codexSubscriptionSearchChoice:has(input:disabled){cursor:not-allowed;opacity:.5}.codexSubscriptionSearchChoice:has(input:checked){border-color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.codexSubscriptionSearchChoice:has(input:focus-visible){outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}.codexSubscriptionSearchInput{width:14px;height:14px;margin:0;accent-color:var(--dsw-alias-label-primary);cursor:inherit}.codexSubscriptionSearchCopy{display:block;min-width:0;pointer-events:none}.codexSubscriptionSearchCopy strong,.codexSubscriptionSearchCopy span{display:block}.codexSubscriptionSearchCopy strong{font-size:12px;line-height:18px;font-weight:500;color:var(--dsw-alias-label-secondary)}.codexSubscriptionSearchChoice:has(input:checked) strong{color:var(--dsw-alias-label-primary)}.codexSubscriptionSearchCopy span{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionDivider{height:1px;background:var(--dsw-alias-border-l2)}
|
|
764
|
+
.codexSubscriptionQuotaModes[data-saving=true] .codexSubscriptionQuotaMode:has(input:disabled){cursor:wait;opacity:1}.codexSubscriptionSearchChoices[data-saving=true] .codexSubscriptionSearchChoice:has(input:disabled){cursor:wait;opacity:1}
|
|
618
765
|
.codexSubscriptionAccountRow,.codexSubscriptionSectionHead{display:flex;align-items:center;justify-content:space-between;gap:12px}.codexSubscriptionStatus{display:flex;align-items:center;gap:8px;font-size:14px;line-height:22px;font-weight:500}
|
|
619
|
-
.codexSubscriptionAccounts{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.codexSubscriptionAccount{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:42px;border-bottom:1px solid var(--dsw-alias-border-l2);font-size:13px}.codexSubscriptionAccount:last-child{border-bottom:0}.codexSubscriptionAccount[data-active=true]>span{font-weight:600}.codexSubscriptionFlow label{display:flex;flex-direction:column;gap:6px;font-size:12px;color:var(--dsw-alias-label-secondary)}
|
|
766
|
+
.codexSubscriptionAccounts{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.codexSubscriptionAccount{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:42px;border-bottom:1px solid var(--dsw-alias-border-l2);font-size:13px}.codexSubscriptionAccount:last-child{border-bottom:0}.codexSubscriptionAccount[data-active=true] .codexSubscriptionEmail,.codexSubscriptionAccount[data-active=true]>span{font-weight:600}.codexSubscriptionEmail{max-width:100%;overflow:hidden;padding:2px 4px;border:0;border-radius:5px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}.codexSubscriptionEmail:hover{background:var(--dsw-alias-interactive-bg-hover)}.codexSubscriptionEmail:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:1px}.codexSubscriptionFlow label{display:flex;flex-direction:column;gap:6px;font-size:12px;color:var(--dsw-alias-label-secondary)}
|
|
620
767
|
.codexSubscriptionDot{width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-label-dimmed)}.codexSubscriptionDot[data-state=connected]{background:var(--dsw-alias-state-success-primary)}.codexSubscriptionDot[data-state=disconnected]{background:var(--dsw-alias-state-error-primary)}
|
|
621
768
|
.codexSubscriptionActions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.codexSubscriptionFlow{display:flex;flex-direction:column;gap:10px;padding:12px 14px;border-radius:10px;background:var(--dsw-alias-bg-module-platform)}
|
|
622
769
|
.codexSubscriptionFlow p{font-size:13px;line-height:20px;color:var(--dsw-alias-label-secondary)}.codexSubscriptionCode{width:max-content;max-width:100%;font:600 16px/22px ui-monospace,SFMono-Regular,Consolas,monospace;letter-spacing:.08em;overflow-wrap:anywhere}
|
|
623
770
|
.codexSubscriptionError{font-size:13px;line-height:20px;color:var(--dsw-alias-state-error-primary)}.codexSubscriptionInput{width:100%;box-sizing:border-box}
|
|
624
771
|
.codexSubscriptionRecover{display:flex;align-items:center;justify-content:space-between;gap:12px}.codexSubscriptionRecover .codexSubscriptionError{flex:1}.codexSubscriptionRecover button{flex:0 0 auto}
|
|
625
|
-
.codexSubscriptionDiagnostics pre{max-height:240px;margin:0;padding:10px 12px;border-radius:8px;background:var(--dsw-alias-bg-module-platform);overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font:11px/17px ui-monospace,SFMono-Regular,Consolas,monospace;color:var(--dsw-alias-label-secondary)}.codexSubscriptionLink{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-height:32px;padding:0 13px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:transparent;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;text-decoration:none;white-space:nowrap}.codexSubscriptionLink:hover{background:var(--dsw-alias-bg-module-platform)}.codexSubscriptionLink:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}
|
|
772
|
+
.codexSubscriptionDiagnostics{padding:8px 12px;gap:8px;background:transparent;color:var(--dsw-alias-label-secondary)}.codexSubscriptionDiagnostics pre{max-height:240px;margin:0;padding:10px 12px;border-radius:8px;background:var(--dsw-alias-bg-module-platform);overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font:11px/17px ui-monospace,SFMono-Regular,Consolas,monospace;color:var(--dsw-alias-label-secondary)}.codexSubscriptionLink{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-height:32px;padding:0 13px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:transparent;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;text-decoration:none;white-space:nowrap}.codexSubscriptionLink:hover{background:var(--dsw-alias-bg-module-platform)}.codexSubscriptionLink:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}
|
|
626
773
|
.codexSubscriptionSectionTitle{display:flex;flex:1;min-width:0;flex-direction:column;gap:2px}.codexSubscriptionFreshness{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
|
|
627
774
|
.codexSubscriptionRefresh{flex:0 0 auto;min-width:72px;width:max-content;white-space:nowrap!important;word-break:keep-all!important;overflow-wrap:normal!important;writing-mode:horizontal-tb!important}.codexSubscriptionRefresh *{white-space:nowrap!important;word-break:keep-all!important;writing-mode:horizontal-tb!important}
|
|
628
775
|
.codexSubscriptionEmpty{padding:18px;border:1px dashed var(--dsw-alias-border-l3);border-radius:10px;text-align:center;font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}
|
|
@@ -632,7 +779,7 @@ window.__ModuleLoader__.load({
|
|
|
632
779
|
.codexSubscriptionLimit progress::-webkit-progress-bar{background:var(--dsw-alias-border-l3);border-radius:999px}.codexSubscriptionLimit progress::-webkit-progress-value{background:var(--dsw-alias-brand-primary,#3964fe);border-radius:999px}.codexSubscriptionLimit progress::-moz-progress-bar{background:var(--dsw-alias-brand-primary,#3964fe);border-radius:999px}.codexSubscriptionLimitMeta{display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
|
|
633
780
|
.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)}
|
|
634
781
|
.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}
|
|
635
|
-
.
|
|
782
|
+
.codexSubscriptionCreditRows{display:flex;flex-direction:column;gap:6px}.codexSubscriptionResetMeta{display:flex;min-width:0;flex-direction:column;gap:1px}.codexSubscriptionResetBalance{display:flex;flex-direction:column;gap:8px}.codexSubscriptionResetCard{display:flex;align-items:center;justify-content:space-between;gap:10px;min-width:0;padding:9px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-bg-module-platform)}.codexSubscriptionResetCard .codexSubscriptionResetMeta{flex:1}.codexSubscriptionResetCard strong{overflow:hidden;font-size:12px;line-height:18px;font-weight:500;text-overflow:ellipsis;white-space:nowrap}.codexSubscriptionResetCard .codexSubscriptionActions{flex:0 0 auto}.codexSubscriptionResetCard .codexSubscriptionResetUse{min-height:28px;padding:0 10px}.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)}
|
|
636
783
|
.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}
|
|
637
784
|
.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}
|
|
638
785
|
.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}
|
|
@@ -664,6 +811,12 @@ window.__ModuleLoader__.load({
|
|
|
664
811
|
return response.value;
|
|
665
812
|
};
|
|
666
813
|
const fill = (text, values) => Object.entries(values).reduce((next, [key, value]) => next.replace(`{${key}}`, String(value)), text);
|
|
814
|
+
const maskEmail = (value) => {
|
|
815
|
+
if (typeof value !== "string" || !value.includes("@")) return "••••";
|
|
816
|
+
const [local, domain] = value.split("@", 2);
|
|
817
|
+
if (local.length <= 2) return `${local.slice(0, 1)}••@${domain}`;
|
|
818
|
+
return `${local[0]}•••${local.at(-1)}@${domain}`;
|
|
819
|
+
};
|
|
667
820
|
const hours = (seconds) => Math.round(seconds / 3600 * 10) / 10;
|
|
668
821
|
const percent = (value) => Number(value).toLocaleString(void 0, { maximumFractionDigits: 1 });
|
|
669
822
|
const isApproximateWindow = (seconds, expected) => seconds >= expected * .95 && seconds <= expected * 1.05;
|
|
@@ -1108,131 +1261,6 @@ window.__ModuleLoader__.load({
|
|
|
1108
1261
|
]
|
|
1109
1262
|
});
|
|
1110
1263
|
}
|
|
1111
|
-
function createPreferenceController(scope, rpc) {
|
|
1112
|
-
let updating = false;
|
|
1113
|
-
let error = false;
|
|
1114
|
-
let fallbackStatus = "loading";
|
|
1115
|
-
let fallback;
|
|
1116
|
-
let failedPatch;
|
|
1117
|
-
let generation = 0;
|
|
1118
|
-
let contextModels = [];
|
|
1119
|
-
let verbosityModels = [];
|
|
1120
|
-
const nativeSnapshot = () => scope.getSnapshot();
|
|
1121
|
-
const read = () => {
|
|
1122
|
-
const native = nativeSnapshot();
|
|
1123
|
-
const current = native.status === "ready" ? native : fallbackStatus === "ready" ? fallback : native;
|
|
1124
|
-
return Object.freeze({
|
|
1125
|
-
status: updating ? "updating" : current.status,
|
|
1126
|
-
quickQuotaMode: normalizeQuickQuotaMode(current.value?.[QUICK_QUOTA_MODE_FIELD], current.value?.[LEGACY_QUICK_QUOTA_FIELD]),
|
|
1127
|
-
searchProvider: normalizeSearchProvider(current.value?.[SEARCH_PROVIDER_FIELD]),
|
|
1128
|
-
speedMode: normalizeSpeedMode(current.value?.[SPEED_MODE_FIELD]),
|
|
1129
|
-
outputVerbosity: normalizeOutputVerbosity(current.value?.[OUTPUT_VERBOSITY_FIELD]),
|
|
1130
|
-
contextMode: normalizeContextMode(current.value?.[CONTEXT_MODE_FIELD]),
|
|
1131
|
-
customContextWindow: normalizeCustomContextWindow(current.value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
|
|
1132
|
-
customContextWindows: Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [modelKey, normalizeCustomContextWindow(current.value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])])),
|
|
1133
|
-
contextModels,
|
|
1134
|
-
verbosityModels,
|
|
1135
|
-
writable: !updating && current.status === "ready" && current.writable === true,
|
|
1136
|
-
error
|
|
1137
|
-
});
|
|
1138
|
-
};
|
|
1139
|
-
let snapshot = read();
|
|
1140
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
1141
|
-
const publish = () => {
|
|
1142
|
-
snapshot = read();
|
|
1143
|
-
for (const listener of listeners) listener();
|
|
1144
|
-
};
|
|
1145
|
-
const disposeScope = scope.subscribe(() => {
|
|
1146
|
-
error = false;
|
|
1147
|
-
failedPatch = void 0;
|
|
1148
|
-
publish();
|
|
1149
|
-
});
|
|
1150
|
-
const acceptFallback = (value) => {
|
|
1151
|
-
contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
|
|
1152
|
-
verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
1153
|
-
fallbackStatus = "ready";
|
|
1154
|
-
fallback = {
|
|
1155
|
-
status: "ready",
|
|
1156
|
-
value: {
|
|
1157
|
-
[QUICK_QUOTA_MODE_FIELD]: normalizeQuickQuotaMode(value?.[QUICK_QUOTA_MODE_FIELD], value?.[LEGACY_QUICK_QUOTA_FIELD]),
|
|
1158
|
-
[SEARCH_PROVIDER_FIELD]: normalizeSearchProvider(value?.[SEARCH_PROVIDER_FIELD]),
|
|
1159
|
-
[SPEED_MODE_FIELD]: normalizeSpeedMode(value?.[SPEED_MODE_FIELD]),
|
|
1160
|
-
[OUTPUT_VERBOSITY_FIELD]: normalizeOutputVerbosity(value?.[OUTPUT_VERBOSITY_FIELD]),
|
|
1161
|
-
[CONTEXT_MODE_FIELD]: normalizeContextMode(value?.[CONTEXT_MODE_FIELD]),
|
|
1162
|
-
[CUSTOM_CONTEXT_WINDOW_FIELD]: normalizeCustomContextWindow(value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
|
|
1163
|
-
...Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [field, normalizeCustomContextWindow(value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])]))
|
|
1164
|
-
},
|
|
1165
|
-
writable: value?.writable === true
|
|
1166
|
-
};
|
|
1167
|
-
};
|
|
1168
|
-
const load = async () => {
|
|
1169
|
-
const current = ++generation;
|
|
1170
|
-
updating = false;
|
|
1171
|
-
fallbackStatus = "loading";
|
|
1172
|
-
fallback = void 0;
|
|
1173
|
-
error = false;
|
|
1174
|
-
publish();
|
|
1175
|
-
nativeSnapshot();
|
|
1176
|
-
try {
|
|
1177
|
-
const value = unwrap(await rpc.call(CHANNEL, "preferences/status", {}));
|
|
1178
|
-
if (current !== generation) return;
|
|
1179
|
-
if (nativeSnapshot().status === "ready") {
|
|
1180
|
-
contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
|
|
1181
|
-
verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
1182
|
-
} else acceptFallback(value);
|
|
1183
|
-
publish();
|
|
1184
|
-
} catch {
|
|
1185
|
-
if (current !== generation || nativeSnapshot().status === "ready") return;
|
|
1186
|
-
fallbackStatus = "unavailable";
|
|
1187
|
-
publish();
|
|
1188
|
-
}
|
|
1189
|
-
};
|
|
1190
|
-
const set = async (patch) => {
|
|
1191
|
-
if (snapshot.status !== "ready" || snapshot.writable !== true) return;
|
|
1192
|
-
const current = ++generation;
|
|
1193
|
-
const entries = Object.entries(patch);
|
|
1194
|
-
updating = true;
|
|
1195
|
-
error = false;
|
|
1196
|
-
failedPatch = void 0;
|
|
1197
|
-
publish();
|
|
1198
|
-
try {
|
|
1199
|
-
if (nativeSnapshot().status === "ready") {
|
|
1200
|
-
for (const [field, value] of entries) {
|
|
1201
|
-
if (current !== generation) return;
|
|
1202
|
-
await scope.set(field, value);
|
|
1203
|
-
}
|
|
1204
|
-
if (current !== generation) return;
|
|
1205
|
-
const accepted = nativeSnapshot().value;
|
|
1206
|
-
error = entries.some(([field, value]) => accepted?.[field] !== value);
|
|
1207
|
-
} else {
|
|
1208
|
-
const value = unwrap(await rpc.call(CHANNEL, "preferences/update", patch));
|
|
1209
|
-
if (current !== generation) return;
|
|
1210
|
-
acceptFallback(value);
|
|
1211
|
-
}
|
|
1212
|
-
} catch {
|
|
1213
|
-
if (current === generation) {
|
|
1214
|
-
error = true;
|
|
1215
|
-
failedPatch = patch;
|
|
1216
|
-
}
|
|
1217
|
-
} finally {
|
|
1218
|
-
if (current === generation) {
|
|
1219
|
-
updating = false;
|
|
1220
|
-
publish();
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
};
|
|
1224
|
-
return {
|
|
1225
|
-
getSnapshot: () => snapshot,
|
|
1226
|
-
subscribe: (listener) => {
|
|
1227
|
-
listeners.add(listener);
|
|
1228
|
-
return () => listeners.delete(listener);
|
|
1229
|
-
},
|
|
1230
|
-
load,
|
|
1231
|
-
set,
|
|
1232
|
-
retry: () => failedPatch === void 0 ? load() : set(failedPatch),
|
|
1233
|
-
dispose: disposeScope
|
|
1234
|
-
};
|
|
1235
|
-
}
|
|
1236
1264
|
const usePreferenceSnapshot = (preference) => (0, react.useSyncExternalStore)(preference.subscribe, preference.getSnapshot);
|
|
1237
1265
|
const notifyQuickQuota = () => window.dispatchEvent(new Event(QUICK_QUOTA_REFRESH_EVENT));
|
|
1238
1266
|
const formatRunway = (seconds, t) => {
|
|
@@ -1331,6 +1359,8 @@ window.__ModuleLoader__.load({
|
|
|
1331
1359
|
}) : null]
|
|
1332
1360
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1333
1361
|
className: "codexSubscriptionQuotaModes",
|
|
1362
|
+
"data-saving": snapshot.saving || void 0,
|
|
1363
|
+
"aria-busy": snapshot.saving || void 0,
|
|
1334
1364
|
role: "radiogroup",
|
|
1335
1365
|
"aria-label": t("quickQuotaSetting"),
|
|
1336
1366
|
children: [
|
|
@@ -1375,6 +1405,8 @@ window.__ModuleLoader__.load({
|
|
|
1375
1405
|
})]
|
|
1376
1406
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1377
1407
|
className: "codexSubscriptionSearchChoices",
|
|
1408
|
+
"data-saving": snapshot.saving || void 0,
|
|
1409
|
+
"aria-busy": snapshot.saving || void 0,
|
|
1378
1410
|
role: "radiogroup",
|
|
1379
1411
|
"aria-label": t("searchTitle"),
|
|
1380
1412
|
children: [
|
|
@@ -1885,15 +1917,37 @@ window.__ModuleLoader__.load({
|
|
|
1885
1917
|
}) : null]
|
|
1886
1918
|
});
|
|
1887
1919
|
}
|
|
1920
|
+
function AccountEmail({ candidate, fallback, t, emailVisible, onClick }) {
|
|
1921
|
+
if (typeof candidate?.email !== "string" || candidate.email.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1922
|
+
title: t("emailUnavailable"),
|
|
1923
|
+
children: fallback ?? candidate?.label ?? t("emailUnavailable")
|
|
1924
|
+
});
|
|
1925
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1926
|
+
type: "button",
|
|
1927
|
+
className: "codexSubscriptionEmail",
|
|
1928
|
+
"aria-label": t(emailVisible ? "hideEmail" : "showEmail"),
|
|
1929
|
+
"aria-pressed": emailVisible,
|
|
1930
|
+
onClick,
|
|
1931
|
+
children: emailVisible ? candidate.email : maskEmail(candidate.email)
|
|
1932
|
+
});
|
|
1933
|
+
}
|
|
1888
1934
|
function AccountCard({ rpc, t, account, setAccount, onSignedOut }) {
|
|
1889
1935
|
const [flow, setFlow] = (0, react.useState)();
|
|
1890
1936
|
const [manualCode, setManualCode] = (0, react.useState)("");
|
|
1891
1937
|
const [adding, setAdding] = (0, react.useState)(false);
|
|
1892
|
-
const [accountLabel, setAccountLabel] = (0, react.useState)("");
|
|
1893
1938
|
const [removeId, setRemoveId] = (0, react.useState)();
|
|
1939
|
+
const [emailVisible, setEmailVisible] = (0, react.useState)(false);
|
|
1940
|
+
const accounts = account?.accounts ?? [];
|
|
1941
|
+
const accountVisibilityKey = `${account?.authenticated === true ? "signed-in" : "signed-out"}:${accounts.map((candidate) => `${candidate.id ?? ""}:${candidate.active === true}:${candidate.email ?? ""}`).join("|")}`;
|
|
1942
|
+
const [emailVisibilityKey, setEmailVisibilityKey] = (0, react.useState)(accountVisibilityKey);
|
|
1894
1943
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
1895
1944
|
const [error, setError] = (0, react.useState)();
|
|
1896
1945
|
const call = (endpoint, payload = {}) => rpc.call(CHANNEL, endpoint, payload).then(unwrap);
|
|
1946
|
+
(0, react.useEffect)(() => {
|
|
1947
|
+
if (emailVisibilityKey === accountVisibilityKey) return;
|
|
1948
|
+
setEmailVisible(false);
|
|
1949
|
+
setEmailVisibilityKey(accountVisibilityKey);
|
|
1950
|
+
}, [accountVisibilityKey, emailVisibilityKey]);
|
|
1897
1951
|
(0, react.useEffect)(() => {
|
|
1898
1952
|
if (flow?.id === void 0 || [
|
|
1899
1953
|
"authenticated",
|
|
@@ -1915,7 +1969,6 @@ window.__ModuleLoader__.load({
|
|
|
1915
1969
|
setAccount(next.account);
|
|
1916
1970
|
onSignedOut();
|
|
1917
1971
|
setAdding(false);
|
|
1918
|
-
setAccountLabel("");
|
|
1919
1972
|
setFlow(void 0);
|
|
1920
1973
|
notifyQuickQuota();
|
|
1921
1974
|
}
|
|
@@ -1931,10 +1984,11 @@ window.__ModuleLoader__.load({
|
|
|
1931
1984
|
setFlow(void 0);
|
|
1932
1985
|
setBusy(true);
|
|
1933
1986
|
setError(void 0);
|
|
1987
|
+
const loginLabel = adding && label === void 0 ? `Account ${accounts.length + 1}` : label;
|
|
1934
1988
|
call("login/start", {
|
|
1935
1989
|
method,
|
|
1936
1990
|
openExternal: true,
|
|
1937
|
-
...
|
|
1991
|
+
...loginLabel === void 0 ? {} : { label: loginLabel }
|
|
1938
1992
|
}).then(setFlow).catch(() => setError(t("failed"))).finally(() => setBusy(false));
|
|
1939
1993
|
};
|
|
1940
1994
|
const cancel = () => {
|
|
@@ -1942,10 +1996,7 @@ window.__ModuleLoader__.load({
|
|
|
1942
1996
|
setBusy(true);
|
|
1943
1997
|
call("login/cancel", { id: flow.id }).then((next) => {
|
|
1944
1998
|
setFlow(adding ? void 0 : next);
|
|
1945
|
-
if (adding)
|
|
1946
|
-
setAdding(false);
|
|
1947
|
-
setAccountLabel("");
|
|
1948
|
-
}
|
|
1999
|
+
if (adding) setAdding(false);
|
|
1949
2000
|
if (adding) return void 0;
|
|
1950
2001
|
return call("status").then((account) => {
|
|
1951
2002
|
if (account.authenticated === true) {
|
|
@@ -2008,13 +2059,16 @@ window.__ModuleLoader__.load({
|
|
|
2008
2059
|
};
|
|
2009
2060
|
const signedIn = account?.authenticated === true;
|
|
2010
2061
|
const accountReady = account !== void 0;
|
|
2011
|
-
const accounts = account?.accounts ?? [];
|
|
2012
|
-
const activeAccount = accounts.find((candidate) => candidate.active);
|
|
2013
2062
|
const loginVisible = flow !== void 0 && ![
|
|
2014
2063
|
"authenticated",
|
|
2015
2064
|
"failed",
|
|
2016
2065
|
"cancelled"
|
|
2017
2066
|
].includes(flow.phase);
|
|
2067
|
+
const toggleEmail = () => {
|
|
2068
|
+
setEmailVisibilityKey(accountVisibilityKey);
|
|
2069
|
+
setEmailVisible((value) => emailVisibilityKey === accountVisibilityKey ? !value : true);
|
|
2070
|
+
};
|
|
2071
|
+
const emailVisibleForAccount = emailVisible && emailVisibilityKey === accountVisibilityKey;
|
|
2018
2072
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2019
2073
|
className: "codexSubscriptionCard",
|
|
2020
2074
|
children: [
|
|
@@ -2028,7 +2082,7 @@ window.__ModuleLoader__.load({
|
|
|
2028
2082
|
className: "codexSubscriptionDot",
|
|
2029
2083
|
"data-state": accountReady ? signedIn ? "connected" : "disconnected" : "loading",
|
|
2030
2084
|
"aria-hidden": "true"
|
|
2031
|
-
}), accountReady ? signedIn ?
|
|
2085
|
+
}), accountReady ? signedIn ? t("connected") : t("disconnected") : t("accountLoading")]
|
|
2032
2086
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2033
2087
|
className: "codexSubscriptionActions",
|
|
2034
2088
|
children: signedIn ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
@@ -2038,7 +2092,6 @@ window.__ModuleLoader__.load({
|
|
|
2038
2092
|
onClick: () => {
|
|
2039
2093
|
setFlow(void 0);
|
|
2040
2094
|
setAdding(true);
|
|
2041
|
-
setAccountLabel(`Account ${accounts.length + 1}`);
|
|
2042
2095
|
},
|
|
2043
2096
|
children: t("addAccount")
|
|
2044
2097
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
@@ -2067,7 +2120,13 @@ window.__ModuleLoader__.load({
|
|
|
2067
2120
|
children: accounts.map((candidate) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2068
2121
|
className: "codexSubscriptionAccount",
|
|
2069
2122
|
"data-active": candidate.active,
|
|
2070
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
2123
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountEmail, {
|
|
2124
|
+
candidate,
|
|
2125
|
+
fallback: candidate.label,
|
|
2126
|
+
t,
|
|
2127
|
+
emailVisible: emailVisibleForAccount,
|
|
2128
|
+
onClick: toggleEmail
|
|
2129
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2071
2130
|
className: "codexSubscriptionActions",
|
|
2072
2131
|
children: [
|
|
2073
2132
|
candidate.active ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
@@ -2095,42 +2154,34 @@ window.__ModuleLoader__.load({
|
|
|
2095
2154
|
})]
|
|
2096
2155
|
}, candidate.id))
|
|
2097
2156
|
}) : null,
|
|
2098
|
-
signedIn && adding && flow === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.
|
|
2157
|
+
signedIn && adding && flow === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2099
2158
|
className: "codexSubscriptionFlow",
|
|
2100
|
-
children:
|
|
2101
|
-
className: "codexSubscriptionInput",
|
|
2102
|
-
value: accountLabel,
|
|
2103
|
-
maxLength: 48,
|
|
2104
|
-
onChange: (event) => setAccountLabel(event.currentTarget.value)
|
|
2105
|
-
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2159
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2106
2160
|
className: "codexSubscriptionActions",
|
|
2107
2161
|
children: [
|
|
2108
2162
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2109
2163
|
type: "button",
|
|
2110
2164
|
variant: "primary",
|
|
2111
|
-
disabled: busy
|
|
2112
|
-
onClick: () => begin("browser"
|
|
2165
|
+
disabled: busy,
|
|
2166
|
+
onClick: () => begin("browser"),
|
|
2113
2167
|
children: t("browserLogin")
|
|
2114
2168
|
}),
|
|
2115
2169
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2116
2170
|
type: "button",
|
|
2117
2171
|
variant: "outline",
|
|
2118
|
-
disabled: busy
|
|
2119
|
-
onClick: () => begin("device_code"
|
|
2172
|
+
disabled: busy,
|
|
2173
|
+
onClick: () => begin("device_code"),
|
|
2120
2174
|
children: t("deviceLogin")
|
|
2121
2175
|
}),
|
|
2122
2176
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2123
2177
|
type: "button",
|
|
2124
2178
|
variant: "outline",
|
|
2125
2179
|
disabled: busy,
|
|
2126
|
-
onClick: () =>
|
|
2127
|
-
setAdding(false);
|
|
2128
|
-
setAccountLabel("");
|
|
2129
|
-
},
|
|
2180
|
+
onClick: () => setAdding(false),
|
|
2130
2181
|
children: t("cancel")
|
|
2131
2182
|
})
|
|
2132
2183
|
]
|
|
2133
|
-
})
|
|
2184
|
+
})
|
|
2134
2185
|
}) : null,
|
|
2135
2186
|
flow?.phase === "waiting_device" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2136
2187
|
className: "codexSubscriptionFlow",
|
|
@@ -2240,12 +2291,9 @@ window.__ModuleLoader__.load({
|
|
|
2240
2291
|
children: [
|
|
2241
2292
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2242
2293
|
className: "codexSubscriptionSectionHead",
|
|
2243
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
2294
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2244
2295
|
className: "codexSubscriptionSectionTitle",
|
|
2245
|
-
children:
|
|
2246
|
-
className: "codexSubscriptionNote",
|
|
2247
|
-
children: t("diagnosticsHint")
|
|
2248
|
-
})]
|
|
2296
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("diagnostics") })
|
|
2249
2297
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2250
2298
|
className: "codexSubscriptionActions",
|
|
2251
2299
|
children: [
|
|
@@ -2254,7 +2302,7 @@ window.__ModuleLoader__.load({
|
|
|
2254
2302
|
variant: "outline",
|
|
2255
2303
|
disabled: busy,
|
|
2256
2304
|
onClick: load,
|
|
2257
|
-
children: t("diagnosticsLoad")
|
|
2305
|
+
children: busy ? t("diagnosticsLoading") : t("diagnosticsLoad")
|
|
2258
2306
|
}),
|
|
2259
2307
|
report === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2260
2308
|
type: "button",
|
|
@@ -2307,29 +2355,19 @@ window.__ModuleLoader__.load({
|
|
|
2307
2355
|
})
|
|
2308
2356
|
});
|
|
2309
2357
|
}
|
|
2310
|
-
function
|
|
2311
|
-
const [
|
|
2312
|
-
const [
|
|
2313
|
-
const [resetAcknowledged, setResetAcknowledged] = (0, react.useState)(false);
|
|
2314
|
-
const [resetCountdown, setResetCountdown] = (0, react.useState)(0);
|
|
2315
|
-
const [resetError, setResetError] = (0, react.useState)();
|
|
2316
|
-
const [resetResult, setResetResult] = (0, react.useState)();
|
|
2317
|
-
const [inspectedExpiry, setInspectedExpiry] = (0, react.useState)(nextExpiresAt);
|
|
2318
|
-
const [expiryState, setExpiryState] = (0, react.useState)(nextExpiresAt === void 0 ? "loading" : "ready");
|
|
2358
|
+
function ResetCreditList({ rpc, t, count, nextExpiresAt, initialCredits, refreshKey, hasExhaustedQuota, onConsumed }) {
|
|
2359
|
+
const [credits, setCredits] = (0, react.useState)(initialCredits ?? (nextExpiresAt === void 0 ? [] : [{ expiresAt: nextExpiresAt }]));
|
|
2360
|
+
const [state, setState] = (0, react.useState)("loading");
|
|
2319
2361
|
(0, react.useEffect)(() => {
|
|
2320
|
-
if (nextExpiresAt !== void 0) {
|
|
2321
|
-
setInspectedExpiry(nextExpiresAt);
|
|
2322
|
-
setExpiryState("ready");
|
|
2323
|
-
return;
|
|
2324
|
-
}
|
|
2325
2362
|
let live = true;
|
|
2326
|
-
|
|
2363
|
+
setState("loading");
|
|
2364
|
+
setCredits([]);
|
|
2327
2365
|
rpc.call(CHANNEL, "reset-credit/inspect", {}).then(unwrap).then((value) => {
|
|
2328
2366
|
if (!live) return;
|
|
2329
|
-
|
|
2330
|
-
|
|
2367
|
+
setCredits(Array.isArray(value.credits) ? value.credits : []);
|
|
2368
|
+
setState("ready");
|
|
2331
2369
|
}).catch(() => {
|
|
2332
|
-
if (live)
|
|
2370
|
+
if (live) setState("error");
|
|
2333
2371
|
});
|
|
2334
2372
|
return () => {
|
|
2335
2373
|
live = false;
|
|
@@ -2337,8 +2375,35 @@ window.__ModuleLoader__.load({
|
|
|
2337
2375
|
}, [
|
|
2338
2376
|
rpc,
|
|
2339
2377
|
count,
|
|
2340
|
-
|
|
2378
|
+
refreshKey
|
|
2341
2379
|
]);
|
|
2380
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2381
|
+
className: "codexSubscriptionResetBalance",
|
|
2382
|
+
"aria-label": t("resetCredits"),
|
|
2383
|
+
children: [credits.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2384
|
+
className: "codexSubscriptionCreditNote",
|
|
2385
|
+
role: "status",
|
|
2386
|
+
children: state === "loading" ? t("resetCreditExpiryLoading") : t("resetCreditExpiryFailed")
|
|
2387
|
+
}) : credits.map((credit, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditControl, {
|
|
2388
|
+
rpc,
|
|
2389
|
+
t,
|
|
2390
|
+
credit,
|
|
2391
|
+
hasExhaustedQuota,
|
|
2392
|
+
onConsumed
|
|
2393
|
+
}, credit.ref ?? `pending-${index}`)), state === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2394
|
+
className: "codexSubscriptionCreditNote",
|
|
2395
|
+
role: "status",
|
|
2396
|
+
children: t("resetCreditExpiryFailed")
|
|
2397
|
+
}) : null]
|
|
2398
|
+
});
|
|
2399
|
+
}
|
|
2400
|
+
function ResetCreditControl({ rpc, t, credit, hasExhaustedQuota, onConsumed }) {
|
|
2401
|
+
const [challenge, setChallenge] = (0, react.useState)();
|
|
2402
|
+
const [resetBusy, setResetBusy] = (0, react.useState)(false);
|
|
2403
|
+
const [resetAcknowledged, setResetAcknowledged] = (0, react.useState)(false);
|
|
2404
|
+
const [resetCountdown, setResetCountdown] = (0, react.useState)(0);
|
|
2405
|
+
const [resetError, setResetError] = (0, react.useState)();
|
|
2406
|
+
const [resetResult, setResetResult] = (0, react.useState)();
|
|
2342
2407
|
(0, react.useEffect)(() => {
|
|
2343
2408
|
if (challenge === void 0) {
|
|
2344
2409
|
setResetCountdown(0);
|
|
@@ -2350,11 +2415,11 @@ window.__ModuleLoader__.load({
|
|
|
2350
2415
|
return () => window.clearInterval(timer);
|
|
2351
2416
|
}, [challenge]);
|
|
2352
2417
|
const prepareReset = () => {
|
|
2353
|
-
if (resetBusy) return;
|
|
2418
|
+
if (resetBusy || typeof credit.ref !== "string") return;
|
|
2354
2419
|
setResetBusy(true);
|
|
2355
2420
|
setResetError(void 0);
|
|
2356
2421
|
setResetResult(void 0);
|
|
2357
|
-
rpc.call(CHANNEL, "reset-credit/prepare", {}).then(unwrap).then((next) => {
|
|
2422
|
+
rpc.call(CHANNEL, "reset-credit/prepare", { creditRef: credit.ref }).then(unwrap).then((next) => {
|
|
2358
2423
|
setChallenge(next);
|
|
2359
2424
|
setResetAcknowledged(false);
|
|
2360
2425
|
}).catch((error) => setResetError(resetCreditErrorText(error, t))).finally(() => setResetBusy(false));
|
|
@@ -2384,36 +2449,26 @@ window.__ModuleLoader__.load({
|
|
|
2384
2449
|
}).catch((error) => setResetError(resetCreditErrorText(error, t))).finally(() => setResetBusy(false));
|
|
2385
2450
|
};
|
|
2386
2451
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2387
|
-
className: "
|
|
2452
|
+
className: "codexSubscriptionResetCard",
|
|
2388
2453
|
children: [
|
|
2389
|
-
challenge === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.
|
|
2390
|
-
className: "
|
|
2391
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
className: "codexSubscriptionResetExpiry",
|
|
2395
|
-
role: "status",
|
|
2396
|
-
children: t("resetCreditExpiryLoading")
|
|
2397
|
-
}) : expiryState === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2398
|
-
className: "codexSubscriptionResetExpiry",
|
|
2399
|
-
children: t("resetCreditExpiryFailed")
|
|
2400
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditExpiry, {
|
|
2401
|
-
expiresAt: inspectedExpiry,
|
|
2402
|
-
t
|
|
2403
|
-
})]
|
|
2404
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2405
|
-
className: "codexSubscriptionActions",
|
|
2406
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2407
|
-
className: "codexSubscriptionResetUse",
|
|
2408
|
-
type: "button",
|
|
2409
|
-
variant: "outline",
|
|
2410
|
-
disabled: resetBusy,
|
|
2411
|
-
"aria-busy": resetBusy,
|
|
2412
|
-
onClick: prepareReset,
|
|
2413
|
-
children: resetBusy ? t("resetPreparing") : t("resetUse")
|
|
2414
|
-
})
|
|
2454
|
+
challenge === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2455
|
+
className: "codexSubscriptionResetMeta",
|
|
2456
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: credit.name ?? t("resetCreditDefaultName") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditExpiry, {
|
|
2457
|
+
expiresAt: credit.expiresAt,
|
|
2458
|
+
t
|
|
2415
2459
|
})]
|
|
2416
|
-
})
|
|
2460
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2461
|
+
className: "codexSubscriptionActions",
|
|
2462
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2463
|
+
className: "codexSubscriptionResetUse",
|
|
2464
|
+
type: "button",
|
|
2465
|
+
variant: "outline",
|
|
2466
|
+
disabled: resetBusy || typeof credit.ref !== "string",
|
|
2467
|
+
"aria-busy": resetBusy,
|
|
2468
|
+
onClick: prepareReset,
|
|
2469
|
+
children: resetBusy ? t("resetPreparing") : t("resetUse")
|
|
2470
|
+
})
|
|
2471
|
+
})] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2417
2472
|
className: "codexSubscriptionResetFlow",
|
|
2418
2473
|
role: "group",
|
|
2419
2474
|
"aria-labelledby": "codex-reset-confirm-title",
|
|
@@ -2498,6 +2553,7 @@ window.__ModuleLoader__.load({
|
|
|
2498
2553
|
}
|
|
2499
2554
|
function UsageCard({ rpc, t, signedIn, resetKey }) {
|
|
2500
2555
|
const [usage, setUsage] = (0, react.useState)();
|
|
2556
|
+
const [usageRefreshGeneration, setUsageRefreshGeneration] = (0, react.useState)(0);
|
|
2501
2557
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
2502
2558
|
const [error, setError] = (0, react.useState)();
|
|
2503
2559
|
const request = (0, react.useRef)(0);
|
|
@@ -2509,6 +2565,7 @@ window.__ModuleLoader__.load({
|
|
|
2509
2565
|
rpc.call(CHANNEL, "usage", { force }).then(unwrap).then((next) => {
|
|
2510
2566
|
if (request.current === id) {
|
|
2511
2567
|
setUsage(next);
|
|
2568
|
+
setUsageRefreshGeneration((value) => value + 1);
|
|
2512
2569
|
if (force) notifyQuickQuota();
|
|
2513
2570
|
}
|
|
2514
2571
|
}).catch((error) => {
|
|
@@ -2626,11 +2683,13 @@ window.__ModuleLoader__.load({
|
|
|
2626
2683
|
}) : null,
|
|
2627
2684
|
visibleUsage?.resetCredits?.availableCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2628
2685
|
className: "codexSubscriptionCreditBalance",
|
|
2629
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetCredits") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
2686
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetCredits") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditList, {
|
|
2630
2687
|
rpc,
|
|
2631
2688
|
t,
|
|
2632
2689
|
count: visibleUsage.resetCredits.availableCount,
|
|
2633
2690
|
nextExpiresAt: visibleUsage.resetCredits.nextExpiresAt,
|
|
2691
|
+
initialCredits: visibleUsage.resetCredits.credits,
|
|
2692
|
+
refreshKey: `${resetKey}:${usageRefreshGeneration}`,
|
|
2634
2693
|
hasExhaustedQuota: exhausted,
|
|
2635
2694
|
onConsumed: () => load(true)
|
|
2636
2695
|
})]
|
package/lib/index.js
CHANGED
|
@@ -21,6 +21,41 @@ import { dirname, join, resolve } from "node:path";
|
|
|
21
21
|
const VERSION = 1;
|
|
22
22
|
const DEFAULT_LABEL = "Account 1";
|
|
23
23
|
const clone$1 = (value) => value === void 0 ? void 0 : structuredClone(value);
|
|
24
|
+
const EMAIL_MAX_LENGTH = 254;
|
|
25
|
+
const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/u;
|
|
26
|
+
/** Keep only a bounded, display-safe email address from a trusted OAuth result. */
|
|
27
|
+
function normalizeAccountEmail(value) {
|
|
28
|
+
if (typeof value !== "string") return void 0;
|
|
29
|
+
const email = value.trim();
|
|
30
|
+
return email.length > 0 && email.length <= EMAIL_MAX_LENGTH && EMAIL_PATTERN.test(email) ? email : void 0;
|
|
31
|
+
}
|
|
32
|
+
function decodeJwtPayload(access) {
|
|
33
|
+
if (typeof access !== "string") return void 0;
|
|
34
|
+
const encoded = access.split(".")[1];
|
|
35
|
+
if (typeof encoded !== "string" || encoded.length === 0) return void 0;
|
|
36
|
+
try {
|
|
37
|
+
return JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
|
|
38
|
+
} catch {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function emailFromAccessToken(access) {
|
|
43
|
+
const payload = decodeJwtPayload(access);
|
|
44
|
+
return normalizeAccountEmail(payload?.["https://api.openai.com/profile"]?.email ?? payload?.email);
|
|
45
|
+
}
|
|
46
|
+
/** Normalize the one non-secret account attribute that may cross the UI boundary. */
|
|
47
|
+
function sanitizeOAuthCredential(value) {
|
|
48
|
+
const credential = assertOAuthCredential$1(value);
|
|
49
|
+
const email = emailFromAccessToken(credential.access) ?? normalizeAccountEmail(credential.email);
|
|
50
|
+
if (email === void 0) {
|
|
51
|
+
delete credential.email;
|
|
52
|
+
return credential;
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
...credential,
|
|
56
|
+
email
|
|
57
|
+
};
|
|
58
|
+
}
|
|
24
59
|
function assertOAuthCredential$1(value) {
|
|
25
60
|
if (value === null || typeof value !== "object" || value.type !== "oauth" || typeof value.access !== "string" || value.access.length === 0 || typeof value.refresh !== "string" || value.refresh.length === 0 || typeof value.expires !== "number" || !Number.isFinite(value.expires)) throw new Error("Codex account vault received a malformed OAuth credential");
|
|
26
61
|
return clone$1(value);
|
|
@@ -48,7 +83,7 @@ function assertVaultRecord(record) {
|
|
|
48
83
|
return {
|
|
49
84
|
id: account.id,
|
|
50
85
|
label: normalizeLabel(account.label),
|
|
51
|
-
credential:
|
|
86
|
+
credential: sanitizeOAuthCredential(account.credential)
|
|
52
87
|
};
|
|
53
88
|
});
|
|
54
89
|
if (!ids.has(record.payload.activeId)) throw new Error("Codex account vault active account is missing");
|
|
@@ -80,7 +115,7 @@ var PendingOAuthCredentialStore = class {
|
|
|
80
115
|
async modify(providerId, update) {
|
|
81
116
|
if (providerId !== "openai-codex") throw new Error("Pending Codex login received an unknown provider");
|
|
82
117
|
const next = await update(clone$1(this.#credential));
|
|
83
|
-
if (next !== void 0) this.#credential =
|
|
118
|
+
if (next !== void 0) this.#credential = sanitizeOAuthCredential(next);
|
|
84
119
|
return clone$1(this.#credential);
|
|
85
120
|
}
|
|
86
121
|
async delete(providerId) {
|
|
@@ -170,7 +205,8 @@ var DshOAuthAccountVault = class {
|
|
|
170
205
|
id: account.id,
|
|
171
206
|
label: account.label,
|
|
172
207
|
active: account.id === payload.activeId,
|
|
173
|
-
expiresAt: account.credential.expires
|
|
208
|
+
expiresAt: account.credential.expires,
|
|
209
|
+
...account.credential.email === void 0 ? {} : { email: account.credential.email }
|
|
174
210
|
}));
|
|
175
211
|
});
|
|
176
212
|
}
|
|
@@ -186,7 +222,7 @@ var DshOAuthAccountVault = class {
|
|
|
186
222
|
add(label, credential) {
|
|
187
223
|
return this.#enqueue(async () => {
|
|
188
224
|
const normalizedLabel = normalizeLabel(label);
|
|
189
|
-
const validated =
|
|
225
|
+
const validated = sanitizeOAuthCredential(credential);
|
|
190
226
|
await this.#ensurePayload();
|
|
191
227
|
const id = this.createId();
|
|
192
228
|
const account = (await this.#modifyPayload((current) => ({
|
|
@@ -202,7 +238,8 @@ var DshOAuthAccountVault = class {
|
|
|
202
238
|
id,
|
|
203
239
|
label: account.label,
|
|
204
240
|
active: true,
|
|
205
|
-
expiresAt: account.credential.expires
|
|
241
|
+
expiresAt: account.credential.expires,
|
|
242
|
+
...account.credential.email === void 0 ? {} : { email: account.credential.email }
|
|
206
243
|
};
|
|
207
244
|
});
|
|
208
245
|
}
|
|
@@ -222,7 +259,7 @@ var DshOAuthAccountVault = class {
|
|
|
222
259
|
if (await this.#ensurePayload() === void 0) {
|
|
223
260
|
const initial = await update(void 0);
|
|
224
261
|
if (initial === void 0) return void 0;
|
|
225
|
-
const credential =
|
|
262
|
+
const credential = sanitizeOAuthCredential(initial);
|
|
226
263
|
await this.credentials.set(this.legacyRef, JSON.stringify(credential));
|
|
227
264
|
await this.#ensurePayload();
|
|
228
265
|
return clone$1(credential);
|
|
@@ -236,7 +273,8 @@ var DshOAuthAccountVault = class {
|
|
|
236
273
|
result = previous;
|
|
237
274
|
return current;
|
|
238
275
|
}
|
|
239
|
-
const credential =
|
|
276
|
+
const credential = sanitizeOAuthCredential(next);
|
|
277
|
+
if (credential.email === void 0 && previous.email !== void 0) credential.email = previous.email;
|
|
240
278
|
const accounts = [...current.accounts];
|
|
241
279
|
accounts[index] = {
|
|
242
280
|
...accounts[index],
|
|
@@ -1265,7 +1303,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
|
|
|
1265
1303
|
}
|
|
1266
1304
|
//#endregion
|
|
1267
1305
|
//#region src/version.js
|
|
1268
|
-
const PACKAGE_VERSION = "1.
|
|
1306
|
+
const PACKAGE_VERSION = "1.13.1";
|
|
1269
1307
|
const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
|
|
1270
1308
|
//#endregion
|
|
1271
1309
|
//#region src/model-catalog.js
|
|
@@ -2244,15 +2282,23 @@ function resetCreditsOf(value) {
|
|
|
2244
2282
|
if (value === void 0 || value === null) return void 0;
|
|
2245
2283
|
if (!record$1(value) || !Number.isSafeInteger(value.available_count) || value.available_count < 0) throw new Error("Codex returned malformed reset credit details");
|
|
2246
2284
|
if (value.credits !== void 0 && value.credits !== null && !Array.isArray(value.credits)) throw new Error("Codex returned malformed reset credit details");
|
|
2247
|
-
const
|
|
2248
|
-
|
|
2249
|
-
|
|
2285
|
+
const available = (value.credits ?? []).filter((credit) => record$1(credit) && credit.status?.toLowerCase?.() === "available").map((credit) => {
|
|
2286
|
+
const name = typeof credit.title === "string" && credit.title.trim().length > 0 ? credit.title.trim().slice(0, 120) : void 0;
|
|
2287
|
+
let expiresAt;
|
|
2288
|
+
if (Number.isSafeInteger(credit.expires_at) && credit.expires_at > 0) expiresAt = credit.expires_at * 1e3;
|
|
2289
|
+
else if (typeof credit.expires_at === "string" && credit.expires_at.length <= 64) {
|
|
2250
2290
|
const parsed = Date.parse(credit.expires_at);
|
|
2251
|
-
if (Number.isFinite(parsed) && parsed > 0)
|
|
2291
|
+
if (Number.isFinite(parsed) && parsed > 0) expiresAt = parsed;
|
|
2252
2292
|
}
|
|
2253
|
-
|
|
2293
|
+
return {
|
|
2294
|
+
...name === void 0 ? {} : { name },
|
|
2295
|
+
...expiresAt === void 0 ? {} : { expiresAt }
|
|
2296
|
+
};
|
|
2297
|
+
});
|
|
2298
|
+
const expirations = available.map((credit) => credit.expiresAt).filter((expiration) => expiration !== void 0);
|
|
2254
2299
|
return {
|
|
2255
2300
|
availableCount: value.available_count,
|
|
2301
|
+
...available.length === 0 ? {} : { credits: available },
|
|
2256
2302
|
...expirations.length === 0 ? {} : { nextExpiresAt: Math.min(...expirations) }
|
|
2257
2303
|
};
|
|
2258
2304
|
}
|
|
@@ -2691,10 +2737,13 @@ function parseDetails(value, now) {
|
|
|
2691
2737
|
if (available.length === 0) throw new Error("No usable quota reset is available");
|
|
2692
2738
|
return {
|
|
2693
2739
|
availableCount: value.available_count,
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2740
|
+
credits: available.map(({ credit, expiresAt }, index) => ({
|
|
2741
|
+
creditId: credit.id,
|
|
2742
|
+
title: safeCopy(credit.title),
|
|
2743
|
+
description: safeCopy(credit.description),
|
|
2744
|
+
creditExpiresAt: expiresAt,
|
|
2745
|
+
index
|
|
2746
|
+
}))
|
|
2698
2747
|
};
|
|
2699
2748
|
}
|
|
2700
2749
|
function parseConsumeResult(value) {
|
|
@@ -2728,6 +2777,23 @@ function createCodexResetCreditService(options) {
|
|
|
2728
2777
|
const challengeTtlMs = options.challengeTtlMs ?? DEFAULT_CHALLENGE_TTL_MS;
|
|
2729
2778
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
2730
2779
|
const challenges = /* @__PURE__ */ new Map();
|
|
2780
|
+
const creditRefs = /* @__PURE__ */ new Map();
|
|
2781
|
+
let creditRefSequence = 0;
|
|
2782
|
+
const rememberCreditRef = (accountId, credit) => {
|
|
2783
|
+
const ref = `${randomUUID$1()}-${++creditRefSequence}`;
|
|
2784
|
+
creditRefs.set(ref, {
|
|
2785
|
+
accountId,
|
|
2786
|
+
creditId: credit.creditId,
|
|
2787
|
+
index: credit.index
|
|
2788
|
+
});
|
|
2789
|
+
while (creditRefs.size > 64) creditRefs.delete(creditRefs.keys().next().value);
|
|
2790
|
+
return ref;
|
|
2791
|
+
};
|
|
2792
|
+
const publicCredit = (accountId, credit) => ({
|
|
2793
|
+
ref: rememberCreditRef(accountId, credit),
|
|
2794
|
+
...credit.title === void 0 ? {} : { name: credit.title },
|
|
2795
|
+
...credit.creditExpiresAt === void 0 ? {} : { expiresAt: credit.creditExpiresAt }
|
|
2796
|
+
});
|
|
2731
2797
|
const resolveCredentials = async (signal) => credentialsOf(await getAuth({ signal }), await readCredential({ signal }));
|
|
2732
2798
|
const readDetails = async (signal, credentials) => {
|
|
2733
2799
|
const { access, accountId } = credentials ?? await resolveCredentials(signal);
|
|
@@ -2757,16 +2823,27 @@ function createCodexResetCreditService(options) {
|
|
|
2757
2823
|
};
|
|
2758
2824
|
return Object.freeze({
|
|
2759
2825
|
async inspect({ signal } = {}) {
|
|
2760
|
-
const { details } = await readDetails(signal);
|
|
2826
|
+
const { accountId, details } = await readDetails(signal);
|
|
2761
2827
|
return {
|
|
2762
2828
|
availableCount: details.availableCount,
|
|
2763
|
-
|
|
2829
|
+
credits: details.credits.map((credit) => publicCredit(accountId, credit)),
|
|
2830
|
+
...details.credits[0]?.creditExpiresAt === void 0 ? {} : { nextExpiresAt: details.credits[0].creditExpiresAt }
|
|
2764
2831
|
};
|
|
2765
2832
|
},
|
|
2766
|
-
async prepare({ signal } = {}) {
|
|
2833
|
+
async prepare({ creditRef, signal } = {}) {
|
|
2767
2834
|
const credentials = await resolveCredentials(signal);
|
|
2768
2835
|
for (const [challengeId, challenge] of challenges) {
|
|
2769
|
-
if (challenge.accountId
|
|
2836
|
+
if (challenge.accountId === credentials.accountId && challenge.uncertain === false && challenge.creditRef === creditRef) if (now() > challenge.expiresAt) challenges.delete(challengeId);
|
|
2837
|
+
else return {
|
|
2838
|
+
challengeId,
|
|
2839
|
+
availableCount: challenge.availableCount,
|
|
2840
|
+
readyAt: challenge.readyAt,
|
|
2841
|
+
expiresAt: challenge.expiresAt,
|
|
2842
|
+
...challenge.creditExpiresAt === void 0 ? {} : { creditExpiresAt: challenge.creditExpiresAt },
|
|
2843
|
+
...challenge.title === void 0 ? {} : { title: challenge.title },
|
|
2844
|
+
...challenge.description === void 0 ? {} : { description: challenge.description }
|
|
2845
|
+
};
|
|
2846
|
+
if (challenge.accountId !== credentials.accountId || challenge.uncertain !== true || creditRef !== void 0 && challenge.creditRef !== creditRef) continue;
|
|
2770
2847
|
if (now() > challenge.expiresAt) {
|
|
2771
2848
|
challenges.delete(challengeId);
|
|
2772
2849
|
continue;
|
|
@@ -2782,22 +2859,31 @@ function createCodexResetCreditService(options) {
|
|
|
2782
2859
|
};
|
|
2783
2860
|
}
|
|
2784
2861
|
const { accountId, details } = await readDetails(signal, credentials);
|
|
2862
|
+
let selected = details.credits[0];
|
|
2863
|
+
if (creditRef !== void 0) {
|
|
2864
|
+
const reference = typeof creditRef === "string" ? creditRefs.get(creditRef) : void 0;
|
|
2865
|
+
if (reference === void 0 || reference.accountId !== accountId) throw new Error("This quota reset confirmation is no longer valid");
|
|
2866
|
+
selected = details.credits.find((credit) => credit.creditId === reference.creditId && credit.index === reference.index);
|
|
2867
|
+
if (selected === void 0) throw new Error("This quota reset confirmation is no longer valid");
|
|
2868
|
+
}
|
|
2869
|
+
if (selected === void 0) throw new Error("No usable quota reset is available");
|
|
2785
2870
|
const preparedAt = now();
|
|
2786
2871
|
const readyAt = preparedAt + confirmDelayMs;
|
|
2787
|
-
const expiresAt = Math.min(preparedAt + challengeTtlMs,
|
|
2872
|
+
const expiresAt = Math.min(preparedAt + challengeTtlMs, selected.creditExpiresAt ?? Number.MAX_SAFE_INTEGER);
|
|
2788
2873
|
if (expiresAt <= readyAt) throw new Error("The available quota reset expires too soon");
|
|
2789
2874
|
const challengeId = randomUUID$1();
|
|
2790
2875
|
challenges.set(challengeId, {
|
|
2791
2876
|
state: "prepared",
|
|
2792
2877
|
accountId,
|
|
2793
|
-
|
|
2878
|
+
creditRef,
|
|
2879
|
+
creditId: selected.creditId,
|
|
2794
2880
|
redeemRequestId: randomUUID$1(),
|
|
2795
2881
|
readyAt,
|
|
2796
2882
|
expiresAt,
|
|
2797
2883
|
availableCount: details.availableCount,
|
|
2798
|
-
creditExpiresAt:
|
|
2799
|
-
title:
|
|
2800
|
-
description:
|
|
2884
|
+
creditExpiresAt: selected.creditExpiresAt,
|
|
2885
|
+
title: selected.title,
|
|
2886
|
+
description: selected.description,
|
|
2801
2887
|
uncertain: false
|
|
2802
2888
|
});
|
|
2803
2889
|
return {
|
|
@@ -2805,9 +2891,9 @@ function createCodexResetCreditService(options) {
|
|
|
2805
2891
|
availableCount: details.availableCount,
|
|
2806
2892
|
readyAt,
|
|
2807
2893
|
expiresAt,
|
|
2808
|
-
...
|
|
2809
|
-
...
|
|
2810
|
-
...
|
|
2894
|
+
...selected.creditExpiresAt === void 0 ? {} : { creditExpiresAt: selected.creditExpiresAt },
|
|
2895
|
+
...selected.title === void 0 ? {} : { title: selected.title },
|
|
2896
|
+
...selected.description === void 0 ? {} : { description: selected.description }
|
|
2811
2897
|
};
|
|
2812
2898
|
},
|
|
2813
2899
|
async consume({ challengeId, acknowledged, signal } = {}) {
|
|
@@ -2885,6 +2971,7 @@ function createCodexResetCreditService(options) {
|
|
|
2885
2971
|
},
|
|
2886
2972
|
clear() {
|
|
2887
2973
|
challenges.clear();
|
|
2974
|
+
creditRefs.clear();
|
|
2888
2975
|
}
|
|
2889
2976
|
});
|
|
2890
2977
|
}
|
|
@@ -3026,7 +3113,10 @@ function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditSer
|
|
|
3026
3113
|
signal.throwIfAborted();
|
|
3027
3114
|
return {
|
|
3028
3115
|
ok: true,
|
|
3029
|
-
value: endpoint === "reset-credit/inspect" ? await resetCreditService.inspect({ signal }) : endpoint === "reset-credit/prepare" ? await resetCreditService.prepare({
|
|
3116
|
+
value: endpoint === "reset-credit/inspect" ? await resetCreditService.inspect({ signal }) : endpoint === "reset-credit/prepare" ? await resetCreditService.prepare({
|
|
3117
|
+
creditRef: payload?.creditRef,
|
|
3118
|
+
signal
|
|
3119
|
+
}) : await resetCreditService.consume({
|
|
3030
3120
|
challengeId: payload?.challengeId,
|
|
3031
3121
|
acknowledged: payload?.acknowledged,
|
|
3032
3122
|
signal
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-codex-subscription",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.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",
|