dsh-provider-qoder 0.2.0 → 0.3.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 +9 -8
- package/README_CN.md +9 -8
- package/cordis.patch.yml +5 -0
- package/lib/client.js +408 -176
- package/lib/index.d.ts +113 -2
- package/lib/index.js +638 -79
- package/package.json +4 -2
package/lib/client.js
CHANGED
|
@@ -14,8 +14,186 @@ window.__ModuleLoader__.load({
|
|
|
14
14
|
return source === "env" || source?.endsWith("-env") === true;
|
|
15
15
|
}
|
|
16
16
|
//#endregion
|
|
17
|
+
//#region src/client/locales.ts
|
|
18
|
+
const zh = {
|
|
19
|
+
nav: "Qoder",
|
|
20
|
+
title: "Qoder 凭据",
|
|
21
|
+
configured: "已配置",
|
|
22
|
+
missing: "未配置",
|
|
23
|
+
loading: "正在读取凭据状态…",
|
|
24
|
+
loadFailed: "无法读取凭据状态。",
|
|
25
|
+
retry: "重试",
|
|
26
|
+
edit: "编辑",
|
|
27
|
+
cancel: "取消",
|
|
28
|
+
regionLabel: "服务区域",
|
|
29
|
+
regionGlobal: "国际版 (Global)",
|
|
30
|
+
regionChina: "中国区 (CN)",
|
|
31
|
+
regionHint: "请确保 PAT 与所选服务区域匹配。",
|
|
32
|
+
tokenLabel: "API 密钥",
|
|
33
|
+
tokenPlaceholder: "输入新的 Personal Access Token",
|
|
34
|
+
configuredHint: "已配置——输入新值可替换",
|
|
35
|
+
readOnly: "当前凭据存储不可写。",
|
|
36
|
+
save: "保存",
|
|
37
|
+
saving: "正在保存…",
|
|
38
|
+
saved: "Qoder 设置已保存。",
|
|
39
|
+
saveFailed: "Qoder 设置保存失败,请重试。",
|
|
40
|
+
remove: "删除",
|
|
41
|
+
removing: "正在删除…",
|
|
42
|
+
removeFailed: "凭据删除失败,请重试。",
|
|
43
|
+
confirmRemove: "删除已保存的 Qoder 凭据?删除后,新的模型请求将无法运行。",
|
|
44
|
+
customized: "自定义设置",
|
|
45
|
+
modelsTitle: "模型目录",
|
|
46
|
+
modelsLoading: "正在读取模型设置…",
|
|
47
|
+
modelsUnavailable: "当前无法读取或保存模型设置。",
|
|
48
|
+
modelsEnabled: "已启用 {count} 个模型",
|
|
49
|
+
modelsFetch: "获取可用模型",
|
|
50
|
+
modelsFetching: "正在获取…",
|
|
51
|
+
modelsFetchFailed: "无法获取可用模型。",
|
|
52
|
+
modelsRequired: "至少需要保留一个模型。",
|
|
53
|
+
modelUnavailable: "不可用",
|
|
54
|
+
modelRate: "{value}x",
|
|
55
|
+
modelRateUnknown: "倍率未知",
|
|
56
|
+
accountTitle: "Qoder",
|
|
57
|
+
accountLoading: "正在读取账号与额度…",
|
|
58
|
+
accountFailed: "无法读取账号信息与额度。",
|
|
59
|
+
accountCredentialHint: "请先在“模型”设置中配置 Qoder Personal Access Token。",
|
|
60
|
+
refresh: "刷新",
|
|
61
|
+
refreshing: "正在刷新…",
|
|
62
|
+
userQuotaTitle: "个人额度",
|
|
63
|
+
orgResourceTitle: "组织资源包",
|
|
64
|
+
dedicatedResourceTitle: "专属资源包",
|
|
65
|
+
dedicatedResourceExpiresAt: "有效期至:{value}",
|
|
66
|
+
quotaRemaining: "剩余 {value}%",
|
|
67
|
+
quotaUsed: "已用 {used} / {total} {unit}",
|
|
68
|
+
resetsAt: "重置时间:{value}",
|
|
69
|
+
noQuota: "暂无可用额度信息",
|
|
70
|
+
quotaExceeded: "当前订阅额度已用尽。",
|
|
71
|
+
plan: "套餐计划",
|
|
72
|
+
planExpiresAt: "有效期至:{value}",
|
|
73
|
+
organization: "组织:{name}",
|
|
74
|
+
accountSuspended: "当前账号或组织已被暂停/冻结。",
|
|
75
|
+
searchModeLabel: "联网搜索模式",
|
|
76
|
+
searchModeAuto: "智能路由 (自动)",
|
|
77
|
+
searchModeAlways: "始终使用 Qoder",
|
|
78
|
+
searchModeDisabled: "禁用",
|
|
79
|
+
searchModeHint: "智能路由模式下,使用 Qoder 模型时走 Qoder 搜索,使用其他模型时自动回退给备用搜索。"
|
|
80
|
+
};
|
|
81
|
+
const en = {
|
|
82
|
+
nav: "Qoder",
|
|
83
|
+
title: "Qoder credential",
|
|
84
|
+
configured: "Configured",
|
|
85
|
+
missing: "Not configured",
|
|
86
|
+
loading: "Reading credential status…",
|
|
87
|
+
loadFailed: "Could not read credential status.",
|
|
88
|
+
retry: "Retry",
|
|
89
|
+
edit: "Edit",
|
|
90
|
+
cancel: "Cancel",
|
|
91
|
+
regionLabel: "Service Region",
|
|
92
|
+
regionGlobal: "Global",
|
|
93
|
+
regionChina: "China (CN)",
|
|
94
|
+
regionHint: "Ensure your PAT matches the selected service region.",
|
|
95
|
+
tokenLabel: "API Key",
|
|
96
|
+
tokenPlaceholder: "Enter a new Personal Access Token",
|
|
97
|
+
configuredHint: "Configured — enter a new value to replace",
|
|
98
|
+
readOnly: "The current credential store is read-only.",
|
|
99
|
+
save: "Save",
|
|
100
|
+
saving: "Saving…",
|
|
101
|
+
saved: "Qoder settings saved.",
|
|
102
|
+
saveFailed: "Could not save the Qoder settings. Try again.",
|
|
103
|
+
remove: "Remove",
|
|
104
|
+
removing: "Removing…",
|
|
105
|
+
removeFailed: "Could not remove the credential. Try again.",
|
|
106
|
+
confirmRemove: "Remove the stored Qoder credential? New model requests will stop working.",
|
|
107
|
+
customized: "Custom settings",
|
|
108
|
+
modelsTitle: "Model catalog",
|
|
109
|
+
modelsLoading: "Reading model settings…",
|
|
110
|
+
modelsUnavailable: "Model settings cannot currently be read or saved.",
|
|
111
|
+
modelsEnabled: "{count} models enabled",
|
|
112
|
+
modelsFetch: "Fetch available models",
|
|
113
|
+
modelsFetching: "Fetching…",
|
|
114
|
+
modelsFetchFailed: "Could not fetch available models.",
|
|
115
|
+
modelsRequired: "Keep at least one model.",
|
|
116
|
+
modelUnavailable: "Unavailable",
|
|
117
|
+
modelRate: "{value}x",
|
|
118
|
+
modelRateUnknown: "Rate unknown",
|
|
119
|
+
accountTitle: "Qoder",
|
|
120
|
+
accountLoading: "Reading account and quota…",
|
|
121
|
+
accountFailed: "Could not read account details or quota.",
|
|
122
|
+
accountCredentialHint: "Configure the Qoder Personal Access Token in Models settings first.",
|
|
123
|
+
refresh: "Refresh",
|
|
124
|
+
refreshing: "Refreshing…",
|
|
125
|
+
userQuotaTitle: "Personal Quota",
|
|
126
|
+
orgResourceTitle: "Org Resource Package",
|
|
127
|
+
dedicatedResourceTitle: "Dedicated Resource Package",
|
|
128
|
+
dedicatedResourceExpiresAt: "Expires at: {value}",
|
|
129
|
+
quotaRemaining: "{value}% remaining",
|
|
130
|
+
quotaUsed: "Used {used} / {total} {unit}",
|
|
131
|
+
resetsAt: "Resets: {value}",
|
|
132
|
+
noQuota: "No quota metrics available",
|
|
133
|
+
quotaExceeded: "The current subscription quota is exhausted.",
|
|
134
|
+
plan: "Plan",
|
|
135
|
+
planExpiresAt: "Expires at: {value}",
|
|
136
|
+
organization: "Org: {name}",
|
|
137
|
+
accountSuspended: "Account or organization is currently suspended.",
|
|
138
|
+
searchModeLabel: "Web Search Mode",
|
|
139
|
+
searchModeAuto: "Smart Routing (Auto)",
|
|
140
|
+
searchModeAlways: "Always use Qoder",
|
|
141
|
+
searchModeDisabled: "Disabled",
|
|
142
|
+
searchModeHint: "In auto mode, searches route to Qoder when using Qoder models, and fall back to ambient providers otherwise."
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Compare one provider language tag against the requested locale.
|
|
146
|
+
*
|
|
147
|
+
* `prefix` additionally accepts a shared primary subtag, which is what lets the
|
|
148
|
+
* built-in `zh`/`en` ids reach the provider's `zh-CN`/`en-US` keys.
|
|
149
|
+
*/
|
|
150
|
+
function localeMatches(tag, requested, prefix) {
|
|
151
|
+
const normalized = tag.trim().toLowerCase();
|
|
152
|
+
if (normalized === requested) return true;
|
|
153
|
+
if (!prefix) return false;
|
|
154
|
+
const primary = requested.split("-")[0];
|
|
155
|
+
return primary.length > 0 && normalized.split("-")[0] === primary;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Return the first provider translation whose language tag matches the request.
|
|
159
|
+
*
|
|
160
|
+
* `prefix` decides whether a shared primary subtag counts as a match; blank
|
|
161
|
+
* translations are skipped so they cannot shadow a later usable one.
|
|
162
|
+
*/
|
|
163
|
+
function pickLocalizedValue(values, requested, prefix) {
|
|
164
|
+
for (const [tag, value] of Object.entries(values)) {
|
|
165
|
+
if (!localeMatches(tag, requested, prefix)) continue;
|
|
166
|
+
const text = typeof value === "string" ? value.trim() : "";
|
|
167
|
+
if (text.length > 0) return text;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Resolve provider copy for the active UI locale.
|
|
172
|
+
*
|
|
173
|
+
* Order: exact language tag, then a shared primary subtag, then the provider's
|
|
174
|
+
* language-neutral fallback, then any translation at all. The client owns this
|
|
175
|
+
* choice because only it knows the locale the user is reading.
|
|
176
|
+
*/
|
|
177
|
+
function resolveLocalizedText(text, locale) {
|
|
178
|
+
if (!text) return void 0;
|
|
179
|
+
const values = text.values ?? {};
|
|
180
|
+
const requested = typeof locale === "string" ? locale.trim().toLowerCase() : "";
|
|
181
|
+
if (requested.length > 0) {
|
|
182
|
+
const exact = pickLocalizedValue(values, requested, false);
|
|
183
|
+
if (exact !== void 0) return exact;
|
|
184
|
+
const related = pickLocalizedValue(values, requested, true);
|
|
185
|
+
if (related !== void 0) return related;
|
|
186
|
+
}
|
|
187
|
+
const fallback = typeof text.fallback === "string" ? text.fallback.trim() : "";
|
|
188
|
+
if (fallback.length > 0) return fallback;
|
|
189
|
+
for (const value of Object.values(values)) {
|
|
190
|
+
const candidate = typeof value === "string" ? value.trim() : "";
|
|
191
|
+
if (candidate.length > 0) return candidate;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
//#endregion
|
|
17
195
|
//#region \0dsh-css:/home/runner/work/dsh-provider-qoder/dsh-provider-qoder/src/client/QoderCredentialCard.module.css.mjs
|
|
18
|
-
const css = ".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:1px solid var(--dsw-alias-border-l2);border-radius: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-top:1px solid var(--dsw-alias-border-l2);margin-top:14px;padding-top:10px}.SRqrhW_customizedSummary{cursor:pointer;width:fit-content;color:var(--dsw-alias-label-secondary);border-radius:6px;align-items:center;gap:6px;margin-left:-4px;padding:2px 4px;font-size:12px;font-weight:500;line-height:18px;list-style:none;display: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_customizedBody{padding-top:12px}.SRqrhW_modelCatalog,.SRqrhW_modelList{flex-direction:column;gap:10px;display:flex}.SRqrhW_modelCatalogHead{justify-content:space-between;align-items:flex-start;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{cursor:pointer;border-radius:6px;grid-template-columns:auto minmax(0,1fr) auto auto auto;align-items:center;gap:8px;padding:6px 8px;font-size:13px;display:grid}.SRqrhW_modelChoice:hover{background:var(--dsw-alias-interactive-bg-hover)}.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{background:var(--dsw-alias-bg-module-platform);border-radius:8px;flex-direction:column;gap:10px;margin-top:12px;padding:12px;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_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}";
|
|
196
|
+
const css = ".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:1px solid var(--dsw-alias-border-l2);border-radius: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-top:1px solid var(--dsw-alias-border-l2);margin-top:14px;padding-top:10px}.SRqrhW_customizedSummary{cursor:pointer;width:fit-content;color:var(--dsw-alias-label-secondary);border-radius:6px;align-items:center;gap:6px;margin-left:-4px;padding:2px 4px;font-size:12px;font-weight:500;line-height:18px;list-style:none;display: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_customizedBody{padding-top:12px}.SRqrhW_modelCatalog,.SRqrhW_modelList{flex-direction:column;gap:10px;display:flex}.SRqrhW_modelCatalogHead{justify-content:space-between;align-items:flex-start;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{cursor:pointer;border-radius:6px;grid-template-columns:auto minmax(0,1fr) auto auto auto;align-items:center;gap:8px;padding:6px 8px;font-size:13px;display:grid}.SRqrhW_modelChoice:hover{background:var(--dsw-alias-interactive-bg-hover)}.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{background:var(--dsw-alias-bg-module-platform);border-radius:8px;flex-direction:column;gap:10px;margin-top:12px;padding:12px;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-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:8px;margin-top:16px;padding-top:14px;display:flex}.SRqrhW_searchModeHintText{color:var(--dsw-alias-label-secondary);margin:4px 0 0;font-size:12px;line-height:18px}";
|
|
19
197
|
const tagId = "dsh-provider-qoder/QoderCredentialCard.module.css";
|
|
20
198
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
21
199
|
const tag = document.createElement("style");
|
|
@@ -67,6 +245,7 @@ window.__ModuleLoader__.load({
|
|
|
67
245
|
"planBadge": "SRqrhW_planBadge",
|
|
68
246
|
"primary": "SRqrhW_primary",
|
|
69
247
|
"quotaBlock": "SRqrhW_quotaBlock",
|
|
248
|
+
"quotaDescription": "SRqrhW_quotaDescription",
|
|
70
249
|
"quotaHeader": "SRqrhW_quotaHeader",
|
|
71
250
|
"quotaLabel": "SRqrhW_quotaLabel",
|
|
72
251
|
"quotaMeta": "SRqrhW_quotaMeta",
|
|
@@ -79,6 +258,8 @@ window.__ModuleLoader__.load({
|
|
|
79
258
|
"regionOptionActive": "SRqrhW_regionOptionActive",
|
|
80
259
|
"regionOptionDisabled": "SRqrhW_regionOptionDisabled",
|
|
81
260
|
"regionSelector": "SRqrhW_regionSelector",
|
|
261
|
+
"searchModeHintText": "SRqrhW_searchModeHintText",
|
|
262
|
+
"searchModeSection": "SRqrhW_searchModeSection",
|
|
82
263
|
"secondary": "SRqrhW_secondary",
|
|
83
264
|
"status": "SRqrhW_status",
|
|
84
265
|
"success": "SRqrhW_success",
|
|
@@ -102,12 +283,17 @@ window.__ModuleLoader__.load({
|
|
|
102
283
|
minute: "2-digit"
|
|
103
284
|
});
|
|
104
285
|
}
|
|
105
|
-
|
|
286
|
+
/**
|
|
287
|
+
* Settings card for the Qoder subscription: credential state, subscriber
|
|
288
|
+
* profile, and every quota block the provider reports.
|
|
289
|
+
*/
|
|
290
|
+
function QoderAccountCard({ operations, t, activeLocale }) {
|
|
106
291
|
const [credentialState, setCredentialState] = (0, react.useState)({ status: "loading" });
|
|
107
292
|
const [accountState, setAccountState] = (0, react.useState)({ status: "idle" });
|
|
108
293
|
const [refreshing, setRefreshing] = (0, react.useState)(false);
|
|
109
294
|
const [credentialRevision, setCredentialRevision] = (0, react.useState)(0);
|
|
110
295
|
const latestAccountRequest = (0, react.useRef)(0);
|
|
296
|
+
const modelSnapshot = (0, react.useSyncExternalStore)(operations.subscribeModels, operations.getModelSnapshot, operations.getModelSnapshot);
|
|
111
297
|
const loadCredential = (0, react.useCallback)(async () => {
|
|
112
298
|
const info = await operations.describe();
|
|
113
299
|
setCredentialState(info === void 0 ? { status: "failed" } : {
|
|
@@ -122,13 +308,13 @@ window.__ModuleLoader__.load({
|
|
|
122
308
|
try {
|
|
123
309
|
const result = await operations.getAccount(force);
|
|
124
310
|
if (requestId !== latestAccountRequest.current) return;
|
|
125
|
-
if (result
|
|
311
|
+
if (result && result.ok) setAccountState({
|
|
126
312
|
status: "ready",
|
|
127
|
-
account: result.
|
|
313
|
+
account: result.value
|
|
128
314
|
});
|
|
129
315
|
else setAccountState({
|
|
130
316
|
status: "failed",
|
|
131
|
-
error: result?.error
|
|
317
|
+
error: result?.error?.message
|
|
132
318
|
});
|
|
133
319
|
} catch (error) {
|
|
134
320
|
if (requestId !== latestAccountRequest.current) return;
|
|
@@ -179,9 +365,17 @@ window.__ModuleLoader__.load({
|
|
|
179
365
|
children: t("retry")
|
|
180
366
|
})]
|
|
181
367
|
});
|
|
182
|
-
|
|
368
|
+
/**
|
|
369
|
+
* Render one quota block.
|
|
370
|
+
*
|
|
371
|
+
* `expiresAt` wins over `resetDate` when both are supplied, because a
|
|
372
|
+
* dedicated package expires on its own date rather than on the subscription
|
|
373
|
+
* reset horizon. A package with no size renders nothing.
|
|
374
|
+
*/
|
|
375
|
+
const renderQuota = (key, label, quota, options) => {
|
|
183
376
|
if (!quota || quota.total <= 0) return null;
|
|
184
377
|
const remainingPercent = Math.max(0, Math.min(100, Math.round(quota.remaining / quota.total * 100)));
|
|
378
|
+
const meta = options?.expiresAt ? t("dedicatedResourceExpiresAt", { value: options.expiresAt }) : options?.resetDate ? t("resetsAt", { value: options.resetDate }) : void 0;
|
|
185
379
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
186
380
|
className: QoderCredentialCard_module_css_default.quotaBlock,
|
|
187
381
|
children: [
|
|
@@ -200,18 +394,22 @@ window.__ModuleLoader__.load({
|
|
|
200
394
|
unit: quota.unit
|
|
201
395
|
}) })
|
|
202
396
|
}),
|
|
397
|
+
options?.description ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
398
|
+
className: QoderCredentialCard_module_css_default.quotaDescription,
|
|
399
|
+
children: options.description
|
|
400
|
+
}) : null,
|
|
203
401
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("progress", {
|
|
204
402
|
className: QoderCredentialCard_module_css_default.quotaProgress,
|
|
205
403
|
max: quota.total,
|
|
206
404
|
value: Math.min(quota.total, quota.used),
|
|
207
405
|
"aria-label": `${label} ${t("quotaRemaining", { value: remainingPercent })}`
|
|
208
406
|
}),
|
|
209
|
-
|
|
407
|
+
meta ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
210
408
|
className: QoderCredentialCard_module_css_default.quotaMeta,
|
|
211
|
-
children:
|
|
409
|
+
children: meta
|
|
212
410
|
}) : null
|
|
213
411
|
]
|
|
214
|
-
},
|
|
412
|
+
}, key);
|
|
215
413
|
};
|
|
216
414
|
const renderAccount = () => {
|
|
217
415
|
if (!configured) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
@@ -249,10 +447,13 @@ window.__ModuleLoader__.load({
|
|
|
249
447
|
const { profile, usage, plan } = accountState.account;
|
|
250
448
|
const userQuota = usage?.userQuota;
|
|
251
449
|
const orgPackage = usage?.orgResourcePackage;
|
|
450
|
+
const dedicatedPackages = usage?.dedicatedResourcePackages ?? [];
|
|
451
|
+
const locale = activeLocale();
|
|
252
452
|
const avatarInitial = (profile.name || profile.email || "Q").charAt(0).toUpperCase();
|
|
253
453
|
const resetDate = formatResetDate(usage?.expiresAt);
|
|
254
454
|
const planExpiry = plan?.endDate ? formatResetDate(plan.endDate) : void 0;
|
|
255
455
|
const isSuspended = plan?.organization?.isSuspended === true;
|
|
456
|
+
const hasQuota = (userQuota?.total ?? 0) > 0 || (orgPackage?.total ?? 0) > 0 || dedicatedPackages.some((pkg) => pkg.total > 0);
|
|
256
457
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
257
458
|
className: QoderCredentialCard_module_css_default.accountSection,
|
|
258
459
|
children: [
|
|
@@ -307,28 +508,100 @@ window.__ModuleLoader__.load({
|
|
|
307
508
|
className: QoderCredentialCard_module_css_default.error,
|
|
308
509
|
children: t("quotaExceeded")
|
|
309
510
|
}) : null,
|
|
310
|
-
renderQuota(t("userQuotaTitle"), userQuota, resetDate),
|
|
311
|
-
renderQuota(t("orgResourceTitle"), orgPackage, resetDate),
|
|
312
|
-
(
|
|
511
|
+
renderQuota("userQuota", t("userQuotaTitle"), userQuota, { resetDate }),
|
|
512
|
+
renderQuota("orgResource", t("orgResourceTitle"), orgPackage, { resetDate }),
|
|
513
|
+
dedicatedPackages.map((pkg, index) => renderQuota(`dedicatedResource-${pkg.id ?? index}`, resolveLocalizedText(pkg.title, locale) ?? t("dedicatedResourceTitle"), pkg, {
|
|
514
|
+
expiresAt: formatResetDate(pkg.expiresAt),
|
|
515
|
+
description: resolveLocalizedText(pkg.description, locale)
|
|
516
|
+
})),
|
|
517
|
+
hasQuota ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
313
518
|
className: QoderCredentialCard_module_css_default.accountEmptyText,
|
|
314
519
|
children: t("noQuota")
|
|
315
|
-
})
|
|
520
|
+
})
|
|
521
|
+
]
|
|
522
|
+
});
|
|
523
|
+
};
|
|
524
|
+
const webSearchMode = modelSnapshot.value?.webSearchMode ?? "auto";
|
|
525
|
+
const canModifySearchMode = modelSnapshot.status === "ready" && modelSnapshot.writable;
|
|
526
|
+
const handleSearchModeChange = async (mode) => {
|
|
527
|
+
if (!canModifySearchMode || mode === webSearchMode) return;
|
|
528
|
+
await operations.storeWebSearchMode(mode);
|
|
529
|
+
};
|
|
530
|
+
const renderWebSearchSection = () => {
|
|
531
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
532
|
+
className: QoderCredentialCard_module_css_default.searchModeSection,
|
|
533
|
+
children: [
|
|
534
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
535
|
+
className: QoderCredentialCard_module_css_default.quotaHeader,
|
|
536
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
537
|
+
className: QoderCredentialCard_module_css_default.quotaLabel,
|
|
538
|
+
children: t("searchModeLabel")
|
|
539
|
+
})
|
|
540
|
+
}),
|
|
541
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
542
|
+
className: QoderCredentialCard_module_css_default.regionGroup,
|
|
543
|
+
role: "radiogroup",
|
|
544
|
+
"aria-label": t("searchModeLabel"),
|
|
545
|
+
children: [
|
|
546
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
547
|
+
type: "button",
|
|
548
|
+
role: "radio",
|
|
549
|
+
"aria-checked": webSearchMode === "auto",
|
|
550
|
+
className: `${QoderCredentialCard_module_css_default.regionOption} ${webSearchMode === "auto" ? QoderCredentialCard_module_css_default.regionOptionActive : ""}`,
|
|
551
|
+
disabled: !canModifySearchMode,
|
|
552
|
+
onClick: () => {
|
|
553
|
+
handleSearchModeChange("auto");
|
|
554
|
+
},
|
|
555
|
+
children: t("searchModeAuto")
|
|
556
|
+
}),
|
|
557
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
558
|
+
type: "button",
|
|
559
|
+
role: "radio",
|
|
560
|
+
"aria-checked": webSearchMode === "always",
|
|
561
|
+
className: `${QoderCredentialCard_module_css_default.regionOption} ${webSearchMode === "always" ? QoderCredentialCard_module_css_default.regionOptionActive : ""}`,
|
|
562
|
+
disabled: !canModifySearchMode,
|
|
563
|
+
onClick: () => {
|
|
564
|
+
handleSearchModeChange("always");
|
|
565
|
+
},
|
|
566
|
+
children: t("searchModeAlways")
|
|
567
|
+
}),
|
|
568
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
569
|
+
type: "button",
|
|
570
|
+
role: "radio",
|
|
571
|
+
"aria-checked": webSearchMode === "disabled",
|
|
572
|
+
className: `${QoderCredentialCard_module_css_default.regionOption} ${webSearchMode === "disabled" ? QoderCredentialCard_module_css_default.regionOptionActive : ""}`,
|
|
573
|
+
disabled: !canModifySearchMode,
|
|
574
|
+
onClick: () => {
|
|
575
|
+
handleSearchModeChange("disabled");
|
|
576
|
+
},
|
|
577
|
+
children: t("searchModeDisabled")
|
|
578
|
+
})
|
|
579
|
+
]
|
|
580
|
+
}),
|
|
581
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
582
|
+
className: QoderCredentialCard_module_css_default.searchModeHintText,
|
|
583
|
+
children: t("searchModeHint")
|
|
584
|
+
})
|
|
316
585
|
]
|
|
317
586
|
});
|
|
318
587
|
};
|
|
319
588
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
320
589
|
className: QoderCredentialCard_module_css_default.credential,
|
|
321
590
|
"aria-label": t("accountTitle"),
|
|
322
|
-
children: [
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
591
|
+
children: [
|
|
592
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
593
|
+
className: QoderCredentialCard_module_css_default.head,
|
|
594
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
595
|
+
className: QoderCredentialCard_module_css_default.heading,
|
|
596
|
+
children: t("accountTitle")
|
|
597
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
598
|
+
className: configured ? `${QoderCredentialCard_module_css_default.status} ${QoderCredentialCard_module_css_default.configured}` : QoderCredentialCard_module_css_default.status,
|
|
599
|
+
children: configured ? t("configured") : t("missing")
|
|
600
|
+
})]
|
|
601
|
+
}),
|
|
602
|
+
renderAccount(),
|
|
603
|
+
renderWebSearchSection()
|
|
604
|
+
]
|
|
332
605
|
});
|
|
333
606
|
}
|
|
334
607
|
//#endregion
|
|
@@ -421,10 +694,10 @@ window.__ModuleLoader__.load({
|
|
|
421
694
|
const result = await operations.discoverModels();
|
|
422
695
|
setFetching(false);
|
|
423
696
|
if (!result.ok) {
|
|
424
|
-
setFailure(result.error || t("modelsFetchFailed"));
|
|
697
|
+
setFailure(result.error.message || t("modelsFetchFailed"));
|
|
425
698
|
return;
|
|
426
699
|
}
|
|
427
|
-
const reconciled = reconcileQoderModels(catalog ?? models, result.
|
|
700
|
+
const reconciled = reconcileQoderModels(catalog ?? models, result.value);
|
|
428
701
|
setCatalog(reconciled.catalog);
|
|
429
702
|
setUnavailableIds(reconciled.unavailableIds);
|
|
430
703
|
onChange(reconciled.selected);
|
|
@@ -791,131 +1064,109 @@ window.__ModuleLoader__.load({
|
|
|
791
1064
|
]
|
|
792
1065
|
});
|
|
793
1066
|
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Absolute Fetch-route prefix. Connection mounts its shared, authenticated API
|
|
1069
|
+
* channel at `/api`, and every exact Fetch route lives directly below it.
|
|
1070
|
+
*/
|
|
1071
|
+
const qoderRpcApiPath = `/api/qoder-subscription`;
|
|
1072
|
+
/** Absolute Fetch-route path of one endpoint. */
|
|
1073
|
+
function qoderRpcPath(endpoint) {
|
|
1074
|
+
return `${qoderRpcApiPath}/${endpoint}`;
|
|
1075
|
+
}
|
|
1076
|
+
/** Standard diagnostic codes carried in a settings RPC failure envelope. */
|
|
1077
|
+
const qoderRpcErrorCodes = [
|
|
1078
|
+
"NO_CREDENTIALS",
|
|
1079
|
+
"UNAUTHENTICATED",
|
|
1080
|
+
"UPSTREAM_ERROR",
|
|
1081
|
+
"TIMEOUT",
|
|
1082
|
+
"ABORTED",
|
|
1083
|
+
"UNKNOWN_ENDPOINT",
|
|
1084
|
+
"INTERNAL"
|
|
1085
|
+
];
|
|
1086
|
+
/** Type guard for an untrusted error code. */
|
|
1087
|
+
function isQoderRpcErrorCode(value) {
|
|
1088
|
+
return typeof value === "string" && qoderRpcErrorCodes.includes(value);
|
|
1089
|
+
}
|
|
794
1090
|
//#endregion
|
|
795
|
-
//#region src/client/
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
regionHint: "Ensure your PAT matches the selected service region.",
|
|
866
|
-
tokenLabel: "API Key",
|
|
867
|
-
tokenPlaceholder: "Enter a new Personal Access Token",
|
|
868
|
-
configuredHint: "Configured — enter a new value to replace",
|
|
869
|
-
readOnly: "The current credential store is read-only.",
|
|
870
|
-
save: "Save",
|
|
871
|
-
saving: "Saving…",
|
|
872
|
-
saved: "Qoder settings saved.",
|
|
873
|
-
saveFailed: "Could not save the Qoder settings. Try again.",
|
|
874
|
-
remove: "Remove",
|
|
875
|
-
removing: "Removing…",
|
|
876
|
-
removeFailed: "Could not remove the credential. Try again.",
|
|
877
|
-
confirmRemove: "Remove the stored Qoder credential? New model requests will stop working.",
|
|
878
|
-
customized: "Custom settings",
|
|
879
|
-
modelsTitle: "Model catalog",
|
|
880
|
-
modelsLoading: "Reading model settings…",
|
|
881
|
-
modelsUnavailable: "Model settings cannot currently be read or saved.",
|
|
882
|
-
modelsEnabled: "{count} models enabled",
|
|
883
|
-
modelsFetch: "Fetch available models",
|
|
884
|
-
modelsFetching: "Fetching…",
|
|
885
|
-
modelsFetchFailed: "Could not fetch available models.",
|
|
886
|
-
modelsRequired: "Keep at least one model.",
|
|
887
|
-
modelUnavailable: "Unavailable",
|
|
888
|
-
modelRate: "{value}x",
|
|
889
|
-
modelRateUnknown: "Rate unknown",
|
|
890
|
-
accountTitle: "Qoder",
|
|
891
|
-
accountLoading: "Reading account and quota…",
|
|
892
|
-
accountFailed: "Could not read account details or quota.",
|
|
893
|
-
accountCredentialHint: "Configure the Qoder Personal Access Token in Models settings first.",
|
|
894
|
-
refresh: "Refresh",
|
|
895
|
-
refreshing: "Refreshing…",
|
|
896
|
-
userQuotaTitle: "Personal Quota",
|
|
897
|
-
orgResourceTitle: "Org Resource Package",
|
|
898
|
-
quotaRemaining: "{value}% remaining",
|
|
899
|
-
quotaUsed: "Used {used} / {total} {unit}",
|
|
900
|
-
resetsAt: "Resets: {value}",
|
|
901
|
-
noQuota: "No quota metrics available",
|
|
902
|
-
quotaExceeded: "The current subscription quota is exhausted.",
|
|
903
|
-
plan: "Plan",
|
|
904
|
-
planExpiresAt: "Expires at: {value}",
|
|
905
|
-
organization: "Org: {name}",
|
|
906
|
-
accountSuspended: "Account or organization is currently suspended."
|
|
907
|
-
};
|
|
1091
|
+
//#region src/client/rpc-client.ts
|
|
1092
|
+
/**
|
|
1093
|
+
* Browser caller for the Qoder settings RPC.
|
|
1094
|
+
*
|
|
1095
|
+
* Requests go to Connection's shared `/api` channel, which the connection
|
|
1096
|
+
* plugin mounts itself and guards with its Host/Origin fence and browser
|
|
1097
|
+
* authentication; the caller only has to carry the session cookie.
|
|
1098
|
+
*/
|
|
1099
|
+
/**
|
|
1100
|
+
* Create the caller used by the account card and the model catalog.
|
|
1101
|
+
*
|
|
1102
|
+
* Failures are returned rather than thrown so the cards keep their existing
|
|
1103
|
+
* "result or undefined" handling: a transport status becomes a transport
|
|
1104
|
+
* failure message, and an endpoint failure keeps the provider's own message.
|
|
1105
|
+
*/
|
|
1106
|
+
function createQoderRpcCaller(transport = {}) {
|
|
1107
|
+
const send = transport.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
1108
|
+
return { async call(endpoint, payload, signal) {
|
|
1109
|
+
const path = qoderRpcPath(endpoint);
|
|
1110
|
+
try {
|
|
1111
|
+
const response = await send(path, {
|
|
1112
|
+
method: "POST",
|
|
1113
|
+
headers: { "content-type": "application/json" },
|
|
1114
|
+
credentials: "include",
|
|
1115
|
+
body: JSON.stringify(payload ?? {}),
|
|
1116
|
+
...signal === void 0 ? {} : { signal }
|
|
1117
|
+
});
|
|
1118
|
+
if (!response.ok) return {
|
|
1119
|
+
ok: false,
|
|
1120
|
+
error: {
|
|
1121
|
+
code: signal?.aborted ? "ABORTED" : "UPSTREAM_ERROR",
|
|
1122
|
+
message: `transport failure for ${path}: HTTP ${response.status}`
|
|
1123
|
+
}
|
|
1124
|
+
};
|
|
1125
|
+
const envelope = await response.json();
|
|
1126
|
+
if (envelope?.ok === true) return {
|
|
1127
|
+
ok: true,
|
|
1128
|
+
value: envelope.value
|
|
1129
|
+
};
|
|
1130
|
+
const rawError = envelope?.error;
|
|
1131
|
+
let code = "INTERNAL";
|
|
1132
|
+
let message = "RPC returned error";
|
|
1133
|
+
let details;
|
|
1134
|
+
if (typeof rawError === "string") message = rawError;
|
|
1135
|
+
else if (typeof rawError === "object" && rawError !== null) {
|
|
1136
|
+
const errObj = rawError;
|
|
1137
|
+
if (isQoderRpcErrorCode(errObj.code)) code = errObj.code;
|
|
1138
|
+
if (typeof errObj.message === "string") message = errObj.message;
|
|
1139
|
+
if (typeof errObj.details === "object" && errObj.details !== null) details = errObj.details;
|
|
1140
|
+
}
|
|
1141
|
+
if (code === "INTERNAL" && signal?.aborted) code = "ABORTED";
|
|
1142
|
+
return {
|
|
1143
|
+
ok: false,
|
|
1144
|
+
error: {
|
|
1145
|
+
code,
|
|
1146
|
+
message,
|
|
1147
|
+
...details === void 0 ? {} : { details }
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
} catch (error) {
|
|
1151
|
+
return {
|
|
1152
|
+
ok: false,
|
|
1153
|
+
error: {
|
|
1154
|
+
code: signal?.aborted || error instanceof Error && error.name === "AbortError" ? "ABORTED" : "INTERNAL",
|
|
1155
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1156
|
+
}
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
} };
|
|
1160
|
+
}
|
|
908
1161
|
//#endregion
|
|
909
1162
|
//#region src/client/index.ts
|
|
910
1163
|
const localeNamespace = "settings.qoderCredential";
|
|
911
|
-
const qoderChannel = "/qoder-subscription";
|
|
912
1164
|
const settingsNamespace = "provider-qoder";
|
|
913
1165
|
const inject = [
|
|
914
1166
|
"slots",
|
|
915
1167
|
"locale",
|
|
916
1168
|
"remote",
|
|
917
1169
|
"remote.credentials",
|
|
918
|
-
"connection",
|
|
919
1170
|
"settingsScope"
|
|
920
1171
|
];
|
|
921
1172
|
const fill = (text, values) => {
|
|
@@ -928,7 +1179,7 @@ window.__ModuleLoader__.load({
|
|
|
928
1179
|
en
|
|
929
1180
|
}), "provider-qoder: credential copy");
|
|
930
1181
|
const credentials = ctx.remote.credentials;
|
|
931
|
-
const
|
|
1182
|
+
const rpc = createQoderRpcCaller();
|
|
932
1183
|
const modelScope = ctx.settingsScope.bind({ namespace: settingsNamespace });
|
|
933
1184
|
const operations = {
|
|
934
1185
|
describe: async () => {
|
|
@@ -953,24 +1204,7 @@ window.__ModuleLoader__.load({
|
|
|
953
1204
|
return false;
|
|
954
1205
|
}
|
|
955
1206
|
},
|
|
956
|
-
getAccount: async (force) => {
|
|
957
|
-
try {
|
|
958
|
-
const response = await connection.rpc.call(qoderChannel, "account", { force });
|
|
959
|
-
if (response.ok) return {
|
|
960
|
-
ok: true,
|
|
961
|
-
data: response.value
|
|
962
|
-
};
|
|
963
|
-
return {
|
|
964
|
-
ok: false,
|
|
965
|
-
error: response.error?.message || "RPC returned error"
|
|
966
|
-
};
|
|
967
|
-
} catch (error) {
|
|
968
|
-
return {
|
|
969
|
-
ok: false,
|
|
970
|
-
error: error instanceof Error ? error.message : String(error)
|
|
971
|
-
};
|
|
972
|
-
}
|
|
973
|
-
},
|
|
1207
|
+
getAccount: async (force) => await rpc.call("account", { force }),
|
|
974
1208
|
getModelSnapshot: () => modelScope.getSnapshot(),
|
|
975
1209
|
subscribeModels: (listener) => modelScope.subscribe(listener),
|
|
976
1210
|
storeModels: async (region, models) => {
|
|
@@ -993,24 +1227,15 @@ window.__ModuleLoader__.load({
|
|
|
993
1227
|
return false;
|
|
994
1228
|
}
|
|
995
1229
|
},
|
|
996
|
-
|
|
1230
|
+
storeWebSearchMode: async (mode) => {
|
|
997
1231
|
try {
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
};
|
|
1003
|
-
return {
|
|
1004
|
-
ok: false,
|
|
1005
|
-
error: response.error?.message || "RPC returned error"
|
|
1006
|
-
};
|
|
1007
|
-
} catch (error) {
|
|
1008
|
-
return {
|
|
1009
|
-
ok: false,
|
|
1010
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1011
|
-
};
|
|
1232
|
+
await modelScope.set("webSearchMode", mode);
|
|
1233
|
+
return true;
|
|
1234
|
+
} catch {
|
|
1235
|
+
return false;
|
|
1012
1236
|
}
|
|
1013
1237
|
},
|
|
1238
|
+
discoverModels: async () => await rpc.call("models", {}),
|
|
1014
1239
|
subscribe: (listener) => ctx.remote.$on("credentials/reference-updated", (ref) => {
|
|
1015
1240
|
if (ref === "QODER_MANAGED_CREDENTIAL") listener();
|
|
1016
1241
|
})
|
|
@@ -1020,6 +1245,11 @@ window.__ModuleLoader__.load({
|
|
|
1020
1245
|
const raw = rawT(key);
|
|
1021
1246
|
return fill(raw, values);
|
|
1022
1247
|
};
|
|
1248
|
+
/**
|
|
1249
|
+
* Read the live UI locale. Cards call this during render, so a language
|
|
1250
|
+
* switch re-resolves provider copy instead of reusing a setup-time snapshot.
|
|
1251
|
+
*/
|
|
1252
|
+
const activeLocale = () => ctx.locale.getLocale().active;
|
|
1023
1253
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
1024
1254
|
name: "settings.section",
|
|
1025
1255
|
id: "qoder",
|
|
@@ -1028,7 +1258,8 @@ window.__ModuleLoader__.load({
|
|
|
1028
1258
|
locale: localeNamespace,
|
|
1029
1259
|
inject: () => ({
|
|
1030
1260
|
operations,
|
|
1031
|
-
t
|
|
1261
|
+
t,
|
|
1262
|
+
activeLocale
|
|
1032
1263
|
})
|
|
1033
1264
|
}, QoderAccountCard));
|
|
1034
1265
|
ctx.slots.inject("settings.models.footer", () => ctx.slots.register({
|
|
@@ -1037,7 +1268,8 @@ window.__ModuleLoader__.load({
|
|
|
1037
1268
|
order: 15,
|
|
1038
1269
|
inject: () => ({
|
|
1039
1270
|
operations,
|
|
1040
|
-
t
|
|
1271
|
+
t,
|
|
1272
|
+
activeLocale
|
|
1041
1273
|
})
|
|
1042
1274
|
}, QoderCredentialCard));
|
|
1043
1275
|
}
|