@qilin-agent/client-ui-settings-models 3.1.6 → 3.1.7
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.i18n.yaml +6 -6
- package/README.md +9 -5
- package/README.zh.md +9 -5
- package/lib/client.js +987 -50
- package/lib/index.js +24 -4
- package/lib/types/client/CustomProviderCard.d.ts +5 -0
- package/lib/types/client/ModelListEditor.d.ts +7 -0
- package/lib/types/client/ProviderEditor.d.ts +12 -0
- package/lib/types/client/index.d.ts +4 -2
- package/lib/types/client/locales.d.ts +5 -3
- package/lib/types/client/operations.d.ts +1 -7
- package/lib/types/index.d.ts +10 -3
- package/lib/types/onboarding-config.d.ts +16 -0
- package/package.json +16 -11
package/lib/client.js
CHANGED
|
@@ -507,7 +507,7 @@ window.__ModuleLoader__.load({
|
|
|
507
507
|
"aria-expanded": props.expanded,
|
|
508
508
|
title: t("modelAdvanced"),
|
|
509
509
|
onClick: props.onToggle,
|
|
510
|
-
children: props.expanded ? (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
510
|
+
children: props.expanded ? (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconChevronDownOutlineRegular, {}) : (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconChevronRightOutlineRegular, {})
|
|
511
511
|
}),
|
|
512
512
|
(0, react_jsx_runtime.jsx)("button", {
|
|
513
513
|
type: "button",
|
|
@@ -516,7 +516,7 @@ window.__ModuleLoader__.load({
|
|
|
516
516
|
title: t("removeModel"),
|
|
517
517
|
disabled,
|
|
518
518
|
onClick: props.onRemove,
|
|
519
|
-
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
519
|
+
children: (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconTrashOutlineRegular, { size: 14 })
|
|
520
520
|
})
|
|
521
521
|
]
|
|
522
522
|
}), props.expanded ? (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -798,7 +798,7 @@ window.__ModuleLoader__.load({
|
|
|
798
798
|
onClick: () => {
|
|
799
799
|
props.onChange([...props.models.map((model) => ({ ...model })), { id: "" }]);
|
|
800
800
|
},
|
|
801
|
-
children: [(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
801
|
+
children: [(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconPlusOutlineRegular, { size: 14 }), props.t("addModel")]
|
|
802
802
|
})
|
|
803
803
|
]
|
|
804
804
|
});
|
|
@@ -871,9 +871,12 @@ window.__ModuleLoader__.load({
|
|
|
871
871
|
* @returns the model-list editor.
|
|
872
872
|
*/
|
|
873
873
|
function ModelListEditor(props) {
|
|
874
|
-
const { models, onChange, probe, operations, t, disabled } = props;
|
|
874
|
+
const { models, onChange, probe, operations, t, disabled, onBusyChange } = props;
|
|
875
875
|
const { catalogProvider } = props;
|
|
876
876
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
877
|
+
(0, react.useEffect)(() => {
|
|
878
|
+
onBusyChange(busy);
|
|
879
|
+
}, [busy, onBusyChange]);
|
|
877
880
|
const [failure, setFailure] = (0, react.useState)(void 0);
|
|
878
881
|
const [inheritedCatalog, setInheritedCatalog] = (0, react.useState)(void 0);
|
|
879
882
|
(0, react.useEffect)(() => {
|
|
@@ -1098,7 +1101,7 @@ window.__ModuleLoader__.load({
|
|
|
1098
1101
|
onClick: () => {
|
|
1099
1102
|
onChange([...models, { id: "" }]);
|
|
1100
1103
|
},
|
|
1101
|
-
children: [(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
1104
|
+
children: [(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconPlusOutlineRegular, { size: 14 }), t("addModel")]
|
|
1102
1105
|
}),
|
|
1103
1106
|
failure !== void 0 ? (0, react_jsx_runtime.jsx)("p", {
|
|
1104
1107
|
className: ModelsSection_module_css_default["error"],
|
|
@@ -1346,7 +1349,9 @@ window.__ModuleLoader__.load({
|
|
|
1346
1349
|
}
|
|
1347
1350
|
const mirrored = this.describeFace.getSnapshot();
|
|
1348
1351
|
if (mirrored.view === void 0) {
|
|
1349
|
-
|
|
1352
|
+
/* v8 ignore next -- SettingsDescribeFace.ensure settles with a view or the read's error */
|
|
1353
|
+
if (mirrored.error === null) throw new Error("settings describe settled with neither a view nor an error");
|
|
1354
|
+
this.failLoad(mirrored.error);
|
|
1350
1355
|
return;
|
|
1351
1356
|
}
|
|
1352
1357
|
const providers = joinProviderDirectory(registered.value, declared.value);
|
|
@@ -1541,7 +1546,7 @@ window.__ModuleLoader__.load({
|
|
|
1541
1546
|
* @returns the creation card.
|
|
1542
1547
|
*/
|
|
1543
1548
|
function CustomProviderCard(props) {
|
|
1544
|
-
const { taken, protocols, reasoningLevels, operations, t } = props;
|
|
1549
|
+
const { taken, protocols, reasoningLevels, operations, t, onBusyChange } = props;
|
|
1545
1550
|
const [openedAt] = (0, react.useState)(() => props.revision);
|
|
1546
1551
|
const [route, setRoute] = (0, react.useState)("");
|
|
1547
1552
|
const [displayName, setDisplayName] = (0, react.useState)("");
|
|
@@ -1550,6 +1555,14 @@ window.__ModuleLoader__.load({
|
|
|
1550
1555
|
const [keyDraft, setKeyDraft] = (0, react.useState)("");
|
|
1551
1556
|
const [models, setModels] = (0, react.useState)([]);
|
|
1552
1557
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
1558
|
+
const [listBusy, setListBusy] = (0, react.useState)(false);
|
|
1559
|
+
(0, react.useEffect)(() => {
|
|
1560
|
+
onBusyChange?.(busy || listBusy);
|
|
1561
|
+
}, [
|
|
1562
|
+
busy,
|
|
1563
|
+
listBusy,
|
|
1564
|
+
onBusyChange
|
|
1565
|
+
]);
|
|
1553
1566
|
const [failure, setFailure] = (0, react.useState)(void 0);
|
|
1554
1567
|
/**
|
|
1555
1568
|
* The profile write landed. Only the key write can still be outstanding, so
|
|
@@ -1668,7 +1681,7 @@ window.__ModuleLoader__.load({
|
|
|
1668
1681
|
className: ModelsSection_module_css_default["input"],
|
|
1669
1682
|
type: "text",
|
|
1670
1683
|
value: baseURL,
|
|
1671
|
-
placeholder: t("customBaseUrlPlaceholder"),
|
|
1684
|
+
placeholder: t(protocol === "anthropic-messages" ? "customAnthropicBaseUrlPlaceholder" : "customBaseUrlPlaceholder"),
|
|
1672
1685
|
"aria-label": t("baseUrl"),
|
|
1673
1686
|
"aria-invalid": baseUrlInvalid,
|
|
1674
1687
|
disabled: profileDisabled,
|
|
@@ -1736,7 +1749,8 @@ window.__ModuleLoader__.load({
|
|
|
1736
1749
|
probeBlocked: baseUrlInvalid ? "customBaseUrlInvalid" : keyFailure === "keyBlank" ? "keyBlankNew" : keyFailure,
|
|
1737
1750
|
operations,
|
|
1738
1751
|
t,
|
|
1739
|
-
disabled: profileDisabled
|
|
1752
|
+
disabled: profileDisabled,
|
|
1753
|
+
onBusyChange: setListBusy
|
|
1740
1754
|
}),
|
|
1741
1755
|
failure !== void 0 ? (0, react_jsx_runtime.jsx)("p", {
|
|
1742
1756
|
className: ModelsSection_module_css_default["error"],
|
|
@@ -1841,8 +1855,16 @@ window.__ModuleLoader__.load({
|
|
|
1841
1855
|
const { namespace, schema, settingsPath, operations, t } = props;
|
|
1842
1856
|
const [draft, setDraft] = (0, react.useState)(() => draftAt(schema, namespace, settingsPath));
|
|
1843
1857
|
const [keyDraft, setKeyDraft] = (0, react.useState)("");
|
|
1844
|
-
const [keyState, setKeyState] = (0, react.useState)(void 0);
|
|
1845
1858
|
const [busy, setBusy] = (0, react.useState)(false);
|
|
1859
|
+
const [listBusy, setListBusy] = (0, react.useState)(false);
|
|
1860
|
+
const { onBusyChange } = props;
|
|
1861
|
+
(0, react.useEffect)(() => {
|
|
1862
|
+
onBusyChange?.(busy || listBusy);
|
|
1863
|
+
}, [
|
|
1864
|
+
busy,
|
|
1865
|
+
listBusy,
|
|
1866
|
+
onBusyChange
|
|
1867
|
+
]);
|
|
1846
1868
|
const [failure, setFailure] = (0, react.useState)(void 0);
|
|
1847
1869
|
const [committedOriginal, setCommittedOriginal] = (0, react.useState)(() => schema.getPath(namespace.user, settingsPath));
|
|
1848
1870
|
const [expectedRevision, setExpectedRevision] = (0, react.useState)(() => namespace.revision);
|
|
@@ -1861,17 +1883,6 @@ window.__ModuleLoader__.load({
|
|
|
1861
1883
|
namespace,
|
|
1862
1884
|
schema
|
|
1863
1885
|
]);
|
|
1864
|
-
(0, react.useEffect)(() => {
|
|
1865
|
-
let stale = false;
|
|
1866
|
-
setKeyState(void 0);
|
|
1867
|
-
operations.describeCredential(keyRef).then((described) => {
|
|
1868
|
-
if (stale) return;
|
|
1869
|
-
setKeyState(described);
|
|
1870
|
-
});
|
|
1871
|
-
return () => {
|
|
1872
|
-
stale = true;
|
|
1873
|
-
};
|
|
1874
|
-
}, [operations, keyRef]);
|
|
1875
1886
|
const stringAt = (source, key) => {
|
|
1876
1887
|
const value = schema.getPath(source, [key]);
|
|
1877
1888
|
return typeof value === "string" && value.trim().length > 0 ? value : void 0;
|
|
@@ -1961,7 +1972,6 @@ window.__ModuleLoader__.load({
|
|
|
1961
1972
|
props.t("settingsPathUnresolvable")
|
|
1962
1973
|
]
|
|
1963
1974
|
});
|
|
1964
|
-
const keyLocked = keyState?.writable === false;
|
|
1965
1975
|
/**
|
|
1966
1976
|
* The catalog beneath the user layer: what the composition entry pinned, or
|
|
1967
1977
|
* else the schema default that `resolve` would supply. The effective value
|
|
@@ -1985,22 +1995,38 @@ window.__ModuleLoader__.load({
|
|
|
1985
1995
|
const defaultContextWindow = schema.getPath(fallback, ["defaultContextWindow"]);
|
|
1986
1996
|
const defaultMaxTokens = schema.getPath(fallback, ["maxTokens"]);
|
|
1987
1997
|
const defaultInput = schema.getPath(fallback, ["defaultInput"]);
|
|
1988
|
-
const
|
|
1989
|
-
const nativeAuth = namedRef === void 0 ? props.nativeAuth : void 0;
|
|
1998
|
+
const baseURL = stringAt(fallback, "baseURL") ?? props.defaultBaseURL;
|
|
1990
1999
|
const endpointEnv = props.baseURLEnv ?? [];
|
|
1991
|
-
const baseURL = stringAt(fallback, "baseURL");
|
|
1992
2000
|
const endpointHint = family === "deepseek" ? t("deepSeekEndpointHint") : baseURL === void 0 && endpointEnv.length > 0 ? t("baseUrlEnvironment").replace("{env}", () => endpointEnv.join(", ")) : void 0;
|
|
2001
|
+
const namedRef = stringAt(fallback, "apiKeyEnv");
|
|
2002
|
+
const nativeAuth = namedRef === void 0 ? props.nativeAuth : void 0;
|
|
1993
2003
|
const authRefs = namedRef === void 0 ? (nativeAuth?.env ?? []).filter((ref) => !endpointEnv.includes(ref)) : [namedRef];
|
|
1994
2004
|
const visibleRefs = authRefs.filter((ref) => !ref.toLowerCase().includes("oauth"));
|
|
1995
2005
|
const keyHint = visibleRefs[0];
|
|
1996
|
-
const checkedRefs = authRefs.map((ref) => [ref, props.credentialChecks?.[ref] ?? (ref ===
|
|
2006
|
+
const checkedRefs = authRefs.map((ref) => [ref, props.credentialChecks?.[ref] ?? (ref === namedRef ? props.credential : void 0)]);
|
|
1997
2007
|
const detected = checkedRefs.find(([, info]) => info?.configured === true);
|
|
1998
2008
|
const detectedRef = detected?.[0];
|
|
1999
2009
|
const detectedVisibleRef = detectedRef === void 0 || !visibleRefs.includes(detectedRef) ? void 0 : detectedRef;
|
|
2000
2010
|
const missingRefs = checkedRefs.length > 0 && checkedRefs.every(([, info]) => info?.configured === false);
|
|
2001
2011
|
const savedCredential = detected?.[1]?.source === "file";
|
|
2002
|
-
const credentialHint = keyDraft.length > 0 || savedCredential || keyHint === void 0 || props.credentialRequired === true
|
|
2003
|
-
const
|
|
2012
|
+
const credentialHint = keyDraft.length > 0 || savedCredential || keyHint === void 0 || props.credentialRequired === true ? void 0 : t(detectedRef === void 0 ? missingRefs ? "keyFallbackMissing" : "keyFallbackUnchecked" : detectedVisibleRef === void 0 ? "keyFallbackDetectedHidden" : "keyFallbackDetected").replace("{hint}", () => detectedVisibleRef ?? keyHint);
|
|
2013
|
+
const keyHelp = visibleRefs.length === 0 ? void 0 : t("keyHelp").replace("{env}", () => visibleRefs.join(" / "));
|
|
2014
|
+
const authHelp = keyHelp === void 0 ? null : (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.Tooltip, {
|
|
2015
|
+
label: keyHelp,
|
|
2016
|
+
side: "right",
|
|
2017
|
+
delayMs: 0,
|
|
2018
|
+
focusDelayMs: 0,
|
|
2019
|
+
portal: true,
|
|
2020
|
+
openOnClick: true,
|
|
2021
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
2022
|
+
type: "button",
|
|
2023
|
+
className: ModelsSection_module_css_default["helpButton"],
|
|
2024
|
+
"aria-label": t("authHelp"),
|
|
2025
|
+
children: "?"
|
|
2026
|
+
})
|
|
2027
|
+
});
|
|
2028
|
+
const keylessNativeAuth = nativeAuth?.env.length === 0 && nativeAuth.oauth;
|
|
2029
|
+
const keyPlaceholder = keyHint === void 0 || props.credentialRequired === true ? t("keyPlaceholder") : t(savedCredential ? "keyPlaceholderSaved" : "keyPlaceholderFallback").replace("{hint}", () => keyHint);
|
|
2004
2030
|
/** What both family editors take: the rows, whose layer owns them, and the two writes. */
|
|
2005
2031
|
const catalogProps = {
|
|
2006
2032
|
models,
|
|
@@ -2014,12 +2040,12 @@ window.__ModuleLoader__.load({
|
|
|
2014
2040
|
setDraft((current) => schema.deletePath(current, ["models"]));
|
|
2015
2041
|
}
|
|
2016
2042
|
};
|
|
2017
|
-
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
2043
|
+
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [keylessNativeAuth ? null : (0, react_jsx_runtime.jsxs)("div", {
|
|
2018
2044
|
className: ModelsSection_module_css_default["field"],
|
|
2019
2045
|
children: [
|
|
2020
|
-
(0, react_jsx_runtime.
|
|
2046
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
2021
2047
|
className: ModelsSection_module_css_default["fieldLabel"],
|
|
2022
|
-
children: t("keyInput")
|
|
2048
|
+
children: [t("keyInput"), authHelp]
|
|
2023
2049
|
}),
|
|
2024
2050
|
(0, react_jsx_runtime.jsx)(ApiKeyInput, {
|
|
2025
2051
|
t,
|
|
@@ -2030,7 +2056,7 @@ window.__ModuleLoader__.load({
|
|
|
2030
2056
|
"aria-describedby": credentialHint === void 0 ? void 0 : `${props.provider}-credential-hint`,
|
|
2031
2057
|
required: props.credentialRequired === true,
|
|
2032
2058
|
autoFocus: props.autoFocusCredential === true,
|
|
2033
|
-
disabled
|
|
2059
|
+
disabled,
|
|
2034
2060
|
onChange: (event) => {
|
|
2035
2061
|
setKeyDraft(event.target.value);
|
|
2036
2062
|
}
|
|
@@ -2081,7 +2107,7 @@ window.__ModuleLoader__.load({
|
|
|
2081
2107
|
className: ModelsSection_module_css_default["input"],
|
|
2082
2108
|
type: "text",
|
|
2083
2109
|
value: stringAt(draft, "baseURL") ?? "",
|
|
2084
|
-
placeholder: family === "deepseek" ? t("deepSeekBaseUrl") : baseURL === void 0 ? t(endpointEnv.length > 0 ? "baseUrlConfigured" : "baseUrlDefault") : baseURL,
|
|
2110
|
+
placeholder: family === "deepseek" ? t("deepSeekBaseUrl") : baseURL === void 0 ? t(endpointEnv.length > 0 ? "baseUrlConfigured" : "baseUrlDefault") : t("baseUrlPlaceholder").replace("{url}", () => baseURL),
|
|
2085
2111
|
"aria-describedby": endpointHint === void 0 ? void 0 : `${props.provider}-endpoint-hint`,
|
|
2086
2112
|
"aria-label": t("baseUrl"),
|
|
2087
2113
|
disabled,
|
|
@@ -2129,7 +2155,8 @@ window.__ModuleLoader__.load({
|
|
|
2129
2155
|
defaultInput: Array.isArray(defaultInput) ? defaultInput : void 0,
|
|
2130
2156
|
probe,
|
|
2131
2157
|
probeBlocked: keyFailure,
|
|
2132
|
-
operations
|
|
2158
|
+
operations,
|
|
2159
|
+
onBusyChange: setListBusy
|
|
2133
2160
|
})
|
|
2134
2161
|
]
|
|
2135
2162
|
})]
|
|
@@ -2171,6 +2198,7 @@ window.__ModuleLoader__.load({
|
|
|
2171
2198
|
props.onClose(false);
|
|
2172
2199
|
},
|
|
2173
2200
|
onSubmit: () => {
|
|
2201
|
+
props.onSubmitCredential?.();
|
|
2174
2202
|
apply();
|
|
2175
2203
|
}
|
|
2176
2204
|
})
|
|
@@ -2199,8 +2227,10 @@ window.__ModuleLoader__.load({
|
|
|
2199
2227
|
displayName: target.displayName,
|
|
2200
2228
|
settingsPath: target.settingsPath,
|
|
2201
2229
|
...target.declared === true ? { declared: true } : {},
|
|
2230
|
+
...target.defaultBaseURL === void 0 ? {} : { defaultBaseURL: target.defaultBaseURL },
|
|
2202
2231
|
...target.baseURLEnv === void 0 ? {} : { baseURLEnv: target.baseURLEnv },
|
|
2203
2232
|
...target.nativeAuth === void 0 ? {} : { nativeAuth: target.nativeAuth },
|
|
2233
|
+
...row.credential === void 0 ? {} : { credential: row.credential },
|
|
2204
2234
|
...row.credentialChecks === void 0 ? {} : { credentialChecks: row.credentialChecks },
|
|
2205
2235
|
...props
|
|
2206
2236
|
});
|
|
@@ -2262,6 +2292,7 @@ window.__ModuleLoader__.load({
|
|
|
2262
2292
|
settingsPath: row.entry.settingsPath,
|
|
2263
2293
|
...credentialRef === void 0 ? {} : { credentialRef },
|
|
2264
2294
|
...row.entry.declared === true ? { declared: true } : {},
|
|
2295
|
+
...row.entry.defaultBaseURL === void 0 ? {} : { defaultBaseURL: row.entry.defaultBaseURL },
|
|
2265
2296
|
...row.entry.baseURLEnv === void 0 ? {} : { baseURLEnv: row.entry.baseURLEnv },
|
|
2266
2297
|
...row.entry.nativeAuth === void 0 ? {} : { nativeAuth: row.entry.nativeAuth }
|
|
2267
2298
|
};
|
|
@@ -2307,6 +2338,8 @@ window.__ModuleLoader__.load({
|
|
|
2307
2338
|
const [deleteFailure, setDeleteFailure] = (0, react.useState)(void 0);
|
|
2308
2339
|
const [savedTarget, setSavedTarget] = (0, react.useState)(void 0);
|
|
2309
2340
|
const [declaring, setDeclaring] = (0, react.useState)(false);
|
|
2341
|
+
/** Whether the add card's editor has a write or an interrogation in flight. */
|
|
2342
|
+
const [addBusy, setAddBusy] = (0, react.useState)(false);
|
|
2310
2343
|
const [dismissedSetup, setDismissedSetup] = (0, react.useState)(() => /* @__PURE__ */ new Set());
|
|
2311
2344
|
const announceSaved = (target) => {
|
|
2312
2345
|
controller.load().then(() => {
|
|
@@ -2317,6 +2350,7 @@ window.__ModuleLoader__.load({
|
|
|
2317
2350
|
setEditing(void 0);
|
|
2318
2351
|
setAdding(false);
|
|
2319
2352
|
setDeclaring(false);
|
|
2353
|
+
setAddBusy(false);
|
|
2320
2354
|
if (changed) announceSaved(target);
|
|
2321
2355
|
};
|
|
2322
2356
|
/**
|
|
@@ -2546,6 +2580,7 @@ window.__ModuleLoader__.load({
|
|
|
2546
2580
|
className: `${ModelsSection_module_css_default["input"]} ${ModelsSection_module_css_default["selectInput"]}`,
|
|
2547
2581
|
value: addTarget.provider,
|
|
2548
2582
|
"aria-label": t("provider"),
|
|
2583
|
+
disabled: addBusy,
|
|
2549
2584
|
onChange: (event) => {
|
|
2550
2585
|
const row = addable.find((candidate) => candidate.entry.provider === event.target.value);
|
|
2551
2586
|
/* v8 ignore next -- the select only lists addable rows */
|
|
@@ -2565,6 +2600,7 @@ window.__ModuleLoader__.load({
|
|
|
2565
2600
|
namespace: addNamespace,
|
|
2566
2601
|
schema,
|
|
2567
2602
|
settingsPath: addTarget.settingsPath,
|
|
2603
|
+
...addTarget.defaultBaseURL === void 0 ? {} : { defaultBaseURL: addTarget.defaultBaseURL },
|
|
2568
2604
|
...addTarget.baseURLEnv === void 0 ? {} : { baseURLEnv: addTarget.baseURLEnv },
|
|
2569
2605
|
...addTarget.nativeAuth === void 0 ? {} : { nativeAuth: addTarget.nativeAuth },
|
|
2570
2606
|
...addRow?.credentialChecks === void 0 ? {} : { credentialChecks: addRow.credentialChecks },
|
|
@@ -2573,7 +2609,8 @@ window.__ModuleLoader__.load({
|
|
|
2573
2609
|
readOnly: !state.writable,
|
|
2574
2610
|
onClose: (changed) => {
|
|
2575
2611
|
closeEditor(changed, addTarget);
|
|
2576
|
-
}
|
|
2612
|
+
},
|
|
2613
|
+
onBusyChange: setAddBusy
|
|
2577
2614
|
}, addTarget.provider),
|
|
2578
2615
|
addRow === void 0 ? null : renderSlot("settings.models.provider-card", {
|
|
2579
2616
|
provider: addRow.entry,
|
|
@@ -2613,7 +2650,7 @@ window.__ModuleLoader__.load({
|
|
|
2613
2650
|
setAdding(true);
|
|
2614
2651
|
setEditing(targetOf(first));
|
|
2615
2652
|
},
|
|
2616
|
-
children: [(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
2653
|
+
children: [(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconPlusOutlineRegular, { size: 14 }), t("add")]
|
|
2617
2654
|
}), state.namespaces.has("llm-pi-ai") && (0, react_jsx_runtime.jsxs)("button", {
|
|
2618
2655
|
type: "button",
|
|
2619
2656
|
className: ModelsSection_module_css_default["addButton"],
|
|
@@ -2626,7 +2663,7 @@ window.__ModuleLoader__.load({
|
|
|
2626
2663
|
setEditing(void 0);
|
|
2627
2664
|
setDeclaring(true);
|
|
2628
2665
|
},
|
|
2629
|
-
children: [(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.
|
|
2666
|
+
children: [(0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.IconPlusOutlineRegular, { size: 14 }), t("customAdd")]
|
|
2630
2667
|
})]
|
|
2631
2668
|
})
|
|
2632
2669
|
}),
|
|
@@ -2829,10 +2866,6 @@ window.__ModuleLoader__.load({
|
|
|
2829
2866
|
*/
|
|
2830
2867
|
function createModelsOperations(ctx) {
|
|
2831
2868
|
return {
|
|
2832
|
-
describeCredential: async (ref) => {
|
|
2833
|
-
const response = await ctx.remote.credentials.describe([ref]);
|
|
2834
|
-
return response.ok ? response.value[ref] : void 0;
|
|
2835
|
-
},
|
|
2836
2869
|
storeCredential: async (ref, value) => {
|
|
2837
2870
|
const response = await ctx.remote.credentials.set(ref, value);
|
|
2838
2871
|
return response.ok ? void 0 : response.error.message;
|
|
@@ -2920,19 +2953,20 @@ window.__ModuleLoader__.load({
|
|
|
2920
2953
|
keyReveal: "Show secret",
|
|
2921
2954
|
keyHide: "Hide secret",
|
|
2922
2955
|
keyPlaceholder: "Enter your API key",
|
|
2923
|
-
|
|
2924
|
-
keyStored: "Configured — enter a new value to replace",
|
|
2925
|
-
keyEnvLocked: "Provided by the launch environment (read-only)",
|
|
2956
|
+
keyPlaceholderFallback: "Leave blank to use env as auth ({hint})",
|
|
2926
2957
|
keyPlaceholderSaved: "Leave blank to use saved credentials",
|
|
2927
2958
|
keyFallbackMissing: "Env var not detected. Enter an API key, or configure {hint} in your env.",
|
|
2928
2959
|
keyFallbackDetected: "Env var detected. ({hint})",
|
|
2929
2960
|
keyFallbackDetectedHidden: "Env var detected.",
|
|
2930
2961
|
keyFallbackUnchecked: "Environment credential status has not been confirmed.",
|
|
2962
|
+
keyHelp: "Saved credentials are used first. Environment fallbacks shown here, in order: {env}. Sources are launch environment, $cwd/.env, then $QILIN_HOME/.env.",
|
|
2963
|
+
authHelp: "Authentication details",
|
|
2931
2964
|
customized: "Customized settings",
|
|
2932
2965
|
baseUrl: "Base URL",
|
|
2933
|
-
baseUrlDefault: "
|
|
2966
|
+
baseUrlDefault: "No default endpoint",
|
|
2934
2967
|
baseUrlEnvironment: "Provider endpoint configuration: {env}",
|
|
2935
2968
|
baseUrlConfigured: "Provider-configured endpoint",
|
|
2969
|
+
baseUrlPlaceholder: "{url}",
|
|
2936
2970
|
deepSeekBaseUrl: "https://api.deepseek.com/anthropic",
|
|
2937
2971
|
deepSeekEndpointHint: "Use an endpoint compatible with the configured connection.",
|
|
2938
2972
|
models: "Models",
|
|
@@ -3003,6 +3037,7 @@ window.__ModuleLoader__.load({
|
|
|
3003
3037
|
customBaseUrlInvalid: "Enter a valid HTTP or HTTPS URL.",
|
|
3004
3038
|
customNeedsModels: "A custom provider needs at least one model.",
|
|
3005
3039
|
customBaseUrlPlaceholder: "https://gateway.example/v1",
|
|
3040
|
+
customAnthropicBaseUrlPlaceholder: "https://gateway.example",
|
|
3006
3041
|
settingsPathUnresolvable: "unresolvable settings path",
|
|
3007
3042
|
create: "Create provider",
|
|
3008
3043
|
creating: "Creating…",
|
|
@@ -3044,19 +3079,20 @@ window.__ModuleLoader__.load({
|
|
|
3044
3079
|
keyReveal: "显示密钥",
|
|
3045
3080
|
keyHide: "隐藏密钥",
|
|
3046
3081
|
keyPlaceholder: "输入 API 密钥",
|
|
3047
|
-
|
|
3048
|
-
keyStored: "已配置——输入新值可替换",
|
|
3049
|
-
keyEnvLocked: "由启动环境提供(只读)",
|
|
3082
|
+
keyPlaceholderFallback: "留空使用环境认证({hint})",
|
|
3050
3083
|
keyPlaceholderSaved: "留空使用已保存凭据",
|
|
3051
3084
|
keyFallbackMissing: "未检测到环境变量。请填写 API 密钥,或设置环境变量 {hint}。",
|
|
3052
3085
|
keyFallbackDetected: "已检测到环境变量({hint})",
|
|
3053
3086
|
keyFallbackDetectedHidden: "已检测到环境变量",
|
|
3054
3087
|
keyFallbackUnchecked: "环境凭据状态尚未确认",
|
|
3088
|
+
keyHelp: "优先使用已保存的凭据。此处显示的环境后备按以下顺序排列:{env}。来源依次为启动环境、$cwd/.env、$QILIN_HOME/.env。",
|
|
3089
|
+
authHelp: "认证说明",
|
|
3055
3090
|
customized: "自定义设置",
|
|
3056
3091
|
baseUrl: "API 地址",
|
|
3057
|
-
baseUrlDefault: "
|
|
3092
|
+
baseUrlDefault: "没有默认地址",
|
|
3058
3093
|
baseUrlEnvironment: "提供方地址配置:{env}",
|
|
3059
3094
|
baseUrlConfigured: "由提供方配置地址",
|
|
3095
|
+
baseUrlPlaceholder: "{url}",
|
|
3060
3096
|
deepSeekBaseUrl: "https://api.deepseek.com/anthropic",
|
|
3061
3097
|
deepSeekEndpointHint: "请填写与当前连接配置兼容的 API 地址。",
|
|
3062
3098
|
models: "模型目录",
|
|
@@ -3127,6 +3163,7 @@ window.__ModuleLoader__.load({
|
|
|
3127
3163
|
customBaseUrlInvalid: "请输入有效的 HTTP 或 HTTPS 地址。",
|
|
3128
3164
|
customNeedsModels: "自定义提供方至少需要一个模型。",
|
|
3129
3165
|
customBaseUrlPlaceholder: "https://gateway.example/v1",
|
|
3166
|
+
customAnthropicBaseUrlPlaceholder: "https://gateway.example",
|
|
3130
3167
|
settingsPathUnresolvable: "无法解析设置路径",
|
|
3131
3168
|
create: "创建提供方",
|
|
3132
3169
|
creating: "创建中…",
|
|
@@ -3138,6 +3175,904 @@ window.__ModuleLoader__.load({
|
|
|
3138
3175
|
keyRequired: "请输入 API 密钥后继续。"
|
|
3139
3176
|
};
|
|
3140
3177
|
//#endregion
|
|
3178
|
+
//#region ../../../vendor/cosmokit/src/misc.ts
|
|
3179
|
+
/** Return true when a value is `null` or `undefined`. */
|
|
3180
|
+
function isNullable(value) {
|
|
3181
|
+
return value === null || value === void 0;
|
|
3182
|
+
}
|
|
3183
|
+
/** Return true for non-array object values. */
|
|
3184
|
+
function isPlainObject(data) {
|
|
3185
|
+
return data && typeof data === "object" && !Array.isArray(data);
|
|
3186
|
+
}
|
|
3187
|
+
/** Filter object entries and return a new object. */
|
|
3188
|
+
function filterKeys(object, filter) {
|
|
3189
|
+
return Object.fromEntries(Object.entries(object).filter(([key, value]) => filter(key, value)));
|
|
3190
|
+
}
|
|
3191
|
+
/** Map object values while preserving the original key set. */
|
|
3192
|
+
function mapValues(object, transform) {
|
|
3193
|
+
return Object.fromEntries(Object.entries(object).map(([key, value]) => [key, transform(value, key)]));
|
|
3194
|
+
}
|
|
3195
|
+
/** Pick selected keys from an object, optionally including `undefined` values. */
|
|
3196
|
+
function pick(source, keys, forced) {
|
|
3197
|
+
if (!keys) return { ...source };
|
|
3198
|
+
const result = {};
|
|
3199
|
+
for (const key of keys) if (forced || source[key] !== void 0) result[key] = source[key];
|
|
3200
|
+
return result;
|
|
3201
|
+
}
|
|
3202
|
+
//#endregion
|
|
3203
|
+
//#region ../../../vendor/cosmokit/src/volatile.ts
|
|
3204
|
+
/** Shared config references used by schema validators and plugin runtimes. */
|
|
3205
|
+
const write = Symbol.for("cosmokit.volatile.write");
|
|
3206
|
+
function snapshot(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
3207
|
+
if (typeof value === "function") throw new TypeError("volatile config cannot contain functions");
|
|
3208
|
+
if (value === null || typeof value !== "object") return value;
|
|
3209
|
+
if (ancestors.has(value)) throw new TypeError("volatile config cannot contain cycles");
|
|
3210
|
+
ancestors.add(value);
|
|
3211
|
+
try {
|
|
3212
|
+
if (Array.isArray(value)) return Object.freeze(value.map((item) => snapshot(item, ancestors)));
|
|
3213
|
+
if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) throw new TypeError("volatile config objects must be plain objects or arrays");
|
|
3214
|
+
return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, item]) => [key, snapshot(item, ancestors)])));
|
|
3215
|
+
} finally {
|
|
3216
|
+
ancestors.delete(value);
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
/**
|
|
3220
|
+
* Create a detached reference containing an immutable copy of the supplied data.
|
|
3221
|
+
* @param value - validated config data; class instances and functions are unsupported.
|
|
3222
|
+
* @returns a reference whose value is updated only by its owning runtime.
|
|
3223
|
+
*/
|
|
3224
|
+
function createVolatile(value) {
|
|
3225
|
+
let current = snapshot(value);
|
|
3226
|
+
return Object.freeze({
|
|
3227
|
+
get: () => current,
|
|
3228
|
+
[write]: (value) => {
|
|
3229
|
+
current = value;
|
|
3230
|
+
}
|
|
3231
|
+
});
|
|
3232
|
+
}
|
|
3233
|
+
/**
|
|
3234
|
+
* Identify references across ESM/CJS copies of the shared library.
|
|
3235
|
+
* @param value - a parsed config value.
|
|
3236
|
+
* @returns whether the value implements the shared reference protocol.
|
|
3237
|
+
*/
|
|
3238
|
+
function isVolatile(value) {
|
|
3239
|
+
return typeof value === "object" && value !== null && write in value;
|
|
3240
|
+
}
|
|
3241
|
+
//#endregion
|
|
3242
|
+
//#region ../../../vendor/cosmokit/src/types.ts
|
|
3243
|
+
/** Test values using `instanceof` with a `toStringTag` fallback. */
|
|
3244
|
+
function is(type, value) {
|
|
3245
|
+
if (arguments.length === 1) return (value) => is(type, value);
|
|
3246
|
+
return type in globalThis && value instanceof globalThis[type] || Object.prototype.toString.call(value).slice(8, -1) === type;
|
|
3247
|
+
}
|
|
3248
|
+
function isArrayBufferLike(value) {
|
|
3249
|
+
return is("ArrayBuffer", value) || is("SharedArrayBuffer", value);
|
|
3250
|
+
}
|
|
3251
|
+
function isArrayBufferSource(value) {
|
|
3252
|
+
return isArrayBufferLike(value) || ArrayBuffer.isView(value);
|
|
3253
|
+
}
|
|
3254
|
+
let Binary;
|
|
3255
|
+
(function(_Binary) {
|
|
3256
|
+
_Binary.is = isArrayBufferLike;
|
|
3257
|
+
_Binary.isSource = isArrayBufferSource;
|
|
3258
|
+
function fromSource(source) {
|
|
3259
|
+
if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength);
|
|
3260
|
+
else return source;
|
|
3261
|
+
}
|
|
3262
|
+
_Binary.fromSource = fromSource;
|
|
3263
|
+
function toBase64(source) {
|
|
3264
|
+
source = fromSource(source);
|
|
3265
|
+
if (typeof Buffer !== "undefined") return Buffer.from(source).toString("base64");
|
|
3266
|
+
let binary = "";
|
|
3267
|
+
const bytes = new Uint8Array(source);
|
|
3268
|
+
for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
|
|
3269
|
+
return btoa(binary);
|
|
3270
|
+
}
|
|
3271
|
+
_Binary.toBase64 = toBase64;
|
|
3272
|
+
function fromBase64(source) {
|
|
3273
|
+
if (typeof Buffer !== "undefined") return fromSource(Buffer.from(source, "base64"));
|
|
3274
|
+
return Uint8Array.from(atob(source), (c) => c.charCodeAt(0));
|
|
3275
|
+
}
|
|
3276
|
+
_Binary.fromBase64 = fromBase64;
|
|
3277
|
+
function toHex(source) {
|
|
3278
|
+
source = fromSource(source);
|
|
3279
|
+
if (typeof Buffer !== "undefined") return Buffer.from(source).toString("hex");
|
|
3280
|
+
return Array.from(new Uint8Array(source), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
3281
|
+
}
|
|
3282
|
+
_Binary.toHex = toHex;
|
|
3283
|
+
function fromHex(source) {
|
|
3284
|
+
if (typeof Buffer !== "undefined") return fromSource(Buffer.from(source, "hex"));
|
|
3285
|
+
const hex = source.length % 2 === 0 ? source : source.slice(0, source.length - 1);
|
|
3286
|
+
const buffer = [];
|
|
3287
|
+
for (let i = 0; i < hex.length; i += 2) buffer.push(parseInt(`${hex[i]}${hex[i + 1]}`, 16));
|
|
3288
|
+
return Uint8Array.from(buffer).buffer;
|
|
3289
|
+
}
|
|
3290
|
+
_Binary.fromHex = fromHex;
|
|
3291
|
+
})(Binary || (Binary = {}));
|
|
3292
|
+
Binary.fromBase64;
|
|
3293
|
+
Binary.toBase64;
|
|
3294
|
+
Binary.fromHex;
|
|
3295
|
+
Binary.toHex;
|
|
3296
|
+
/** Deep-clone common JavaScript values while preserving prototypes and cycles. */
|
|
3297
|
+
function clone(source, refs = /* @__PURE__ */ new Map()) {
|
|
3298
|
+
if (!source || typeof source !== "object") return source;
|
|
3299
|
+
if (is("Date", source)) return new Date(source.valueOf());
|
|
3300
|
+
if (is("RegExp", source)) return new RegExp(source.source, source.flags);
|
|
3301
|
+
if (isArrayBufferLike(source)) return source.slice(0);
|
|
3302
|
+
if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength);
|
|
3303
|
+
const cached = refs.get(source);
|
|
3304
|
+
if (cached) return cached;
|
|
3305
|
+
if (Array.isArray(source)) {
|
|
3306
|
+
const result = [];
|
|
3307
|
+
refs.set(source, result);
|
|
3308
|
+
source.forEach((value, index) => {
|
|
3309
|
+
result[index] = Reflect.apply(clone, null, [value, refs]);
|
|
3310
|
+
});
|
|
3311
|
+
return result;
|
|
3312
|
+
}
|
|
3313
|
+
const result = Object.create(Object.getPrototypeOf(source));
|
|
3314
|
+
refs.set(source, result);
|
|
3315
|
+
for (const key of Reflect.ownKeys(source)) {
|
|
3316
|
+
const descriptor = { ...Reflect.getOwnPropertyDescriptor(source, key) };
|
|
3317
|
+
if ("value" in descriptor) descriptor.value = Reflect.apply(clone, null, [descriptor.value, refs]);
|
|
3318
|
+
Reflect.defineProperty(result, key, descriptor);
|
|
3319
|
+
}
|
|
3320
|
+
return result;
|
|
3321
|
+
}
|
|
3322
|
+
/**
|
|
3323
|
+
* Compare values recursively, treating two volatile references as equal regardless of value.
|
|
3324
|
+
* Strict comparison distinguishes null/undefined, treats opaque objects by identity,
|
|
3325
|
+
* compares URLs by normalized href, treats array holes as undefined, and considers distinct cyclic structures unequal.
|
|
3326
|
+
* @param a - first value.
|
|
3327
|
+
* @param b - second value.
|
|
3328
|
+
* @param strict - whether to require strict data equality outside volatile references.
|
|
3329
|
+
* @returns whether the values compare equal.
|
|
3330
|
+
*/
|
|
3331
|
+
function deepEqual(a, b, strict) {
|
|
3332
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
3333
|
+
function compare(a, b) {
|
|
3334
|
+
if (a === b) return true;
|
|
3335
|
+
if (isVolatile(a) || isVolatile(b)) return isVolatile(a) && isVolatile(b);
|
|
3336
|
+
if (!strict && isNullable(a) && isNullable(b)) return true;
|
|
3337
|
+
if (typeof a !== typeof b || typeof a !== "object" || !a || !b) return false;
|
|
3338
|
+
if (ancestors.has(a)) return false;
|
|
3339
|
+
function check(test, then) {
|
|
3340
|
+
return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : void 0;
|
|
3341
|
+
}
|
|
3342
|
+
ancestors.add(a);
|
|
3343
|
+
try {
|
|
3344
|
+
return check(Array.isArray, (a, b) => {
|
|
3345
|
+
if (a.length !== b.length) return false;
|
|
3346
|
+
for (let index = 0; index < a.length; index++) if (!compare(a[index], b[index])) return false;
|
|
3347
|
+
return true;
|
|
3348
|
+
}) ?? check(is("Date"), (a, b) => a.valueOf() === b.valueOf()) ?? check(is("URL"), (a, b) => a.href === b.href) ?? check(is("RegExp"), (a, b) => a.source === b.source && a.flags === b.flags) ?? check(isArrayBufferLike, (a, b) => {
|
|
3349
|
+
if (a.byteLength !== b.byteLength) return false;
|
|
3350
|
+
const viewA = new Uint8Array(a);
|
|
3351
|
+
const viewB = new Uint8Array(b);
|
|
3352
|
+
for (let i = 0; i < viewA.length; i++) if (viewA[i] !== viewB[i]) return false;
|
|
3353
|
+
return true;
|
|
3354
|
+
}) ?? ((!strict || [a, b].every((value) => Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null)) && Object.keys({
|
|
3355
|
+
...a,
|
|
3356
|
+
...b
|
|
3357
|
+
}).every((key) => compare(a[key], b[key])));
|
|
3358
|
+
} finally {
|
|
3359
|
+
ancestors.delete(a);
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
return compare(a, b);
|
|
3363
|
+
}
|
|
3364
|
+
//#endregion
|
|
3365
|
+
//#region ../../../vendor/cosmokit/src/time.ts
|
|
3366
|
+
let Time;
|
|
3367
|
+
(function(_Time) {
|
|
3368
|
+
_Time.millisecond = 1;
|
|
3369
|
+
const second = _Time.second = 1e3;
|
|
3370
|
+
const minute = _Time.minute = second * 60;
|
|
3371
|
+
const hour = _Time.hour = minute * 60;
|
|
3372
|
+
const day = _Time.day = hour * 24;
|
|
3373
|
+
const week = _Time.week = day * 7;
|
|
3374
|
+
let timezoneOffset = (/* @__PURE__ */ new Date()).getTimezoneOffset();
|
|
3375
|
+
function setTimezoneOffset(offset) {
|
|
3376
|
+
timezoneOffset = offset;
|
|
3377
|
+
}
|
|
3378
|
+
_Time.setTimezoneOffset = setTimezoneOffset;
|
|
3379
|
+
function getTimezoneOffset() {
|
|
3380
|
+
return timezoneOffset;
|
|
3381
|
+
}
|
|
3382
|
+
_Time.getTimezoneOffset = getTimezoneOffset;
|
|
3383
|
+
function getDateNumber(date = /* @__PURE__ */ new Date(), offset) {
|
|
3384
|
+
if (typeof date === "number") date = new Date(date);
|
|
3385
|
+
if (offset === void 0) offset = timezoneOffset;
|
|
3386
|
+
return Math.floor((date.valueOf() / minute - offset) / 1440);
|
|
3387
|
+
}
|
|
3388
|
+
_Time.getDateNumber = getDateNumber;
|
|
3389
|
+
function fromDateNumber(value, offset) {
|
|
3390
|
+
const date = new Date(value * day);
|
|
3391
|
+
if (offset === void 0) offset = timezoneOffset;
|
|
3392
|
+
return new Date(+date + offset * minute);
|
|
3393
|
+
}
|
|
3394
|
+
_Time.fromDateNumber = fromDateNumber;
|
|
3395
|
+
const numeric = /\d+(?:\.\d+)?/.source;
|
|
3396
|
+
const timeRegExp = new RegExp(`^${[
|
|
3397
|
+
"w(?:eek(?:s)?)?",
|
|
3398
|
+
"d(?:ay(?:s)?)?",
|
|
3399
|
+
"h(?:our(?:s)?)?",
|
|
3400
|
+
"m(?:in(?:ute)?(?:s)?)?",
|
|
3401
|
+
"s(?:ec(?:ond)?(?:s)?)?"
|
|
3402
|
+
].map((unit) => `(${numeric}${unit})?`).join("")}$`);
|
|
3403
|
+
function parseTime(source) {
|
|
3404
|
+
const capture = timeRegExp.exec(source);
|
|
3405
|
+
if (!capture) return 0;
|
|
3406
|
+
return (parseFloat(capture[1]) * week || 0) + (parseFloat(capture[2]) * day || 0) + (parseFloat(capture[3]) * hour || 0) + (parseFloat(capture[4]) * minute || 0) + (parseFloat(capture[5]) * second || 0);
|
|
3407
|
+
}
|
|
3408
|
+
_Time.parseTime = parseTime;
|
|
3409
|
+
function parseDate(date) {
|
|
3410
|
+
const parsed = parseTime(date);
|
|
3411
|
+
if (parsed) date = Date.now() + parsed;
|
|
3412
|
+
else if (/^\d{1,2}(:\d{1,2}){1,2}$/.test(date)) date = `${(/* @__PURE__ */ new Date()).toLocaleDateString()}-${date}`;
|
|
3413
|
+
else if (/^\d{1,2}-\d{1,2}-\d{1,2}(:\d{1,2}){1,2}$/.test(date)) date = `${(/* @__PURE__ */ new Date()).getFullYear()}-${date}`;
|
|
3414
|
+
return date ? new Date(date) : /* @__PURE__ */ new Date();
|
|
3415
|
+
}
|
|
3416
|
+
_Time.parseDate = parseDate;
|
|
3417
|
+
function format(ms) {
|
|
3418
|
+
const abs = Math.abs(ms);
|
|
3419
|
+
if (abs >= day - hour / 2) return Math.round(ms / day) + "d";
|
|
3420
|
+
else if (abs >= hour - minute / 2) return Math.round(ms / hour) + "h";
|
|
3421
|
+
else if (abs >= minute - second / 2) return Math.round(ms / minute) + "m";
|
|
3422
|
+
else if (abs >= second) return Math.round(ms / second) + "s";
|
|
3423
|
+
return ms + "ms";
|
|
3424
|
+
}
|
|
3425
|
+
_Time.format = format;
|
|
3426
|
+
function toDigits(source, length = 2) {
|
|
3427
|
+
return source.toString().padStart(length, "0");
|
|
3428
|
+
}
|
|
3429
|
+
_Time.toDigits = toDigits;
|
|
3430
|
+
function template(template, time = /* @__PURE__ */ new Date()) {
|
|
3431
|
+
return template.replace("yyyy", time.getFullYear().toString()).replace("yy", time.getFullYear().toString().slice(2)).replace("MM", toDigits(time.getMonth() + 1)).replace("dd", toDigits(time.getDate())).replace("hh", toDigits(time.getHours())).replace("mm", toDigits(time.getMinutes())).replace("ss", toDigits(time.getSeconds())).replace("SSS", toDigits(time.getMilliseconds(), 3));
|
|
3432
|
+
}
|
|
3433
|
+
_Time.template = template;
|
|
3434
|
+
})(Time || (Time = {}));
|
|
3435
|
+
//#endregion
|
|
3436
|
+
//#region ../../../vendor/schemastery/src/index.ts
|
|
3437
|
+
const kSchema = Symbol.for("schemastery");
|
|
3438
|
+
const kValidationError = Symbol.for("ValidationError");
|
|
3439
|
+
globalThis.__schemastery_index__ ??= 0;
|
|
3440
|
+
globalThis.__schemastery_refs__ = void 0;
|
|
3441
|
+
var ValidationError = class extends TypeError {
|
|
3442
|
+
options;
|
|
3443
|
+
name = "ValidationError";
|
|
3444
|
+
constructor(message, options) {
|
|
3445
|
+
let prefix = "$";
|
|
3446
|
+
for (const segment of options.path || []) if (typeof segment === "string") prefix += "." + segment;
|
|
3447
|
+
else if (typeof segment === "number") prefix += "[" + segment + "]";
|
|
3448
|
+
else if (typeof segment === "symbol") prefix += `[Symbol(${segment.toString()})]`;
|
|
3449
|
+
if (prefix.startsWith(".")) prefix = prefix.slice(1);
|
|
3450
|
+
super((prefix === "$" ? "" : `${prefix} `) + message);
|
|
3451
|
+
this.options = options;
|
|
3452
|
+
}
|
|
3453
|
+
static is(error) {
|
|
3454
|
+
return !!error?.[kValidationError];
|
|
3455
|
+
}
|
|
3456
|
+
};
|
|
3457
|
+
Object.defineProperty(ValidationError.prototype, kValidationError, { value: true });
|
|
3458
|
+
const Schema = function(options) {
|
|
3459
|
+
const schema = function(data, options = {}) {
|
|
3460
|
+
return Schema.resolve(data, schema, options)[0];
|
|
3461
|
+
};
|
|
3462
|
+
if (options.refs) {
|
|
3463
|
+
const refs = mapValues(options.refs, (options) => new Schema(options));
|
|
3464
|
+
const getRef = (uid) => refs[uid];
|
|
3465
|
+
for (const key in refs) {
|
|
3466
|
+
const options = refs[key];
|
|
3467
|
+
options.sKey = getRef(options.sKey);
|
|
3468
|
+
options.inner = getRef(options.inner);
|
|
3469
|
+
options.list = options.list && options.list.map(getRef);
|
|
3470
|
+
options.dict = options.dict && mapValues(options.dict, getRef);
|
|
3471
|
+
}
|
|
3472
|
+
return refs[options.uid];
|
|
3473
|
+
}
|
|
3474
|
+
Object.assign(schema, options);
|
|
3475
|
+
if (typeof schema.callback === "string") try {
|
|
3476
|
+
schema.callback = new Function("return " + schema.callback)();
|
|
3477
|
+
} catch {}
|
|
3478
|
+
Object.defineProperty(schema, "uid", { value: globalThis.__schemastery_index__++ });
|
|
3479
|
+
Object.setPrototypeOf(schema, Schema.prototype);
|
|
3480
|
+
schema.meta ||= {};
|
|
3481
|
+
schema.toString = schema.toString.bind(schema);
|
|
3482
|
+
return schema;
|
|
3483
|
+
};
|
|
3484
|
+
Schema.prototype = Object.create(Function.prototype);
|
|
3485
|
+
Schema.prototype[kSchema] = true;
|
|
3486
|
+
Object.defineProperty(Schema.prototype, "~standard", { get() {
|
|
3487
|
+
return {
|
|
3488
|
+
version: 1,
|
|
3489
|
+
vendor: "schemastery",
|
|
3490
|
+
validate: (value) => {
|
|
3491
|
+
try {
|
|
3492
|
+
return { value: Schema.resolve(value, this, {})[0] };
|
|
3493
|
+
} catch (error) {
|
|
3494
|
+
if (ValidationError.is(error)) return { issues: [{
|
|
3495
|
+
message: error.message,
|
|
3496
|
+
path: error.options.path
|
|
3497
|
+
}] };
|
|
3498
|
+
throw error;
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
};
|
|
3502
|
+
} });
|
|
3503
|
+
Schema.ValidationError = ValidationError;
|
|
3504
|
+
Schema.prototype.toJSON = function toJSON() {
|
|
3505
|
+
if (globalThis.__schemastery_refs__) {
|
|
3506
|
+
globalThis.__schemastery_refs__[this.uid] ??= JSON.parse(JSON.stringify({ ...this }));
|
|
3507
|
+
return this.uid;
|
|
3508
|
+
}
|
|
3509
|
+
globalThis.__schemastery_refs__ = { [this.uid]: { ...this } };
|
|
3510
|
+
globalThis.__schemastery_refs__[this.uid] = JSON.parse(JSON.stringify({ ...this }));
|
|
3511
|
+
const result = {
|
|
3512
|
+
uid: this.uid,
|
|
3513
|
+
refs: globalThis.__schemastery_refs__
|
|
3514
|
+
};
|
|
3515
|
+
globalThis.__schemastery_refs__ = void 0;
|
|
3516
|
+
return result;
|
|
3517
|
+
};
|
|
3518
|
+
Schema.prototype.set = function set(key, value) {
|
|
3519
|
+
this.dict[key] = value;
|
|
3520
|
+
return this;
|
|
3521
|
+
};
|
|
3522
|
+
Schema.prototype.push = function push(value) {
|
|
3523
|
+
this.list.push(value);
|
|
3524
|
+
return this;
|
|
3525
|
+
};
|
|
3526
|
+
function mergeDesc(original, messages) {
|
|
3527
|
+
const result = typeof original === "string" ? { "": original } : { ...original };
|
|
3528
|
+
for (const locale in messages) {
|
|
3529
|
+
const value = messages[locale];
|
|
3530
|
+
if (value?.$description || value?.$desc) result[locale] = value.$description || value.$desc;
|
|
3531
|
+
else if (typeof value === "string") result[locale] = value;
|
|
3532
|
+
}
|
|
3533
|
+
return result;
|
|
3534
|
+
}
|
|
3535
|
+
function getInner(value) {
|
|
3536
|
+
return value?.$value ?? value?.$inner;
|
|
3537
|
+
}
|
|
3538
|
+
function extractKeys(data) {
|
|
3539
|
+
return filterKeys(data ?? {}, (key) => !key.startsWith("$"));
|
|
3540
|
+
}
|
|
3541
|
+
Schema.prototype.i18n = function i18n(messages) {
|
|
3542
|
+
const schema = Schema(this);
|
|
3543
|
+
const desc = mergeDesc(schema.meta.description, messages);
|
|
3544
|
+
if (Object.keys(desc).length) schema.meta.description = desc;
|
|
3545
|
+
if (schema.dict) schema.dict = mapValues(schema.dict, (inner, key) => {
|
|
3546
|
+
return inner.i18n(mapValues(messages, (data) => getInner(data)?.[key] ?? data?.[key]));
|
|
3547
|
+
});
|
|
3548
|
+
if (schema.list) schema.list = schema.list.map((inner, index) => {
|
|
3549
|
+
return inner.i18n(mapValues(messages, (data = {}) => {
|
|
3550
|
+
if (Array.isArray(getInner(data))) return getInner(data)[index];
|
|
3551
|
+
if (Array.isArray(data)) return data[index];
|
|
3552
|
+
return extractKeys(data);
|
|
3553
|
+
}));
|
|
3554
|
+
});
|
|
3555
|
+
if (schema.inner) schema.inner = schema.inner.i18n(mapValues(messages, (data) => {
|
|
3556
|
+
if (getInner(data)) return getInner(data);
|
|
3557
|
+
return extractKeys(data);
|
|
3558
|
+
}));
|
|
3559
|
+
if (schema.sKey) schema.sKey = schema.sKey.i18n(mapValues(messages, (data) => data?.$key));
|
|
3560
|
+
return schema;
|
|
3561
|
+
};
|
|
3562
|
+
Schema.prototype.extra = function extra(key, value) {
|
|
3563
|
+
const schema = Schema(this);
|
|
3564
|
+
schema.meta = {
|
|
3565
|
+
...schema.meta,
|
|
3566
|
+
[key]: value
|
|
3567
|
+
};
|
|
3568
|
+
return schema;
|
|
3569
|
+
};
|
|
3570
|
+
for (const key of [
|
|
3571
|
+
"required",
|
|
3572
|
+
"disabled",
|
|
3573
|
+
"collapse",
|
|
3574
|
+
"hidden",
|
|
3575
|
+
"loose"
|
|
3576
|
+
]) Object.assign(Schema.prototype, { [key](value = true) {
|
|
3577
|
+
const schema = Schema(this);
|
|
3578
|
+
schema.meta = {
|
|
3579
|
+
...schema.meta,
|
|
3580
|
+
[key]: value
|
|
3581
|
+
};
|
|
3582
|
+
return schema;
|
|
3583
|
+
} });
|
|
3584
|
+
Schema.prototype.deprecated = function deprecated() {
|
|
3585
|
+
const schema = Schema(this);
|
|
3586
|
+
schema.meta.badges ||= [];
|
|
3587
|
+
schema.meta.badges.push({
|
|
3588
|
+
text: "deprecated",
|
|
3589
|
+
type: "danger"
|
|
3590
|
+
});
|
|
3591
|
+
return schema;
|
|
3592
|
+
};
|
|
3593
|
+
Schema.prototype.experimental = function experimental() {
|
|
3594
|
+
const schema = Schema(this);
|
|
3595
|
+
schema.meta.badges ||= [];
|
|
3596
|
+
schema.meta.badges.push({
|
|
3597
|
+
text: "experimental",
|
|
3598
|
+
type: "warning"
|
|
3599
|
+
});
|
|
3600
|
+
return schema;
|
|
3601
|
+
};
|
|
3602
|
+
Schema.prototype.pattern = function pattern(regexp) {
|
|
3603
|
+
const schema = Schema(this);
|
|
3604
|
+
const pattern = pick(regexp, ["source", "flags"]);
|
|
3605
|
+
schema.meta = {
|
|
3606
|
+
...schema.meta,
|
|
3607
|
+
pattern
|
|
3608
|
+
};
|
|
3609
|
+
return schema;
|
|
3610
|
+
};
|
|
3611
|
+
Schema.prototype.simplify = function simplify(value) {
|
|
3612
|
+
if (isVolatile(value)) value = value.get();
|
|
3613
|
+
if (deepEqual(value, this.meta.default, this.type === "dict")) return null;
|
|
3614
|
+
if (isNullable(value)) return value;
|
|
3615
|
+
if (this.type === "object" || this.type === "dict") {
|
|
3616
|
+
const result = {};
|
|
3617
|
+
for (const key in value) {
|
|
3618
|
+
const item = (this.type === "object" ? this.dict[key] : this.inner)?.simplify(value[key]);
|
|
3619
|
+
if (this.type === "dict" || !isNullable(item)) result[key] = item;
|
|
3620
|
+
}
|
|
3621
|
+
if (deepEqual(result, this.meta.default, this.type === "dict")) return null;
|
|
3622
|
+
return result;
|
|
3623
|
+
} else if (this.type === "array" || this.type === "tuple") {
|
|
3624
|
+
const result = [];
|
|
3625
|
+
value.forEach((value, index) => {
|
|
3626
|
+
const schema = this.type === "array" ? this.inner : this.list[index];
|
|
3627
|
+
const item = schema ? schema.simplify(value) : value;
|
|
3628
|
+
result.push(item);
|
|
3629
|
+
});
|
|
3630
|
+
return result;
|
|
3631
|
+
} else if (this.type === "intersect") {
|
|
3632
|
+
const result = {};
|
|
3633
|
+
for (const item of this.list) Object.assign(result, item.simplify(value));
|
|
3634
|
+
return result;
|
|
3635
|
+
} else if (this.type === "union") for (const schema of this.list) try {
|
|
3636
|
+
Schema.resolve(value, schema, {});
|
|
3637
|
+
return schema.simplify(value);
|
|
3638
|
+
} catch {}
|
|
3639
|
+
return value;
|
|
3640
|
+
};
|
|
3641
|
+
Schema.prototype.toString = function toString(inline) {
|
|
3642
|
+
return formatters[this.type]?.(this, inline) ?? `Schema<${this.type}>`;
|
|
3643
|
+
};
|
|
3644
|
+
Schema.prototype.role = function role(role, extra) {
|
|
3645
|
+
const schema = Schema(this);
|
|
3646
|
+
schema.meta = {
|
|
3647
|
+
...schema.meta,
|
|
3648
|
+
role,
|
|
3649
|
+
extra
|
|
3650
|
+
};
|
|
3651
|
+
return schema;
|
|
3652
|
+
};
|
|
3653
|
+
for (const key of [
|
|
3654
|
+
"default",
|
|
3655
|
+
"link",
|
|
3656
|
+
"comment",
|
|
3657
|
+
"description",
|
|
3658
|
+
"max",
|
|
3659
|
+
"min",
|
|
3660
|
+
"step"
|
|
3661
|
+
]) Object.assign(Schema.prototype, { [key](value) {
|
|
3662
|
+
const schema = Schema(this);
|
|
3663
|
+
schema.meta = {
|
|
3664
|
+
...schema.meta,
|
|
3665
|
+
[key]: value
|
|
3666
|
+
};
|
|
3667
|
+
return schema;
|
|
3668
|
+
} });
|
|
3669
|
+
Schema.prototype.volatile = function volatile() {
|
|
3670
|
+
if (this.meta.volatile) throw new TypeError("volatile schema is already wrapped");
|
|
3671
|
+
return this.extra("volatile", true);
|
|
3672
|
+
};
|
|
3673
|
+
const resolvers = {};
|
|
3674
|
+
const checkedVolatile = Symbol("checked-volatile-schema");
|
|
3675
|
+
function validateVolatileSchema(schema, path = [], blocked = false, seen = /* @__PURE__ */ new Map()) {
|
|
3676
|
+
const states = seen.get(schema) ?? /* @__PURE__ */ new Set();
|
|
3677
|
+
if (states.has(blocked)) return;
|
|
3678
|
+
states.add(blocked);
|
|
3679
|
+
seen.set(schema, states);
|
|
3680
|
+
if (schema.meta?.volatile && blocked) throw new ValidationError("volatile fields require a fixed object path without an enclosing volatile field", { path });
|
|
3681
|
+
const nested = blocked || !!schema.meta?.volatile;
|
|
3682
|
+
if (schema.dict) for (const [key, child] of Object.entries(schema.dict)) validateVolatileSchema(child, [...path, key], nested, seen);
|
|
3683
|
+
if (schema.sKey) validateVolatileSchema(schema.sKey, [...path, "<key>"], true, seen);
|
|
3684
|
+
if (schema.inner && (schema.type !== "lazy" || schema.inner[kSchema])) validateVolatileSchema(schema.inner, [...path, "*"], true, seen);
|
|
3685
|
+
if (schema.list) for (let index = 0; index < schema.list.length; index++) validateVolatileSchema(schema.list[index], [...path, String(index)], true, seen);
|
|
3686
|
+
}
|
|
3687
|
+
Schema.extend = function extend(type, resolve) {
|
|
3688
|
+
resolvers[type] = resolve;
|
|
3689
|
+
};
|
|
3690
|
+
Schema.resolve = function resolve(data, schema, options = {}, strict = false) {
|
|
3691
|
+
if (!schema) return [data];
|
|
3692
|
+
if (!options[checkedVolatile]) {
|
|
3693
|
+
validateVolatileSchema(schema, options.path);
|
|
3694
|
+
options = {
|
|
3695
|
+
...options,
|
|
3696
|
+
[checkedVolatile]: true
|
|
3697
|
+
};
|
|
3698
|
+
}
|
|
3699
|
+
if (schema.meta?.volatile) {
|
|
3700
|
+
const inner = Schema(schema);
|
|
3701
|
+
inner.meta = {
|
|
3702
|
+
...schema.meta,
|
|
3703
|
+
volatile: false
|
|
3704
|
+
};
|
|
3705
|
+
const [value, adapted] = Schema.resolve(data, inner, options, strict);
|
|
3706
|
+
try {
|
|
3707
|
+
return [createVolatile(value), adapted];
|
|
3708
|
+
} catch (error) {
|
|
3709
|
+
throw new ValidationError(error instanceof Error ? error.message : String(error), options);
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
if (options.ignore?.(data, schema)) return [data];
|
|
3713
|
+
if (isNullable(data) && schema.type !== "lazy") {
|
|
3714
|
+
if (schema.meta.required) throw new ValidationError(`missing required value`, options);
|
|
3715
|
+
let current = schema;
|
|
3716
|
+
let fallback = schema.meta.default;
|
|
3717
|
+
while (current?.type === "intersect" && isNullable(fallback)) {
|
|
3718
|
+
current = current.list[0];
|
|
3719
|
+
fallback = current?.meta.default;
|
|
3720
|
+
}
|
|
3721
|
+
if (isNullable(fallback)) return [data];
|
|
3722
|
+
data = clone(fallback);
|
|
3723
|
+
}
|
|
3724
|
+
const callback = resolvers[schema.type];
|
|
3725
|
+
if (!callback) throw new ValidationError(`unsupported type "${schema.type}"`, options);
|
|
3726
|
+
try {
|
|
3727
|
+
return callback(data, schema, options, strict);
|
|
3728
|
+
} catch (error) {
|
|
3729
|
+
if (!schema.meta.loose) throw error;
|
|
3730
|
+
return [schema.meta.default];
|
|
3731
|
+
}
|
|
3732
|
+
};
|
|
3733
|
+
Schema.from = function from(source) {
|
|
3734
|
+
if (isNullable(source)) return Schema.any();
|
|
3735
|
+
else if ([
|
|
3736
|
+
"string",
|
|
3737
|
+
"number",
|
|
3738
|
+
"boolean"
|
|
3739
|
+
].includes(typeof source)) return Schema.const(source).required();
|
|
3740
|
+
else if (source[kSchema]) return source;
|
|
3741
|
+
else if (typeof source === "function") switch (source) {
|
|
3742
|
+
case String: return Schema.string().required();
|
|
3743
|
+
case Number: return Schema.number().required();
|
|
3744
|
+
case Boolean: return Schema.boolean().required();
|
|
3745
|
+
case Function: return Schema.function().required();
|
|
3746
|
+
default: return Schema.is(source).required();
|
|
3747
|
+
}
|
|
3748
|
+
else throw new TypeError(`cannot infer schema from ${source}`);
|
|
3749
|
+
};
|
|
3750
|
+
Schema.lazy = function lazy(builder) {
|
|
3751
|
+
const toJSON = () => {
|
|
3752
|
+
if (!schema.inner[kSchema]) {
|
|
3753
|
+
schema.inner = schema.builder();
|
|
3754
|
+
schema.inner.meta = {
|
|
3755
|
+
...schema.meta,
|
|
3756
|
+
...schema.inner.meta
|
|
3757
|
+
};
|
|
3758
|
+
}
|
|
3759
|
+
return schema.inner.toJSON();
|
|
3760
|
+
};
|
|
3761
|
+
const schema = new Schema({
|
|
3762
|
+
type: "lazy",
|
|
3763
|
+
builder,
|
|
3764
|
+
inner: { toJSON }
|
|
3765
|
+
});
|
|
3766
|
+
return schema;
|
|
3767
|
+
};
|
|
3768
|
+
Schema.natural = function natural() {
|
|
3769
|
+
return Schema.number().step(1).min(0);
|
|
3770
|
+
};
|
|
3771
|
+
Schema.percent = function percent() {
|
|
3772
|
+
return Schema.number().step(.01).min(0).max(1).role("slider");
|
|
3773
|
+
};
|
|
3774
|
+
Schema.date = function date() {
|
|
3775
|
+
return Schema.union([Schema.is(Date), Schema.transform(Schema.string().role("datetime"), (value, options) => {
|
|
3776
|
+
const date = new Date(value);
|
|
3777
|
+
if (isNaN(+date)) throw new ValidationError(`invalid date "${value}"`, options);
|
|
3778
|
+
return date;
|
|
3779
|
+
}, true)]);
|
|
3780
|
+
};
|
|
3781
|
+
Schema.regExp = function regExp(flag = "") {
|
|
3782
|
+
return Schema.union([Schema.is(RegExp), Schema.transform(Schema.string().role("regexp", { flag }), (value, options) => {
|
|
3783
|
+
try {
|
|
3784
|
+
return new RegExp(value, flag);
|
|
3785
|
+
} catch (e) {
|
|
3786
|
+
throw new ValidationError(e.message, options);
|
|
3787
|
+
}
|
|
3788
|
+
}, true)]);
|
|
3789
|
+
};
|
|
3790
|
+
Schema.arrayBuffer = function arrayBuffer(encoding) {
|
|
3791
|
+
return Schema.union([
|
|
3792
|
+
Schema.is(ArrayBuffer),
|
|
3793
|
+
Schema.is(SharedArrayBuffer),
|
|
3794
|
+
Schema.transform(Schema.any(), (value, options) => {
|
|
3795
|
+
if (Binary.isSource(value)) return Binary.fromSource(value);
|
|
3796
|
+
throw new ValidationError(`expected ArrayBufferSource but got ${value}`, options);
|
|
3797
|
+
}, true),
|
|
3798
|
+
...encoding ? [Schema.transform(Schema.string(), (value, options) => {
|
|
3799
|
+
try {
|
|
3800
|
+
return encoding === "base64" ? Binary.fromBase64(value) : Binary.fromHex(value);
|
|
3801
|
+
} catch (e) {
|
|
3802
|
+
throw new ValidationError(e.message, options);
|
|
3803
|
+
}
|
|
3804
|
+
}, true)] : []
|
|
3805
|
+
]);
|
|
3806
|
+
};
|
|
3807
|
+
Schema.extend("lazy", (data, schema, options, strict) => {
|
|
3808
|
+
if (!schema.inner[kSchema]) {
|
|
3809
|
+
schema.inner = schema.builder();
|
|
3810
|
+
schema.inner.meta = {
|
|
3811
|
+
...schema.meta,
|
|
3812
|
+
...schema.inner.meta
|
|
3813
|
+
};
|
|
3814
|
+
validateVolatileSchema(schema.inner, options.path, true);
|
|
3815
|
+
}
|
|
3816
|
+
return Schema.resolve(data, schema.inner, options, strict);
|
|
3817
|
+
});
|
|
3818
|
+
Schema.extend("any", (data) => {
|
|
3819
|
+
return [data];
|
|
3820
|
+
});
|
|
3821
|
+
Schema.extend("never", (data, _, options) => {
|
|
3822
|
+
throw new ValidationError(`expected nullable but got ${data}`, options);
|
|
3823
|
+
});
|
|
3824
|
+
Schema.extend("const", (data, { value }, options) => {
|
|
3825
|
+
if (deepEqual(data, value)) return [value];
|
|
3826
|
+
throw new ValidationError(`expected ${value} but got ${data}`, options);
|
|
3827
|
+
});
|
|
3828
|
+
function checkWithinRange(data, meta, description, options, skipMin = false) {
|
|
3829
|
+
const { max = Infinity, min = -Infinity } = meta;
|
|
3830
|
+
if (data > max) throw new ValidationError(`expected ${description} <= ${max} but got ${data}`, options);
|
|
3831
|
+
if (data < min && !skipMin) throw new ValidationError(`expected ${description} >= ${min} but got ${data}`, options);
|
|
3832
|
+
}
|
|
3833
|
+
Schema.extend("string", (data, { meta }, options) => {
|
|
3834
|
+
if (typeof data !== "string") throw new ValidationError(`expected string but got ${data}`, options);
|
|
3835
|
+
if (meta.pattern) {
|
|
3836
|
+
const regexp = new RegExp(meta.pattern.source, meta.pattern.flags);
|
|
3837
|
+
if (!regexp.test(data)) throw new ValidationError(`expect string to match regexp ${regexp}`, options);
|
|
3838
|
+
}
|
|
3839
|
+
checkWithinRange(data.length, meta, "string length", options);
|
|
3840
|
+
return [data];
|
|
3841
|
+
});
|
|
3842
|
+
function decimalShift(data, digits) {
|
|
3843
|
+
const str = data.toString();
|
|
3844
|
+
if (str.includes("e")) return data * Math.pow(10, digits);
|
|
3845
|
+
const index = str.indexOf(".");
|
|
3846
|
+
if (index === -1) return data * Math.pow(10, digits);
|
|
3847
|
+
const frac = str.slice(index + 1);
|
|
3848
|
+
const integer = str.slice(0, index);
|
|
3849
|
+
if (frac.length <= digits) return +(integer + frac.padEnd(digits, "0"));
|
|
3850
|
+
return +(integer + frac.slice(0, digits) + "." + frac.slice(digits));
|
|
3851
|
+
}
|
|
3852
|
+
function isMultipleOf(data, min, step) {
|
|
3853
|
+
step = Math.abs(step);
|
|
3854
|
+
if (!/^\d+\.\d+$/.test(step.toString())) return (data - min) % step === 0;
|
|
3855
|
+
const index = step.toString().indexOf(".");
|
|
3856
|
+
const digits = step.toString().slice(index + 1).length;
|
|
3857
|
+
return Math.abs(decimalShift(data, digits) - decimalShift(min, digits)) % decimalShift(step, digits) === 0;
|
|
3858
|
+
}
|
|
3859
|
+
Schema.extend("number", (data, { meta }, options) => {
|
|
3860
|
+
if (typeof data !== "number") throw new ValidationError(`expected number but got ${data}`, options);
|
|
3861
|
+
checkWithinRange(data, meta, "number", options);
|
|
3862
|
+
const { step } = meta;
|
|
3863
|
+
if (step && !isMultipleOf(data, meta.min ?? 0, step)) throw new ValidationError(`expected number multiple of ${step} but got ${data}`, options);
|
|
3864
|
+
return [data];
|
|
3865
|
+
});
|
|
3866
|
+
Schema.extend("boolean", (data, _, options) => {
|
|
3867
|
+
if (typeof data === "boolean") return [data];
|
|
3868
|
+
throw new ValidationError(`expected boolean but got ${data}`, options);
|
|
3869
|
+
});
|
|
3870
|
+
Schema.extend("bitset", (data, { bits, meta }, options) => {
|
|
3871
|
+
let value = 0, keys = [];
|
|
3872
|
+
if (typeof data === "number") {
|
|
3873
|
+
value = data;
|
|
3874
|
+
for (const key in bits) if (data & bits[key]) keys.push(key);
|
|
3875
|
+
} else if (Array.isArray(data)) {
|
|
3876
|
+
keys = data;
|
|
3877
|
+
for (const key of keys) {
|
|
3878
|
+
if (typeof key !== "string") throw new ValidationError(`expected string but got ${key}`, options);
|
|
3879
|
+
if (key in bits) value |= bits[key];
|
|
3880
|
+
}
|
|
3881
|
+
} else throw new ValidationError(`expected number or array but got ${data}`, options);
|
|
3882
|
+
if (value === meta.default) return [value];
|
|
3883
|
+
return [value, keys];
|
|
3884
|
+
});
|
|
3885
|
+
Schema.extend("function", (data, _, options) => {
|
|
3886
|
+
if (typeof data === "function") return [data];
|
|
3887
|
+
throw new ValidationError(`expected function but got ${data}`, options);
|
|
3888
|
+
});
|
|
3889
|
+
Schema.extend("is", (data, { constructor }, options) => {
|
|
3890
|
+
if (typeof constructor === "function") {
|
|
3891
|
+
if (data instanceof constructor) return [data];
|
|
3892
|
+
throw new ValidationError(`expected ${constructor.name} but got ${data}`, options);
|
|
3893
|
+
} else {
|
|
3894
|
+
if (isNullable(data)) throw new ValidationError(`expected ${constructor} but got ${data}`, options);
|
|
3895
|
+
let prototype = Object.getPrototypeOf(data);
|
|
3896
|
+
while (prototype) {
|
|
3897
|
+
if (prototype.constructor?.name === constructor) return [data];
|
|
3898
|
+
prototype = Object.getPrototypeOf(prototype);
|
|
3899
|
+
}
|
|
3900
|
+
throw new ValidationError(`expected ${constructor} but got ${data}`, options);
|
|
3901
|
+
}
|
|
3902
|
+
});
|
|
3903
|
+
function property(data, key, schema, options) {
|
|
3904
|
+
try {
|
|
3905
|
+
const [value, adapted] = Schema.resolve(data[key], schema, {
|
|
3906
|
+
...options,
|
|
3907
|
+
path: [...options.path || [], key]
|
|
3908
|
+
});
|
|
3909
|
+
if (adapted !== void 0) data[key] = adapted;
|
|
3910
|
+
return value;
|
|
3911
|
+
} catch (e) {
|
|
3912
|
+
if (!options?.autofix) throw e;
|
|
3913
|
+
delete data[key];
|
|
3914
|
+
return schema.meta.volatile ? createVolatile(schema.meta.default) : schema.meta.default;
|
|
3915
|
+
}
|
|
3916
|
+
}
|
|
3917
|
+
Schema.extend("array", (data, { inner, meta }, options) => {
|
|
3918
|
+
if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options);
|
|
3919
|
+
checkWithinRange(data.length, meta, "array length", options, !isNullable(inner.meta.default));
|
|
3920
|
+
return [data.map((_, index) => property(data, index, inner, options))];
|
|
3921
|
+
});
|
|
3922
|
+
Schema.extend("dict", (data, { inner, sKey }, options, strict) => {
|
|
3923
|
+
if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options);
|
|
3924
|
+
const result = {};
|
|
3925
|
+
for (const key in data) {
|
|
3926
|
+
let rKey;
|
|
3927
|
+
try {
|
|
3928
|
+
rKey = Schema.resolve(key, sKey, options)[0];
|
|
3929
|
+
} catch (error) {
|
|
3930
|
+
if (strict) continue;
|
|
3931
|
+
throw error;
|
|
3932
|
+
}
|
|
3933
|
+
result[rKey] = property(data, key, inner, options);
|
|
3934
|
+
data[rKey] = data[key];
|
|
3935
|
+
if (key !== rKey) delete data[key];
|
|
3936
|
+
}
|
|
3937
|
+
return [result];
|
|
3938
|
+
});
|
|
3939
|
+
Schema.extend("tuple", (data, { list }, options, strict) => {
|
|
3940
|
+
if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options);
|
|
3941
|
+
const result = list.map((inner, index) => property(data, index, inner, options));
|
|
3942
|
+
if (strict) return [result];
|
|
3943
|
+
result.push(...data.slice(list.length));
|
|
3944
|
+
return [result];
|
|
3945
|
+
});
|
|
3946
|
+
function merge(result, data) {
|
|
3947
|
+
for (const key in data) {
|
|
3948
|
+
if (key in result) continue;
|
|
3949
|
+
result[key] = data[key];
|
|
3950
|
+
}
|
|
3951
|
+
}
|
|
3952
|
+
Schema.extend("object", (data, { dict }, options, strict) => {
|
|
3953
|
+
if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options);
|
|
3954
|
+
const result = {};
|
|
3955
|
+
for (const key in dict) {
|
|
3956
|
+
const value = property(data, key, dict[key], options);
|
|
3957
|
+
if (!isNullable(value) || key in data) result[key] = value;
|
|
3958
|
+
}
|
|
3959
|
+
if (!strict) merge(result, data);
|
|
3960
|
+
return [result];
|
|
3961
|
+
});
|
|
3962
|
+
Schema.extend("union", (data, { list, toString }, options, strict) => {
|
|
3963
|
+
const messages = [];
|
|
3964
|
+
for (const inner of list) try {
|
|
3965
|
+
return Schema.resolve(data, inner, options, strict);
|
|
3966
|
+
} catch (error) {
|
|
3967
|
+
messages.push(error);
|
|
3968
|
+
}
|
|
3969
|
+
throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options);
|
|
3970
|
+
});
|
|
3971
|
+
Schema.extend("intersect", (data, { list, toString }, options, strict) => {
|
|
3972
|
+
if (!list.length) return [data];
|
|
3973
|
+
let result;
|
|
3974
|
+
for (const inner of list) {
|
|
3975
|
+
const value = Schema.resolve(data, inner, options, true)[0];
|
|
3976
|
+
if (isNullable(value)) continue;
|
|
3977
|
+
if (isNullable(result)) result = value;
|
|
3978
|
+
else if (typeof result !== typeof value) throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options);
|
|
3979
|
+
else if (typeof value === "object") merge(result ??= {}, value);
|
|
3980
|
+
else if (result !== value) throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options);
|
|
3981
|
+
}
|
|
3982
|
+
if (!strict && isPlainObject(data)) merge(result, data);
|
|
3983
|
+
return [result];
|
|
3984
|
+
});
|
|
3985
|
+
Schema.extend("transform", (data, { inner, callback, preserve }, options) => {
|
|
3986
|
+
const [result, adapted = data] = Schema.resolve(data, inner, options, true);
|
|
3987
|
+
if (preserve) return [callback(result)];
|
|
3988
|
+
else return [callback(result), callback(adapted)];
|
|
3989
|
+
});
|
|
3990
|
+
const formatters = {};
|
|
3991
|
+
function defineMethod(name, keys, format) {
|
|
3992
|
+
formatters[name] = format;
|
|
3993
|
+
Object.assign(Schema, { [name](...args) {
|
|
3994
|
+
const schema = new Schema({ type: name });
|
|
3995
|
+
keys.forEach((key, index) => {
|
|
3996
|
+
switch (key) {
|
|
3997
|
+
case "sKey":
|
|
3998
|
+
schema.sKey = args[index] ?? Schema.string();
|
|
3999
|
+
break;
|
|
4000
|
+
case "inner":
|
|
4001
|
+
schema.inner = Schema.from(args[index]);
|
|
4002
|
+
break;
|
|
4003
|
+
case "list":
|
|
4004
|
+
schema.list = args[index].map(Schema.from);
|
|
4005
|
+
break;
|
|
4006
|
+
case "dict":
|
|
4007
|
+
schema.dict = mapValues(args[index], Schema.from);
|
|
4008
|
+
break;
|
|
4009
|
+
case "bits":
|
|
4010
|
+
schema.bits = {};
|
|
4011
|
+
for (const key in args[index]) {
|
|
4012
|
+
if (typeof args[index][key] !== "number") continue;
|
|
4013
|
+
schema.bits[key] = args[index][key];
|
|
4014
|
+
}
|
|
4015
|
+
break;
|
|
4016
|
+
case "callback": {
|
|
4017
|
+
const callback = schema.callback = args[index];
|
|
4018
|
+
callback["toJSON"] ||= () => callback.toString();
|
|
4019
|
+
break;
|
|
4020
|
+
}
|
|
4021
|
+
case "constructor": {
|
|
4022
|
+
const constructor = schema.constructor = args[index];
|
|
4023
|
+
if (typeof constructor === "function") constructor["toJSON"] ||= () => constructor["name"];
|
|
4024
|
+
break;
|
|
4025
|
+
}
|
|
4026
|
+
default: schema[key] = args[index];
|
|
4027
|
+
}
|
|
4028
|
+
});
|
|
4029
|
+
if (name === "object" || name === "dict") schema.meta.default = {};
|
|
4030
|
+
else if (name === "array" || name === "tuple") schema.meta.default = [];
|
|
4031
|
+
else if (name === "bitset") schema.meta.default = 0;
|
|
4032
|
+
return schema;
|
|
4033
|
+
} });
|
|
4034
|
+
}
|
|
4035
|
+
defineMethod("is", ["constructor"], ({ constructor }) => {
|
|
4036
|
+
if (typeof constructor === "function") return constructor.name;
|
|
4037
|
+
else return constructor;
|
|
4038
|
+
});
|
|
4039
|
+
defineMethod("any", [], () => "any");
|
|
4040
|
+
defineMethod("never", [], () => "never");
|
|
4041
|
+
defineMethod("const", ["value"], ({ value }) => typeof value === "string" ? JSON.stringify(value) : value);
|
|
4042
|
+
defineMethod("string", [], () => "string");
|
|
4043
|
+
defineMethod("number", [], () => "number");
|
|
4044
|
+
defineMethod("boolean", [], () => "boolean");
|
|
4045
|
+
defineMethod("bitset", ["bits"], () => "bitset");
|
|
4046
|
+
defineMethod("function", [], () => "function");
|
|
4047
|
+
defineMethod("array", ["inner"], ({ inner }) => `${inner.toString(true)}[]`);
|
|
4048
|
+
defineMethod("dict", ["inner", "sKey"], ({ inner, sKey }) => `{ [key: ${sKey.toString()}]: ${inner.toString()} }`);
|
|
4049
|
+
defineMethod("tuple", ["list"], ({ list }) => `[${list.map((inner) => inner.toString()).join(", ")}]`);
|
|
4050
|
+
defineMethod("object", ["dict"], ({ dict }) => {
|
|
4051
|
+
if (Object.keys(dict).length === 0) return "{}";
|
|
4052
|
+
return `{ ${Object.entries(dict).map(([key, inner]) => {
|
|
4053
|
+
return `${key}${inner.meta.required ? "" : "?"}: ${inner.toString()}`;
|
|
4054
|
+
}).join(", ")} }`;
|
|
4055
|
+
});
|
|
4056
|
+
defineMethod("union", ["list"], ({ list }, inline) => {
|
|
4057
|
+
const result = list.map(({ toString: format }) => format()).join(" | ");
|
|
4058
|
+
return inline ? `(${result})` : result;
|
|
4059
|
+
});
|
|
4060
|
+
defineMethod("intersect", ["list"], ({ list }) => {
|
|
4061
|
+
return `${list.map((inner) => inner.toString(true)).join(" & ")}`;
|
|
4062
|
+
});
|
|
4063
|
+
defineMethod("transform", [
|
|
4064
|
+
"inner",
|
|
4065
|
+
"callback",
|
|
4066
|
+
"preserve"
|
|
4067
|
+
], ({ inner }, isInner) => inner.toString(isInner));
|
|
4068
|
+
//#endregion
|
|
4069
|
+
//#region lib/types/onboarding-config.js
|
|
4070
|
+
/** Public page-bootstrap options shared by the Host and Client halves. */
|
|
4071
|
+
/** Validate Host configuration and its public page-bootstrap payload. */
|
|
4072
|
+
const Config = Schema.object({ credentialOnboarding: Schema.boolean().default(true) });
|
|
4073
|
+
/** Page-global key carrying only the public onboarding options. */
|
|
4074
|
+
const ONBOARDING_CONFIG_GLOBAL = "__QILIN_MODELS_ONBOARDING__";
|
|
4075
|
+
//#endregion
|
|
3141
4076
|
//#region lib/types/client/index.js
|
|
3142
4077
|
/** Dictionary namespace owned by this plugin. */
|
|
3143
4078
|
const NS = "settings.models";
|
|
@@ -3172,6 +4107,8 @@ window.__ModuleLoader__.load({
|
|
|
3172
4107
|
* @param ctx - client root context.
|
|
3173
4108
|
*/
|
|
3174
4109
|
function apply(ctx) {
|
|
4110
|
+
const payload = globalThis[ONBOARDING_CONFIG_GLOBAL];
|
|
4111
|
+
const configured = Config(payload === void 0 ? {} : payload);
|
|
3175
4112
|
ctx.effect(() => ctx.locale.register(NS, {
|
|
3176
4113
|
zh,
|
|
3177
4114
|
en
|
|
@@ -3227,7 +4164,7 @@ window.__ModuleLoader__.load({
|
|
|
3227
4164
|
}
|
|
3228
4165
|
}
|
|
3229
4166
|
}, ModelsSection));
|
|
3230
|
-
ctx.slots.inject("settings.onboarding", () => ctx.slots.register({
|
|
4167
|
+
if (configured.credentialOnboarding) ctx.slots.inject("settings.onboarding", () => ctx.slots.register({
|
|
3231
4168
|
name: "settings.onboarding",
|
|
3232
4169
|
id: "deepseek-official",
|
|
3233
4170
|
order: 0,
|