dsh-provider-qoder 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -8
- package/README_CN.md +12 -8
- package/lib/client.js +1355 -384
- package/lib/index.d.ts +69 -24
- package/lib/index.js +2669 -635
- package/package.json +3 -1
package/lib/client.js
CHANGED
|
@@ -5,6 +5,7 @@ window.__ModuleLoader__.load({
|
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
7
|
let react = require("react");
|
|
8
|
+
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
8
9
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
10
|
//#region src/dsh/credential-contract.ts
|
|
10
11
|
/** Shared DSH host/browser contract for the one managed Qoder credential. */
|
|
@@ -14,6 +15,172 @@ window.__ModuleLoader__.load({
|
|
|
14
15
|
return source === "env" || source?.endsWith("-env") === true;
|
|
15
16
|
}
|
|
16
17
|
//#endregion
|
|
18
|
+
//#region src/client/queue-status.ts
|
|
19
|
+
/** Match DSH's running status clock: whole hours, minutes and seconds. */
|
|
20
|
+
function formatQueueDuration(ms, t) {
|
|
21
|
+
const total = Math.max(0, Math.floor(ms / 1e3));
|
|
22
|
+
const hours = Math.floor(total / 3600);
|
|
23
|
+
const minutes = Math.floor(total / 60) % 60;
|
|
24
|
+
const seconds = total % 60;
|
|
25
|
+
return (hours > 0 ? `${hours}${t("queueHourUnit")}` : "") + (total >= 60 ? `${minutes}${t("queueMinuteUnit")}` : "") + `${seconds}${t("queueSecondUnit")}`;
|
|
26
|
+
}
|
|
27
|
+
function parseQueueSnapshots(value, sessionId) {
|
|
28
|
+
if (!Array.isArray(value) || value.length > 256) throw new Error("Invalid queue snapshots");
|
|
29
|
+
return value.map((item) => {
|
|
30
|
+
if (!item || typeof item !== "object" || item.sessionId !== sessionId || typeof item.callId !== "string" || !item.callId || typeof item.model !== "string" || item.modelName !== void 0 && (typeof item.modelName !== "string" || !item.modelName.trim()) || ![
|
|
31
|
+
"waitElapsedMs",
|
|
32
|
+
"maxWaitMs",
|
|
33
|
+
"updatedAt"
|
|
34
|
+
].every((key) => typeof item[key] === "number" && Number.isFinite(item[key]) && item[key] >= 0) || !["queueCount", "waitTimeMs"].every((key) => item[key] === void 0 || typeof item[key] === "number" && Number.isFinite(item[key]) && item[key] >= 0)) throw new Error("Invalid queue snapshot");
|
|
35
|
+
return item;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function watchQueueStatus(rpc, sessionId, visibility, changed) {
|
|
39
|
+
let disposed = false;
|
|
40
|
+
let generation = 0;
|
|
41
|
+
let timer;
|
|
42
|
+
let active;
|
|
43
|
+
let items = [];
|
|
44
|
+
const poll = async () => {
|
|
45
|
+
if (disposed || visibility.hidden || active) return;
|
|
46
|
+
const revision = generation;
|
|
47
|
+
const controller = new AbortController();
|
|
48
|
+
active = controller;
|
|
49
|
+
const timeout = setTimeout(() => controller.abort(), 5e3);
|
|
50
|
+
try {
|
|
51
|
+
const result = await rpc.call("queue", { sessionId }, controller.signal);
|
|
52
|
+
if (disposed || revision !== generation) return;
|
|
53
|
+
if (!result.ok) throw new Error("Queue status unavailable");
|
|
54
|
+
items = parseQueueSnapshots(result.value, sessionId);
|
|
55
|
+
changed({
|
|
56
|
+
items,
|
|
57
|
+
unavailable: false
|
|
58
|
+
});
|
|
59
|
+
} catch {
|
|
60
|
+
if (!disposed && revision === generation) changed({
|
|
61
|
+
items,
|
|
62
|
+
unavailable: true
|
|
63
|
+
});
|
|
64
|
+
} finally {
|
|
65
|
+
clearTimeout(timeout);
|
|
66
|
+
if (active === controller) active = void 0;
|
|
67
|
+
if (!disposed && revision === generation && !visibility.hidden) timer = setTimeout(() => {
|
|
68
|
+
poll();
|
|
69
|
+
}, 1e3);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const stop = () => {
|
|
73
|
+
generation++;
|
|
74
|
+
clearTimeout(timer);
|
|
75
|
+
active?.abort();
|
|
76
|
+
active = void 0;
|
|
77
|
+
};
|
|
78
|
+
const onVisibility = () => {
|
|
79
|
+
stop();
|
|
80
|
+
if (!visibility.hidden) poll();
|
|
81
|
+
};
|
|
82
|
+
visibility.addEventListener("visibilitychange", onVisibility);
|
|
83
|
+
poll();
|
|
84
|
+
return () => {
|
|
85
|
+
disposed = true;
|
|
86
|
+
stop();
|
|
87
|
+
visibility.removeEventListener("visibilitychange", onVisibility);
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region \0dsh-css:/home/runner/work/dsh-provider-qoder/dsh-provider-qoder/src/client/QoderQueueStatus.module.css.mjs
|
|
92
|
+
const css$2 = "._8MdOdG_queues{box-sizing:border-box;width:calc(100% - 2 * var(--dsh-composer-side-clearance,16px) - 2 * var(--dsh-composer-dock-inset,8px));max-width:calc(var(--dsh-composer-card-max-width,952px) - 2 * var(--dsh-composer-dock-inset,8px));padding:0 var(--dsh-composer-dock-inset,8px);--dsw-alias-label-shimmer:var(--dsw-alias-label-deep-diving-shimmer);color:var(--dsw-alias-label-deep-diving,#4d6bfe);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(22px + var(--dsh-content-font-delta,0px));flex:none;margin:0 auto}._8MdOdG_panel{isolation:isolate;border-radius:var(--dsw-radius-lg,16px);width:100%;padding:2px 0;position:relative;overflow:hidden}._8MdOdG_panel:before{z-index:-1;border-radius:inherit;background:var(--dsw-specific-menu,var(--dsw-alias-bg-layer-1,#242629));backdrop-filter:var(--dsw-menu-backdrop-filter,none);content:\"\";pointer-events:none;position:absolute;inset:0}._8MdOdG_panel:after{border:.5px solid var(--dsw-alias-border-l1,#42454a);border-radius:inherit;content:\"\";pointer-events:none;position:absolute;inset:0}._8MdOdG_row{min-width:0}._8MdOdG_row+._8MdOdG_row{box-shadow:inset 0 1px 0 var(--dsw-alias-border-l1,#42454a)}._8MdOdG_row[data-unavailable]{color:var(--dsw-alias-label-secondary)}._8MdOdG_summary{box-sizing:border-box;cursor:pointer;align-items:center;gap:10px;width:100%;min-width:0;min-height:36px;padding:7px 12px;list-style:none;display:flex}._8MdOdG_summary::-webkit-details-marker{display:none}._8MdOdG_summary:focus-visible{outline-offset:-2px;border-radius:var(--dsw-radius-md,8px);outline:2px solid}._8MdOdG_icon{flex:none;width:14px;height:14px}._8MdOdG_text{font-variant-numeric:tabular-nums;overflow-wrap:anywhere;flex:1;min-width:0}._8MdOdG_chevron{width:6px;height:6px;color:var(--dsw-alias-label-tertiary);border-bottom:1.5px solid;border-right:1.5px solid;flex:none;margin:0 3px 3px;transform:rotate(45deg)}._8MdOdG_row>details[open] ._8MdOdG_chevron{margin-bottom:-3px;transform:rotate(225deg)}._8MdOdG_details{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:2px 16px;padding:0 12px 10px 36px;display:flex}._8MdOdG_visuallyHidden{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;padding:0;position:absolute;overflow:hidden}";
|
|
93
|
+
const tagId$2 = "dsh-provider-qoder/QoderQueueStatus.module.css";
|
|
94
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
|
|
95
|
+
const tag = document.createElement("style");
|
|
96
|
+
tag.dataset.plugin = "dsh-provider-qoder";
|
|
97
|
+
tag.dataset.pluginCss = tagId$2;
|
|
98
|
+
tag.textContent = css$2;
|
|
99
|
+
document.head.appendChild(tag);
|
|
100
|
+
}
|
|
101
|
+
var QoderQueueStatus_module_css_default = {
|
|
102
|
+
"chevron": "_8MdOdG_chevron",
|
|
103
|
+
"details": "_8MdOdG_details",
|
|
104
|
+
"icon": "_8MdOdG_icon",
|
|
105
|
+
"panel": "_8MdOdG_panel",
|
|
106
|
+
"queues": "_8MdOdG_queues",
|
|
107
|
+
"row": "_8MdOdG_row",
|
|
108
|
+
"summary": "_8MdOdG_summary",
|
|
109
|
+
"text": "_8MdOdG_text",
|
|
110
|
+
"visuallyHidden": "_8MdOdG_visuallyHidden"
|
|
111
|
+
};
|
|
112
|
+
//#endregion
|
|
113
|
+
//#region src/client/QoderQueueStatus.tsx
|
|
114
|
+
function QueueRow({ item, unavailable, t }) {
|
|
115
|
+
const elapsed = Math.min(item.maxWaitMs, item.waitElapsedMs + Math.max(0, Date.now() - item.updatedAt));
|
|
116
|
+
const name = item.modelName ?? item.model;
|
|
117
|
+
const status = unavailable ? t("queueUnavailable") : t("queueWaiting", { model: name });
|
|
118
|
+
const label = unavailable ? status : t("queueRunningFor", {
|
|
119
|
+
model: name,
|
|
120
|
+
duration: formatQueueDuration(elapsed, t)
|
|
121
|
+
});
|
|
122
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
123
|
+
className: QoderQueueStatus_module_css_default.row,
|
|
124
|
+
"data-unavailable": unavailable || void 0,
|
|
125
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
126
|
+
className: QoderQueueStatus_module_css_default.visuallyHidden,
|
|
127
|
+
role: "status",
|
|
128
|
+
"aria-live": "polite",
|
|
129
|
+
"aria-atomic": "true",
|
|
130
|
+
children: status
|
|
131
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
|
|
132
|
+
className: QoderQueueStatus_module_css_default.summary,
|
|
133
|
+
"aria-label": status,
|
|
134
|
+
children: [
|
|
135
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconQueueOutlineRegular, {
|
|
136
|
+
className: QoderQueueStatus_module_css_default.icon,
|
|
137
|
+
"aria-hidden": "true"
|
|
138
|
+
}),
|
|
139
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.TextShimmer, {
|
|
140
|
+
active: !unavailable,
|
|
141
|
+
className: QoderQueueStatus_module_css_default.text,
|
|
142
|
+
"aria-hidden": "true",
|
|
143
|
+
children: label
|
|
144
|
+
}),
|
|
145
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
146
|
+
className: QoderQueueStatus_module_css_default.chevron,
|
|
147
|
+
"aria-hidden": "true"
|
|
148
|
+
})
|
|
149
|
+
]
|
|
150
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
151
|
+
className: QoderQueueStatus_module_css_default.details,
|
|
152
|
+
children: [
|
|
153
|
+
item.queueCount !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("queueCount", { count: item.queueCount }) }),
|
|
154
|
+
item.waitTimeMs !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("queueEstimate", { seconds: Math.ceil(item.waitTimeMs / 1e3) }) }),
|
|
155
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("queueBudget", { seconds: Math.ceil(item.maxWaitMs / 1e3) }) }),
|
|
156
|
+
item.serviceAvailable === false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("queueServiceUnavailable") })
|
|
157
|
+
]
|
|
158
|
+
})] })]
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/** A provider contribution in DSH's input dock, using its shared process-row primitives. */
|
|
162
|
+
function QoderQueueStatus({ sessionId, rpc, t }) {
|
|
163
|
+
const [view, setView] = (0, react.useState)();
|
|
164
|
+
(0, react.useEffect)(() => watchQueueStatus(rpc, sessionId, document, (state) => setView({
|
|
165
|
+
sessionId,
|
|
166
|
+
state
|
|
167
|
+
})), [rpc, sessionId]);
|
|
168
|
+
const state = view?.sessionId === sessionId ? view.state : void 0;
|
|
169
|
+
if (!state?.items.length) return null;
|
|
170
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
171
|
+
className: QoderQueueStatus_module_css_default.queues,
|
|
172
|
+
"aria-label": t("queueTitle"),
|
|
173
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
174
|
+
className: QoderQueueStatus_module_css_default.panel,
|
|
175
|
+
children: state.items.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QueueRow, {
|
|
176
|
+
item,
|
|
177
|
+
unavailable: state.unavailable,
|
|
178
|
+
t
|
|
179
|
+
}, item.callId))
|
|
180
|
+
})
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
//#endregion
|
|
17
184
|
//#region src/qoder/catalog.ts
|
|
18
185
|
function positiveNumber(value) {
|
|
19
186
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
@@ -170,6 +337,61 @@ window.__ModuleLoader__.load({
|
|
|
170
337
|
//#endregion
|
|
171
338
|
//#region src/client/locales.ts
|
|
172
339
|
const zh = {
|
|
340
|
+
accountConnectionTitle: "Qoder 账号",
|
|
341
|
+
signInDescription: "登录 Qoder,使用当前区域的订阅和模型。",
|
|
342
|
+
manageAccount: "管理账号",
|
|
343
|
+
manageCredential: "管理凭据",
|
|
344
|
+
changeAccount: "更换账号",
|
|
345
|
+
editPat: "编辑 PAT",
|
|
346
|
+
patActive: "正在使用 PAT",
|
|
347
|
+
saveAndUsePat: "保存并使用 PAT",
|
|
348
|
+
useSavedPat: "使用已保存的 PAT",
|
|
349
|
+
signInAgain: "重新登录",
|
|
350
|
+
reopenLogin: "重新打开官网",
|
|
351
|
+
loginLinkCopied: "链接已复制",
|
|
352
|
+
loginTimeRemaining: "链接剩余有效时间:{seconds} 秒",
|
|
353
|
+
regionChanged: "已切换服务区域;原区域如有未完成的登录,已取消。",
|
|
354
|
+
regionChangeFailed: "服务区域切换失败,请重试。",
|
|
355
|
+
browserRejected: "Qoder 未完成授权,请重新登录。",
|
|
356
|
+
browserStorageFailed: "官网授权已完成,但凭据保存失败。请检查存储后重新登录。",
|
|
357
|
+
authorizationConnectionFailed: "暂时无法连接或读取登录状态,请稍后重试。",
|
|
358
|
+
patSaveFailed: "PAT 保存或启用失败,请重试。",
|
|
359
|
+
browserRemoveFailed: "浏览器授权移除失败,请检查凭据存储是否可写后重试。",
|
|
360
|
+
browserLoginTitle: "Qoder 官网登录",
|
|
361
|
+
browserMethod: "浏览器授权",
|
|
362
|
+
savedBrowserAccount: "已保存的浏览器账号",
|
|
363
|
+
patMethod: "PAT 鉴权",
|
|
364
|
+
signedOut: "未连接",
|
|
365
|
+
sharedAuthorization: "当前区域的账号由所有连接此 DSH 实例的客户端共享。",
|
|
366
|
+
signInQoder: "通过 Qoder 登录",
|
|
367
|
+
signOutQoder: "移除浏览器授权",
|
|
368
|
+
usePat: "使用 PAT",
|
|
369
|
+
useBrowser: "使用已保存的浏览器授权",
|
|
370
|
+
cancelLogin: "取消登录",
|
|
371
|
+
openLogin: "打开登录页面",
|
|
372
|
+
copyLogin: "复制登录链接",
|
|
373
|
+
copyLoginFailed: "无法复制,请使用“打开登录页面”。",
|
|
374
|
+
browserWaiting: "等待在 Qoder 官网完成验证与授权…",
|
|
375
|
+
browserSaving: "正在保存授权…",
|
|
376
|
+
browserComplete: "已登录。",
|
|
377
|
+
browserCancelled: "登录已取消。",
|
|
378
|
+
browserTimeout: "登录链接已过期,请重新发起登录。",
|
|
379
|
+
browserFailed: "登录未完成,或授权保存失败。请检查账号状态后重试。",
|
|
380
|
+
browserExpired: "浏览器授权已失效,请重新登录。",
|
|
381
|
+
browserUnsaved: "续期凭据尚未保存,重启后可能需要重新登录;下次使用时将重试保存。",
|
|
382
|
+
browserOperationFailed: "无法更新登录状态,请重试。",
|
|
383
|
+
queueTitle: "Qoder 模型排队",
|
|
384
|
+
queueWaiting: "{model} 正在排队",
|
|
385
|
+
queueRunningFor: "{model} 正在排队,用时 {duration} ···",
|
|
386
|
+
queueHourUnit: "小时",
|
|
387
|
+
queueMinuteUnit: "分",
|
|
388
|
+
queueSecondUnit: "秒",
|
|
389
|
+
queueCount: "排队数量:{count}",
|
|
390
|
+
queueEstimate: "预计等待 {seconds} 秒",
|
|
391
|
+
queueElapsed: "已等待 {seconds} 秒",
|
|
392
|
+
queueUnavailable: "Qoder 排队状态暂不可用",
|
|
393
|
+
queueServiceUnavailable: "服务暂不可用,继续等待",
|
|
394
|
+
queueBudget: "等待上限 {seconds} 秒",
|
|
173
395
|
nav: "Qoder",
|
|
174
396
|
title: "Qoder 凭据",
|
|
175
397
|
configured: "已配置",
|
|
@@ -183,7 +405,7 @@ window.__ModuleLoader__.load({
|
|
|
183
405
|
regionGlobal: "国际版 (Global)",
|
|
184
406
|
regionChina: "中国区 (CN)",
|
|
185
407
|
regionHint: "请确保 PAT 与所选服务区域匹配。",
|
|
186
|
-
tokenLabel: "
|
|
408
|
+
tokenLabel: "Personal Access Token (PAT)",
|
|
187
409
|
tokenPlaceholder: "输入新的 Personal Access Token",
|
|
188
410
|
configuredHint: "已配置——输入新值可替换",
|
|
189
411
|
readOnly: "当前凭据存储不可写。",
|
|
@@ -218,11 +440,12 @@ window.__ModuleLoader__.load({
|
|
|
218
440
|
accountTitle: "Qoder",
|
|
219
441
|
accountLoading: "正在读取账号与额度…",
|
|
220
442
|
accountFailed: "无法读取账号信息与额度。",
|
|
221
|
-
accountCredentialHint: "
|
|
443
|
+
accountCredentialHint: "请先在“模型”设置中登录 Qoder 或选择已配置的 PAT。",
|
|
222
444
|
refresh: "刷新",
|
|
223
445
|
refreshing: "正在刷新…",
|
|
224
446
|
userQuotaTitle: "个人额度",
|
|
225
447
|
orgResourceTitle: "组织资源包",
|
|
448
|
+
addOnQuotaTitle: "增值额度",
|
|
226
449
|
dedicatedResourceTitle: "专属资源包",
|
|
227
450
|
dedicatedResourceExpiresAt: "有效期至:{value}",
|
|
228
451
|
quotaRemaining: "剩余 {value}%",
|
|
@@ -241,6 +464,61 @@ window.__ModuleLoader__.load({
|
|
|
241
464
|
searchModeHint: "智能路由模式下,使用 Qoder 模型时走 Qoder 搜索,使用其他模型时自动回退给备用搜索。"
|
|
242
465
|
};
|
|
243
466
|
const en = {
|
|
467
|
+
accountConnectionTitle: "Qoder account",
|
|
468
|
+
signInDescription: "Sign in to use your subscription and models for this region.",
|
|
469
|
+
manageAccount: "Manage account",
|
|
470
|
+
manageCredential: "Manage credentials",
|
|
471
|
+
changeAccount: "Change account",
|
|
472
|
+
editPat: "Edit PAT",
|
|
473
|
+
patActive: "Using PAT",
|
|
474
|
+
saveAndUsePat: "Save and use PAT",
|
|
475
|
+
useSavedPat: "Use saved PAT",
|
|
476
|
+
signInAgain: "Sign in again",
|
|
477
|
+
reopenLogin: "Reopen Qoder website",
|
|
478
|
+
loginLinkCopied: "Link copied",
|
|
479
|
+
loginTimeRemaining: "Link expires in {seconds} seconds",
|
|
480
|
+
regionChanged: "Region changed; any unfinished sign-in for the previous region was cancelled.",
|
|
481
|
+
regionChangeFailed: "Could not change region. Please retry.",
|
|
482
|
+
browserRejected: "Qoder authorization was not completed. Sign in again.",
|
|
483
|
+
browserStorageFailed: "Website authorization completed, but credentials could not be saved. Check storage and sign in again.",
|
|
484
|
+
authorizationConnectionFailed: "Could not connect or read sign-in status. Please retry shortly.",
|
|
485
|
+
patSaveFailed: "Could not save or activate the PAT. Please retry.",
|
|
486
|
+
browserRemoveFailed: "Could not remove browser authorization. Check that credential storage is writable and retry.",
|
|
487
|
+
browserLoginTitle: "Qoder website sign-in",
|
|
488
|
+
browserMethod: "Browser authorization",
|
|
489
|
+
savedBrowserAccount: "Saved browser account",
|
|
490
|
+
patMethod: "PAT authentication",
|
|
491
|
+
signedOut: "Disconnected",
|
|
492
|
+
sharedAuthorization: "The account for this region is shared by all clients connected to this DSH instance.",
|
|
493
|
+
signInQoder: "Sign in with Qoder",
|
|
494
|
+
signOutQoder: "Remove browser authorization",
|
|
495
|
+
usePat: "Use PAT",
|
|
496
|
+
useBrowser: "Use saved browser authorization",
|
|
497
|
+
cancelLogin: "Cancel sign-in",
|
|
498
|
+
openLogin: "Open sign-in page",
|
|
499
|
+
copyLogin: "Copy sign-in link",
|
|
500
|
+
copyLoginFailed: "Could not copy. Use Open sign-in page.",
|
|
501
|
+
browserWaiting: "Complete verification and authorization on the Qoder website…",
|
|
502
|
+
browserSaving: "Saving authorization…",
|
|
503
|
+
browserComplete: "Signed in.",
|
|
504
|
+
browserCancelled: "Sign-in cancelled.",
|
|
505
|
+
browserTimeout: "Sign-in link expired. Start a new sign-in.",
|
|
506
|
+
browserFailed: "Sign-in or saving authorization failed. Check account status and retry.",
|
|
507
|
+
browserExpired: "Browser authorization expired. Sign in again.",
|
|
508
|
+
browserUnsaved: "Renewed credentials have not been saved. Restarting may require sign-in; saving will be retried on next use.",
|
|
509
|
+
browserOperationFailed: "Could not update sign-in status. Please retry.",
|
|
510
|
+
queueTitle: "Qoder model queue",
|
|
511
|
+
queueWaiting: "{model} is queued",
|
|
512
|
+
queueRunningFor: "{model} queued for {duration} ···",
|
|
513
|
+
queueHourUnit: "h",
|
|
514
|
+
queueMinuteUnit: "m",
|
|
515
|
+
queueSecondUnit: "s",
|
|
516
|
+
queueCount: "Queue count: {count}",
|
|
517
|
+
queueEstimate: "Estimated wait: {seconds}s",
|
|
518
|
+
queueElapsed: "Waited {seconds}s",
|
|
519
|
+
queueUnavailable: "Qoder queue status is temporarily unavailable",
|
|
520
|
+
queueServiceUnavailable: "Service unavailable; waiting",
|
|
521
|
+
queueBudget: "Wait limit: {seconds}s",
|
|
244
522
|
nav: "Qoder",
|
|
245
523
|
title: "Qoder credential",
|
|
246
524
|
configured: "Configured",
|
|
@@ -254,7 +532,7 @@ window.__ModuleLoader__.load({
|
|
|
254
532
|
regionGlobal: "Global",
|
|
255
533
|
regionChina: "China (CN)",
|
|
256
534
|
regionHint: "Ensure your PAT matches the selected service region.",
|
|
257
|
-
tokenLabel: "
|
|
535
|
+
tokenLabel: "Personal Access Token (PAT)",
|
|
258
536
|
tokenPlaceholder: "Enter a new Personal Access Token",
|
|
259
537
|
configuredHint: "Configured — enter a new value to replace",
|
|
260
538
|
readOnly: "The current credential store is read-only.",
|
|
@@ -289,11 +567,12 @@ window.__ModuleLoader__.load({
|
|
|
289
567
|
accountTitle: "Qoder",
|
|
290
568
|
accountLoading: "Reading account and quota…",
|
|
291
569
|
accountFailed: "Could not read account details or quota.",
|
|
292
|
-
accountCredentialHint: "
|
|
570
|
+
accountCredentialHint: "Sign in to Qoder or select a configured PAT in Models settings first.",
|
|
293
571
|
refresh: "Refresh",
|
|
294
572
|
refreshing: "Refreshing…",
|
|
295
573
|
userQuotaTitle: "Personal Quota",
|
|
296
574
|
orgResourceTitle: "Org Resource Package",
|
|
575
|
+
addOnQuotaTitle: "Add-on Credits",
|
|
297
576
|
dedicatedResourceTitle: "Dedicated Resource Package",
|
|
298
577
|
dedicatedResourceExpiresAt: "Expires at: {value}",
|
|
299
578
|
quotaRemaining: "{value}% remaining",
|
|
@@ -362,8 +641,148 @@ window.__ModuleLoader__.load({
|
|
|
362
641
|
}
|
|
363
642
|
}
|
|
364
643
|
//#endregion
|
|
644
|
+
//#region src/client/model-catalog-editor.ts
|
|
645
|
+
/** One mounted region owns its directory and asynchronous edits. */
|
|
646
|
+
var QoderModelCatalogEditor = class {
|
|
647
|
+
region;
|
|
648
|
+
operations;
|
|
649
|
+
active = true;
|
|
650
|
+
confirmed;
|
|
651
|
+
snapshot;
|
|
652
|
+
listeners = /* @__PURE__ */ new Set();
|
|
653
|
+
constructor(region, models, operations) {
|
|
654
|
+
this.region = region;
|
|
655
|
+
this.operations = operations;
|
|
656
|
+
this.confirmed = models.map(cloneCatalogModel);
|
|
657
|
+
this.snapshot = {
|
|
658
|
+
models: this.confirmed,
|
|
659
|
+
catalog: this.confirmed,
|
|
660
|
+
unavailableIds: /* @__PURE__ */ new Set()
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
getSnapshot = () => this.snapshot;
|
|
664
|
+
subscribe = (listener) => {
|
|
665
|
+
this.listeners.add(listener);
|
|
666
|
+
return () => {
|
|
667
|
+
this.listeners.delete(listener);
|
|
668
|
+
};
|
|
669
|
+
};
|
|
670
|
+
/** ConfigForms supplies accepted values, including its recovery read after refusal. */
|
|
671
|
+
replaceModels(models) {
|
|
672
|
+
const followsConfig = this.snapshot.catalog === this.confirmed;
|
|
673
|
+
this.confirmed = models.map(cloneCatalogModel);
|
|
674
|
+
const selected = new Map(this.confirmed.map((model) => [model.id, model]));
|
|
675
|
+
this.publish({
|
|
676
|
+
...this.snapshot,
|
|
677
|
+
models: this.confirmed,
|
|
678
|
+
catalog: followsConfig ? this.confirmed : this.snapshot.catalog.map((model) => selected.get(model.id) ?? model)
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
activate() {
|
|
682
|
+
this.active = true;
|
|
683
|
+
}
|
|
684
|
+
dispose() {
|
|
685
|
+
this.active = false;
|
|
686
|
+
this.listeners.clear();
|
|
687
|
+
}
|
|
688
|
+
publish(snapshot) {
|
|
689
|
+
if (!this.active) return;
|
|
690
|
+
this.snapshot = snapshot;
|
|
691
|
+
for (const listener of this.listeners) listener();
|
|
692
|
+
}
|
|
693
|
+
async discover() {
|
|
694
|
+
if (!this.active || this.snapshot.pending) return;
|
|
695
|
+
this.publish({
|
|
696
|
+
...this.snapshot,
|
|
697
|
+
pending: "discovering",
|
|
698
|
+
failure: void 0,
|
|
699
|
+
failureMessage: void 0
|
|
700
|
+
});
|
|
701
|
+
try {
|
|
702
|
+
const result = await this.operations.discoverModels();
|
|
703
|
+
if (!this.active) return;
|
|
704
|
+
if (!result.ok) {
|
|
705
|
+
this.publish({
|
|
706
|
+
...this.snapshot,
|
|
707
|
+
pending: void 0,
|
|
708
|
+
failure: "modelsFetchFailed",
|
|
709
|
+
failureMessage: result.error.message
|
|
710
|
+
});
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
const reconciled = reconcileQoderModels(this.snapshot.catalog, result.value);
|
|
714
|
+
await this.save(reconciled.selected, reconciled.catalog, reconciled.unavailableIds);
|
|
715
|
+
} catch (error) {
|
|
716
|
+
this.publish({
|
|
717
|
+
...this.snapshot,
|
|
718
|
+
pending: void 0,
|
|
719
|
+
failure: "modelsFetchFailed",
|
|
720
|
+
failureMessage: error instanceof Error ? error.message : void 0
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
async toggle(id, enabled) {
|
|
725
|
+
if (!this.active || this.snapshot.pending || this.snapshot.unavailableIds.has(id)) return;
|
|
726
|
+
const selected = new Set(this.snapshot.models.map((model) => model.id));
|
|
727
|
+
if (enabled) selected.add(id);
|
|
728
|
+
else selected.delete(id);
|
|
729
|
+
await this.save(this.snapshot.catalog.filter((model) => selected.has(model.id) && !this.snapshot.unavailableIds.has(model.id)));
|
|
730
|
+
}
|
|
731
|
+
async selectTier(id, tierKey) {
|
|
732
|
+
if (!this.active || this.snapshot.pending || !this.snapshot.models.some((model) => model.id === id)) return;
|
|
733
|
+
const tokenCount = this.snapshot.catalog.find((model) => model.id === id)?.contextOptions?.[tierKey]?.tokenCount;
|
|
734
|
+
if (typeof tokenCount !== "number" || !Number.isFinite(tokenCount) || tokenCount <= 0) return;
|
|
735
|
+
const apply = (candidate) => candidate.id === id ? {
|
|
736
|
+
...candidate,
|
|
737
|
+
contextTier: tierKey,
|
|
738
|
+
contextWindow: tokenCount
|
|
739
|
+
} : candidate;
|
|
740
|
+
await this.save(this.snapshot.models.map(apply), this.snapshot.catalog.map(apply));
|
|
741
|
+
}
|
|
742
|
+
async save(models, catalog = this.snapshot.catalog, unavailableIds = this.snapshot.unavailableIds) {
|
|
743
|
+
if (models.length === 0) {
|
|
744
|
+
this.publish({
|
|
745
|
+
...this.snapshot,
|
|
746
|
+
pending: void 0,
|
|
747
|
+
failure: "modelsRequired",
|
|
748
|
+
failureMessage: void 0
|
|
749
|
+
});
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
752
|
+
const submitted = models.map(cloneCatalogModel);
|
|
753
|
+
const confirmedAtSubmission = this.confirmed;
|
|
754
|
+
this.publish({
|
|
755
|
+
...this.snapshot,
|
|
756
|
+
pending: "saving",
|
|
757
|
+
failure: void 0,
|
|
758
|
+
failureMessage: void 0
|
|
759
|
+
});
|
|
760
|
+
let saved = false;
|
|
761
|
+
try {
|
|
762
|
+
saved = await this.operations.storeModels(this.region, submitted);
|
|
763
|
+
} catch {}
|
|
764
|
+
if (!this.active) return;
|
|
765
|
+
if (saved) {
|
|
766
|
+
if (this.confirmed === confirmedAtSubmission) this.confirmed = submitted;
|
|
767
|
+
const accepted = new Map(this.confirmed.map((model) => [model.id, model]));
|
|
768
|
+
const directory = new Map(catalog.map((model) => [model.id, model]));
|
|
769
|
+
for (const [id, model] of accepted) directory.set(id, model);
|
|
770
|
+
this.publish({
|
|
771
|
+
models: this.confirmed,
|
|
772
|
+
catalog: [...directory.values()],
|
|
773
|
+
unavailableIds: new Set([...unavailableIds].filter((id) => !accepted.has(id)))
|
|
774
|
+
});
|
|
775
|
+
} else this.publish({
|
|
776
|
+
models: this.confirmed,
|
|
777
|
+
catalog: this.confirmed,
|
|
778
|
+
unavailableIds: /* @__PURE__ */ new Set(),
|
|
779
|
+
failure: "saveFailed"
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
};
|
|
783
|
+
//#endregion
|
|
365
784
|
//#region \0dsh-css:/home/runner/work/dsh-provider-qoder/dsh-provider-qoder/src/client/QoderCredentialCard.module.css.mjs
|
|
366
|
-
const css$1 = ".SRqrhW_credential{color:var(--dsw-alias-label-primary);border-radius:10px;margin-top:12px}.SRqrhW_credential p{margin:8px 0 0}.SRqrhW_credentialEditor{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);flex-direction:column;gap:12px;padding:12px 14px;display:flex}.SRqrhW_credentialRowHead{align-items:center;gap:10px;display:flex}.SRqrhW_credentialIdentity{align-items:center;gap:6px;min-width:0;display:inline-flex}.SRqrhW_credentialName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.SRqrhW_credentialDot{box-sizing:border-box;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.SRqrhW_credentialDotConfigured{background:var(--dsw-alias-state-success-primary)}.SRqrhW_credentialDotMissing{background:var(--dsw-alias-state-error-primary)}.SRqrhW_regionBadge{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:4px;align-items:center;padding:1px 6px;font-size:11px;font-weight:500;line-height:16px;display:inline-flex}.SRqrhW_regionSelector{flex-direction:column;gap:8px;margin-bottom:14px;display:flex}.SRqrhW_regionGroup{gap:8px;display:flex}.SRqrhW_regionOption{border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);user-select:none;border-radius:8px;align-items:center;gap:6px;padding:6px 12px;font-size:12px;line-height:18px;transition:all .12s;display:inline-flex}.SRqrhW_regionOption:hover:not(.SRqrhW_regionOptionDisabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.SRqrhW_credential button.SRqrhW_regionOptionActive{border-color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-interactive-bg-selected);color:var(--dsw-alias-brand-primary);font-weight:500}.SRqrhW_regionOptionDisabled{cursor:not-allowed;opacity:.5}.SRqrhW_editButton{box-sizing:border-box;font:inherit;background:0 0;margin-left:auto;font-size:12px;line-height:18px;border:1px solid var(--dsw-alias-border-l2)!important;border-radius:14px!important;height:28px!important;padding:0 10px!important}.SRqrhW_editButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.SRqrhW_editor{background:var(--dsw-alias-bg-module-platform);border-radius:12px;padding:14px 16px}.SRqrhW_customized{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);background:var(--dsw-alias-bg-module-platform);margin-top:12px;transition:all .12s;overflow:hidden}.SRqrhW_customizedSummary{box-sizing:border-box;border-radius:var(--dsw-radius-xl,12px);cursor:pointer;width:100%;color:var(--dsw-alias-label-primary);user-select:none;align-items:center;gap:8px;margin:0;padding:12px 14px;font-size:13px;font-weight:600;line-height:18px;list-style:none;transition:background .12s;display:flex}.SRqrhW_customizedSummary:hover{background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_modelSummaryBadge{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-tertiary);border-radius:4px;align-items:center;padding:1px 6px;font-size:11px;font-weight:400;line-height:16px;display:inline-flex}.SRqrhW_customizedSummary::-webkit-details-marker{display:none}.SRqrhW_customizedSummary:before{content:\"\";border-bottom:1.5px solid;border-right:1.5px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)translate(-1px,-1px)}.SRqrhW_customized[open]>.SRqrhW_customizedSummary:before{transform:rotate(45deg)translate(-1px,-1px)}.SRqrhW_customized[open]>.SRqrhW_customizedSummary{border-bottom:.5px solid var(--dsw-alias-border-l2);border-bottom-right-radius:0;border-bottom-left-radius:0}.SRqrhW_customizedBody{padding:12px 14px 14px}.SRqrhW_modelCatalog{flex-direction:column;gap:10px;display:flex}.SRqrhW_modelList{flex-direction:column;gap:10px;max-height:360px;padding-right:4px;display:flex;overflow-y:auto}.SRqrhW_modelList::-webkit-scrollbar{width:4px}.SRqrhW_modelList::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3);border-radius:2px}.SRqrhW_modelCatalogHead{justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.SRqrhW_modelCatalogHeadCompact{justify-content:flex-end;align-items:center;gap:12px;display:flex}.SRqrhW_modelCatalogTitle{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.SRqrhW_modelCatalogMeta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:2px 0 0!important}.SRqrhW_linkButton{box-sizing:border-box;font:inherit;background:0 0;font-size:12px;line-height:18px;border:none!important;border-radius:14px!important;height:28px!important;padding:0 10px!important}.SRqrhW_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_modelChoice{border-radius:6px;flex-direction:column;gap:4px;padding:6px 8px;font-size:13px;display:flex}.SRqrhW_modelChoice:hover{background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_modelChoiceHead{cursor:pointer;grid-template-columns:auto minmax(0,1fr) auto auto auto;align-items:center;gap:8px;display:grid}.SRqrhW_modelTier{align-items:center;gap:8px;padding-left:24px;display:flex}.SRqrhW_modelTierLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:18px}.SRqrhW_modelTierSelect{box-sizing:border-box;background:var(--dsw-alias-bg-layer-1);height:24px;color:inherit;font:inherit;cursor:pointer;border:0;border-radius:6px;padding:0 6px;font-size:12px}.SRqrhW_modelTierHint{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:18px;margin:0!important}.SRqrhW_modelChoiceName{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.SRqrhW_modelChoice code{color:var(--dsw-alias-label-tertiary);font-size:11px}.SRqrhW_modelRate{min-width:34px;color:var(--dsw-alias-brand-primary);text-align:right;font-size:12px;font-weight:600}.SRqrhW_modelUnavailable{cursor:not-allowed;opacity:.55}.SRqrhW_modelBadge{color:var(--dsw-alias-state-error-primary);font-size:11px}@media (prefers-reduced-motion:reduce){.SRqrhW_customizedSummary:before{transition:none}}.SRqrhW_head{justify-content:space-between;align-items:center;gap:12px;margin-bottom:20px;display:flex}.SRqrhW_heading{margin:0;font-size:18px;font-weight:600}.SRqrhW_status{color:var(--dsw-alias-label-secondary);font-size:12px}.SRqrhW_configured,.SRqrhW_success{color:var(--dsw-alias-state-success-primary)}.SRqrhW_label{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px;display:block}.SRqrhW_input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;height:32px;color:var(--dsw-alias-label-primary);border-radius:8px;outline:none;margin-top:6px;padding:0 10px}.SRqrhW_input:focus{border-color:var(--dsw-alias-brand-primary)}.SRqrhW_input::placeholder{color:var(--dsw-alias-label-dimmed)}.SRqrhW_input:disabled{cursor:not-allowed;opacity:.4}.SRqrhW_hint{color:var(--dsw-alias-label-secondary);font-size:12px}.SRqrhW_actions{justify-content:flex-end;gap:8px;margin-top:14px;display:flex}.SRqrhW_credential button{cursor:pointer;height:32px;color:var(--dsw-alias-label-primary);border:1px solid #0000;border-radius:16px;padding:0 12px}.SRqrhW_credential button:disabled{cursor:not-allowed;opacity:.4}.SRqrhW_primary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)!important}.SRqrhW_primary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.SRqrhW_secondary{background:0 0;border-color:var(--dsw-alias-border-l2)!important}.SRqrhW_secondary:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_danger{background:0 0;border-color:var(--dsw-alias-state-error-primary)!important;color:var(--dsw-alias-state-error-primary)!important}.SRqrhW_danger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.SRqrhW_error{color:var(--dsw-alias-state-error-primary);font-size:12px}.SRqrhW_success{font-size:12px}.SRqrhW_accountSection{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:10px;margin-top:12px;padding:12px 14px;display:flex}.SRqrhW_accountHead{justify-content:space-between;align-items:center;gap:8px;display:flex}.SRqrhW_userInfo{align-items:center;gap:10px;min-width:0;display:flex}.SRqrhW_avatar{background:var(--dsw-alias-brand-primary);width:32px;height:32px;color:var(--dsw-alias-label-primary-foreground);text-transform:uppercase;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;font-size:14px;font-weight:600;display:flex}.SRqrhW_userDetails{flex-direction:column;gap:2px;min-width:0;display:flex}.SRqrhW_userName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:600;overflow:hidden}.SRqrhW_userEmail{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.SRqrhW_refreshBtn{border:1px solid var(--dsw-alias-border-l2)!important;height:26px!important;color:var(--dsw-alias-label-secondary)!important;background:0 0!important;border-radius:13px!important;padding:0 8px!important;font-size:12px!important}.SRqrhW_refreshBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)!important}.SRqrhW_quotaBlock{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:6px;padding-top:8px;display:flex}.SRqrhW_quotaHeader{justify-content:space-between;align-items:center;gap:8px;display:flex}.SRqrhW_quotaLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}.SRqrhW_quotaTop{justify-content:space-between;align-items:baseline;gap:8px;font-size:12px;display:flex}.SRqrhW_quotaTop strong{color:var(--dsw-alias-brand-primary);font-size:13px}.SRqrhW_quotaDescription{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;margin:0!important}.SRqrhW_quotaProgress{background:var(--dsw-alias-border-l3);width:100%;height:6px;accent-color:var(--dsw-alias-brand-primary);-webkit-appearance:none;appearance:none;border:0;border-radius:999px;overflow:hidden}.SRqrhW_quotaProgress::-webkit-progress-bar{background:var(--dsw-alias-border-l3);border-radius:999px}.SRqrhW_quotaProgress::-webkit-progress-value{background:var(--dsw-alias-brand-primary);border-radius:999px}.SRqrhW_quotaProgress::-moz-progress-bar{background:var(--dsw-alias-brand-primary);border-radius:999px}.SRqrhW_quotaMeta{color:var(--dsw-alias-label-tertiary);justify-content:space-between;align-items:center;gap:8px;font-size:11px;display:flex}.SRqrhW_accountLoadingText,.SRqrhW_accountEmptyText{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.SRqrhW_userNameRow{align-items:center;gap:8px;display:flex}.SRqrhW_planBadge{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-brand-primary);border-radius:4px;align-items:center;padding:1px 6px;font-size:11px;font-weight:600;line-height:16px;display:inline-flex}.SRqrhW_orgTag{color:var(--dsw-alias-label-tertiary);font-size:11px}.SRqrhW_suspendedBanner{background:var(--dsw-alias-state-error-subtle,#ff4d4f1a);color:var(--dsw-alias-state-error-primary);border-radius:6px;align-items:center;gap:6px;margin-bottom:8px;padding:6px 10px;font-size:12px;display:flex}.SRqrhW_searchModeSection{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:10px;margin-top:12px;padding:12px 14px;display:flex}.SRqrhW_searchModeHintText{color:var(--dsw-alias-label-secondary);margin:4px 0 0;font-size:12px;line-height:18px}";
|
|
785
|
+
const css$1 = ".SRqrhW_credential{color:var(--dsw-alias-label-primary);border-radius:10px;margin-top:12px}.SRqrhW_connectionBody{flex-direction:column;gap:10px;display:flex}.SRqrhW_connectionHead,.SRqrhW_subscriberRow{justify-content:space-between;align-items:center;gap:16px;display:flex}.SRqrhW_connectionHead{flex-wrap:wrap}.SRqrhW_subscriberRow{padding:10px 0}.SRqrhW_subscriberAvatar{width:42px;height:42px;color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-interactive-bg-selected);border-radius:50%;flex:none;place-items:center;font-size:18px;font-weight:600;display:grid}.SRqrhW_subscriberIdentity{overflow-wrap:anywhere;flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.SRqrhW_subscriberIdentity>span{color:var(--dsw-alias-label-secondary);font-size:12px}.SRqrhW_connectionActions{flex-wrap:wrap;align-items:center;gap:10px;margin-top:12px;display:flex}.SRqrhW_loginProgress{background:var(--dsw-alias-interactive-bg-hover);border-radius:10px;flex-direction:column;gap:8px;padding:14px;display:flex}.SRqrhW_managementPanel{background:var(--dsw-alias-bg-module-platform);border-radius:10px;flex-wrap:wrap;align-items:center;gap:10px;padding:12px;display:flex}.SRqrhW_credential .SRqrhW_textButton{color:var(--dsw-alias-brand-primary);background:0 0;border:0!important;padding:4px 2px!important}.SRqrhW_primaryLink{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border-radius:18px;padding:8px 14px;font-size:12px;text-decoration:none;display:inline-flex}.SRqrhW_credential p.SRqrhW_sharedNote{border-top:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);margin-top:6px;padding-top:12px;font-size:12px}@media (width<=480px){.SRqrhW_subscriberRow{flex-wrap:wrap}.SRqrhW_subscriberIdentity{flex-basis:calc(100% - 60px)}}.SRqrhW_credential p{margin:8px 0 0}.SRqrhW_credentialEditor{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);flex-direction:column;gap:12px;padding:12px 14px;display:flex}.SRqrhW_credentialRowHead{align-items:center;gap:10px;display:flex}.SRqrhW_credentialIdentity{align-items:center;gap:6px;min-width:0;display:inline-flex}.SRqrhW_credentialName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.SRqrhW_credentialDot{box-sizing:border-box;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.SRqrhW_credentialDotConfigured{background:var(--dsw-alias-state-success-primary)}.SRqrhW_credentialDotMissing{background:var(--dsw-alias-state-error-primary)}.SRqrhW_regionBadge{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:4px;align-items:center;padding:1px 6px;font-size:11px;font-weight:500;line-height:16px;display:inline-flex}.SRqrhW_regionSelector{flex-direction:column;gap:8px;margin-bottom:14px;display:flex}.SRqrhW_regionGroup{gap:8px;display:flex}.SRqrhW_regionOption{border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);user-select:none;border-radius:8px;align-items:center;gap:6px;padding:6px 12px;font-size:12px;line-height:18px;transition:all .12s;display:inline-flex}.SRqrhW_regionOption:hover:not(.SRqrhW_regionOptionDisabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.SRqrhW_credential button.SRqrhW_regionOptionActive{border-color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-interactive-bg-selected);color:var(--dsw-alias-brand-primary);font-weight:500}.SRqrhW_regionOptionDisabled{cursor:not-allowed;opacity:.5}.SRqrhW_editButton{box-sizing:border-box;font:inherit;background:0 0;margin-left:auto;font-size:12px;line-height:18px;border:1px solid var(--dsw-alias-border-l2)!important;border-radius:14px!important;height:28px!important;padding:0 10px!important}.SRqrhW_editButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.SRqrhW_editor{background:var(--dsw-alias-bg-module-platform);border-radius:12px;padding:14px 16px}.SRqrhW_customized{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);background:var(--dsw-alias-bg-module-platform);margin-top:12px;transition:all .12s;overflow:hidden}.SRqrhW_customizedSummary{box-sizing:border-box;border-radius:var(--dsw-radius-xl,12px);cursor:pointer;width:100%;color:var(--dsw-alias-label-primary);user-select:none;align-items:center;gap:8px;margin:0;padding:12px 14px;font-size:13px;font-weight:600;line-height:18px;list-style:none;transition:background .12s;display:flex}.SRqrhW_customizedSummary:hover{background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_modelSummaryBadge{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-tertiary);border-radius:4px;align-items:center;padding:1px 6px;font-size:11px;font-weight:400;line-height:16px;display:inline-flex}.SRqrhW_customizedSummary::-webkit-details-marker{display:none}.SRqrhW_customizedSummary:before{content:\"\";border-bottom:1.5px solid;border-right:1.5px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)translate(-1px,-1px)}.SRqrhW_customized[open]>.SRqrhW_customizedSummary:before{transform:rotate(45deg)translate(-1px,-1px)}.SRqrhW_customized[open]>.SRqrhW_customizedSummary{border-bottom:.5px solid var(--dsw-alias-border-l2);border-bottom-right-radius:0;border-bottom-left-radius:0}.SRqrhW_customizedBody{padding:12px 14px 14px}.SRqrhW_modelCatalog{flex-direction:column;gap:10px;display:flex}.SRqrhW_modelList{flex-direction:column;gap:10px;max-height:360px;padding-right:4px;display:flex;overflow-y:auto}.SRqrhW_modelList::-webkit-scrollbar{width:4px}.SRqrhW_modelList::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3);border-radius:2px}.SRqrhW_modelCatalogHead{justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.SRqrhW_modelCatalogHeadCompact{justify-content:flex-end;align-items:center;gap:12px;display:flex}.SRqrhW_modelCatalogTitle{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.SRqrhW_modelCatalogMeta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:2px 0 0!important}.SRqrhW_linkButton{box-sizing:border-box;font:inherit;background:0 0;font-size:12px;line-height:18px;border:none!important;border-radius:14px!important;height:28px!important;padding:0 10px!important}.SRqrhW_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_modelChoice{border-radius:6px;flex-direction:column;gap:4px;padding:6px 8px;font-size:13px;display:flex}.SRqrhW_modelChoice:hover{background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_modelChoiceHead{cursor:pointer;grid-template-columns:auto minmax(0,1fr) auto auto auto;align-items:center;gap:8px;display:grid}.SRqrhW_modelTier{align-items:center;gap:8px;padding-left:24px;display:flex}.SRqrhW_modelTierLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:18px}.SRqrhW_modelTierSelect{box-sizing:border-box;background:var(--dsw-alias-bg-layer-1);height:24px;color:inherit;font:inherit;cursor:pointer;border:0;border-radius:6px;padding:0 6px;font-size:12px}.SRqrhW_modelTierHint{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:18px;margin:0!important}.SRqrhW_modelChoiceName{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.SRqrhW_modelChoice code{color:var(--dsw-alias-label-tertiary);font-size:11px}.SRqrhW_modelRate{min-width:34px;color:var(--dsw-alias-brand-primary);text-align:right;font-size:12px;font-weight:600}.SRqrhW_modelUnavailable{cursor:not-allowed;opacity:.55}.SRqrhW_modelBadge{color:var(--dsw-alias-state-error-primary);font-size:11px}@media (prefers-reduced-motion:reduce){.SRqrhW_customizedSummary:before{transition:none}}.SRqrhW_head{justify-content:space-between;align-items:center;gap:12px;margin-bottom:20px;display:flex}.SRqrhW_heading{margin:0;font-size:18px;font-weight:600}.SRqrhW_status{color:var(--dsw-alias-label-secondary);font-size:12px}.SRqrhW_configured,.SRqrhW_success{color:var(--dsw-alias-state-success-primary)}.SRqrhW_label{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px;display:block}.SRqrhW_input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;height:32px;color:var(--dsw-alias-label-primary);border-radius:8px;outline:none;margin-top:6px;padding:0 10px}.SRqrhW_input:focus{border-color:var(--dsw-alias-brand-primary)}.SRqrhW_input::placeholder{color:var(--dsw-alias-label-dimmed)}.SRqrhW_input:disabled{cursor:not-allowed;opacity:.4}.SRqrhW_hint{color:var(--dsw-alias-label-secondary);font-size:12px}.SRqrhW_actions{justify-content:flex-end;gap:8px;margin-top:14px;display:flex}.SRqrhW_credential button{cursor:pointer;height:32px;color:var(--dsw-alias-label-primary);border:1px solid #0000;border-radius:16px;padding:0 12px}.SRqrhW_credential button:disabled{cursor:not-allowed;opacity:.4}.SRqrhW_primary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)!important}.SRqrhW_primary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.SRqrhW_secondary{background:0 0;border-color:var(--dsw-alias-border-l2)!important}.SRqrhW_secondary:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.SRqrhW_danger{background:0 0;border-color:var(--dsw-alias-state-error-primary)!important;color:var(--dsw-alias-state-error-primary)!important}.SRqrhW_danger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.SRqrhW_error{color:var(--dsw-alias-state-error-primary);font-size:12px}.SRqrhW_success{font-size:12px}.SRqrhW_accountSection{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:10px;margin-top:12px;padding:12px 14px;display:flex}.SRqrhW_accountHead{justify-content:space-between;align-items:center;gap:8px;display:flex}.SRqrhW_userInfo{align-items:center;gap:10px;min-width:0;display:flex}.SRqrhW_avatar{background:var(--dsw-alias-brand-primary);width:32px;height:32px;color:var(--dsw-alias-label-primary-foreground);text-transform:uppercase;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;font-size:14px;font-weight:600;display:flex}.SRqrhW_userDetails{flex-direction:column;gap:2px;min-width:0;display:flex}.SRqrhW_userName{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:600;overflow:hidden}.SRqrhW_userEmail{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.SRqrhW_refreshBtn{border:1px solid var(--dsw-alias-border-l2)!important;height:26px!important;color:var(--dsw-alias-label-secondary)!important;background:0 0!important;border-radius:13px!important;padding:0 8px!important;font-size:12px!important}.SRqrhW_refreshBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)!important}.SRqrhW_quotaBlock{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:6px;padding-top:8px;display:flex}.SRqrhW_quotaHeader{justify-content:space-between;align-items:center;gap:8px;display:flex}.SRqrhW_quotaLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}.SRqrhW_quotaTop{justify-content:space-between;align-items:baseline;gap:8px;font-size:12px;display:flex}.SRqrhW_quotaTop strong{color:var(--dsw-alias-brand-primary);font-size:13px}.SRqrhW_quotaDescription{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;margin:0!important}.SRqrhW_quotaProgress{background:var(--dsw-alias-border-l3);width:100%;height:6px;accent-color:var(--dsw-alias-brand-primary);-webkit-appearance:none;appearance:none;border:0;border-radius:999px;overflow:hidden}.SRqrhW_quotaProgress::-webkit-progress-bar{background:var(--dsw-alias-border-l3);border-radius:999px}.SRqrhW_quotaProgress::-webkit-progress-value{background:var(--dsw-alias-brand-primary);border-radius:999px}.SRqrhW_quotaProgress::-moz-progress-bar{background:var(--dsw-alias-brand-primary);border-radius:999px}.SRqrhW_quotaMeta{color:var(--dsw-alias-label-tertiary);justify-content:space-between;align-items:center;gap:8px;font-size:11px;display:flex}.SRqrhW_accountLoadingText,.SRqrhW_accountEmptyText{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.SRqrhW_userNameRow{align-items:center;gap:8px;display:flex}.SRqrhW_planBadge{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-brand-primary);border-radius:4px;align-items:center;padding:1px 6px;font-size:11px;font-weight:600;line-height:16px;display:inline-flex}.SRqrhW_orgTag{color:var(--dsw-alias-label-tertiary);font-size:11px}.SRqrhW_suspendedBanner{background:var(--dsw-alias-state-error-subtle,#ff4d4f1a);color:var(--dsw-alias-state-error-primary);border-radius:6px;align-items:center;gap:6px;margin-bottom:8px;padding:6px 10px;font-size:12px;display:flex}.SRqrhW_searchModeSection{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-xl,12px);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:10px;margin-top:12px;padding:12px 14px;display:flex}.SRqrhW_searchModeHintText{color:var(--dsw-alias-label-secondary);margin:4px 0 0;font-size:12px;line-height:18px}";
|
|
367
786
|
const tagId$1 = "dsh-provider-qoder/QoderCredentialCard.module.css";
|
|
368
787
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
369
788
|
const tag = document.createElement("style");
|
|
@@ -380,6 +799,9 @@ window.__ModuleLoader__.load({
|
|
|
380
799
|
"actions": "SRqrhW_actions",
|
|
381
800
|
"avatar": "SRqrhW_avatar",
|
|
382
801
|
"configured": "SRqrhW_configured",
|
|
802
|
+
"connectionActions": "SRqrhW_connectionActions",
|
|
803
|
+
"connectionBody": "SRqrhW_connectionBody",
|
|
804
|
+
"connectionHead": "SRqrhW_connectionHead",
|
|
383
805
|
"credential": "SRqrhW_credential",
|
|
384
806
|
"credentialDot": "SRqrhW_credentialDot",
|
|
385
807
|
"credentialDotConfigured": "SRqrhW_credentialDotConfigured",
|
|
@@ -401,6 +823,8 @@ window.__ModuleLoader__.load({
|
|
|
401
823
|
"input": "SRqrhW_input",
|
|
402
824
|
"label": "SRqrhW_label",
|
|
403
825
|
"linkButton": "SRqrhW_linkButton",
|
|
826
|
+
"loginProgress": "SRqrhW_loginProgress",
|
|
827
|
+
"managementPanel": "SRqrhW_managementPanel",
|
|
404
828
|
"modelBadge": "SRqrhW_modelBadge",
|
|
405
829
|
"modelCatalog": "SRqrhW_modelCatalog",
|
|
406
830
|
"modelCatalogHead": "SRqrhW_modelCatalogHead",
|
|
@@ -421,6 +845,7 @@ window.__ModuleLoader__.load({
|
|
|
421
845
|
"orgTag": "SRqrhW_orgTag",
|
|
422
846
|
"planBadge": "SRqrhW_planBadge",
|
|
423
847
|
"primary": "SRqrhW_primary",
|
|
848
|
+
"primaryLink": "SRqrhW_primaryLink",
|
|
424
849
|
"quotaBlock": "SRqrhW_quotaBlock",
|
|
425
850
|
"quotaDescription": "SRqrhW_quotaDescription",
|
|
426
851
|
"quotaHeader": "SRqrhW_quotaHeader",
|
|
@@ -438,9 +863,14 @@ window.__ModuleLoader__.load({
|
|
|
438
863
|
"searchModeHintText": "SRqrhW_searchModeHintText",
|
|
439
864
|
"searchModeSection": "SRqrhW_searchModeSection",
|
|
440
865
|
"secondary": "SRqrhW_secondary",
|
|
866
|
+
"sharedNote": "SRqrhW_sharedNote",
|
|
441
867
|
"status": "SRqrhW_status",
|
|
868
|
+
"subscriberAvatar": "SRqrhW_subscriberAvatar",
|
|
869
|
+
"subscriberIdentity": "SRqrhW_subscriberIdentity",
|
|
870
|
+
"subscriberRow": "SRqrhW_subscriberRow",
|
|
442
871
|
"success": "SRqrhW_success",
|
|
443
872
|
"suspendedBanner": "SRqrhW_suspendedBanner",
|
|
873
|
+
"textButton": "SRqrhW_textButton",
|
|
444
874
|
"userDetails": "SRqrhW_userDetails",
|
|
445
875
|
"userEmail": "SRqrhW_userEmail",
|
|
446
876
|
"userInfo": "SRqrhW_userInfo",
|
|
@@ -449,59 +879,28 @@ window.__ModuleLoader__.load({
|
|
|
449
879
|
};
|
|
450
880
|
//#endregion
|
|
451
881
|
//#region src/client/QoderModelCatalog.tsx
|
|
452
|
-
|
|
453
|
-
return models.length === 0 ? "modelsRequired" : void 0;
|
|
454
|
-
}
|
|
882
|
+
/** The key resets directory state whenever the active Qoder service region changes. */
|
|
455
883
|
function QoderModelCatalog(props) {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
const [
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
setUnavailableIds(reconciled.unavailableIds);
|
|
475
|
-
onChange(reconciled.selected);
|
|
476
|
-
};
|
|
477
|
-
const toggleModel = (id, enabled) => {
|
|
478
|
-
if (unavailableIds.has(id)) return;
|
|
479
|
-
const source = catalog ?? models;
|
|
480
|
-
if (catalog === void 0) setCatalog(source);
|
|
481
|
-
const nextSelected = new Set(selectedIds);
|
|
482
|
-
if (enabled) nextSelected.add(id);
|
|
483
|
-
else nextSelected.delete(id);
|
|
484
|
-
onChange(source.filter((model) => nextSelected.has(model.id) && !unavailableIds.has(model.id)));
|
|
485
|
-
};
|
|
486
|
-
const changeContextTier = (id, tierKey) => {
|
|
487
|
-
const source = catalog ?? models;
|
|
488
|
-
if (catalog === void 0) setCatalog(source);
|
|
489
|
-
const apply = (model) => {
|
|
490
|
-
if (model.id !== id) return model;
|
|
491
|
-
const tokenCount = model.contextOptions?.[tierKey]?.tokenCount;
|
|
492
|
-
if (typeof tokenCount !== "number" || !Number.isFinite(tokenCount) || tokenCount <= 0) return model;
|
|
493
|
-
return {
|
|
494
|
-
...model,
|
|
495
|
-
contextTier: tierKey,
|
|
496
|
-
contextWindow: tokenCount
|
|
497
|
-
};
|
|
498
|
-
};
|
|
499
|
-
const nextCatalog = source.map(apply);
|
|
500
|
-
setCatalog(nextCatalog);
|
|
501
|
-
onChange(models.map(apply));
|
|
502
|
-
};
|
|
884
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RegionModelCatalog, { ...props }, props.region);
|
|
885
|
+
}
|
|
886
|
+
function RegionModelCatalog({ operations, models, region, disabled, fetchDisabled, hideTitle, t }) {
|
|
887
|
+
const [editor] = (0, react.useState)(() => new QoderModelCatalogEditor(region, models, operations));
|
|
888
|
+
const snapshot = (0, react.useSyncExternalStore)(editor.subscribe, editor.getSnapshot, editor.getSnapshot);
|
|
889
|
+
(0, react.useLayoutEffect)(() => {
|
|
890
|
+
editor.activate();
|
|
891
|
+
return () => editor.dispose();
|
|
892
|
+
}, [editor]);
|
|
893
|
+
(0, react.useLayoutEffect)(() => {
|
|
894
|
+
editor.replaceModels(models);
|
|
895
|
+
}, [editor, models]);
|
|
896
|
+
const displayedModels = snapshot.catalog;
|
|
897
|
+
const unavailableIds = snapshot.unavailableIds;
|
|
898
|
+
const selectedIds = new Set(snapshot.models.map((model) => model.id));
|
|
899
|
+
const busy = snapshot.pending !== void 0;
|
|
900
|
+
const fetching = snapshot.pending === "discovering";
|
|
901
|
+
const failure = snapshot.failureMessage || (snapshot.failure ? t(snapshot.failure) : void 0);
|
|
503
902
|
const renderRate = (model) => {
|
|
504
|
-
if (model.
|
|
903
|
+
if (model.priceFactor === 0 || model.priceFactor === void 0 && model.isFree) return t("modelRateFree");
|
|
505
904
|
if (model.priceFactor === void 0) return t("modelRateUnknown");
|
|
506
905
|
const current = formatRateFactor(model.priceFactor);
|
|
507
906
|
if (model.originalPriceFactor !== void 0 && model.originalPriceFactor > model.priceFactor) return t("modelRateDiscount", {
|
|
@@ -522,13 +921,13 @@ window.__ModuleLoader__.load({
|
|
|
522
921
|
children: t("modelsTitle")
|
|
523
922
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
524
923
|
className: QoderCredentialCard_module_css_default.modelCatalogMeta,
|
|
525
|
-
children: t("modelsEnabled", { count: models.length })
|
|
924
|
+
children: t("modelsEnabled", { count: snapshot.models.length })
|
|
526
925
|
})] }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
527
926
|
type: "button",
|
|
528
927
|
className: QoderCredentialCard_module_css_default.linkButton,
|
|
529
|
-
disabled: disabled ||
|
|
928
|
+
disabled: disabled || busy || Boolean(fetchDisabled),
|
|
530
929
|
onClick: () => {
|
|
531
|
-
|
|
930
|
+
if (!disabled && !fetchDisabled) editor.discover();
|
|
532
931
|
},
|
|
533
932
|
children: fetching ? t("modelsFetching") : t("modelsFetch")
|
|
534
933
|
})]
|
|
@@ -553,9 +952,9 @@ window.__ModuleLoader__.load({
|
|
|
553
952
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
554
953
|
type: "checkbox",
|
|
555
954
|
checked: !unavailable && selectedIds.has(model.id),
|
|
556
|
-
disabled: disabled || unavailable,
|
|
955
|
+
disabled: disabled || busy || unavailable,
|
|
557
956
|
onChange: (event) => {
|
|
558
|
-
|
|
957
|
+
if (!disabled) editor.toggle(model.id, event.currentTarget.checked);
|
|
559
958
|
}
|
|
560
959
|
}),
|
|
561
960
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -580,9 +979,9 @@ window.__ModuleLoader__.load({
|
|
|
580
979
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
|
|
581
980
|
className: QoderCredentialCard_module_css_default.modelTierSelect,
|
|
582
981
|
value: selectedTier ?? "",
|
|
583
|
-
disabled: disabled || unavailable || !selectedIds.has(model.id),
|
|
982
|
+
disabled: disabled || busy || unavailable || !selectedIds.has(model.id),
|
|
584
983
|
onChange: (event) => {
|
|
585
|
-
|
|
984
|
+
if (!disabled) editor.selectTier(model.id, event.currentTarget.value);
|
|
586
985
|
},
|
|
587
986
|
children: tiers.map((tier) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
588
987
|
value: tier.key,
|
|
@@ -615,18 +1014,31 @@ window.__ModuleLoader__.load({
|
|
|
615
1014
|
}
|
|
616
1015
|
/**
|
|
617
1016
|
* Settings card for the Qoder subscription: credential state, subscriber
|
|
618
|
-
* profile, and every quota block the provider reports.
|
|
1017
|
+
* profile, and every quota block the provider reports. Region changes remount
|
|
1018
|
+
* the account state before any old profile can be displayed.
|
|
619
1019
|
*/
|
|
620
|
-
function QoderAccountCard(
|
|
1020
|
+
function QoderAccountCard(props) {
|
|
1021
|
+
const modelSnapshot = (0, react.useSyncExternalStore)(props.operations.subscribeModels, props.operations.getModelSnapshot, props.operations.getModelSnapshot);
|
|
1022
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RegionAccountCard, {
|
|
1023
|
+
...props,
|
|
1024
|
+
modelSnapshot
|
|
1025
|
+
}, regionOf(modelSnapshot.value));
|
|
1026
|
+
}
|
|
1027
|
+
function RegionAccountCard({ operations, t, activeLocale, modelSnapshot }) {
|
|
621
1028
|
const [credentialState, setCredentialState] = (0, react.useState)({ status: "loading" });
|
|
622
1029
|
const [accountState, setAccountState] = (0, react.useState)({ status: "idle" });
|
|
623
1030
|
const [refreshing, setRefreshing] = (0, react.useState)(false);
|
|
624
1031
|
const [credentialRevision, setCredentialRevision] = (0, react.useState)(0);
|
|
625
|
-
const [modelSaveError, setModelSaveError] = (0, react.useState)();
|
|
626
1032
|
const latestAccountRequest = (0, react.useRef)(0);
|
|
627
|
-
const
|
|
1033
|
+
const latestCredentialRequest = (0, react.useRef)(0);
|
|
1034
|
+
(0, react.useLayoutEffect)(() => () => {
|
|
1035
|
+
latestAccountRequest.current++;
|
|
1036
|
+
latestCredentialRequest.current++;
|
|
1037
|
+
}, []);
|
|
628
1038
|
const loadCredential = (0, react.useCallback)(async () => {
|
|
1039
|
+
const requestId = ++latestCredentialRequest.current;
|
|
629
1040
|
const info = await operations.describe();
|
|
1041
|
+
if (requestId !== latestCredentialRequest.current) return;
|
|
630
1042
|
setCredentialState(info === void 0 ? { status: "failed" } : {
|
|
631
1043
|
status: "ready",
|
|
632
1044
|
info
|
|
@@ -745,7 +1157,7 @@ window.__ModuleLoader__.load({
|
|
|
745
1157
|
const renderAccount = () => {
|
|
746
1158
|
if (!configured) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
747
1159
|
className: QoderCredentialCard_module_css_default.accountSection,
|
|
748
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
1160
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
749
1161
|
className: QoderCredentialCard_module_css_default.accountEmptyText,
|
|
750
1162
|
children: t("accountCredentialHint")
|
|
751
1163
|
})
|
|
@@ -781,13 +1193,14 @@ window.__ModuleLoader__.load({
|
|
|
781
1193
|
const { profile, usage, plan } = accountState.account;
|
|
782
1194
|
const userQuota = usage?.userQuota;
|
|
783
1195
|
const orgPackage = usage?.orgResourcePackage;
|
|
1196
|
+
const addOnQuota = usage?.addOnQuota;
|
|
784
1197
|
const dedicatedPackages = usage?.dedicatedResourcePackages ?? [];
|
|
785
1198
|
const locale = activeLocale();
|
|
786
1199
|
const avatarInitial = (profile.name || profile.email || "Q").charAt(0).toUpperCase();
|
|
787
1200
|
const resetDate = formatResetDate(usage?.expiresAt);
|
|
788
1201
|
const planExpiry = plan?.endDate ? formatResetDate(plan.endDate) : void 0;
|
|
789
1202
|
const isSuspended = plan?.organization?.isSuspended === true;
|
|
790
|
-
const hasQuota = (userQuota?.total ?? 0) > 0 || (orgPackage?.total ?? 0) > 0 || dedicatedPackages.some((pkg) => pkg.total > 0);
|
|
1203
|
+
const hasQuota = (userQuota?.total ?? 0) > 0 || (orgPackage?.total ?? 0) > 0 || (addOnQuota?.total ?? 0) > 0 || dedicatedPackages.some((pkg) => pkg.total > 0);
|
|
791
1204
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
792
1205
|
className: QoderCredentialCard_module_css_default.accountSection,
|
|
793
1206
|
children: [
|
|
@@ -844,6 +1257,7 @@ window.__ModuleLoader__.load({
|
|
|
844
1257
|
}) : null,
|
|
845
1258
|
renderQuota("userQuota", t("userQuotaTitle"), userQuota, { resetDate }),
|
|
846
1259
|
renderQuota("orgResource", t("orgResourceTitle"), orgPackage, { resetDate }),
|
|
1260
|
+
renderQuota("addOnQuota", t("addOnQuotaTitle"), addOnQuota),
|
|
847
1261
|
dedicatedPackages.map((pkg, index) => renderQuota(`dedicatedResource-${pkg.id ?? index}`, resolveLocalizedText(pkg.title, locale) ?? t("dedicatedResourceTitle"), pkg, {
|
|
848
1262
|
expiresAt: formatResetDate(pkg.expiresAt),
|
|
849
1263
|
description: resolveLocalizedText(pkg.description, locale)
|
|
@@ -922,16 +1336,6 @@ window.__ModuleLoader__.load({
|
|
|
922
1336
|
const currentRegion = regionOf(modelSnapshot.value);
|
|
923
1337
|
const currentModels = modelsOf(modelSnapshot.value, currentRegion);
|
|
924
1338
|
const canModifyModels = modelSnapshot.status === "ready" && modelSnapshot.writable;
|
|
925
|
-
const handleModelsChange = async (models) => {
|
|
926
|
-
if (!canModifyModels) return;
|
|
927
|
-
setModelSaveError(void 0);
|
|
928
|
-
const failure = validateModelCatalog(models);
|
|
929
|
-
if (failure) {
|
|
930
|
-
setModelSaveError(t(failure));
|
|
931
|
-
return;
|
|
932
|
-
}
|
|
933
|
-
if (!await operations.storeModels(currentRegion, models)) setModelSaveError(t("saveFailed"));
|
|
934
|
-
};
|
|
935
1339
|
const renderModelCatalogSection = () => {
|
|
936
1340
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
937
1341
|
className: QoderCredentialCard_module_css_default.customized,
|
|
@@ -941,29 +1345,23 @@ window.__ModuleLoader__.load({
|
|
|
941
1345
|
className: QoderCredentialCard_module_css_default.modelSummaryBadge,
|
|
942
1346
|
children: t("modelsEnabled", { count: currentModels.length })
|
|
943
1347
|
})]
|
|
944
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
1348
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
945
1349
|
className: QoderCredentialCard_module_css_default.customizedBody,
|
|
946
|
-
children:
|
|
1350
|
+
children: modelSnapshot.status === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
947
1351
|
className: QoderCredentialCard_module_css_default.hint,
|
|
948
1352
|
children: t("modelsLoading")
|
|
949
1353
|
}) : modelSnapshot.status === "unavailable" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
950
1354
|
className: QoderCredentialCard_module_css_default.error,
|
|
951
1355
|
children: t("modelsUnavailable")
|
|
952
1356
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QoderModelCatalog, {
|
|
1357
|
+
region: currentRegion,
|
|
953
1358
|
operations,
|
|
954
1359
|
models: currentModels,
|
|
955
1360
|
disabled: !canModifyModels,
|
|
956
1361
|
fetchDisabled: !configured,
|
|
957
1362
|
hideTitle: true,
|
|
958
|
-
t
|
|
959
|
-
|
|
960
|
-
handleModelsChange(models);
|
|
961
|
-
}
|
|
962
|
-
}), modelSaveError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
963
|
-
className: QoderCredentialCard_module_css_default.error,
|
|
964
|
-
role: "alert",
|
|
965
|
-
children: modelSaveError
|
|
966
|
-
}) : null]
|
|
1363
|
+
t
|
|
1364
|
+
})
|
|
967
1365
|
})]
|
|
968
1366
|
});
|
|
969
1367
|
};
|
|
@@ -988,228 +1386,539 @@ window.__ModuleLoader__.load({
|
|
|
988
1386
|
});
|
|
989
1387
|
}
|
|
990
1388
|
//#endregion
|
|
991
|
-
//#region src/client/
|
|
992
|
-
|
|
993
|
-
|
|
1389
|
+
//#region src/client/QoderBrowserLogin.tsx
|
|
1390
|
+
/** A single current identity, with browser and PAT management revealed only when needed. */
|
|
1391
|
+
function QoderBrowserLogin({ region, operations, credentials, onBusyChange, t }) {
|
|
1392
|
+
const [view, setView] = (0, react.useState)();
|
|
1393
|
+
const [pat, setPat] = (0, react.useState)();
|
|
1394
|
+
const [profile, setProfile] = (0, react.useState)();
|
|
1395
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
1396
|
+
const [error, setError] = (0, react.useState)();
|
|
1397
|
+
const [readFailed, setReadFailed] = (0, react.useState)(false);
|
|
994
1398
|
const [editing, setEditing] = (0, react.useState)(false);
|
|
1399
|
+
const [menu, setMenu] = (0, react.useState)(false);
|
|
995
1400
|
const [draft, setDraft] = (0, react.useState)("");
|
|
996
|
-
const [
|
|
997
|
-
const [
|
|
998
|
-
const [
|
|
999
|
-
const [
|
|
1000
|
-
const
|
|
1401
|
+
const [copyFailed, setCopyFailed] = (0, react.useState)(false);
|
|
1402
|
+
const [copied, setCopied] = (0, react.useState)(false);
|
|
1403
|
+
const [now, setNow] = (0, react.useState)(Date.now());
|
|
1404
|
+
const [accountRevision, setAccountRevision] = (0, react.useState)(0);
|
|
1405
|
+
const mounted = (0, react.useRef)(false);
|
|
1406
|
+
const revision = (0, react.useRef)(0);
|
|
1407
|
+
const mutating = (0, react.useRef)(false);
|
|
1408
|
+
const waitingRef = (0, react.useRef)(false);
|
|
1409
|
+
const wakeRef = (0, react.useRef)(void 0);
|
|
1410
|
+
const attempt = view?.attempt;
|
|
1411
|
+
const pending = attempt !== void 0 && [
|
|
1412
|
+
"waiting",
|
|
1413
|
+
"verifying",
|
|
1414
|
+
"saving"
|
|
1415
|
+
].includes(attempt.phase);
|
|
1416
|
+
const connected = view?.configured === true && !view.expired;
|
|
1417
|
+
const identity = view?.method === "browser" ? view.profile : profile;
|
|
1418
|
+
const patConfigured = pat?.configured === true && !isEnvironmentCredentialSource(pat.source);
|
|
1419
|
+
const remaining = Math.max(0, Math.ceil(((attempt?.expiresAt ?? now) - now) / 1e3));
|
|
1420
|
+
const read = async () => {
|
|
1421
|
+
const info = await (credentials.describePat ?? credentials.describe)();
|
|
1422
|
+
const result = operations ? await operations.read(region) : void 0;
|
|
1423
|
+
if (result && !result.ok) throw new Error("Authorization status unavailable");
|
|
1424
|
+
if (!result && !info) throw new Error("Credential status unavailable");
|
|
1425
|
+
return {
|
|
1426
|
+
info,
|
|
1427
|
+
value: result?.value ?? {
|
|
1428
|
+
region,
|
|
1429
|
+
method: "pat",
|
|
1430
|
+
configured: info?.configured === true && !isEnvironmentCredentialSource(info.source),
|
|
1431
|
+
writable: false
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
};
|
|
1001
1435
|
(0, react.useEffect)(() => {
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
const
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1436
|
+
mounted.current = true;
|
|
1437
|
+
let active = true;
|
|
1438
|
+
let timer;
|
|
1439
|
+
const poll = async (identityChanged = false) => {
|
|
1440
|
+
const version = revision.current;
|
|
1441
|
+
try {
|
|
1442
|
+
const result = await read();
|
|
1443
|
+
if (active && mounted.current && version === revision.current && !mutating.current) {
|
|
1444
|
+
waitingRef.current = result.value.attempt !== void 0 && [
|
|
1445
|
+
"waiting",
|
|
1446
|
+
"verifying",
|
|
1447
|
+
"saving"
|
|
1448
|
+
].includes(result.value.attempt.phase);
|
|
1449
|
+
setView(result.value);
|
|
1450
|
+
setPat(result.info);
|
|
1451
|
+
setReadFailed(false);
|
|
1452
|
+
setNow(Date.now());
|
|
1453
|
+
if (identityChanged) setAccountRevision((value) => value + 1);
|
|
1454
|
+
}
|
|
1455
|
+
} catch {
|
|
1456
|
+
if (mounted.current && version === revision.current) setReadFailed(true);
|
|
1457
|
+
}
|
|
1458
|
+
if (active && mounted.current) {
|
|
1459
|
+
clearTimeout(timer);
|
|
1460
|
+
timer = setTimeout(() => {
|
|
1461
|
+
poll();
|
|
1462
|
+
}, waitingRef.current ? 1e3 : 1e4);
|
|
1463
|
+
}
|
|
1464
|
+
};
|
|
1465
|
+
poll();
|
|
1466
|
+
wakeRef.current = () => {
|
|
1467
|
+
clearTimeout(timer);
|
|
1468
|
+
timer = setTimeout(() => {
|
|
1469
|
+
poll();
|
|
1470
|
+
}, 1e3);
|
|
1471
|
+
};
|
|
1472
|
+
const unsubscribe = credentials.subscribe?.(() => {
|
|
1473
|
+
if (mutating.current || !active) return;
|
|
1474
|
+
revision.current++;
|
|
1475
|
+
setProfile(void 0);
|
|
1476
|
+
poll(true);
|
|
1009
1477
|
});
|
|
1010
|
-
|
|
1478
|
+
return () => {
|
|
1479
|
+
active = false;
|
|
1480
|
+
mounted.current = false;
|
|
1481
|
+
wakeRef.current = void 0;
|
|
1482
|
+
clearTimeout(timer);
|
|
1483
|
+
unsubscribe?.();
|
|
1484
|
+
revision.current++;
|
|
1485
|
+
};
|
|
1486
|
+
}, [
|
|
1487
|
+
operations,
|
|
1488
|
+
credentials,
|
|
1489
|
+
region
|
|
1490
|
+
]);
|
|
1011
1491
|
(0, react.useEffect)(() => {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
setNotice("saveFailed");
|
|
1056
|
-
setMutation(void 0);
|
|
1492
|
+
let active = true;
|
|
1493
|
+
setProfile(void 0);
|
|
1494
|
+
if (view?.method === "pat" && view.configured) {
|
|
1495
|
+
const version = revision.current;
|
|
1496
|
+
credentials.getAccount().then((result) => {
|
|
1497
|
+
if (active && version === revision.current && result?.ok) setProfile(result.value.profile);
|
|
1498
|
+
}).catch(() => {});
|
|
1499
|
+
}
|
|
1500
|
+
return () => {
|
|
1501
|
+
active = false;
|
|
1502
|
+
};
|
|
1503
|
+
}, [
|
|
1504
|
+
credentials,
|
|
1505
|
+
view?.method,
|
|
1506
|
+
view?.configured,
|
|
1507
|
+
accountRevision
|
|
1508
|
+
]);
|
|
1509
|
+
const mutate = async (action) => {
|
|
1510
|
+
if (mutating.current) return;
|
|
1511
|
+
const popup = action === "begin" ? window.open("about:blank", "_blank") : null;
|
|
1512
|
+
if (popup) popup.opener = null;
|
|
1513
|
+
const version = ++revision.current;
|
|
1514
|
+
mutating.current = true;
|
|
1515
|
+
onBusyChange?.(true);
|
|
1516
|
+
setBusy(true);
|
|
1517
|
+
setError(void 0);
|
|
1518
|
+
setMenu(false);
|
|
1519
|
+
try {
|
|
1520
|
+
let result;
|
|
1521
|
+
if (action === "savePat") if (draft.trim()) {
|
|
1522
|
+
if (!await credentials.store(draft.trim())) throw new Error("PAT save failed");
|
|
1523
|
+
} else if (patConfigured) {
|
|
1524
|
+
if (operations) result = await operations.select(region, "pat");
|
|
1525
|
+
} else throw new Error("A PAT is required");
|
|
1526
|
+
else if (action === "removePat") {
|
|
1527
|
+
if (!await credentials.remove()) throw new Error("PAT removal failed");
|
|
1528
|
+
} else if (operations) result = action === "begin" ? await operations.begin(region) : action === "cancel" ? await operations.cancel(region) : await operations.select(region, action);
|
|
1529
|
+
if (result && !result.ok) {
|
|
1530
|
+
if (mounted.current && version === revision.current) {
|
|
1531
|
+
const code = result.error.code;
|
|
1532
|
+
setError(action === "none" ? "browserRemoveFailed" : code === "TIMEOUT" ? "browserTimeout" : code === "UNAUTHENTICATED" ? "browserRejected" : "authorizationConnectionFailed");
|
|
1533
|
+
}
|
|
1534
|
+
popup?.close();
|
|
1057
1535
|
return;
|
|
1058
1536
|
}
|
|
1059
|
-
|
|
1537
|
+
const current = result?.value;
|
|
1538
|
+
if (!mounted.current || version !== revision.current) {
|
|
1539
|
+
popup?.close();
|
|
1540
|
+
return;
|
|
1541
|
+
}
|
|
1542
|
+
if (popup && current?.attempt?.url) popup.location.replace(current.attempt.url);
|
|
1543
|
+
else popup?.close();
|
|
1544
|
+
const refreshed = current ? {
|
|
1545
|
+
value: current,
|
|
1546
|
+
info: pat
|
|
1547
|
+
} : await read();
|
|
1548
|
+
if (!mounted.current || version !== revision.current) {
|
|
1549
|
+
popup?.close();
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
setView(refreshed.value);
|
|
1553
|
+
setPat(refreshed.info);
|
|
1554
|
+
setReadFailed(false);
|
|
1555
|
+
setNow(Date.now());
|
|
1556
|
+
waitingRef.current = refreshed.value.attempt !== void 0 && [
|
|
1557
|
+
"waiting",
|
|
1558
|
+
"verifying",
|
|
1559
|
+
"saving"
|
|
1560
|
+
].includes(refreshed.value.attempt.phase);
|
|
1561
|
+
if (action === "savePat" || action === "removePat") {
|
|
1562
|
+
setDraft("");
|
|
1563
|
+
setEditing(false);
|
|
1564
|
+
setProfile(void 0);
|
|
1565
|
+
setAccountRevision((value) => value + 1);
|
|
1566
|
+
}
|
|
1567
|
+
} catch {
|
|
1568
|
+
popup?.close();
|
|
1569
|
+
if (mounted.current && version === revision.current) setError(action === "savePat" ? "patSaveFailed" : action === "removePat" ? "removeFailed" : action === "none" ? "browserRemoveFailed" : "authorizationConnectionFailed");
|
|
1570
|
+
} finally {
|
|
1571
|
+
mutating.current = false;
|
|
1572
|
+
onBusyChange?.(false);
|
|
1573
|
+
if (mounted.current && version === revision.current) {
|
|
1574
|
+
revision.current++;
|
|
1575
|
+
setBusy(false);
|
|
1576
|
+
}
|
|
1577
|
+
if (mounted.current) wakeRef.current?.();
|
|
1060
1578
|
}
|
|
1061
|
-
if (normalized.length === 0 || await operations.store(normalized)) {
|
|
1062
|
-
setDraft("");
|
|
1063
|
-
setNotice("saved");
|
|
1064
|
-
if (normalized.length > 0) await load();
|
|
1065
|
-
setEditing(false);
|
|
1066
|
-
} else setNotice("saveFailed");
|
|
1067
|
-
setMutation(void 0);
|
|
1068
1579
|
};
|
|
1069
|
-
const
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
setDraft("");
|
|
1075
|
-
await load();
|
|
1076
|
-
} else setNotice("removeFailed");
|
|
1077
|
-
setMutation(void 0);
|
|
1580
|
+
const openPat = () => {
|
|
1581
|
+
setMenu(false);
|
|
1582
|
+
setDraft("");
|
|
1583
|
+
setError(void 0);
|
|
1584
|
+
setEditing(true);
|
|
1078
1585
|
};
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1586
|
+
const initial = (identity?.name || identity?.email || "Q").slice(0, 1).toUpperCase();
|
|
1587
|
+
const failure = attempt?.phase === "failed" ? attempt.failure === "storage" ? "browserStorageFailed" : attempt.failure === "connection" ? "authorizationConnectionFailed" : "browserRejected" : void 0;
|
|
1588
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1589
|
+
className: QoderCredentialCard_module_css_default.connectionBody,
|
|
1590
|
+
"aria-label": t("accountConnectionTitle"),
|
|
1082
1591
|
children: [
|
|
1083
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1084
|
-
|
|
1085
|
-
children:
|
|
1086
|
-
|
|
1592
|
+
!view ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1593
|
+
role: "status",
|
|
1594
|
+
children: t(readFailed ? "authorizationConnectionFailed" : "loading")
|
|
1595
|
+
}) : null,
|
|
1596
|
+
readFailed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1597
|
+
type: "button",
|
|
1598
|
+
className: QoderCredentialCard_module_css_default.secondary,
|
|
1599
|
+
onClick: () => wakeRef.current?.(),
|
|
1600
|
+
children: t("retry")
|
|
1601
|
+
}) : null,
|
|
1602
|
+
view ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1603
|
+
connected || view.expired ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1604
|
+
className: QoderCredentialCard_module_css_default.subscriberRow,
|
|
1087
1605
|
children: [
|
|
1088
1606
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1089
|
-
className: QoderCredentialCard_module_css_default.
|
|
1090
|
-
|
|
1607
|
+
className: QoderCredentialCard_module_css_default.subscriberAvatar,
|
|
1608
|
+
"aria-hidden": "true",
|
|
1609
|
+
children: initial
|
|
1091
1610
|
}),
|
|
1092
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1093
|
-
className: QoderCredentialCard_module_css_default.
|
|
1094
|
-
children:
|
|
1611
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1612
|
+
className: QoderCredentialCard_module_css_default.subscriberIdentity,
|
|
1613
|
+
children: [
|
|
1614
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: identity?.name || t(view.method === "pat" ? "patActive" : "browserMethod") }),
|
|
1615
|
+
identity?.email ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: identity.email }) : null,
|
|
1616
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1617
|
+
className: QoderCredentialCard_module_css_default.label,
|
|
1618
|
+
children: t(view.method === "browser" ? "browserMethod" : "patMethod")
|
|
1619
|
+
})
|
|
1620
|
+
]
|
|
1095
1621
|
}),
|
|
1622
|
+
!pending && !editing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1623
|
+
type: "button",
|
|
1624
|
+
className: QoderCredentialCard_module_css_default.secondary,
|
|
1625
|
+
"aria-expanded": menu,
|
|
1626
|
+
"aria-controls": "qoder-account-management",
|
|
1627
|
+
disabled: busy,
|
|
1628
|
+
onClick: () => setMenu(!menu),
|
|
1629
|
+
children: t(view.method === "pat" ? "manageCredential" : "manageAccount")
|
|
1630
|
+
}) : null
|
|
1631
|
+
]
|
|
1632
|
+
}) : !pending && !editing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1633
|
+
className: QoderCredentialCard_module_css_default.label,
|
|
1634
|
+
children: t("signInDescription")
|
|
1635
|
+
}) : null,
|
|
1636
|
+
pending ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1637
|
+
className: QoderCredentialCard_module_css_default.loginProgress,
|
|
1638
|
+
role: "status",
|
|
1639
|
+
children: [
|
|
1640
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t(attempt.phase === "saving" ? "browserSaving" : "browserWaiting") }),
|
|
1096
1641
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1097
|
-
className:
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1642
|
+
className: QoderCredentialCard_module_css_default.label,
|
|
1643
|
+
children: t("loginTimeRemaining", { seconds: remaining })
|
|
1644
|
+
}),
|
|
1645
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1646
|
+
className: QoderCredentialCard_module_css_default.connectionActions,
|
|
1647
|
+
children: [
|
|
1648
|
+
attempt.url ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
1649
|
+
className: QoderCredentialCard_module_css_default.primaryLink,
|
|
1650
|
+
href: attempt.url,
|
|
1651
|
+
target: "_blank",
|
|
1652
|
+
rel: "noopener noreferrer",
|
|
1653
|
+
referrerPolicy: "no-referrer",
|
|
1654
|
+
children: t("reopenLogin")
|
|
1655
|
+
}) : null,
|
|
1656
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1657
|
+
type: "button",
|
|
1658
|
+
className: QoderCredentialCard_module_css_default.secondary,
|
|
1659
|
+
disabled: busy || !view.writable,
|
|
1660
|
+
onClick: () => {
|
|
1661
|
+
mutate("cancel");
|
|
1662
|
+
},
|
|
1663
|
+
children: t("cancelLogin")
|
|
1664
|
+
}),
|
|
1665
|
+
attempt.url ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1666
|
+
type: "button",
|
|
1667
|
+
className: QoderCredentialCard_module_css_default.textButton,
|
|
1668
|
+
onClick: () => {
|
|
1669
|
+
if (!navigator.clipboard) {
|
|
1670
|
+
setCopyFailed(true);
|
|
1671
|
+
return;
|
|
1672
|
+
}
|
|
1673
|
+
navigator.clipboard.writeText(attempt.url).then(() => {
|
|
1674
|
+
if (mounted.current) {
|
|
1675
|
+
setCopied(true);
|
|
1676
|
+
setCopyFailed(false);
|
|
1677
|
+
}
|
|
1678
|
+
}, () => {
|
|
1679
|
+
if (mounted.current) setCopyFailed(true);
|
|
1680
|
+
});
|
|
1681
|
+
},
|
|
1682
|
+
children: t(copied ? "loginLinkCopied" : "copyLogin")
|
|
1683
|
+
}) : null
|
|
1684
|
+
]
|
|
1101
1685
|
})
|
|
1102
1686
|
]
|
|
1103
|
-
})
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1687
|
+
}) : null,
|
|
1688
|
+
view.expired ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1689
|
+
role: "status",
|
|
1690
|
+
className: QoderCredentialCard_module_css_default.error,
|
|
1691
|
+
children: t("browserExpired")
|
|
1692
|
+
}) : null,
|
|
1693
|
+
view.unsaved ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1694
|
+
role: "alert",
|
|
1695
|
+
className: QoderCredentialCard_module_css_default.error,
|
|
1696
|
+
children: t("browserUnsaved")
|
|
1697
|
+
}) : null,
|
|
1698
|
+
!pending && attempt?.phase === "timeout" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1699
|
+
role: "status",
|
|
1700
|
+
className: QoderCredentialCard_module_css_default.error,
|
|
1701
|
+
children: t("browserTimeout")
|
|
1702
|
+
}) : null,
|
|
1703
|
+
!pending && failure ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1704
|
+
role: "alert",
|
|
1705
|
+
className: QoderCredentialCard_module_css_default.error,
|
|
1706
|
+
children: t(failure)
|
|
1707
|
+
}) : null,
|
|
1708
|
+
menu && !pending && !editing ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1709
|
+
id: "qoder-account-management",
|
|
1710
|
+
className: QoderCredentialCard_module_css_default.managementPanel,
|
|
1711
|
+
children: [
|
|
1712
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1713
|
+
type: "button",
|
|
1714
|
+
className: QoderCredentialCard_module_css_default.textButton,
|
|
1715
|
+
disabled: busy || !view.writable,
|
|
1716
|
+
onClick: () => {
|
|
1717
|
+
mutate("begin");
|
|
1718
|
+
},
|
|
1719
|
+
children: t("changeAccount")
|
|
1720
|
+
}),
|
|
1721
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1722
|
+
type: "button",
|
|
1723
|
+
className: QoderCredentialCard_module_css_default.textButton,
|
|
1724
|
+
disabled: busy || !pat?.writable,
|
|
1725
|
+
onClick: openPat,
|
|
1726
|
+
children: t(view.method === "pat" ? "editPat" : "usePat")
|
|
1727
|
+
}),
|
|
1728
|
+
view.method !== "browser" && view.profile ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1729
|
+
type: "button",
|
|
1730
|
+
className: QoderCredentialCard_module_css_default.textButton,
|
|
1731
|
+
disabled: busy || !view.writable,
|
|
1732
|
+
onClick: () => {
|
|
1733
|
+
mutate("browser");
|
|
1734
|
+
},
|
|
1735
|
+
children: t("useBrowser")
|
|
1736
|
+
}) : null,
|
|
1737
|
+
view.profile ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1738
|
+
type: "button",
|
|
1739
|
+
className: QoderCredentialCard_module_css_default.danger,
|
|
1740
|
+
disabled: busy || !view.writable,
|
|
1741
|
+
onClick: () => {
|
|
1742
|
+
mutate("none");
|
|
1743
|
+
},
|
|
1744
|
+
children: t("signOutQoder")
|
|
1745
|
+
}) : null
|
|
1746
|
+
]
|
|
1747
|
+
}) : null,
|
|
1748
|
+
!pending && !editing && (!connected || view.expired) ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1749
|
+
className: QoderCredentialCard_module_css_default.connectionActions,
|
|
1750
|
+
children: [
|
|
1751
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1752
|
+
type: "button",
|
|
1753
|
+
className: QoderCredentialCard_module_css_default.primary,
|
|
1754
|
+
disabled: busy || !view.writable,
|
|
1755
|
+
onClick: () => {
|
|
1756
|
+
mutate("begin");
|
|
1757
|
+
},
|
|
1758
|
+
children: t(view.expired ? "signInAgain" : "signInQoder")
|
|
1759
|
+
}),
|
|
1760
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1761
|
+
type: "button",
|
|
1762
|
+
className: QoderCredentialCard_module_css_default.textButton,
|
|
1763
|
+
disabled: busy || !pat?.writable,
|
|
1764
|
+
onClick: openPat,
|
|
1765
|
+
children: t("usePat")
|
|
1766
|
+
}),
|
|
1767
|
+
view.profile && view.method !== "browser" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1768
|
+
type: "button",
|
|
1769
|
+
className: QoderCredentialCard_module_css_default.textButton,
|
|
1770
|
+
disabled: busy || !view.writable,
|
|
1771
|
+
onClick: () => {
|
|
1772
|
+
mutate("browser");
|
|
1773
|
+
},
|
|
1774
|
+
children: t("useBrowser")
|
|
1775
|
+
}) : null
|
|
1776
|
+
]
|
|
1777
|
+
}) : null,
|
|
1778
|
+
editing ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1779
|
+
className: QoderCredentialCard_module_css_default.editor,
|
|
1780
|
+
children: [
|
|
1781
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
1782
|
+
className: QoderCredentialCard_module_css_default.label,
|
|
1783
|
+
htmlFor: "qoder-managed-credential",
|
|
1784
|
+
children: t("tokenLabel")
|
|
1785
|
+
}),
|
|
1786
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1787
|
+
id: "qoder-managed-credential",
|
|
1788
|
+
className: QoderCredentialCard_module_css_default.input,
|
|
1789
|
+
type: "password",
|
|
1790
|
+
autoComplete: "new-password",
|
|
1791
|
+
value: draft,
|
|
1792
|
+
disabled: busy || !pat?.writable,
|
|
1793
|
+
placeholder: patConfigured ? t("configuredHint") : t("tokenPlaceholder"),
|
|
1794
|
+
onChange: (event) => setDraft(event.currentTarget.value)
|
|
1795
|
+
}),
|
|
1796
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1797
|
+
className: QoderCredentialCard_module_css_default.connectionActions,
|
|
1798
|
+
children: [
|
|
1799
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1800
|
+
type: "button",
|
|
1801
|
+
className: QoderCredentialCard_module_css_default.primary,
|
|
1802
|
+
disabled: busy || !pat?.writable || !draft.trim() && !patConfigured,
|
|
1803
|
+
onClick: () => {
|
|
1804
|
+
mutate("savePat");
|
|
1805
|
+
},
|
|
1806
|
+
children: t(busy ? "saving" : draft.trim() || !patConfigured ? "saveAndUsePat" : "useSavedPat")
|
|
1807
|
+
}),
|
|
1808
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1809
|
+
type: "button",
|
|
1810
|
+
className: QoderCredentialCard_module_css_default.secondary,
|
|
1811
|
+
disabled: busy,
|
|
1812
|
+
onClick: () => {
|
|
1813
|
+
setDraft("");
|
|
1814
|
+
setEditing(false);
|
|
1815
|
+
setError(void 0);
|
|
1816
|
+
},
|
|
1817
|
+
children: t("cancel")
|
|
1818
|
+
}),
|
|
1819
|
+
patConfigured ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1820
|
+
type: "button",
|
|
1821
|
+
className: QoderCredentialCard_module_css_default.danger,
|
|
1822
|
+
disabled: busy || !pat?.writable,
|
|
1823
|
+
onClick: () => {
|
|
1824
|
+
if (window.confirm(t("confirmRemove"))) mutate("removePat");
|
|
1825
|
+
},
|
|
1826
|
+
children: t("remove")
|
|
1827
|
+
}) : null
|
|
1828
|
+
]
|
|
1829
|
+
})
|
|
1830
|
+
]
|
|
1831
|
+
}) : null
|
|
1832
|
+
] }) : null,
|
|
1833
|
+
view && !view.writable && !pat?.writable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1834
|
+
className: QoderCredentialCard_module_css_default.label,
|
|
1835
|
+
children: t("readOnly")
|
|
1836
|
+
}) : null,
|
|
1837
|
+
copyFailed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1838
|
+
role: "alert",
|
|
1839
|
+
className: QoderCredentialCard_module_css_default.error,
|
|
1840
|
+
children: t("copyLoginFailed")
|
|
1841
|
+
}) : null,
|
|
1842
|
+
error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1843
|
+
role: "alert",
|
|
1844
|
+
className: QoderCredentialCard_module_css_default.error,
|
|
1845
|
+
children: t(error)
|
|
1846
|
+
}) : null,
|
|
1847
|
+
readFailed && view ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1848
|
+
role: "alert",
|
|
1849
|
+
className: QoderCredentialCard_module_css_default.error,
|
|
1850
|
+
children: t("authorizationConnectionFailed")
|
|
1851
|
+
}) : null
|
|
1852
|
+
]
|
|
1853
|
+
});
|
|
1854
|
+
}
|
|
1855
|
+
//#endregion
|
|
1856
|
+
//#region src/client/QoderCredentialCard.tsx
|
|
1857
|
+
/** Region selection stays outside the keyed account state, so old identities never flash. */
|
|
1858
|
+
function QoderCredentialCard({ operations, t }) {
|
|
1859
|
+
const snapshot = (0, react.useSyncExternalStore)(operations.subscribeModels, operations.getModelSnapshot, operations.getModelSnapshot);
|
|
1860
|
+
const region = regionOf(snapshot.value);
|
|
1861
|
+
const [changing, setChanging] = (0, react.useState)(false);
|
|
1862
|
+
const [accountBusy, setAccountBusy] = (0, react.useState)(false);
|
|
1863
|
+
const [notice, setNotice] = (0, react.useState)();
|
|
1864
|
+
const mutating = (0, react.useRef)(false);
|
|
1865
|
+
const canChange = snapshot.status === "ready" && snapshot.writable && !changing && !accountBusy;
|
|
1866
|
+
const changeRegion = async (next) => {
|
|
1867
|
+
if (!canChange || next === region || mutating.current) return;
|
|
1868
|
+
mutating.current = true;
|
|
1869
|
+
setChanging(true);
|
|
1870
|
+
setNotice(void 0);
|
|
1871
|
+
try {
|
|
1872
|
+
setNotice(await operations.storeRegion(next) ? "regionChanged" : "regionChangeFailed");
|
|
1873
|
+
} catch {
|
|
1874
|
+
setNotice("regionChangeFailed");
|
|
1875
|
+
} finally {
|
|
1876
|
+
mutating.current = false;
|
|
1877
|
+
setChanging(false);
|
|
1878
|
+
}
|
|
1879
|
+
};
|
|
1880
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1881
|
+
className: `${QoderCredentialCard_module_css_default.credential} ${QoderCredentialCard_module_css_default.credentialEditor}`,
|
|
1882
|
+
"aria-label": t("accountConnectionTitle"),
|
|
1883
|
+
children: [
|
|
1884
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1885
|
+
className: QoderCredentialCard_module_css_default.connectionHead,
|
|
1886
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
1887
|
+
className: QoderCredentialCard_module_css_default.credentialName,
|
|
1888
|
+
children: t("accountConnectionTitle")
|
|
1889
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1890
|
+
className: QoderCredentialCard_module_css_default.regionGroup,
|
|
1891
|
+
role: "radiogroup",
|
|
1892
|
+
"aria-label": t("regionLabel"),
|
|
1893
|
+
children: ["global", "china"].map((value) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1894
|
+
type: "button",
|
|
1895
|
+
role: "radio",
|
|
1896
|
+
"aria-checked": region === value,
|
|
1897
|
+
disabled: !canChange,
|
|
1898
|
+
className: `${QoderCredentialCard_module_css_default.regionOption} ${region === value ? QoderCredentialCard_module_css_default.regionOptionActive : ""}`,
|
|
1899
|
+
onClick: () => {
|
|
1900
|
+
changeRegion(value);
|
|
1901
|
+
},
|
|
1902
|
+
children: t(value === "china" ? "regionChina" : "regionGlobal")
|
|
1903
|
+
}, value))
|
|
1116
1904
|
})]
|
|
1117
1905
|
}),
|
|
1118
|
-
notice
|
|
1119
|
-
className: notice === "saved" ? QoderCredentialCard_module_css_default.success : QoderCredentialCard_module_css_default.error,
|
|
1906
|
+
notice ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1120
1907
|
role: "status",
|
|
1908
|
+
className: notice === "regionChangeFailed" ? QoderCredentialCard_module_css_default.error : QoderCredentialCard_module_css_default.label,
|
|
1121
1909
|
children: t(notice)
|
|
1122
|
-
}),
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
role: "radiogroup",
|
|
1135
|
-
"aria-label": t("regionLabel"),
|
|
1136
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1137
|
-
type: "button",
|
|
1138
|
-
role: "radio",
|
|
1139
|
-
"aria-checked": regionDraft === "global",
|
|
1140
|
-
className: `${QoderCredentialCard_module_css_default.regionOption} ${regionDraft === "global" ? QoderCredentialCard_module_css_default.regionOptionActive : ""}`,
|
|
1141
|
-
disabled: !canModifyRegion || busy,
|
|
1142
|
-
onClick: () => {
|
|
1143
|
-
setRegionDraft("global");
|
|
1144
|
-
setRegionDirty(true);
|
|
1145
|
-
},
|
|
1146
|
-
children: t("regionGlobal")
|
|
1147
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1148
|
-
type: "button",
|
|
1149
|
-
role: "radio",
|
|
1150
|
-
"aria-checked": regionDraft === "china",
|
|
1151
|
-
className: `${QoderCredentialCard_module_css_default.regionOption} ${regionDraft === "china" ? QoderCredentialCard_module_css_default.regionOptionActive : ""}`,
|
|
1152
|
-
disabled: !canModifyRegion || busy,
|
|
1153
|
-
onClick: () => {
|
|
1154
|
-
setRegionDraft("china");
|
|
1155
|
-
setRegionDirty(true);
|
|
1156
|
-
},
|
|
1157
|
-
children: t("regionChina")
|
|
1158
|
-
})]
|
|
1159
|
-
})]
|
|
1160
|
-
}),
|
|
1161
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
1162
|
-
className: QoderCredentialCard_module_css_default.label,
|
|
1163
|
-
htmlFor: "qoder-managed-credential",
|
|
1164
|
-
children: t("tokenLabel")
|
|
1165
|
-
}),
|
|
1166
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1167
|
-
id: "qoder-managed-credential",
|
|
1168
|
-
className: QoderCredentialCard_module_css_default.input,
|
|
1169
|
-
type: "password",
|
|
1170
|
-
autoComplete: "new-password",
|
|
1171
|
-
value: draft,
|
|
1172
|
-
disabled: !writable || busy,
|
|
1173
|
-
placeholder: configured ? t("configuredHint") : t("tokenPlaceholder"),
|
|
1174
|
-
onChange: (event) => setDraft(event.currentTarget.value)
|
|
1175
|
-
}),
|
|
1176
|
-
!writable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1177
|
-
className: QoderCredentialCard_module_css_default.error,
|
|
1178
|
-
role: "alert",
|
|
1179
|
-
children: t("readOnly")
|
|
1180
|
-
}) : null,
|
|
1181
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1182
|
-
className: QoderCredentialCard_module_css_default.actions,
|
|
1183
|
-
children: [
|
|
1184
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1185
|
-
type: "button",
|
|
1186
|
-
className: QoderCredentialCard_module_css_default.secondary,
|
|
1187
|
-
disabled: busy,
|
|
1188
|
-
onClick: closeEditor,
|
|
1189
|
-
children: t("cancel")
|
|
1190
|
-
}),
|
|
1191
|
-
configured ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1192
|
-
type: "button",
|
|
1193
|
-
className: QoderCredentialCard_module_css_default.danger,
|
|
1194
|
-
disabled: !writable || busy,
|
|
1195
|
-
onClick: () => {
|
|
1196
|
-
remove();
|
|
1197
|
-
},
|
|
1198
|
-
children: mutation === "removing" ? t("removing") : t("remove")
|
|
1199
|
-
}) : null,
|
|
1200
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1201
|
-
type: "button",
|
|
1202
|
-
className: QoderCredentialCard_module_css_default.primary,
|
|
1203
|
-
disabled: busy || !regionDirty && normalized.length === 0 || regionDirty && !canModifyRegion || normalized.length > 0 && !writable,
|
|
1204
|
-
onClick: () => {
|
|
1205
|
-
save();
|
|
1206
|
-
},
|
|
1207
|
-
children: mutation === "saving" ? t("saving") : t("save")
|
|
1208
|
-
})
|
|
1209
|
-
]
|
|
1210
|
-
})
|
|
1211
|
-
]
|
|
1212
|
-
}) : null
|
|
1910
|
+
}) : null,
|
|
1911
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(QoderBrowserLogin, {
|
|
1912
|
+
region,
|
|
1913
|
+
operations: operations.authorization,
|
|
1914
|
+
credentials: operations,
|
|
1915
|
+
onBusyChange: setAccountBusy,
|
|
1916
|
+
t
|
|
1917
|
+
}, region),
|
|
1918
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1919
|
+
className: QoderCredentialCard_module_css_default.sharedNote,
|
|
1920
|
+
children: t("sharedAuthorization")
|
|
1921
|
+
})
|
|
1213
1922
|
]
|
|
1214
1923
|
});
|
|
1215
1924
|
}
|
|
@@ -1227,17 +1936,102 @@ window.__ModuleLoader__.load({
|
|
|
1227
1936
|
"qoder-subscription"
|
|
1228
1937
|
].includes(provider ?? "");
|
|
1229
1938
|
}
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1939
|
+
//#endregion
|
|
1940
|
+
//#region src/client/session-tier-state.ts
|
|
1941
|
+
/** A mounted view of the host's accepted selection; it owns no manual tier map. */
|
|
1942
|
+
var SessionTierState = class {
|
|
1943
|
+
snapshot = {
|
|
1944
|
+
loading: true,
|
|
1945
|
+
saving: false,
|
|
1946
|
+
error: false
|
|
1947
|
+
};
|
|
1948
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1949
|
+
generation = 0;
|
|
1950
|
+
active = false;
|
|
1951
|
+
lifetime = 0;
|
|
1952
|
+
unsubscribe;
|
|
1953
|
+
scope;
|
|
1954
|
+
operations;
|
|
1955
|
+
constructor(scope, operations) {
|
|
1956
|
+
this.scope = scope;
|
|
1957
|
+
this.operations = operations;
|
|
1239
1958
|
}
|
|
1240
|
-
|
|
1959
|
+
getSnapshot = () => this.snapshot;
|
|
1960
|
+
subscribe = (listener) => {
|
|
1961
|
+
this.listeners.add(listener);
|
|
1962
|
+
return () => {
|
|
1963
|
+
this.listeners.delete(listener);
|
|
1964
|
+
};
|
|
1965
|
+
};
|
|
1966
|
+
publish(value) {
|
|
1967
|
+
this.snapshot = {
|
|
1968
|
+
...this.snapshot,
|
|
1969
|
+
...value
|
|
1970
|
+
};
|
|
1971
|
+
for (const listener of this.listeners) listener();
|
|
1972
|
+
}
|
|
1973
|
+
activate() {
|
|
1974
|
+
this.active = true;
|
|
1975
|
+
this.lifetime++;
|
|
1976
|
+
this.publish({ saving: false });
|
|
1977
|
+
this.unsubscribe = this.operations.subscribeSessionTiers?.(this.scope, () => {
|
|
1978
|
+
this.refresh();
|
|
1979
|
+
});
|
|
1980
|
+
this.refresh();
|
|
1981
|
+
}
|
|
1982
|
+
dispose() {
|
|
1983
|
+
this.active = false;
|
|
1984
|
+
this.generation++;
|
|
1985
|
+
this.unsubscribe?.();
|
|
1986
|
+
this.unsubscribe = void 0;
|
|
1987
|
+
}
|
|
1988
|
+
matches(value) {
|
|
1989
|
+
return !!value && value.region === this.scope.region && value.sessionId === this.scope.sessionId && value.modelId === this.scope.modelId;
|
|
1990
|
+
}
|
|
1991
|
+
async refresh() {
|
|
1992
|
+
if (!this.active) return;
|
|
1993
|
+
const generation = ++this.generation;
|
|
1994
|
+
this.publish({ loading: true });
|
|
1995
|
+
try {
|
|
1996
|
+
const selection = await this.operations.readSessionTier?.(this.scope);
|
|
1997
|
+
if (this.active && generation === this.generation) this.publish(this.matches(selection) ? {
|
|
1998
|
+
selection,
|
|
1999
|
+
loading: false,
|
|
2000
|
+
error: false
|
|
2001
|
+
} : {
|
|
2002
|
+
loading: false,
|
|
2003
|
+
error: true
|
|
2004
|
+
});
|
|
2005
|
+
} catch {
|
|
2006
|
+
if (this.active && generation === this.generation) this.publish({
|
|
2007
|
+
loading: false,
|
|
2008
|
+
error: true
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
async select(tierKey) {
|
|
2013
|
+
if (!this.active || this.snapshot.loading || this.snapshot.saving || !this.snapshot.selection) return;
|
|
2014
|
+
if (tierKey === this.snapshot.selection.tierKey && !this.snapshot.error) return;
|
|
2015
|
+
const generation = ++this.generation;
|
|
2016
|
+
const lifetime = this.lifetime;
|
|
2017
|
+
this.publish({
|
|
2018
|
+
saving: true,
|
|
2019
|
+
error: false
|
|
2020
|
+
});
|
|
2021
|
+
try {
|
|
2022
|
+
const { sessionId, modelId, region } = this.scope;
|
|
2023
|
+
const selection = await this.operations.setSessionTier?.(sessionId, modelId, tierKey, region);
|
|
2024
|
+
if (this.active && generation === this.generation) this.publish(this.matches(selection) ? {
|
|
2025
|
+
selection,
|
|
2026
|
+
error: false
|
|
2027
|
+
} : { error: true });
|
|
2028
|
+
} catch {
|
|
2029
|
+
if (this.active && generation === this.generation) this.publish({ error: true });
|
|
2030
|
+
} finally {
|
|
2031
|
+
if (this.active && lifetime === this.lifetime) this.publish({ saving: false });
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
};
|
|
1241
2035
|
//#endregion
|
|
1242
2036
|
//#region \0dsh-css:/home/runner/work/dsh-provider-qoder/dsh-provider-qoder/src/client/QoderContextSelect.module.css.mjs
|
|
1243
2037
|
const css = ".hiDrJa_root{align-items:center;display:inline-flex;position:relative}.hiDrJa_trigger{height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;user-select:none;background:0 0;border:none;border-radius:24px;outline:none;align-items:center;gap:4px;padding:0 8px;font-size:13px;font-weight:500;line-height:20px;transition:background .12s,color .12s;display:flex}.hiDrJa_trigger:hover,.hiDrJa_triggerActive{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.hiDrJa_trigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.hiDrJa_icon{color:var(--dsw-alias-label-caption);justify-content:center;align-items:center;display:inline-flex}.hiDrJa_label{white-space:nowrap}.hiDrJa_chevron{color:var(--dsw-alias-label-caption);align-items:center;transition:transform .12s;display:inline-flex}.hiDrJa_chevronOpen{transform:rotate(180deg)}.hiDrJa_menu{z-index:1100;background:var(--dsw-menu-surface-fill);min-width:180px;backdrop-filter:var(--dsw-menu-backdrop-filter);border:1px solid var(--dsw-alias-border-l1);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);border-radius:14px;flex-direction:column;padding:4px;animation:.12s hiDrJa_fadeIn;display:flex;position:absolute;bottom:calc(100% + 8px);right:0}@keyframes hiDrJa_fadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.hiDrJa_menuHeader{text-transform:uppercase;letter-spacing:.5px;color:var(--dsw-alias-label-tertiary);border-bottom:1px solid var(--dsw-alias-border-l1);margin-bottom:4px;padding:6px 10px 4px;font-size:11px;font-weight:600}.hiDrJa_option{box-sizing:border-box;width:100%;color:inherit;cursor:pointer;text-align:left;background:0 0;border:none;border-radius:8px;justify-content:space-between;align-items:center;gap:8px;padding:6px 10px;font-size:13px;line-height:20px;transition:background .1s;display:flex}.hiDrJa_option:hover{background:var(--dsw-alias-interactive-bg-hover)}.hiDrJa_optionSelected{color:var(--dsw-alias-state-brand);font-weight:600}.hiDrJa_optionInfo{align-items:center;gap:6px;display:flex}.hiDrJa_tag{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-caption);border-radius:4px;padding:1px 5px;font-size:11px;font-weight:500}.hiDrJa_check{color:var(--dsw-alias-state-brand);align-items:center;font-size:12px;display:inline-flex}.hiDrJa_error{color:var(--dsw-alias-label-primary);max-width:240px;font-size:12px}";
|
|
@@ -1270,30 +2064,9 @@ window.__ModuleLoader__.load({
|
|
|
1270
2064
|
//#endregion
|
|
1271
2065
|
//#region src/client/QoderContextSelect.tsx
|
|
1272
2066
|
function QoderContextSelect(props) {
|
|
1273
|
-
const { directory, operations,
|
|
1274
|
-
const [open, setOpen] = (0, react.useState)(false);
|
|
1275
|
-
const [manualTiers, setManualTiers] = (0, react.useState)({});
|
|
1276
|
-
const [pending, setPending] = (0, react.useState)(false);
|
|
1277
|
-
const [error, setError] = (0, react.useState)(null);
|
|
1278
|
-
const saving = (0, react.useRef)(false);
|
|
1279
|
-
const rootRef = (0, react.useRef)(null);
|
|
2067
|
+
const { directory, operations, sessionId, useProjection } = props;
|
|
1280
2068
|
const directoryState = (0, react.useSyncExternalStore)((fn) => directory ? directory.subscribe(fn) : () => () => {}, () => directory ? directory.getSnapshot() : null);
|
|
1281
2069
|
const modelSnapshot = (0, react.useSyncExternalStore)((fn) => operations ? operations.subscribeModels(fn) : () => () => {}, () => operations ? operations.getModelSnapshot() : null);
|
|
1282
|
-
(0, react.useEffect)(() => {
|
|
1283
|
-
if (!open) return;
|
|
1284
|
-
const handleClickOutside = (e) => {
|
|
1285
|
-
if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false);
|
|
1286
|
-
};
|
|
1287
|
-
const handleKeyDown = (e) => {
|
|
1288
|
-
if (e.key === "Escape") setOpen(false);
|
|
1289
|
-
};
|
|
1290
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
1291
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
1292
|
-
return () => {
|
|
1293
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
1294
|
-
document.removeEventListener("keydown", handleKeyDown);
|
|
1295
|
-
};
|
|
1296
|
-
}, [open]);
|
|
1297
2070
|
const modelProj = useProjection ? useProjection("modelSelection") : void 0;
|
|
1298
2071
|
const pressure = useProjection ? useProjection("contextPressure") : void 0;
|
|
1299
2072
|
if (!operations) return null;
|
|
@@ -1309,34 +2082,71 @@ window.__ModuleLoader__.load({
|
|
|
1309
2082
|
const currentProviderId = current.provider ?? (current.model.includes("/") ? current.model.split("/")[0] : void 0);
|
|
1310
2083
|
const activeModel = models.find((m) => m.id === currentModelId || m.id === current.model);
|
|
1311
2084
|
if (!isQoderProvider(currentProviderId) || !activeModel) return null;
|
|
1312
|
-
|
|
1313
|
-
if (
|
|
1314
|
-
|
|
2085
|
+
if (contextTiersOf(activeModel).length <= 1) return null;
|
|
2086
|
+
if (!sessionId) return null;
|
|
2087
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionContextSelect, {
|
|
2088
|
+
...props,
|
|
2089
|
+
sessionId,
|
|
2090
|
+
operations,
|
|
2091
|
+
region,
|
|
2092
|
+
activeModel,
|
|
2093
|
+
historicalWindow: pressure?.contextWindow,
|
|
2094
|
+
lastUsed: modelProj?.lastUsed
|
|
2095
|
+
}, JSON.stringify([
|
|
1315
2096
|
region,
|
|
1316
2097
|
sessionId,
|
|
1317
2098
|
activeModel.id
|
|
1318
|
-
])
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
const
|
|
1323
|
-
const
|
|
2099
|
+
]));
|
|
2100
|
+
}
|
|
2101
|
+
function SessionContextSelect({ operations, sessionId, region, activeModel, t, historicalWindow, lastUsed }) {
|
|
2102
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
2103
|
+
const rootRef = (0, react.useRef)(null);
|
|
2104
|
+
const state = (0, react.useMemo)(() => new SessionTierState({
|
|
2105
|
+
region,
|
|
2106
|
+
sessionId,
|
|
2107
|
+
modelId: activeModel.id
|
|
2108
|
+
}, operations), [
|
|
2109
|
+
region,
|
|
2110
|
+
sessionId,
|
|
2111
|
+
activeModel.id,
|
|
2112
|
+
operations
|
|
2113
|
+
]);
|
|
2114
|
+
const snapshot = (0, react.useSyncExternalStore)(state.subscribe, state.getSnapshot);
|
|
2115
|
+
(0, react.useLayoutEffect)(() => {
|
|
2116
|
+
state.activate();
|
|
2117
|
+
return () => state.dispose();
|
|
2118
|
+
}, [state]);
|
|
2119
|
+
(0, react.useEffect)(() => {
|
|
2120
|
+
state.refresh();
|
|
2121
|
+
}, [
|
|
2122
|
+
state,
|
|
2123
|
+
JSON.stringify(activeModel),
|
|
2124
|
+
historicalWindow,
|
|
2125
|
+
lastUsed?.provider,
|
|
2126
|
+
lastUsed?.model
|
|
2127
|
+
]);
|
|
2128
|
+
(0, react.useEffect)(() => {
|
|
2129
|
+
if (!open) return;
|
|
2130
|
+
const handleClickOutside = (e) => {
|
|
2131
|
+
if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false);
|
|
2132
|
+
};
|
|
2133
|
+
const handleKeyDown = (e) => {
|
|
2134
|
+
if (e.key === "Escape") setOpen(false);
|
|
2135
|
+
};
|
|
2136
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
2137
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
2138
|
+
return () => {
|
|
2139
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
2140
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
2141
|
+
};
|
|
2142
|
+
}, [open]);
|
|
2143
|
+
const tiers = contextTiersOf(activeModel);
|
|
2144
|
+
const currentTier = snapshot.selection;
|
|
2145
|
+
const selectedTierKey = currentTier?.tierKey;
|
|
2146
|
+
const pending = snapshot.loading || snapshot.saving;
|
|
2147
|
+
const selectTier = (tierKey) => {
|
|
1324
2148
|
setOpen(false);
|
|
1325
|
-
|
|
1326
|
-
if (tierKey === selectedTierKey && error?.key !== sessionKey) return;
|
|
1327
|
-
saving.current = true;
|
|
1328
|
-
setPending(true);
|
|
1329
|
-
setError(null);
|
|
1330
|
-
try {
|
|
1331
|
-
if (await saveContextSelection(operations, sessionId, region, activeModel.id, tierKey) === "saved") setManualTiers((prev) => ({
|
|
1332
|
-
...prev,
|
|
1333
|
-
[sessionKey]: tierKey
|
|
1334
|
-
}));
|
|
1335
|
-
else setError({ key: sessionKey });
|
|
1336
|
-
} finally {
|
|
1337
|
-
saving.current = false;
|
|
1338
|
-
setPending(false);
|
|
1339
|
-
}
|
|
2149
|
+
state.select(tierKey);
|
|
1340
2150
|
};
|
|
1341
2151
|
const defaultSuffix = t ? t("contextTierDefaultSuffix").replace(/[()()]/g, "") : "默认";
|
|
1342
2152
|
const selectTitle = t ? t("contextSelectTitle") : "选择上下文大小";
|
|
@@ -1348,10 +2158,10 @@ window.__ModuleLoader__.load({
|
|
|
1348
2158
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1349
2159
|
type: "button",
|
|
1350
2160
|
className: `${QoderContextSelect_module_css_default.trigger} ${open ? QoderContextSelect_module_css_default.triggerActive : ""}`,
|
|
1351
|
-
disabled: pending || !
|
|
2161
|
+
disabled: pending || !currentTier,
|
|
1352
2162
|
"aria-expanded": open,
|
|
1353
2163
|
"aria-label": selectTitle,
|
|
1354
|
-
title: `${selectTitle}: ${formatContextTokens(currentTier.tokenCount)}`,
|
|
2164
|
+
title: `${selectTitle}: ${currentTier ? formatContextTokens(currentTier.tokenCount) : "…"}`,
|
|
1355
2165
|
onClick: () => setOpen((prev) => !prev),
|
|
1356
2166
|
children: [
|
|
1357
2167
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -1366,7 +2176,7 @@ window.__ModuleLoader__.load({
|
|
|
1366
2176
|
}),
|
|
1367
2177
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1368
2178
|
className: QoderContextSelect_module_css_default.label,
|
|
1369
|
-
children: formatContextTokens(currentTier.tokenCount)
|
|
2179
|
+
children: currentTier ? formatContextTokens(currentTier.tokenCount) : "…"
|
|
1370
2180
|
}),
|
|
1371
2181
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1372
2182
|
className: `${QoderContextSelect_module_css_default.chevron} ${open ? QoderContextSelect_module_css_default.chevronOpen : ""}`,
|
|
@@ -1384,10 +2194,21 @@ window.__ModuleLoader__.load({
|
|
|
1384
2194
|
})
|
|
1385
2195
|
]
|
|
1386
2196
|
}),
|
|
1387
|
-
error &&
|
|
2197
|
+
snapshot.error && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1388
2198
|
role: "alert",
|
|
1389
2199
|
className: QoderContextSelect_module_css_default.error,
|
|
1390
|
-
children:
|
|
2200
|
+
children: [
|
|
2201
|
+
t ? t("contextSelectFailed") : "contextSelectFailed",
|
|
2202
|
+
" ",
|
|
2203
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2204
|
+
type: "button",
|
|
2205
|
+
disabled: pending,
|
|
2206
|
+
onClick: () => {
|
|
2207
|
+
state.refresh();
|
|
2208
|
+
},
|
|
2209
|
+
children: t ? t("refresh") : "refresh"
|
|
2210
|
+
})
|
|
2211
|
+
]
|
|
1391
2212
|
}),
|
|
1392
2213
|
open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1393
2214
|
className: QoderContextSelect_module_css_default.menu,
|
|
@@ -1401,6 +2222,7 @@ window.__ModuleLoader__.load({
|
|
|
1401
2222
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1402
2223
|
type: "button",
|
|
1403
2224
|
role: "menuitemradio",
|
|
2225
|
+
disabled: pending,
|
|
1404
2226
|
"aria-checked": isSelected,
|
|
1405
2227
|
className: `${QoderContextSelect_module_css_default.option} ${isSelected ? QoderContextSelect_module_css_default.optionSelected : ""}`,
|
|
1406
2228
|
onClick: () => {
|
|
@@ -1456,6 +2278,97 @@ window.__ModuleLoader__.load({
|
|
|
1456
2278
|
return typeof value === "string" && qoderRpcErrorCodes.includes(value);
|
|
1457
2279
|
}
|
|
1458
2280
|
//#endregion
|
|
2281
|
+
//#region src/client/session-tier-events.ts
|
|
2282
|
+
/** One authenticated host change stream shared by the mounted composer controls. */
|
|
2283
|
+
function createSessionTierEvents(send = (...args) => globalThis.fetch(...args)) {
|
|
2284
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
2285
|
+
let active;
|
|
2286
|
+
let disposed = false;
|
|
2287
|
+
const notify = (scope) => {
|
|
2288
|
+
for (const entry of listeners) if (!scope || entry.scope.region === scope.region && entry.scope.sessionId === scope.sessionId && entry.scope.modelId === scope.modelId) try {
|
|
2289
|
+
entry.listener();
|
|
2290
|
+
} catch {}
|
|
2291
|
+
};
|
|
2292
|
+
const start = () => {
|
|
2293
|
+
if (active || disposed || !listeners.size) return;
|
|
2294
|
+
const controller = new AbortController();
|
|
2295
|
+
active = controller;
|
|
2296
|
+
follow(controller).finally(() => {
|
|
2297
|
+
if (active === controller) active = void 0;
|
|
2298
|
+
});
|
|
2299
|
+
};
|
|
2300
|
+
async function follow(controller) {
|
|
2301
|
+
let delay = 1e3;
|
|
2302
|
+
while (!controller.signal.aborted) {
|
|
2303
|
+
try {
|
|
2304
|
+
const response = await send(qoderRpcPath("sessionTierEvents"), {
|
|
2305
|
+
method: "POST",
|
|
2306
|
+
credentials: "include",
|
|
2307
|
+
signal: controller.signal,
|
|
2308
|
+
headers: { "content-type": "application/json" },
|
|
2309
|
+
body: "{}"
|
|
2310
|
+
});
|
|
2311
|
+
if (!response.ok || !response.body) throw new Error("Context tier stream unavailable");
|
|
2312
|
+
const reader = response.body.getReader();
|
|
2313
|
+
const decoder = new TextDecoder();
|
|
2314
|
+
let buffered = "";
|
|
2315
|
+
try {
|
|
2316
|
+
while (!controller.signal.aborted) {
|
|
2317
|
+
const { value, done } = await reader.read();
|
|
2318
|
+
if (done) break;
|
|
2319
|
+
buffered += decoder.decode(value, { stream: true });
|
|
2320
|
+
let newline;
|
|
2321
|
+
while ((newline = buffered.indexOf("\n")) >= 0) {
|
|
2322
|
+
const item = JSON.parse(buffered.slice(0, newline));
|
|
2323
|
+
buffered = buffered.slice(newline + 1);
|
|
2324
|
+
delay = 1e3;
|
|
2325
|
+
if (item.ready === true) notify();
|
|
2326
|
+
else if ((item.region === "global" || item.region === "china") && typeof item.sessionId === "string" && typeof item.modelId === "string") notify(item);
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
} finally {
|
|
2330
|
+
await reader.cancel().catch(() => {});
|
|
2331
|
+
reader.releaseLock();
|
|
2332
|
+
}
|
|
2333
|
+
} catch {}
|
|
2334
|
+
if (controller.signal.aborted) break;
|
|
2335
|
+
await new Promise((resolve) => {
|
|
2336
|
+
const finish = () => {
|
|
2337
|
+
clearTimeout(timer);
|
|
2338
|
+
controller.signal.removeEventListener("abort", finish);
|
|
2339
|
+
resolve();
|
|
2340
|
+
};
|
|
2341
|
+
const timer = setTimeout(finish, delay);
|
|
2342
|
+
controller.signal.addEventListener("abort", finish, { once: true });
|
|
2343
|
+
});
|
|
2344
|
+
delay = Math.min(delay * 2, 3e4);
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
return {
|
|
2348
|
+
subscribe(scope, listener) {
|
|
2349
|
+
const entry = {
|
|
2350
|
+
scope,
|
|
2351
|
+
listener
|
|
2352
|
+
};
|
|
2353
|
+
listeners.add(entry);
|
|
2354
|
+
start();
|
|
2355
|
+
return () => {
|
|
2356
|
+
listeners.delete(entry);
|
|
2357
|
+
if (!listeners.size) {
|
|
2358
|
+
active?.abort();
|
|
2359
|
+
active = void 0;
|
|
2360
|
+
}
|
|
2361
|
+
};
|
|
2362
|
+
},
|
|
2363
|
+
dispose() {
|
|
2364
|
+
disposed = true;
|
|
2365
|
+
listeners.clear();
|
|
2366
|
+
active?.abort();
|
|
2367
|
+
active = void 0;
|
|
2368
|
+
}
|
|
2369
|
+
};
|
|
2370
|
+
}
|
|
2371
|
+
//#endregion
|
|
1459
2372
|
//#region src/client/rpc-client.ts
|
|
1460
2373
|
/**
|
|
1461
2374
|
* Browser caller for the Qoder settings RPC.
|
|
@@ -1551,23 +2464,29 @@ window.__ModuleLoader__.load({
|
|
|
1551
2464
|
}), "provider-qoder: credential copy");
|
|
1552
2465
|
const credentials = ctx.remote.credentials;
|
|
1553
2466
|
const rpc = createQoderRpcCaller();
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
const readModelSnapshot = () =>
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
2467
|
+
const tierEvents = createSessionTierEvents();
|
|
2468
|
+
ctx.effect(() => () => tierEvents.dispose(), "provider-qoder: session context tier events");
|
|
2469
|
+
const readModelSnapshot = () => modelScope.getSnapshot();
|
|
2470
|
+
const authorizationOperations = {
|
|
2471
|
+
read: (region) => rpc.call("authorization", { region }),
|
|
2472
|
+
begin: (region) => rpc.call("beginLogin", { region }),
|
|
2473
|
+
cancel: (region) => rpc.call("cancelLogin", { region }),
|
|
2474
|
+
select: (region, method) => rpc.call("selectAuthorization", {
|
|
2475
|
+
region,
|
|
2476
|
+
method
|
|
2477
|
+
})
|
|
1564
2478
|
};
|
|
1565
|
-
readModelSnapshot();
|
|
1566
|
-
ctx.effect(() => modelScope.subscribe(() => {
|
|
1567
|
-
readModelSnapshot();
|
|
1568
|
-
}), "provider-qoder: context history region");
|
|
1569
2479
|
const operations = {
|
|
2480
|
+
authorization: authorizationOperations,
|
|
1570
2481
|
describe: async () => {
|
|
2482
|
+
const result = await authorizationOperations.read(regionOf(readModelSnapshot().value));
|
|
2483
|
+
return result.ok ? {
|
|
2484
|
+
configured: result.value.configured && !result.value.expired,
|
|
2485
|
+
source: result.value.method,
|
|
2486
|
+
writable: result.value.writable
|
|
2487
|
+
} : void 0;
|
|
2488
|
+
},
|
|
2489
|
+
describePat: async () => {
|
|
1571
2490
|
try {
|
|
1572
2491
|
const response = await credentials.describe([qoderCredentialRef]);
|
|
1573
2492
|
return response.ok ? response.value[qoderCredentialRef] : void 0;
|
|
@@ -1577,7 +2496,13 @@ window.__ModuleLoader__.load({
|
|
|
1577
2496
|
},
|
|
1578
2497
|
store: async (value) => {
|
|
1579
2498
|
try {
|
|
1580
|
-
|
|
2499
|
+
const response = await credentials.set(qoderCredentialRef, value.trim());
|
|
2500
|
+
if (response.ok) {
|
|
2501
|
+
const region = regionOf(readModelSnapshot().value);
|
|
2502
|
+
const current = await authorizationOperations.read(region);
|
|
2503
|
+
if (current.ok && current.value.method !== "pat") return (await authorizationOperations.select(region, "pat")).ok;
|
|
2504
|
+
}
|
|
2505
|
+
return response.ok;
|
|
1581
2506
|
} catch {
|
|
1582
2507
|
return false;
|
|
1583
2508
|
}
|
|
@@ -1591,16 +2516,15 @@ window.__ModuleLoader__.load({
|
|
|
1591
2516
|
},
|
|
1592
2517
|
getAccount: async (force) => await rpc.call("account", { force }),
|
|
1593
2518
|
getModelSnapshot: readModelSnapshot,
|
|
1594
|
-
canRestoreContextHistory: () => !historyRegionChanged,
|
|
1595
2519
|
subscribeModels: (listener) => modelScope.subscribe(listener),
|
|
1596
2520
|
storeModels: async (region, models) => {
|
|
1597
2521
|
try {
|
|
1598
|
-
const
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
}) !== false;
|
|
2522
|
+
const clonedModels = JSON.parse(JSON.stringify(models));
|
|
2523
|
+
return await modelScope.mutate([{
|
|
2524
|
+
op: "set",
|
|
2525
|
+
path: ["modelsByRegion", region],
|
|
2526
|
+
value: clonedModels
|
|
2527
|
+
}]) !== false;
|
|
1604
2528
|
} catch {
|
|
1605
2529
|
return false;
|
|
1606
2530
|
}
|
|
@@ -1621,20 +2545,56 @@ window.__ModuleLoader__.load({
|
|
|
1621
2545
|
},
|
|
1622
2546
|
discoverModels: async () => await rpc.call("models", {}),
|
|
1623
2547
|
setSessionTier: async (sessionId, modelId, tierKey, region) => {
|
|
2548
|
+
const scope = {
|
|
2549
|
+
sessionId,
|
|
2550
|
+
modelId,
|
|
2551
|
+
tierKey,
|
|
2552
|
+
region
|
|
2553
|
+
};
|
|
1624
2554
|
try {
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
} catch {
|
|
1632
|
-
|
|
2555
|
+
const res = await rpc.call("sessionTier", scope);
|
|
2556
|
+
if (!res.ok) console.error("[Qoder context tier] Failed to save selection", {
|
|
2557
|
+
...scope,
|
|
2558
|
+
error: res.error
|
|
2559
|
+
});
|
|
2560
|
+
return res.ok ? res.value : void 0;
|
|
2561
|
+
} catch (error) {
|
|
2562
|
+
console.error("[Qoder context tier] Failed to save selection", {
|
|
2563
|
+
...scope,
|
|
2564
|
+
error
|
|
2565
|
+
});
|
|
2566
|
+
return;
|
|
1633
2567
|
}
|
|
1634
2568
|
},
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
2569
|
+
readSessionTier: async (scope) => {
|
|
2570
|
+
try {
|
|
2571
|
+
const result = await rpc.call("readSessionTier", scope);
|
|
2572
|
+
if (!result.ok) console.error("[Qoder context tier] Failed to read selection", {
|
|
2573
|
+
...scope,
|
|
2574
|
+
error: result.error
|
|
2575
|
+
});
|
|
2576
|
+
return result.ok ? result.value : void 0;
|
|
2577
|
+
} catch (error) {
|
|
2578
|
+
console.error("[Qoder context tier] Failed to read selection", {
|
|
2579
|
+
...scope,
|
|
2580
|
+
error
|
|
2581
|
+
});
|
|
2582
|
+
return;
|
|
2583
|
+
}
|
|
2584
|
+
},
|
|
2585
|
+
subscribeSessionTiers: (scope, listener) => tierEvents.subscribe(scope, listener),
|
|
2586
|
+
subscribe: (listener) => {
|
|
2587
|
+
const reference = ctx.remote.$on("credentials/reference-updated", (ref) => {
|
|
2588
|
+
if (ref === "QODER_MANAGED_CREDENTIAL") listener();
|
|
2589
|
+
});
|
|
2590
|
+
const record = ctx.remote.$on("credentials/record-updated", (key) => {
|
|
2591
|
+
if (key === `provider-qoder/${regionOf(readModelSnapshot().value)}`) listener();
|
|
2592
|
+
});
|
|
2593
|
+
return () => {
|
|
2594
|
+
reference();
|
|
2595
|
+
record();
|
|
2596
|
+
};
|
|
2597
|
+
}
|
|
1638
2598
|
};
|
|
1639
2599
|
const rawT = ctx.locale.bind(localeNamespace);
|
|
1640
2600
|
const t = (key, values) => {
|
|
@@ -1646,6 +2606,17 @@ window.__ModuleLoader__.load({
|
|
|
1646
2606
|
* switch re-resolves provider copy instead of reusing a setup-time snapshot.
|
|
1647
2607
|
*/
|
|
1648
2608
|
const activeLocale = () => ctx.locale.getLocale().active;
|
|
2609
|
+
ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
|
|
2610
|
+
name: "conversation.input.dock",
|
|
2611
|
+
id: "qoder-model-queue",
|
|
2612
|
+
order: 30,
|
|
2613
|
+
locale: localeNamespace,
|
|
2614
|
+
inject: (sessionId) => ({
|
|
2615
|
+
sessionId,
|
|
2616
|
+
rpc,
|
|
2617
|
+
t
|
|
2618
|
+
})
|
|
2619
|
+
}, QoderQueueStatus));
|
|
1649
2620
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
1650
2621
|
name: "settings.section",
|
|
1651
2622
|
id: "qoder",
|