@yuhere/js-jsonrpc2 2.1.12 → 2.1.14
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/dist/cli/cli.d.ts +0 -1
- package/dist/cli/cli.js +0 -1
- package/dist/cli/demo-methods.d.ts +0 -1
- package/dist/cli/demo-methods.js +0 -1
- package/dist/cli/express.d.ts +0 -1
- package/dist/cli/express.js +0 -1
- package/dist/cli/stdio.d.ts +0 -1
- package/dist/cli/stdio.js +0 -1
- package/dist/core/Repository.d.ts +0 -1
- package/dist/core/Repository.js +0 -1
- package/dist/core/convert.d.ts +0 -1
- package/dist/core/convert.js +0 -1
- package/dist/core/descriptor.d.ts +0 -1
- package/dist/core/descriptor.js +0 -1
- package/dist/core/index.d.ts +0 -1
- package/dist/core/index.js +0 -1
- package/dist/core/llm-tools.d.ts +0 -1
- package/dist/core/llm-tools.js +41 -43
- package/dist/core/permission.d.ts +0 -1
- package/dist/core/permission.js +0 -1
- package/dist/core/spec-check.d.ts +0 -1
- package/dist/core/spec-check.js +0 -1
- package/dist/core/system-methods.d.ts +0 -1
- package/dist/core/system-methods.js +0 -1
- package/dist/errors/RPCError.d.ts +0 -1
- package/dist/errors/RPCError.js +0 -1
- package/dist/errors/codes.d.ts +0 -1
- package/dist/errors/codes.js +0 -1
- package/dist/errors/index.d.ts +0 -1
- package/dist/errors/index.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/metrics/memory.d.ts +0 -1
- package/dist/metrics/memory.js +0 -1
- package/dist/metrics/prom.d.ts +0 -1
- package/dist/metrics/prom.js +0 -1
- package/dist/schema/json/index.d.ts +1 -2
- package/dist/schema/json/index.js +0 -1
- package/dist/schema/json/marker.d.ts +0 -1
- package/dist/schema/json/marker.js +0 -1
- package/dist/schema/json/primitives.d.ts +49 -70
- package/dist/schema/json/primitives.js +70 -77
- package/dist/schema/z/protocol.d.ts +1 -2
- package/dist/schema/z/protocol.js +0 -1
- package/dist/schema/z/register.d.ts +0 -1
- package/dist/schema/z/register.js +0 -1
- package/dist/stream/stringify-stream.d.ts +0 -1
- package/dist/stream/stringify-stream.js +94 -70
- package/dist/transport/express/body.d.ts +0 -1
- package/dist/transport/express/body.js +0 -1
- package/dist/transport/express/index.d.ts +0 -1
- package/dist/transport/express/index.js +0 -1
- package/dist/transport/express/middleware.d.ts +0 -1
- package/dist/transport/express/middleware.js +0 -1
- package/dist/transport/express/respond.d.ts +0 -1
- package/dist/transport/express/respond.js +0 -1
- package/dist/transport/stdio/index.d.ts +0 -1
- package/dist/transport/stdio/index.js +0 -1
- package/dist/transport/stdio/middleware.d.ts +0 -1
- package/dist/transport/stdio/middleware.js +0 -1
- package/dist/transport/ws/index.d.ts +0 -1
- package/dist/transport/ws/index.js +0 -1
- package/dist/transport/ws/middleware.d.ts +0 -1
- package/dist/transport/ws/middleware.js +0 -1
- package/dist/transport/ws/standalone.d.ts +0 -1
- package/dist/transport/ws/standalone.js +0 -1
- package/dist/types.d.ts +0 -1
- package/dist/types.js +0 -1
- package/dist/webclient/webui/src/client/httpTransport.d.ts +8 -0
- package/dist/webclient/webui/src/client/httpTransport.js +114 -0
- package/dist/webclient/webui/src/client/index.d.ts +4 -0
- package/dist/webclient/webui/src/client/index.js +2 -0
- package/dist/webclient/webui/src/client/rpc.d.ts +24 -0
- package/dist/webclient/webui/src/client/rpc.js +32 -0
- package/dist/webclient/webui/src/client/types.d.ts +14 -0
- package/dist/webclient/webui/src/client/types.js +1 -0
- package/dist/webclient/webui/src/client/wsTransport.d.ts +8 -0
- package/{webui/src/api/wsTransport.ts → dist/webclient/webui/src/client/wsTransport.js} +263 -305
- package/htdoc/assets/favicon-CXdFuLlv.png +0 -0
- package/{webui/src/styles/geek.css → htdoc/assets/index-Rq1yIwo2.css} +58 -0
- package/htdoc/assets/{index-Cr0Jnrgb.js → index-mYqtDOwe.js} +1344 -398
- package/htdoc/assets/index-mYqtDOwe.js.map +1 -0
- package/htdoc/index.html +4 -2
- package/package.json +10 -7
- package/dist/cli/cli.d.ts.map +0 -1
- package/dist/cli/cli.js.map +0 -1
- package/dist/cli/demo-methods.d.ts.map +0 -1
- package/dist/cli/demo-methods.js.map +0 -1
- package/dist/cli/express.d.ts.map +0 -1
- package/dist/cli/express.js.map +0 -1
- package/dist/cli/stdio.d.ts.map +0 -1
- package/dist/cli/stdio.js.map +0 -1
- package/dist/core/Repository.d.ts.map +0 -1
- package/dist/core/Repository.js.map +0 -1
- package/dist/core/convert.d.ts.map +0 -1
- package/dist/core/convert.js.map +0 -1
- package/dist/core/descriptor.d.ts.map +0 -1
- package/dist/core/descriptor.js.map +0 -1
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js.map +0 -1
- package/dist/core/llm-tools.d.ts.map +0 -1
- package/dist/core/llm-tools.js.map +0 -1
- package/dist/core/permission.d.ts.map +0 -1
- package/dist/core/permission.js.map +0 -1
- package/dist/core/spec-check.d.ts.map +0 -1
- package/dist/core/spec-check.js.map +0 -1
- package/dist/core/system-methods.d.ts.map +0 -1
- package/dist/core/system-methods.js.map +0 -1
- package/dist/errors/RPCError.d.ts.map +0 -1
- package/dist/errors/RPCError.js.map +0 -1
- package/dist/errors/codes.d.ts.map +0 -1
- package/dist/errors/codes.js.map +0 -1
- package/dist/errors/index.d.ts.map +0 -1
- package/dist/errors/index.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/metrics/memory.d.ts.map +0 -1
- package/dist/metrics/memory.js.map +0 -1
- package/dist/metrics/prom.d.ts.map +0 -1
- package/dist/metrics/prom.js.map +0 -1
- package/dist/schema/json/index.d.ts.map +0 -1
- package/dist/schema/json/index.js.map +0 -1
- package/dist/schema/json/marker.d.ts.map +0 -1
- package/dist/schema/json/marker.js.map +0 -1
- package/dist/schema/json/primitives.d.ts.map +0 -1
- package/dist/schema/json/primitives.js.map +0 -1
- package/dist/schema/z/protocol.d.ts.map +0 -1
- package/dist/schema/z/protocol.js.map +0 -1
- package/dist/schema/z/register.d.ts.map +0 -1
- package/dist/schema/z/register.js.map +0 -1
- package/dist/stream/stringify-stream.d.ts.map +0 -1
- package/dist/stream/stringify-stream.js.map +0 -1
- package/dist/transport/express/body.d.ts.map +0 -1
- package/dist/transport/express/body.js.map +0 -1
- package/dist/transport/express/index.d.ts.map +0 -1
- package/dist/transport/express/index.js.map +0 -1
- package/dist/transport/express/middleware.d.ts.map +0 -1
- package/dist/transport/express/middleware.js.map +0 -1
- package/dist/transport/express/respond.d.ts.map +0 -1
- package/dist/transport/express/respond.js.map +0 -1
- package/dist/transport/stdio/index.d.ts.map +0 -1
- package/dist/transport/stdio/index.js.map +0 -1
- package/dist/transport/stdio/middleware.d.ts.map +0 -1
- package/dist/transport/stdio/middleware.js.map +0 -1
- package/dist/transport/ws/index.d.ts.map +0 -1
- package/dist/transport/ws/index.js.map +0 -1
- package/dist/transport/ws/middleware.d.ts.map +0 -1
- package/dist/transport/ws/middleware.js.map +0 -1
- package/dist/transport/ws/standalone.d.ts.map +0 -1
- package/dist/transport/ws/standalone.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/htdoc/assets/index-Ck-39Igh.css +0 -963
- package/htdoc/assets/index-Cr0Jnrgb.js.map +0 -1
- package/webui/index.html +0 -12
- package/webui/src/App.tsx +0 -164
- package/webui/src/api/docGen.ts +0 -188
- package/webui/src/api/glob.ts +0 -90
- package/webui/src/api/httpTransport.ts +0 -148
- package/webui/src/api/metrics.ts +0 -135
- package/webui/src/api/paramForm.ts +0 -80
- package/webui/src/api/rpc.ts +0 -57
- package/webui/src/api/schema.ts +0 -12
- package/webui/src/api/types.ts +0 -16
- package/webui/src/components/MethodDetail.tsx +0 -43
- package/webui/src/components/MethodTree.tsx +0 -118
- package/webui/src/components/MetricsPanel.md +0 -126
- package/webui/src/components/MetricsPanel.tsx +0 -290
- package/webui/src/components/SchemaForm.tsx +0 -697
- package/webui/src/components/SchemaView.tsx +0 -151
- package/webui/src/components/TestPanel.tsx +0 -322
- package/webui/src/components/Toolbar.tsx +0 -82
- package/webui/src/hooks/useMethodDetail.ts +0 -61
- package/webui/src/hooks/useMethods.ts +0 -27
- package/webui/src/hooks/useMetrics.ts +0 -91
- package/webui/src/main.tsx +0 -13
- package/webui/src/theme/ThemeProvider.tsx +0 -79
- package/webui/src/vite-env.d.ts +0 -1
- package/webui/tsconfig.json +0 -34
- package/webui/tsconfig.node.json +0 -13
- package/webui/vite.config.ts +0 -15
|
@@ -7537,9 +7537,7 @@ var require_client = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7537
7537
|
exports.hydrateRoot = m.hydrateRoot;
|
|
7538
7538
|
}));
|
|
7539
7539
|
//#endregion
|
|
7540
|
-
//#region webui/src/
|
|
7541
|
-
var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
|
|
7542
|
-
var import_client = /* @__PURE__ */ __toESM(require_client(), 1);
|
|
7540
|
+
//#region webui/src/client/httpTransport.ts
|
|
7543
7541
|
var idCounter$1 = 0;
|
|
7544
7542
|
async function readLine(reader, decoder, state) {
|
|
7545
7543
|
while (true) {
|
|
@@ -7562,7 +7560,7 @@ async function readLine(reader, decoder, state) {
|
|
|
7562
7560
|
function isStreamFrame$1(v) {
|
|
7563
7561
|
return !!v && typeof v === "object" && typeof v.done === "boolean";
|
|
7564
7562
|
}
|
|
7565
|
-
function
|
|
7563
|
+
function createHttpRPC(options = {}) {
|
|
7566
7564
|
const { endpoint = "", headers = {}, fetchImpl = fetch } = options;
|
|
7567
7565
|
function call(method, ...params) {
|
|
7568
7566
|
const body = {
|
|
@@ -7576,7 +7574,7 @@ function createHttpRpc(options = {}) {
|
|
|
7576
7574
|
method: "POST",
|
|
7577
7575
|
headers: {
|
|
7578
7576
|
"Content-Type": "application/json",
|
|
7579
|
-
"Accept": "application/x-ndjson",
|
|
7577
|
+
"Accept": "application/json, application/x-ndjson",
|
|
7580
7578
|
...headers
|
|
7581
7579
|
},
|
|
7582
7580
|
body: JSON.stringify(body)
|
|
@@ -7643,7 +7641,7 @@ function absoluteEndpoint(endpoint) {
|
|
|
7643
7641
|
}
|
|
7644
7642
|
}
|
|
7645
7643
|
//#endregion
|
|
7646
|
-
//#region webui/src/
|
|
7644
|
+
//#region webui/src/client/wsTransport.ts
|
|
7647
7645
|
var idCounter = 0;
|
|
7648
7646
|
function deriveWsEndpoint() {
|
|
7649
7647
|
const loc = window.location;
|
|
@@ -7652,7 +7650,7 @@ function deriveWsEndpoint() {
|
|
|
7652
7650
|
function isStreamFrame(v) {
|
|
7653
7651
|
return !!v && typeof v === "object" && typeof v.done === "boolean";
|
|
7654
7652
|
}
|
|
7655
|
-
function
|
|
7653
|
+
function createWsRPC(options = {}) {
|
|
7656
7654
|
const { endpoint = deriveWsEndpoint(), connectTimeoutMs = 5e3, callTimeoutMs = 15e3 } = options;
|
|
7657
7655
|
const pending = /* @__PURE__ */ new Map();
|
|
7658
7656
|
const streams = /* @__PURE__ */ new Map();
|
|
@@ -7688,6 +7686,7 @@ function createWsRpc(options = {}) {
|
|
|
7688
7686
|
}
|
|
7689
7687
|
const list = Array.isArray(data) ? data : [data];
|
|
7690
7688
|
for (const msg of list) {
|
|
7689
|
+
if (!msg || typeof msg !== "object") continue;
|
|
7691
7690
|
if (msg.id == null) continue;
|
|
7692
7691
|
const fw = firstWaiters.get(msg.id);
|
|
7693
7692
|
if (fw) {
|
|
@@ -7902,7 +7901,7 @@ function _defineProperty(e, r, t) {
|
|
|
7902
7901
|
}) : e[r] = t, e;
|
|
7903
7902
|
}
|
|
7904
7903
|
//#endregion
|
|
7905
|
-
//#region webui/src/
|
|
7904
|
+
//#region webui/src/client/rpc.ts
|
|
7906
7905
|
var RPCError = class extends Error {
|
|
7907
7906
|
constructor(payload) {
|
|
7908
7907
|
super(payload.message);
|
|
@@ -7920,13 +7919,13 @@ var RPCError = class extends Error {
|
|
|
7920
7919
|
function isStreamResult(v) {
|
|
7921
7920
|
return !!v && typeof v === "object" && typeof v[Symbol.asyncIterator] === "function";
|
|
7922
7921
|
}
|
|
7923
|
-
function
|
|
7924
|
-
if (options.transport === "ws") return
|
|
7922
|
+
function createRPC(options) {
|
|
7923
|
+
if (options.transport === "ws") return createWsRPC({
|
|
7925
7924
|
endpoint: options.endpoint,
|
|
7926
7925
|
connectTimeoutMs: options.connectTimeoutMs,
|
|
7927
7926
|
callTimeoutMs: options.callTimeoutMs
|
|
7928
7927
|
});
|
|
7929
|
-
return
|
|
7928
|
+
return createHttpRPC({
|
|
7930
7929
|
endpoint: options.endpoint,
|
|
7931
7930
|
headers: options.headers,
|
|
7932
7931
|
fetchImpl: options.fetchImpl
|
|
@@ -7934,6 +7933,8 @@ function createRpc(options) {
|
|
|
7934
7933
|
}
|
|
7935
7934
|
//#endregion
|
|
7936
7935
|
//#region webui/src/hooks/useMethods.ts
|
|
7936
|
+
var import_client = /* @__PURE__ */ __toESM(require_client(), 1);
|
|
7937
|
+
var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
|
|
7937
7938
|
function useMethods(rpc) {
|
|
7938
7939
|
const [methods, setMethods] = (0, import_react.useState)([]);
|
|
7939
7940
|
const [loading, setLoading] = (0, import_react.useState)(false);
|
|
@@ -8013,6 +8014,24 @@ function useMethodDetail(rpc, method) {
|
|
|
8013
8014
|
return detail;
|
|
8014
8015
|
}
|
|
8015
8016
|
//#endregion
|
|
8017
|
+
//#region webui/src/hooks/useDebouncedValue.ts
|
|
8018
|
+
/**
|
|
8019
|
+
* 返回 `value` 的防抖版本:`value` 停止变化 `delayMs` 毫秒后才更新返回值。
|
|
8020
|
+
* 初始值立即生效(首次渲染不会延迟)。
|
|
8021
|
+
*/
|
|
8022
|
+
function useDebouncedValue(value, delayMs = 250) {
|
|
8023
|
+
const [debounced, setDebounced] = (0, import_react.useState)(value);
|
|
8024
|
+
(0, import_react.useEffect)(() => {
|
|
8025
|
+
if (delayMs <= 0) {
|
|
8026
|
+
setDebounced(value);
|
|
8027
|
+
return;
|
|
8028
|
+
}
|
|
8029
|
+
const t = setTimeout(() => setDebounced(value), delayMs);
|
|
8030
|
+
return () => clearTimeout(t);
|
|
8031
|
+
}, [value, delayMs]);
|
|
8032
|
+
return debounced;
|
|
8033
|
+
}
|
|
8034
|
+
//#endregion
|
|
8016
8035
|
//#region webui/src/api/metrics.ts
|
|
8017
8036
|
/** 拉取 system.metrics;如果系统方法不可用(withSystemMethods=false),返回 undefined。 */
|
|
8018
8037
|
async function fetchMetrics(rpc) {
|
|
@@ -8187,11 +8206,11 @@ var require_react_jsx_runtime_production_min = /* @__PURE__ */ __commonJSMin(((e
|
|
|
8187
8206
|
var import_jsx_runtime = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
8188
8207
|
module.exports = require_react_jsx_runtime_production_min();
|
|
8189
8208
|
})))();
|
|
8190
|
-
var STORAGE_KEY = "jsonrpc2.theme";
|
|
8209
|
+
var STORAGE_KEY$1 = "jsonrpc2.theme";
|
|
8191
8210
|
var ThemeContext = (0, import_react.createContext)(null);
|
|
8192
|
-
function readStoredMode() {
|
|
8211
|
+
function readStoredMode$1() {
|
|
8193
8212
|
try {
|
|
8194
|
-
const v = localStorage.getItem(STORAGE_KEY);
|
|
8213
|
+
const v = localStorage.getItem(STORAGE_KEY$1);
|
|
8195
8214
|
if (v === "light" || v === "dark" || v === "system") return v;
|
|
8196
8215
|
} catch {}
|
|
8197
8216
|
return "system";
|
|
@@ -8200,7 +8219,7 @@ function prefersDark() {
|
|
|
8200
8219
|
return typeof window !== "undefined" && window.matchMedia?.("(prefers-color-scheme: dark)").matches;
|
|
8201
8220
|
}
|
|
8202
8221
|
function ThemeProvider({ children }) {
|
|
8203
|
-
const [mode, setModeState] = (0, import_react.useState)(readStoredMode);
|
|
8222
|
+
const [mode, setModeState] = (0, import_react.useState)(readStoredMode$1);
|
|
8204
8223
|
const [systemDark, setSystemDark] = (0, import_react.useState)(prefersDark);
|
|
8205
8224
|
(0, import_react.useEffect)(() => {
|
|
8206
8225
|
const mql = window.matchMedia("(prefers-color-scheme: dark)");
|
|
@@ -8219,7 +8238,7 @@ function ThemeProvider({ children }) {
|
|
|
8219
8238
|
(0, import_react.useEffect)(() => {
|
|
8220
8239
|
document.documentElement.setAttribute("data-theme", resolved);
|
|
8221
8240
|
try {
|
|
8222
|
-
localStorage.setItem(STORAGE_KEY, mode);
|
|
8241
|
+
localStorage.setItem(STORAGE_KEY$1, mode);
|
|
8223
8242
|
} catch {}
|
|
8224
8243
|
}, [resolved, mode]);
|
|
8225
8244
|
const setMode = (0, import_react.useCallback)((m) => setModeState(m), []);
|
|
@@ -8242,54 +8261,812 @@ function useTheme() {
|
|
|
8242
8261
|
if (!ctx) throw new Error("useTheme must be used within <ThemeProvider>");
|
|
8243
8262
|
return ctx;
|
|
8244
8263
|
}
|
|
8245
|
-
|
|
8246
|
-
|
|
8247
|
-
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8264
|
+
var MESSAGES = {
|
|
8265
|
+
en: {
|
|
8266
|
+
common: {
|
|
8267
|
+
loading: "Loading…",
|
|
8268
|
+
refresh: "Refresh",
|
|
8269
|
+
refreshing: "Refreshing…",
|
|
8270
|
+
reset: "Reset",
|
|
8271
|
+
clear: "Clear",
|
|
8272
|
+
delete: "Delete",
|
|
8273
|
+
add: "Add",
|
|
8274
|
+
copy: "Copy",
|
|
8275
|
+
copied: "Copied ✓",
|
|
8276
|
+
copyFailed: "Copy failed: {error}",
|
|
8277
|
+
generate: "Generate",
|
|
8278
|
+
generating: "Generating…",
|
|
8279
|
+
none: "None",
|
|
8280
|
+
empty: "Empty"
|
|
8281
|
+
},
|
|
8282
|
+
toolbar: {
|
|
8283
|
+
title: "JSON-RPC 2.0",
|
|
8284
|
+
transport: "Transport",
|
|
8285
|
+
http: "HTTP",
|
|
8286
|
+
ws: "WebSocket",
|
|
8287
|
+
refreshMethods: "Refresh methods",
|
|
8288
|
+
refreshMethodsLoading: "Refreshing…",
|
|
8289
|
+
generateDocs: "Generate docs ⬇",
|
|
8290
|
+
generateDocsLoading: "Generating…",
|
|
8291
|
+
generateDocsTitle: "Fetch help and signatures of all methods, render Markdown and download",
|
|
8292
|
+
theme: "Theme",
|
|
8293
|
+
themeSystem: "System",
|
|
8294
|
+
themeLight: "Light",
|
|
8295
|
+
themeDark: "Dark",
|
|
8296
|
+
language: "Language",
|
|
8297
|
+
languageSystem: "Follow system",
|
|
8298
|
+
languageEn: "English",
|
|
8299
|
+
languageZhCN: "简体中文",
|
|
8300
|
+
languageZhTW: "繁體中文",
|
|
8301
|
+
languageJa: "日本語"
|
|
8302
|
+
},
|
|
8303
|
+
sidebar: {
|
|
8304
|
+
methods: "Methods",
|
|
8305
|
+
metrics: "Metrics",
|
|
8306
|
+
search: "Search",
|
|
8307
|
+
searchPlaceholder: "Type keywords, space separated",
|
|
8308
|
+
matchCount: "Matched {matched} / {total} methods",
|
|
8309
|
+
noMatch: "No matching methods.",
|
|
8310
|
+
noMethods: "No methods available."
|
|
8311
|
+
},
|
|
8312
|
+
view: {
|
|
8313
|
+
label: "View",
|
|
8314
|
+
methods: "Methods",
|
|
8315
|
+
metrics: "Metrics"
|
|
8316
|
+
},
|
|
8317
|
+
method: {
|
|
8318
|
+
selectHint: "← Select a method from the left to view help and signature.",
|
|
8319
|
+
loading: "Loading…",
|
|
8320
|
+
loadFailed: "Load failed: {error}",
|
|
8321
|
+
help: "Help",
|
|
8322
|
+
noHelp: "(no help available)",
|
|
8323
|
+
returnType: "Return type",
|
|
8324
|
+
returnTypeHint: "(the server does not validate execution results against this type; actual values may differ)",
|
|
8325
|
+
none: "(none)"
|
|
8326
|
+
},
|
|
8327
|
+
test: {
|
|
8328
|
+
params: "Parameters",
|
|
8329
|
+
paramsHint: "({count}, auto-generated from signature)",
|
|
8330
|
+
noParams: "This method takes no parameters.",
|
|
8331
|
+
execute: "Execute ▶",
|
|
8332
|
+
executing: "Executing…",
|
|
8333
|
+
executeStream: "Execute & receive stream ▶",
|
|
8334
|
+
receiving: "Receiving…",
|
|
8335
|
+
resetToSample: "Reset to sample",
|
|
8336
|
+
clearOutput: "Clear output",
|
|
8337
|
+
result: "Result",
|
|
8338
|
+
resultStream: " (streaming)",
|
|
8339
|
+
notExecuted: "(not executed yet)",
|
|
8340
|
+
copyCurl: "Copy curl (bash)",
|
|
8341
|
+
copyCurlCmd: "Copy curl (cmd)",
|
|
8342
|
+
copyFetch: "Copy fetch",
|
|
8343
|
+
copyTitle: "Copy equivalent code for current call",
|
|
8344
|
+
copyDisabledTitle: "Only HTTP transport can generate code",
|
|
8345
|
+
chooseFormat: "Choose format",
|
|
8346
|
+
streamEnded: "(stream ended, {count} frames, total {duration})",
|
|
8347
|
+
streamEndedEmpty: "(stream ended, no data, total {duration})",
|
|
8348
|
+
elapsed: "elapsed",
|
|
8349
|
+
firstFrame: "first frame",
|
|
8350
|
+
jsonError: "JSON error: {error}"
|
|
8351
|
+
},
|
|
8352
|
+
schema: {
|
|
8353
|
+
nullable: "nullable",
|
|
8354
|
+
setNull: "Set null",
|
|
8355
|
+
fillValue: "Fill value",
|
|
8356
|
+
fixedValue: "(fixed value)",
|
|
8357
|
+
unionNoBranch: "(union has no branch)",
|
|
8358
|
+
arrayNoItem: "(array has no item schema)",
|
|
8359
|
+
recordNoValue: "(record has no value schema)",
|
|
8360
|
+
recordAddPlaceholder: "New key",
|
|
8361
|
+
addRecordKey: "+ Add key",
|
|
8362
|
+
addItem: "+ Add item",
|
|
8363
|
+
strictHint: "(non-strict mode, extra fields allowed)",
|
|
8364
|
+
paramIndex: "Parameter [{index}]",
|
|
8365
|
+
items: "items",
|
|
8366
|
+
values: "values",
|
|
8367
|
+
optionIndex: "option[{index}]",
|
|
8368
|
+
inner: "inner"
|
|
8369
|
+
},
|
|
8370
|
+
metrics: {
|
|
8371
|
+
title: "Metrics",
|
|
8372
|
+
unavailable: "Server did not enable system.metrics (withSystemMethods: false or not registered).",
|
|
8373
|
+
autoRefresh: "Auto refresh",
|
|
8374
|
+
interval: "Interval",
|
|
8375
|
+
refreshNow: "Refresh now",
|
|
8376
|
+
refreshing: "Refreshing…",
|
|
8377
|
+
uptime: "uptime",
|
|
8378
|
+
loading: "Loading…",
|
|
8379
|
+
methods: "Methods",
|
|
8380
|
+
calls: "Calls",
|
|
8381
|
+
streams: "Streams",
|
|
8382
|
+
errors: "Errors",
|
|
8383
|
+
errorRate: "Error rate",
|
|
8384
|
+
invalidRequests: "Invalid requests",
|
|
8385
|
+
nonStreamTitle: "Non-stream methods",
|
|
8386
|
+
streamTitle: "Stream methods",
|
|
8387
|
+
noData: "No data.",
|
|
8388
|
+
noStreams: "No streaming calls.",
|
|
8389
|
+
countHint: " ({count})",
|
|
8390
|
+
colMethod: "method",
|
|
8391
|
+
colCalls: "calls",
|
|
8392
|
+
colRate: "rate/s",
|
|
8393
|
+
colErrors: "errors",
|
|
8394
|
+
colErrPct: "err%",
|
|
8395
|
+
colP50: "p50",
|
|
8396
|
+
colP95: "p95",
|
|
8397
|
+
colP99: "p99",
|
|
8398
|
+
colAvg: "avg",
|
|
8399
|
+
colOpened: "opened",
|
|
8400
|
+
colCompleted: "completed",
|
|
8401
|
+
colFailed: "failed",
|
|
8402
|
+
colAborted: "aborted",
|
|
8403
|
+
colCompletePct: "complete%",
|
|
8404
|
+
colAbortPct: "abort%",
|
|
8405
|
+
colAvgChunks: "avg chunks",
|
|
8406
|
+
colTtfbP50: "ttfb p50",
|
|
8407
|
+
colTtfbP95: "ttfb p95",
|
|
8408
|
+
colDurationAvg: "duration avg"
|
|
8409
|
+
},
|
|
8410
|
+
footer: {
|
|
8411
|
+
version: "version",
|
|
8412
|
+
npm: "npm package",
|
|
8413
|
+
github: "GitHub repository"
|
|
8414
|
+
},
|
|
8415
|
+
alerts: {
|
|
8416
|
+
emptyMethods: "Method list is empty. Please refresh methods first.",
|
|
8417
|
+
docsFailed: "Failed to generate docs: {error}"
|
|
8418
|
+
}
|
|
8419
|
+
},
|
|
8420
|
+
"zh-CN": {
|
|
8421
|
+
common: {
|
|
8422
|
+
loading: "加载中…",
|
|
8423
|
+
refresh: "刷新",
|
|
8424
|
+
refreshing: "刷新中…",
|
|
8425
|
+
reset: "重置",
|
|
8426
|
+
clear: "清空",
|
|
8427
|
+
delete: "删除",
|
|
8428
|
+
add: "添加",
|
|
8429
|
+
copy: "复制",
|
|
8430
|
+
copied: "已复制 ✓",
|
|
8431
|
+
copyFailed: "复制失败:{error}",
|
|
8432
|
+
generate: "生成",
|
|
8433
|
+
generating: "生成中…",
|
|
8434
|
+
none: "无",
|
|
8435
|
+
empty: "空"
|
|
8436
|
+
},
|
|
8437
|
+
toolbar: {
|
|
8438
|
+
title: "JSON-RPC 2.0",
|
|
8439
|
+
transport: "传输方式",
|
|
8440
|
+
http: "HTTP",
|
|
8441
|
+
ws: "WebSocket",
|
|
8442
|
+
refreshMethods: "刷新方法列表",
|
|
8443
|
+
refreshMethodsLoading: "刷新中…",
|
|
8444
|
+
generateDocs: "生成文档 ⬇",
|
|
8445
|
+
generateDocsLoading: "生成中…",
|
|
8446
|
+
generateDocsTitle: "拉取所有方法的帮助与签名,生成 Markdown 文档并下载",
|
|
8447
|
+
theme: "主题",
|
|
8448
|
+
themeSystem: "跟随系统",
|
|
8449
|
+
themeLight: "亮",
|
|
8450
|
+
themeDark: "暗",
|
|
8451
|
+
language: "语言",
|
|
8452
|
+
languageSystem: "跟随系统语言",
|
|
8453
|
+
languageEn: "English",
|
|
8454
|
+
languageZhCN: "简体中文",
|
|
8455
|
+
languageZhTW: "繁體中文",
|
|
8456
|
+
languageJa: "日本語"
|
|
8457
|
+
},
|
|
8458
|
+
sidebar: {
|
|
8459
|
+
methods: "Methods",
|
|
8460
|
+
metrics: "Metrics",
|
|
8461
|
+
search: "搜索",
|
|
8462
|
+
searchPlaceholder: "输入关键词,空格分隔",
|
|
8463
|
+
matchCount: "匹配 {matched} / {total} 个方法",
|
|
8464
|
+
noMatch: "没有匹配的方法。",
|
|
8465
|
+
noMethods: "暂无可用方法。"
|
|
8466
|
+
},
|
|
8467
|
+
view: {
|
|
8468
|
+
label: "视图",
|
|
8469
|
+
methods: "Methods",
|
|
8470
|
+
metrics: "Metrics"
|
|
8471
|
+
},
|
|
8472
|
+
method: {
|
|
8473
|
+
selectHint: "← 从左侧选择一个方法查看帮助与签名。",
|
|
8474
|
+
loading: "加载中…",
|
|
8475
|
+
loadFailed: "加载失败:{error}",
|
|
8476
|
+
help: "Help",
|
|
8477
|
+
noHelp: "(无帮助信息)",
|
|
8478
|
+
returnType: "返回类型",
|
|
8479
|
+
returnTypeHint: "(服务端不会校验执行结果是否符合此类型,实际返回值可能会有所不同)",
|
|
8480
|
+
none: "(暂无)"
|
|
8481
|
+
},
|
|
8482
|
+
test: {
|
|
8483
|
+
params: "参数",
|
|
8484
|
+
paramsHint: "({count} 个,按签名自动生成)",
|
|
8485
|
+
noParams: "此方法无需参数。",
|
|
8486
|
+
execute: "执行 ▶",
|
|
8487
|
+
executing: "执行中…",
|
|
8488
|
+
executeStream: "执行并接收流 ▶",
|
|
8489
|
+
receiving: "接收中…",
|
|
8490
|
+
resetToSample: "重置为示例",
|
|
8491
|
+
clearOutput: "清空输出",
|
|
8492
|
+
result: "结果",
|
|
8493
|
+
resultStream: "(流式)",
|
|
8494
|
+
notExecuted: "(尚未执行)",
|
|
8495
|
+
copyCurl: "复制 curl (bash)",
|
|
8496
|
+
copyCurlCmd: "复制 curl (cmd)",
|
|
8497
|
+
copyFetch: "复制 fetch",
|
|
8498
|
+
copyTitle: "复制当前调用的等价代码",
|
|
8499
|
+
copyDisabledTitle: "仅 HTTP 传输可生成代码",
|
|
8500
|
+
chooseFormat: "选择复制格式",
|
|
8501
|
+
streamEnded: "(流已结束,共 {count} 帧,总耗时 {duration})",
|
|
8502
|
+
streamEndedEmpty: "(流已结束,无数据,总耗时 {duration})",
|
|
8503
|
+
elapsed: "耗时",
|
|
8504
|
+
firstFrame: "首帧",
|
|
8505
|
+
jsonError: "JSON 错误:{error}"
|
|
8506
|
+
},
|
|
8507
|
+
schema: {
|
|
8508
|
+
nullable: "nullable",
|
|
8509
|
+
setNull: "置 null",
|
|
8510
|
+
fillValue: "填值",
|
|
8511
|
+
fixedValue: "(固定值)",
|
|
8512
|
+
unionNoBranch: "(union 无分支)",
|
|
8513
|
+
arrayNoItem: "(数组无 item schema)",
|
|
8514
|
+
recordNoValue: "(record 无 value schema)",
|
|
8515
|
+
recordAddPlaceholder: "新键名",
|
|
8516
|
+
addRecordKey: "+ 添加键",
|
|
8517
|
+
addItem: "+ 添加项",
|
|
8518
|
+
strictHint: "(非 strict 模式,允许额外字段)",
|
|
8519
|
+
paramIndex: "参数 [{index}]",
|
|
8520
|
+
items: "items",
|
|
8521
|
+
values: "values",
|
|
8522
|
+
optionIndex: "option[{index}]",
|
|
8523
|
+
inner: "inner"
|
|
8524
|
+
},
|
|
8525
|
+
metrics: {
|
|
8526
|
+
title: "Metrics",
|
|
8527
|
+
unavailable: "服务端未启用 system.metrics(withSystemMethods: false 或未注册)。",
|
|
8528
|
+
autoRefresh: "自动刷新",
|
|
8529
|
+
interval: "刷新间隔",
|
|
8530
|
+
refreshNow: "立即刷新",
|
|
8531
|
+
refreshing: "刷新中…",
|
|
8532
|
+
uptime: "uptime",
|
|
8533
|
+
loading: "加载中…",
|
|
8534
|
+
methods: "Methods",
|
|
8535
|
+
calls: "Calls",
|
|
8536
|
+
streams: "Streams",
|
|
8537
|
+
errors: "Errors",
|
|
8538
|
+
errorRate: "Error rate",
|
|
8539
|
+
invalidRequests: "Invalid requests",
|
|
8540
|
+
nonStreamTitle: "Non-stream methods",
|
|
8541
|
+
streamTitle: "Stream methods",
|
|
8542
|
+
noData: "暂无数据。",
|
|
8543
|
+
noStreams: "暂无流式调用。",
|
|
8544
|
+
countHint: "({count})",
|
|
8545
|
+
colMethod: "method",
|
|
8546
|
+
colCalls: "calls",
|
|
8547
|
+
colRate: "rate/s",
|
|
8548
|
+
colErrors: "errors",
|
|
8549
|
+
colErrPct: "err%",
|
|
8550
|
+
colP50: "p50",
|
|
8551
|
+
colP95: "p95",
|
|
8552
|
+
colP99: "p99",
|
|
8553
|
+
colAvg: "avg",
|
|
8554
|
+
colOpened: "opened",
|
|
8555
|
+
colCompleted: "completed",
|
|
8556
|
+
colFailed: "failed",
|
|
8557
|
+
colAborted: "aborted",
|
|
8558
|
+
colCompletePct: "complete%",
|
|
8559
|
+
colAbortPct: "abort%",
|
|
8560
|
+
colAvgChunks: "avg chunks",
|
|
8561
|
+
colTtfbP50: "ttfb p50",
|
|
8562
|
+
colTtfbP95: "ttfb p95",
|
|
8563
|
+
colDurationAvg: "duration avg"
|
|
8564
|
+
},
|
|
8565
|
+
footer: {
|
|
8566
|
+
version: "版本",
|
|
8567
|
+
npm: "npm 包",
|
|
8568
|
+
github: "GitHub 仓库"
|
|
8569
|
+
},
|
|
8570
|
+
alerts: {
|
|
8571
|
+
emptyMethods: "方法列表为空,请先刷新方法列表。",
|
|
8572
|
+
docsFailed: "生成文档失败:{error}"
|
|
8573
|
+
}
|
|
8251
8574
|
},
|
|
8252
|
-
{
|
|
8253
|
-
|
|
8254
|
-
|
|
8575
|
+
"zh-TW": {
|
|
8576
|
+
common: {
|
|
8577
|
+
loading: "載入中…",
|
|
8578
|
+
refresh: "重新整理",
|
|
8579
|
+
refreshing: "重新整理中…",
|
|
8580
|
+
reset: "重設",
|
|
8581
|
+
clear: "清除",
|
|
8582
|
+
delete: "刪除",
|
|
8583
|
+
add: "新增",
|
|
8584
|
+
copy: "複製",
|
|
8585
|
+
copied: "已複製 ✓",
|
|
8586
|
+
copyFailed: "複製失敗:{error}",
|
|
8587
|
+
generate: "產生",
|
|
8588
|
+
generating: "產生中…",
|
|
8589
|
+
none: "無",
|
|
8590
|
+
empty: "空"
|
|
8591
|
+
},
|
|
8592
|
+
toolbar: {
|
|
8593
|
+
title: "JSON-RPC 2.0",
|
|
8594
|
+
transport: "傳輸方式",
|
|
8595
|
+
http: "HTTP",
|
|
8596
|
+
ws: "WebSocket",
|
|
8597
|
+
refreshMethods: "重新整理方法清單",
|
|
8598
|
+
refreshMethodsLoading: "重新整理中…",
|
|
8599
|
+
generateDocs: "產生文件 ⬇",
|
|
8600
|
+
generateDocsLoading: "產生中…",
|
|
8601
|
+
generateDocsTitle: "取得所有方法的說明與簽章,產生 Markdown 文件並下載",
|
|
8602
|
+
theme: "主題",
|
|
8603
|
+
themeSystem: "跟隨系統",
|
|
8604
|
+
themeLight: "亮",
|
|
8605
|
+
themeDark: "暗",
|
|
8606
|
+
language: "語言",
|
|
8607
|
+
languageSystem: "跟隨系統語言",
|
|
8608
|
+
languageEn: "English",
|
|
8609
|
+
languageZhCN: "简体中文",
|
|
8610
|
+
languageZhTW: "繁體中文",
|
|
8611
|
+
languageJa: "日本語"
|
|
8612
|
+
},
|
|
8613
|
+
sidebar: {
|
|
8614
|
+
methods: "Methods",
|
|
8615
|
+
metrics: "Metrics",
|
|
8616
|
+
search: "搜尋",
|
|
8617
|
+
searchPlaceholder: "輸入關鍵字,以空格分隔",
|
|
8618
|
+
matchCount: "符合 {matched} / {total} 個方法",
|
|
8619
|
+
noMatch: "沒有符合的方法。",
|
|
8620
|
+
noMethods: "尚無可用方法。"
|
|
8621
|
+
},
|
|
8622
|
+
view: {
|
|
8623
|
+
label: "檢視",
|
|
8624
|
+
methods: "Methods",
|
|
8625
|
+
metrics: "Metrics"
|
|
8626
|
+
},
|
|
8627
|
+
method: {
|
|
8628
|
+
selectHint: "← 從左側選擇一個方法以檢視說明與簽章。",
|
|
8629
|
+
loading: "載入中…",
|
|
8630
|
+
loadFailed: "載入失敗:{error}",
|
|
8631
|
+
help: "Help",
|
|
8632
|
+
noHelp: "(無說明資訊)",
|
|
8633
|
+
returnType: "回傳型別",
|
|
8634
|
+
returnTypeHint: "(伺服器不會驗證執行結果是否符合此型別,實際回傳值可能有所不同)",
|
|
8635
|
+
none: "(暫無)"
|
|
8636
|
+
},
|
|
8637
|
+
test: {
|
|
8638
|
+
params: "參數",
|
|
8639
|
+
paramsHint: "({count} 個,依簽章自動產生)",
|
|
8640
|
+
noParams: "此方法無需參數。",
|
|
8641
|
+
execute: "執行 ▶",
|
|
8642
|
+
executing: "執行中…",
|
|
8643
|
+
executeStream: "執行並接收串流 ▶",
|
|
8644
|
+
receiving: "接收中…",
|
|
8645
|
+
resetToSample: "重設為範例",
|
|
8646
|
+
clearOutput: "清除輸出",
|
|
8647
|
+
result: "結果",
|
|
8648
|
+
resultStream: "(串流)",
|
|
8649
|
+
notExecuted: "(尚未執行)",
|
|
8650
|
+
copyCurl: "複製 curl (bash)",
|
|
8651
|
+
copyCurlCmd: "複製 curl (cmd)",
|
|
8652
|
+
copyFetch: "複製 fetch",
|
|
8653
|
+
copyTitle: "複製目前呼叫的等效程式碼",
|
|
8654
|
+
copyDisabledTitle: "僅 HTTP 傳輸可產生程式碼",
|
|
8655
|
+
chooseFormat: "選擇複製格式",
|
|
8656
|
+
streamEnded: "(串流已結束,共 {count} 幀,總耗時 {duration})",
|
|
8657
|
+
streamEndedEmpty: "(串流已結束,無資料,總耗時 {duration})",
|
|
8658
|
+
elapsed: "耗時",
|
|
8659
|
+
firstFrame: "首幀",
|
|
8660
|
+
jsonError: "JSON 錯誤:{error}"
|
|
8661
|
+
},
|
|
8662
|
+
schema: {
|
|
8663
|
+
nullable: "nullable",
|
|
8664
|
+
setNull: "設為 null",
|
|
8665
|
+
fillValue: "填入值",
|
|
8666
|
+
fixedValue: "(固定值)",
|
|
8667
|
+
unionNoBranch: "(union 無分支)",
|
|
8668
|
+
arrayNoItem: "(陣列無 item schema)",
|
|
8669
|
+
recordNoValue: "(record 無 value schema)",
|
|
8670
|
+
recordAddPlaceholder: "新鍵名",
|
|
8671
|
+
addRecordKey: "+ 新增鍵",
|
|
8672
|
+
addItem: "+ 新增項目",
|
|
8673
|
+
strictHint: "(非 strict 模式,允許額外欄位)",
|
|
8674
|
+
paramIndex: "參數 [{index}]",
|
|
8675
|
+
items: "items",
|
|
8676
|
+
values: "values",
|
|
8677
|
+
optionIndex: "option[{index}]",
|
|
8678
|
+
inner: "inner"
|
|
8679
|
+
},
|
|
8680
|
+
metrics: {
|
|
8681
|
+
title: "Metrics",
|
|
8682
|
+
unavailable: "伺服器未啟用 system.metrics(withSystemMethods: false 或未註冊)。",
|
|
8683
|
+
autoRefresh: "自動重新整理",
|
|
8684
|
+
interval: "重新整理間隔",
|
|
8685
|
+
refreshNow: "立即重新整理",
|
|
8686
|
+
refreshing: "重新整理中…",
|
|
8687
|
+
uptime: "uptime",
|
|
8688
|
+
loading: "載入中…",
|
|
8689
|
+
methods: "Methods",
|
|
8690
|
+
calls: "Calls",
|
|
8691
|
+
streams: "Streams",
|
|
8692
|
+
errors: "Errors",
|
|
8693
|
+
errorRate: "Error rate",
|
|
8694
|
+
invalidRequests: "Invalid requests",
|
|
8695
|
+
nonStreamTitle: "Non-stream methods",
|
|
8696
|
+
streamTitle: "Stream methods",
|
|
8697
|
+
noData: "尚無資料。",
|
|
8698
|
+
noStreams: "尚無串流呼叫。",
|
|
8699
|
+
countHint: "({count})",
|
|
8700
|
+
colMethod: "method",
|
|
8701
|
+
colCalls: "calls",
|
|
8702
|
+
colRate: "rate/s",
|
|
8703
|
+
colErrors: "errors",
|
|
8704
|
+
colErrPct: "err%",
|
|
8705
|
+
colP50: "p50",
|
|
8706
|
+
colP95: "p95",
|
|
8707
|
+
colP99: "p99",
|
|
8708
|
+
colAvg: "avg",
|
|
8709
|
+
colOpened: "opened",
|
|
8710
|
+
colCompleted: "completed",
|
|
8711
|
+
colFailed: "failed",
|
|
8712
|
+
colAborted: "aborted",
|
|
8713
|
+
colCompletePct: "complete%",
|
|
8714
|
+
colAbortPct: "abort%",
|
|
8715
|
+
colAvgChunks: "avg chunks",
|
|
8716
|
+
colTtfbP50: "ttfb p50",
|
|
8717
|
+
colTtfbP95: "ttfb p95",
|
|
8718
|
+
colDurationAvg: "duration avg"
|
|
8719
|
+
},
|
|
8720
|
+
footer: {
|
|
8721
|
+
version: "版本",
|
|
8722
|
+
npm: "npm 套件",
|
|
8723
|
+
github: "GitHub 儲存庫"
|
|
8724
|
+
},
|
|
8725
|
+
alerts: {
|
|
8726
|
+
emptyMethods: "方法清單為空,請先重新整理方法清單。",
|
|
8727
|
+
docsFailed: "產生文件失敗:{error}"
|
|
8728
|
+
}
|
|
8255
8729
|
},
|
|
8256
|
-
{
|
|
8257
|
-
|
|
8258
|
-
|
|
8730
|
+
ja: {
|
|
8731
|
+
common: {
|
|
8732
|
+
loading: "読み込み中…",
|
|
8733
|
+
refresh: "更新",
|
|
8734
|
+
refreshing: "更新中…",
|
|
8735
|
+
reset: "リセット",
|
|
8736
|
+
clear: "クリア",
|
|
8737
|
+
delete: "削除",
|
|
8738
|
+
add: "追加",
|
|
8739
|
+
copy: "コピー",
|
|
8740
|
+
copied: "コピーしました ✓",
|
|
8741
|
+
copyFailed: "コピーに失敗しました:{error}",
|
|
8742
|
+
generate: "生成",
|
|
8743
|
+
generating: "生成中…",
|
|
8744
|
+
none: "なし",
|
|
8745
|
+
empty: "空"
|
|
8746
|
+
},
|
|
8747
|
+
toolbar: {
|
|
8748
|
+
title: "JSON-RPC 2.0",
|
|
8749
|
+
transport: "トランスポート",
|
|
8750
|
+
http: "HTTP",
|
|
8751
|
+
ws: "WebSocket",
|
|
8752
|
+
refreshMethods: "メソッド一覧を更新",
|
|
8753
|
+
refreshMethodsLoading: "更新中…",
|
|
8754
|
+
generateDocs: "ドキュメント生成 ⬇",
|
|
8755
|
+
generateDocsLoading: "生成中…",
|
|
8756
|
+
generateDocsTitle: "全メソッドのヘルプとシグネチャを取得し、Markdown を生成してダウンロード",
|
|
8757
|
+
theme: "テーマ",
|
|
8758
|
+
themeSystem: "システムに従う",
|
|
8759
|
+
themeLight: "ライト",
|
|
8760
|
+
themeDark: "ダーク",
|
|
8761
|
+
language: "言語",
|
|
8762
|
+
languageSystem: "システム言語に従う",
|
|
8763
|
+
languageEn: "English",
|
|
8764
|
+
languageZhCN: "简体中文",
|
|
8765
|
+
languageZhTW: "繁體中文",
|
|
8766
|
+
languageJa: "日本語"
|
|
8767
|
+
},
|
|
8768
|
+
sidebar: {
|
|
8769
|
+
methods: "Methods",
|
|
8770
|
+
metrics: "Metrics",
|
|
8771
|
+
search: "検索",
|
|
8772
|
+
searchPlaceholder: "キーワードを入力(スペース区切り)",
|
|
8773
|
+
matchCount: "{matched} / {total} 件のメソッドが一致",
|
|
8774
|
+
noMatch: "一致するメソッドはありません。",
|
|
8775
|
+
noMethods: "利用可能なメソッドがありません。"
|
|
8776
|
+
},
|
|
8777
|
+
view: {
|
|
8778
|
+
label: "ビュー",
|
|
8779
|
+
methods: "Methods",
|
|
8780
|
+
metrics: "Metrics"
|
|
8781
|
+
},
|
|
8782
|
+
method: {
|
|
8783
|
+
selectHint: "← 左側からメソッドを選択すると、ヘルプとシグネチャが表示されます。",
|
|
8784
|
+
loading: "読み込み中…",
|
|
8785
|
+
loadFailed: "読み込み失敗:{error}",
|
|
8786
|
+
help: "Help",
|
|
8787
|
+
noHelp: "(ヘルプ情報なし)",
|
|
8788
|
+
returnType: "戻り値の型",
|
|
8789
|
+
returnTypeHint: "(サーバーは実行結果がこの型に一致するか検証しません。実際の戻り値は異なる場合があります)",
|
|
8790
|
+
none: "(なし)"
|
|
8791
|
+
},
|
|
8792
|
+
test: {
|
|
8793
|
+
params: "パラメータ",
|
|
8794
|
+
paramsHint: "({count} 個、シグネチャから自動生成)",
|
|
8795
|
+
noParams: "このメソッドはパラメータを取りません。",
|
|
8796
|
+
execute: "実行 ▶",
|
|
8797
|
+
executing: "実行中…",
|
|
8798
|
+
executeStream: "実行してストリーム受信 ▶",
|
|
8799
|
+
receiving: "受信中…",
|
|
8800
|
+
resetToSample: "サンプルに戻す",
|
|
8801
|
+
clearOutput: "出力をクリア",
|
|
8802
|
+
result: "結果",
|
|
8803
|
+
resultStream: "(ストリーミング)",
|
|
8804
|
+
notExecuted: "(未実行)",
|
|
8805
|
+
copyCurl: "curl をコピー (bash)",
|
|
8806
|
+
copyCurlCmd: "curl をコピー (cmd)",
|
|
8807
|
+
copyFetch: "fetch をコピー",
|
|
8808
|
+
copyTitle: "現在の呼び出しに相当するコードをコピー",
|
|
8809
|
+
copyDisabledTitle: "コード生成は HTTP トランスポートのみ対応",
|
|
8810
|
+
chooseFormat: "コピー形式を選択",
|
|
8811
|
+
streamEnded: "(ストリーム終了、{count} フレーム、合計 {duration})",
|
|
8812
|
+
streamEndedEmpty: "(ストリーム終了、データなし、合計 {duration})",
|
|
8813
|
+
elapsed: "経過",
|
|
8814
|
+
firstFrame: "初回フレーム",
|
|
8815
|
+
jsonError: "JSON エラー:{error}"
|
|
8816
|
+
},
|
|
8817
|
+
schema: {
|
|
8818
|
+
nullable: "nullable",
|
|
8819
|
+
setNull: "null にする",
|
|
8820
|
+
fillValue: "値を入力",
|
|
8821
|
+
fixedValue: "(固定値)",
|
|
8822
|
+
unionNoBranch: "(union に分岐がありません)",
|
|
8823
|
+
arrayNoItem: "(配列に item schema がありません)",
|
|
8824
|
+
recordNoValue: "(record に value schema がありません)",
|
|
8825
|
+
recordAddPlaceholder: "新しいキー",
|
|
8826
|
+
addRecordKey: "+ キーを追加",
|
|
8827
|
+
addItem: "+ 項目を追加",
|
|
8828
|
+
strictHint: "(非 strict モード、追加フィールドを許可)",
|
|
8829
|
+
paramIndex: "パラメータ [{index}]",
|
|
8830
|
+
items: "items",
|
|
8831
|
+
values: "values",
|
|
8832
|
+
optionIndex: "option[{index}]",
|
|
8833
|
+
inner: "inner"
|
|
8834
|
+
},
|
|
8835
|
+
metrics: {
|
|
8836
|
+
title: "Metrics",
|
|
8837
|
+
unavailable: "サーバーで system.metrics が有効になっていません(withSystemMethods: false または未登録)。",
|
|
8838
|
+
autoRefresh: "自動更新",
|
|
8839
|
+
interval: "更新間隔",
|
|
8840
|
+
refreshNow: "今すぐ更新",
|
|
8841
|
+
refreshing: "更新中…",
|
|
8842
|
+
uptime: "uptime",
|
|
8843
|
+
loading: "読み込み中…",
|
|
8844
|
+
methods: "Methods",
|
|
8845
|
+
calls: "Calls",
|
|
8846
|
+
streams: "Streams",
|
|
8847
|
+
errors: "Errors",
|
|
8848
|
+
errorRate: "Error rate",
|
|
8849
|
+
invalidRequests: "Invalid requests",
|
|
8850
|
+
nonStreamTitle: "Non-stream methods",
|
|
8851
|
+
streamTitle: "Stream methods",
|
|
8852
|
+
noData: "データがありません。",
|
|
8853
|
+
noStreams: "ストリーミング呼び出しはありません。",
|
|
8854
|
+
countHint: "({count})",
|
|
8855
|
+
colMethod: "method",
|
|
8856
|
+
colCalls: "calls",
|
|
8857
|
+
colRate: "rate/s",
|
|
8858
|
+
colErrors: "errors",
|
|
8859
|
+
colErrPct: "err%",
|
|
8860
|
+
colP50: "p50",
|
|
8861
|
+
colP95: "p95",
|
|
8862
|
+
colP99: "p99",
|
|
8863
|
+
colAvg: "avg",
|
|
8864
|
+
colOpened: "opened",
|
|
8865
|
+
colCompleted: "completed",
|
|
8866
|
+
colFailed: "failed",
|
|
8867
|
+
colAborted: "aborted",
|
|
8868
|
+
colCompletePct: "complete%",
|
|
8869
|
+
colAbortPct: "abort%",
|
|
8870
|
+
colAvgChunks: "avg chunks",
|
|
8871
|
+
colTtfbP50: "ttfb p50",
|
|
8872
|
+
colTtfbP95: "ttfb p95",
|
|
8873
|
+
colDurationAvg: "duration avg"
|
|
8874
|
+
},
|
|
8875
|
+
footer: {
|
|
8876
|
+
version: "バージョン",
|
|
8877
|
+
npm: "npm パッケージ",
|
|
8878
|
+
github: "GitHub リポジトリ"
|
|
8879
|
+
},
|
|
8880
|
+
alerts: {
|
|
8881
|
+
emptyMethods: "メソッド一覧が空です。先にメソッド一覧を更新してください。",
|
|
8882
|
+
docsFailed: "ドキュメント生成に失敗しました:{error}"
|
|
8883
|
+
}
|
|
8259
8884
|
}
|
|
8885
|
+
};
|
|
8886
|
+
//#endregion
|
|
8887
|
+
//#region webui/src/i18n/detect.ts
|
|
8888
|
+
/** 把 BCP-47 语言标签映射到我们支持的 4 种 locale。 */
|
|
8889
|
+
function normalizeLocale(tag) {
|
|
8890
|
+
if (!tag) return void 0;
|
|
8891
|
+
const t = tag.toLowerCase();
|
|
8892
|
+
if (t === "ja" || t.startsWith("ja-")) return "ja";
|
|
8893
|
+
if (t === "zh" || t.startsWith("zh-")) {
|
|
8894
|
+
if (t.includes("hant") || t.startsWith("zh-tw") || t.startsWith("zh-hk") || t.startsWith("zh-mo")) return "zh-TW";
|
|
8895
|
+
return "zh-CN";
|
|
8896
|
+
}
|
|
8897
|
+
if (t === "en" || t.startsWith("en-")) return "en";
|
|
8898
|
+
}
|
|
8899
|
+
/** 读取浏览器语言偏好,取第一个能映射的;否则回退 en。 */
|
|
8900
|
+
function detectSystemLocale() {
|
|
8901
|
+
const nav = typeof navigator !== "undefined" ? navigator : void 0;
|
|
8902
|
+
const candidates = [];
|
|
8903
|
+
if (nav?.languages && nav.languages.length > 0) candidates.push(...nav.languages);
|
|
8904
|
+
if (nav?.language) candidates.push(nav.language);
|
|
8905
|
+
for (const c of candidates) {
|
|
8906
|
+
const loc = normalizeLocale(c);
|
|
8907
|
+
if (loc) return loc;
|
|
8908
|
+
}
|
|
8909
|
+
return "en";
|
|
8910
|
+
}
|
|
8911
|
+
//#endregion
|
|
8912
|
+
//#region webui/src/i18n/I18nProvider.tsx
|
|
8913
|
+
var STORAGE_KEY = "jsonrpc2.locale";
|
|
8914
|
+
var I18nContext = (0, import_react.createContext)(null);
|
|
8915
|
+
var VALID_MODES = [
|
|
8916
|
+
"system",
|
|
8917
|
+
"en",
|
|
8918
|
+
"zh-CN",
|
|
8919
|
+
"zh-TW",
|
|
8920
|
+
"ja"
|
|
8260
8921
|
];
|
|
8922
|
+
function readStoredMode() {
|
|
8923
|
+
try {
|
|
8924
|
+
const v = localStorage.getItem(STORAGE_KEY);
|
|
8925
|
+
if (v && VALID_MODES.includes(v)) return v;
|
|
8926
|
+
} catch {}
|
|
8927
|
+
return "system";
|
|
8928
|
+
}
|
|
8929
|
+
function getByPath(obj, path) {
|
|
8930
|
+
const parts = path.split(".");
|
|
8931
|
+
let cur = obj;
|
|
8932
|
+
for (const p of parts) {
|
|
8933
|
+
if (cur == null || typeof cur !== "object") return void 0;
|
|
8934
|
+
cur = cur[p];
|
|
8935
|
+
}
|
|
8936
|
+
return cur;
|
|
8937
|
+
}
|
|
8938
|
+
function interpolate(text, vars) {
|
|
8939
|
+
if (!vars) return text;
|
|
8940
|
+
return text.replace(/\{(\w+)\}/g, (_, name) => {
|
|
8941
|
+
const v = vars[name];
|
|
8942
|
+
return v === void 0 ? `{${name}}` : String(v);
|
|
8943
|
+
});
|
|
8944
|
+
}
|
|
8945
|
+
function I18nProvider({ children }) {
|
|
8946
|
+
const [mode, setModeState] = (0, import_react.useState)(readStoredMode);
|
|
8947
|
+
const [systemLocale, setSystemLocale] = (0, import_react.useState)(detectSystemLocale);
|
|
8948
|
+
(0, import_react.useEffect)(() => {
|
|
8949
|
+
const onChange = () => setSystemLocale(detectSystemLocale());
|
|
8950
|
+
window.addEventListener("languagechange", onChange);
|
|
8951
|
+
return () => window.removeEventListener("languagechange", onChange);
|
|
8952
|
+
}, []);
|
|
8953
|
+
const locale = (0, import_react.useMemo)(() => {
|
|
8954
|
+
if (mode === "system") return systemLocale;
|
|
8955
|
+
return normalizeLocale(mode) ?? systemLocale;
|
|
8956
|
+
}, [mode, systemLocale]);
|
|
8957
|
+
(0, import_react.useEffect)(() => {
|
|
8958
|
+
document.documentElement.setAttribute("lang", locale);
|
|
8959
|
+
try {
|
|
8960
|
+
localStorage.setItem(STORAGE_KEY, mode);
|
|
8961
|
+
} catch {}
|
|
8962
|
+
}, [locale, mode]);
|
|
8963
|
+
const messages = MESSAGES[locale];
|
|
8964
|
+
const t = (0, import_react.useCallback)((key, vars) => {
|
|
8965
|
+
const raw = getByPath(messages, key);
|
|
8966
|
+
if (typeof raw === "string") return interpolate(raw, vars);
|
|
8967
|
+
const fallback = getByPath(MESSAGES.en, key);
|
|
8968
|
+
if (typeof fallback === "string") return interpolate(fallback, vars);
|
|
8969
|
+
return key;
|
|
8970
|
+
}, [messages]);
|
|
8971
|
+
const setMode = (0, import_react.useCallback)((m) => setModeState(m), []);
|
|
8972
|
+
const value = (0, import_react.useMemo)(() => ({
|
|
8973
|
+
mode,
|
|
8974
|
+
locale,
|
|
8975
|
+
messages,
|
|
8976
|
+
setMode,
|
|
8977
|
+
t
|
|
8978
|
+
}), [
|
|
8979
|
+
mode,
|
|
8980
|
+
locale,
|
|
8981
|
+
messages,
|
|
8982
|
+
setMode,
|
|
8983
|
+
t
|
|
8984
|
+
]);
|
|
8985
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(I18nContext.Provider, {
|
|
8986
|
+
value,
|
|
8987
|
+
children
|
|
8988
|
+
});
|
|
8989
|
+
}
|
|
8990
|
+
function useI18n() {
|
|
8991
|
+
const ctx = (0, import_react.useContext)(I18nContext);
|
|
8992
|
+
if (!ctx) throw new Error("useI18n must be used within <I18nProvider>");
|
|
8993
|
+
return ctx;
|
|
8994
|
+
}
|
|
8995
|
+
/** 便捷 hook:只取 t */
|
|
8996
|
+
function useT() {
|
|
8997
|
+
return useI18n().t;
|
|
8998
|
+
}
|
|
8999
|
+
//#endregion
|
|
9000
|
+
//#region webui/src/components/Toolbar.tsx
|
|
8261
9001
|
function Toolbar({ transport, onTransportChange, onRefresh, loading, error, onGenerateDocs, generatingDocs }) {
|
|
8262
9002
|
const { mode, setMode } = useTheme();
|
|
9003
|
+
const { t, mode: localeMode, setMode: setLocaleMode } = useI18n();
|
|
9004
|
+
const themeOptions = [
|
|
9005
|
+
{
|
|
9006
|
+
value: "system",
|
|
9007
|
+
label: t("toolbar.themeSystem")
|
|
9008
|
+
},
|
|
9009
|
+
{
|
|
9010
|
+
value: "light",
|
|
9011
|
+
label: t("toolbar.themeLight")
|
|
9012
|
+
},
|
|
9013
|
+
{
|
|
9014
|
+
value: "dark",
|
|
9015
|
+
label: t("toolbar.themeDark")
|
|
9016
|
+
}
|
|
9017
|
+
];
|
|
9018
|
+
const localeOptions = [
|
|
9019
|
+
{
|
|
9020
|
+
value: "system",
|
|
9021
|
+
label: t("toolbar.languageSystem")
|
|
9022
|
+
},
|
|
9023
|
+
{
|
|
9024
|
+
value: "en",
|
|
9025
|
+
label: t("toolbar.languageEn")
|
|
9026
|
+
},
|
|
9027
|
+
{
|
|
9028
|
+
value: "zh-CN",
|
|
9029
|
+
label: t("toolbar.languageZhCN")
|
|
9030
|
+
},
|
|
9031
|
+
{
|
|
9032
|
+
value: "zh-TW",
|
|
9033
|
+
label: t("toolbar.languageZhTW")
|
|
9034
|
+
},
|
|
9035
|
+
{
|
|
9036
|
+
value: "ja",
|
|
9037
|
+
label: t("toolbar.languageJa")
|
|
9038
|
+
}
|
|
9039
|
+
];
|
|
8263
9040
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
|
|
8264
9041
|
className: "toolbar",
|
|
8265
9042
|
children: [
|
|
8266
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { children: "
|
|
9043
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { children: t("toolbar.title") }),
|
|
8267
9044
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
8268
9045
|
className: "segmented",
|
|
8269
9046
|
role: "group",
|
|
8270
|
-
"aria-label": "
|
|
9047
|
+
"aria-label": t("toolbar.transport"),
|
|
8271
9048
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
8272
9049
|
type: "button",
|
|
8273
9050
|
className: transport === "http" ? "active" : "",
|
|
8274
9051
|
onClick: () => onTransportChange("http"),
|
|
8275
|
-
children: "
|
|
9052
|
+
children: t("toolbar.http")
|
|
8276
9053
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
8277
9054
|
type: "button",
|
|
8278
9055
|
className: transport === "ws" ? "active" : "",
|
|
8279
9056
|
onClick: () => onTransportChange("ws"),
|
|
8280
|
-
children: "
|
|
9057
|
+
children: t("toolbar.ws")
|
|
8281
9058
|
})]
|
|
8282
9059
|
}),
|
|
8283
9060
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
8284
9061
|
onClick: onRefresh,
|
|
8285
9062
|
disabled: loading,
|
|
8286
|
-
children: loading ? "
|
|
9063
|
+
children: loading ? t("toolbar.refreshMethodsLoading") : t("toolbar.refreshMethods")
|
|
8287
9064
|
}),
|
|
8288
9065
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
8289
9066
|
onClick: onGenerateDocs,
|
|
8290
|
-
disabled: generatingDocs || loading
|
|
8291
|
-
title: "
|
|
8292
|
-
children: generatingDocs ? "
|
|
9067
|
+
disabled: generatingDocs || loading,
|
|
9068
|
+
title: t("toolbar.generateDocsTitle"),
|
|
9069
|
+
children: generatingDocs ? t("toolbar.generateDocsLoading") : t("toolbar.generateDocs")
|
|
8293
9070
|
}),
|
|
8294
9071
|
error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
8295
9072
|
className: "error",
|
|
@@ -8297,14 +9074,29 @@ function Toolbar({ transport, onTransportChange, onRefresh, loading, error, onGe
|
|
|
8297
9074
|
}),
|
|
8298
9075
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", {
|
|
8299
9076
|
className: "theme-select",
|
|
8300
|
-
title: "
|
|
9077
|
+
title: t("toolbar.language"),
|
|
8301
9078
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
8302
9079
|
className: "theme-select-label",
|
|
8303
|
-
children: "
|
|
9080
|
+
children: t("toolbar.language")
|
|
9081
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", {
|
|
9082
|
+
value: localeMode,
|
|
9083
|
+
onChange: (e) => setLocaleMode(e.target.value),
|
|
9084
|
+
children: localeOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
9085
|
+
value: opt.value,
|
|
9086
|
+
children: opt.label
|
|
9087
|
+
}, opt.value))
|
|
9088
|
+
})]
|
|
9089
|
+
}),
|
|
9090
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", {
|
|
9091
|
+
className: "theme-select",
|
|
9092
|
+
title: t("toolbar.theme"),
|
|
9093
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
9094
|
+
className: "theme-select-label",
|
|
9095
|
+
children: t("toolbar.theme")
|
|
8304
9096
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", {
|
|
8305
9097
|
value: mode,
|
|
8306
9098
|
onChange: (e) => setMode(e.target.value),
|
|
8307
|
-
children:
|
|
9099
|
+
children: themeOptions.map((opt) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
8308
9100
|
value: opt.value,
|
|
8309
9101
|
children: opt.label
|
|
8310
9102
|
}, opt.value))
|
|
@@ -8351,10 +9143,11 @@ function buildTree(methods) {
|
|
|
8351
9143
|
return root.children;
|
|
8352
9144
|
}
|
|
8353
9145
|
function MethodTree({ methods, selected, onSelect }) {
|
|
9146
|
+
const t = useT();
|
|
8354
9147
|
const tree = (0, import_react.useMemo)(() => buildTree(methods), [methods]);
|
|
8355
9148
|
if (methods.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
8356
9149
|
className: "empty",
|
|
8357
|
-
children: "
|
|
9150
|
+
children: t("sidebar.noMethods")
|
|
8358
9151
|
});
|
|
8359
9152
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", {
|
|
8360
9153
|
className: "tree",
|
|
@@ -8424,8 +9217,9 @@ function formatConstraints$1(constraints) {
|
|
|
8424
9217
|
return entries.map(([k, v]) => `${k}=${typeof v === "string" ? JSON.stringify(v) : JSON.stringify(v)}`).join(", ");
|
|
8425
9218
|
}
|
|
8426
9219
|
function SchemaNode({ schema, depth, defaultOpen, label }) {
|
|
9220
|
+
const t = useT();
|
|
8427
9221
|
const [open, setOpen] = (0, import_react.useState)(defaultOpen);
|
|
8428
|
-
const hasChildren =
|
|
9222
|
+
const hasChildren = hasChildNodes(schema);
|
|
8429
9223
|
const constraintsText = formatConstraints$1(schema.constraints);
|
|
8430
9224
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
8431
9225
|
className: "schema-node",
|
|
@@ -8471,59 +9265,107 @@ function SchemaNode({ schema, depth, defaultOpen, label }) {
|
|
|
8471
9265
|
]
|
|
8472
9266
|
}), open && hasChildren && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
8473
9267
|
className: "schema-children",
|
|
8474
|
-
children: renderChildren(schema, depth + 1)
|
|
9268
|
+
children: renderChildren(schema, depth + 1, t)
|
|
8475
9269
|
})]
|
|
8476
9270
|
});
|
|
8477
9271
|
}
|
|
8478
|
-
function
|
|
8479
|
-
|
|
9272
|
+
function isSchemaDescription(v) {
|
|
9273
|
+
return !!v && typeof v === "object" && typeof v.kind === "string";
|
|
9274
|
+
}
|
|
9275
|
+
/** 是否存在可展开的子节点(新结构 + stream 的兼容路径) */
|
|
9276
|
+
function hasChildNodes(schema) {
|
|
9277
|
+
switch (schema.kind) {
|
|
9278
|
+
case "array": return isSchemaDescription(schema.element);
|
|
9279
|
+
case "record": return isSchemaDescription(schema.value);
|
|
9280
|
+
case "tuple": {
|
|
9281
|
+
const els = schema.elements;
|
|
9282
|
+
return Array.isArray(els) && els.some(isSchemaDescription);
|
|
9283
|
+
}
|
|
9284
|
+
case "union": {
|
|
9285
|
+
const opts = schema.options;
|
|
9286
|
+
return Array.isArray(opts) && opts.some(isSchemaDescription);
|
|
9287
|
+
}
|
|
9288
|
+
case "object": {
|
|
9289
|
+
const props = schema.properties;
|
|
9290
|
+
return !!props && typeof props === "object" && !Array.isArray(props) && Object.keys(props).length > 0;
|
|
9291
|
+
}
|
|
9292
|
+
case "stream": {
|
|
9293
|
+
const any = schema;
|
|
9294
|
+
return isSchemaDescription(any.inner) || isSchemaDescription(any.children?.inner);
|
|
9295
|
+
}
|
|
9296
|
+
default: return false;
|
|
9297
|
+
}
|
|
9298
|
+
}
|
|
9299
|
+
function renderChildren(schema, depth, t) {
|
|
8480
9300
|
const out = [];
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
9301
|
+
switch (schema.kind) {
|
|
9302
|
+
case "array": {
|
|
9303
|
+
const element = schema.element;
|
|
9304
|
+
if (isSchemaDescription(element)) out.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaNode, {
|
|
9305
|
+
schema: element,
|
|
9306
|
+
depth,
|
|
9307
|
+
defaultOpen: true
|
|
9308
|
+
}, "element"));
|
|
9309
|
+
break;
|
|
9310
|
+
}
|
|
9311
|
+
case "record": {
|
|
9312
|
+
const value = schema.value;
|
|
9313
|
+
if (isSchemaDescription(value)) out.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaNode, {
|
|
9314
|
+
schema: value,
|
|
9315
|
+
depth,
|
|
9316
|
+
defaultOpen: true
|
|
9317
|
+
}, "value"));
|
|
9318
|
+
break;
|
|
9319
|
+
}
|
|
9320
|
+
case "tuple": {
|
|
9321
|
+
const elements = schema.elements;
|
|
9322
|
+
if (Array.isArray(elements)) elements.forEach((item, i) => {
|
|
9323
|
+
if (isSchemaDescription(item)) out.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaNode, {
|
|
9324
|
+
schema: item,
|
|
9325
|
+
depth,
|
|
9326
|
+
defaultOpen: true,
|
|
9327
|
+
label: String(i)
|
|
9328
|
+
}, `el-${i}`));
|
|
9329
|
+
});
|
|
9330
|
+
break;
|
|
9331
|
+
}
|
|
9332
|
+
case "union": {
|
|
9333
|
+
const options = schema.options;
|
|
9334
|
+
if (Array.isArray(options)) options.forEach((opt, i) => {
|
|
9335
|
+
if (isSchemaDescription(opt)) out.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaNode, {
|
|
9336
|
+
schema: opt,
|
|
9337
|
+
depth,
|
|
9338
|
+
defaultOpen: false,
|
|
9339
|
+
label: t("schema.optionIndex", { index: i })
|
|
9340
|
+
}, `opt-${i}`));
|
|
9341
|
+
});
|
|
9342
|
+
break;
|
|
9343
|
+
}
|
|
9344
|
+
case "object": {
|
|
9345
|
+
const props = schema.properties;
|
|
9346
|
+
if (props && typeof props === "object" && !Array.isArray(props)) {
|
|
9347
|
+
for (const [key, prop] of Object.entries(props)) if (isSchemaDescription(prop)) out.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaNode, {
|
|
9348
|
+
schema: prop,
|
|
9349
|
+
depth,
|
|
9350
|
+
defaultOpen: true,
|
|
9351
|
+
label: key
|
|
9352
|
+
}, `prop-${key}`));
|
|
9353
|
+
}
|
|
9354
|
+
break;
|
|
9355
|
+
}
|
|
9356
|
+
case "stream": {
|
|
9357
|
+
const any = schema;
|
|
9358
|
+
const inner = isSchemaDescription(any.inner) ? any.inner : isSchemaDescription(any.children?.inner) ? any.children.inner : void 0;
|
|
9359
|
+
if (inner) out.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaNode, {
|
|
9360
|
+
schema: inner,
|
|
9361
|
+
depth,
|
|
9362
|
+
defaultOpen: true
|
|
9363
|
+
}, "inner"));
|
|
9364
|
+
break;
|
|
9365
|
+
}
|
|
8515
9366
|
}
|
|
8516
|
-
if (c.values && isSchemaDescription(c.values)) out.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaNode, {
|
|
8517
|
-
schema: c.values,
|
|
8518
|
-
depth,
|
|
8519
|
-
defaultOpen: true,
|
|
8520
|
-
label: "values"
|
|
8521
|
-
}, "values"));
|
|
8522
9367
|
return out;
|
|
8523
9368
|
}
|
|
8524
|
-
function isSchemaDescription(v) {
|
|
8525
|
-
return !!v && typeof v === "object" && typeof v.kind === "string";
|
|
8526
|
-
}
|
|
8527
9369
|
function SchemaView({ schema, defaultOpen = true, depth = 0 }) {
|
|
8528
9370
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaNode, {
|
|
8529
9371
|
schema,
|
|
@@ -8534,11 +9376,12 @@ function SchemaView({ schema, defaultOpen = true, depth = 0 }) {
|
|
|
8534
9376
|
//#endregion
|
|
8535
9377
|
//#region webui/src/components/MethodDetail.tsx
|
|
8536
9378
|
function MethodDetail({ method, detail }) {
|
|
9379
|
+
const t = useT();
|
|
8537
9380
|
if (!method) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", {
|
|
8538
9381
|
className: "detail",
|
|
8539
9382
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
8540
9383
|
className: "hint",
|
|
8541
|
-
children: "
|
|
9384
|
+
children: t("method.selectHint")
|
|
8542
9385
|
})
|
|
8543
9386
|
});
|
|
8544
9387
|
const [returnSchema] = detail.signature;
|
|
@@ -8548,23 +9391,23 @@ function MethodDetail({ method, detail }) {
|
|
|
8548
9391
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: method }),
|
|
8549
9392
|
detail.loading && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
8550
9393
|
className: "hint",
|
|
8551
|
-
children: "
|
|
9394
|
+
children: t("method.loading")
|
|
8552
9395
|
}),
|
|
8553
|
-
detail.error && /* @__PURE__ */ (0, import_jsx_runtime.
|
|
9396
|
+
detail.error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
8554
9397
|
className: "error",
|
|
8555
|
-
children:
|
|
9398
|
+
children: t("method.loadFailed", { error: detail.error })
|
|
8556
9399
|
}),
|
|
8557
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: "
|
|
9400
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { children: t("method.help") }),
|
|
8558
9401
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
|
|
8559
9402
|
className: "help",
|
|
8560
|
-
children: detail.help || "
|
|
9403
|
+
children: detail.help || t("method.noHelp")
|
|
8561
9404
|
}),
|
|
8562
9405
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { children: [
|
|
8563
|
-
"
|
|
9406
|
+
t("method.returnType"),
|
|
8564
9407
|
" ",
|
|
8565
9408
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
8566
9409
|
className: "hint",
|
|
8567
|
-
children: "
|
|
9410
|
+
children: t("method.returnTypeHint")
|
|
8568
9411
|
})
|
|
8569
9412
|
] }),
|
|
8570
9413
|
returnSchema ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaView, {
|
|
@@ -8573,7 +9416,7 @@ function MethodDetail({ method, detail }) {
|
|
|
8573
9416
|
defaultOpen: true
|
|
8574
9417
|
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
8575
9418
|
className: "hint",
|
|
8576
|
-
children: "
|
|
9419
|
+
children: t("method.none")
|
|
8577
9420
|
})
|
|
8578
9421
|
]
|
|
8579
9422
|
});
|
|
@@ -8591,12 +9434,11 @@ function isSchema$1(v) {
|
|
|
8591
9434
|
* - 原始类型返回零值(''、0、false)
|
|
8592
9435
|
* - literal 返回固定值
|
|
8593
9436
|
* - enum 返回第一个枚举值
|
|
8594
|
-
* -
|
|
9437
|
+
* - 容器类型递归展开(按新字段:element / value / properties / options / elements)
|
|
8595
9438
|
* - unknown 返回 null
|
|
8596
9439
|
*/
|
|
8597
9440
|
function sampleFromSchema(schema) {
|
|
8598
9441
|
if (schema.nullable) return null;
|
|
8599
|
-
const c = schema.children ?? {};
|
|
8600
9442
|
switch (schema.kind) {
|
|
8601
9443
|
case "string": return "";
|
|
8602
9444
|
case "number": return 0;
|
|
@@ -8607,19 +9449,19 @@ function sampleFromSchema(schema) {
|
|
|
8607
9449
|
const values = schema.constraints?.values;
|
|
8608
9450
|
return Array.isArray(values) && values.length > 0 ? values[0] : "";
|
|
8609
9451
|
}
|
|
8610
|
-
case "array": return [isSchema$1(
|
|
8611
|
-
case "tuple": return (Array.isArray(
|
|
9452
|
+
case "array": return [isSchema$1(schema.element) ? sampleFromSchema(schema.element) : null];
|
|
9453
|
+
case "tuple": return (Array.isArray(schema.elements) ? schema.elements : []).map((it) => isSchema$1(it) ? sampleFromSchema(it) : null);
|
|
8612
9454
|
case "union": {
|
|
8613
|
-
const options = Array.isArray(
|
|
9455
|
+
const options = Array.isArray(schema.options) ? schema.options : [];
|
|
8614
9456
|
return options.length > 0 && isSchema$1(options[0]) ? sampleFromSchema(options[0]) : null;
|
|
8615
9457
|
}
|
|
8616
9458
|
case "object": {
|
|
8617
|
-
const props =
|
|
9459
|
+
const props = schema.properties ?? {};
|
|
8618
9460
|
const out = {};
|
|
8619
9461
|
for (const [k, v] of Object.entries(props)) if (isSchema$1(v)) out[k] = sampleFromSchema(v);
|
|
8620
9462
|
return out;
|
|
8621
9463
|
}
|
|
8622
|
-
case "record": return { key: isSchema$1(
|
|
9464
|
+
case "record": return { key: isSchema$1(schema.value) ? sampleFromSchema(schema.value) : null };
|
|
8623
9465
|
default: return null;
|
|
8624
9466
|
}
|
|
8625
9467
|
}
|
|
@@ -8647,9 +9489,10 @@ function formatConstraints(c) {
|
|
|
8647
9489
|
return Object.entries(c).filter(([, v]) => v !== void 0).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(", ");
|
|
8648
9490
|
}
|
|
8649
9491
|
function SchemaForm({ params, values, onChange, disabled }) {
|
|
9492
|
+
const t = useT();
|
|
8650
9493
|
if (params.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
8651
9494
|
className: "hint",
|
|
8652
|
-
children: "
|
|
9495
|
+
children: t("test.noParams")
|
|
8653
9496
|
});
|
|
8654
9497
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
8655
9498
|
className: "schema-form",
|
|
@@ -8657,13 +9500,14 @@ function SchemaForm({ params, values, onChange, disabled }) {
|
|
|
8657
9500
|
schema,
|
|
8658
9501
|
value: values[i],
|
|
8659
9502
|
onChange: (v) => onChange(i, v),
|
|
8660
|
-
label:
|
|
9503
|
+
label: t("schema.paramIndex", { index: i }),
|
|
8661
9504
|
depth: 0,
|
|
8662
9505
|
disabled
|
|
8663
9506
|
}, i))
|
|
8664
9507
|
});
|
|
8665
9508
|
}
|
|
8666
9509
|
function SchemaField({ schema, value, onChange, label, depth = 0, defaultOpen = true, disabled }) {
|
|
9510
|
+
const t = useT();
|
|
8667
9511
|
const [open, setOpen] = (0, import_react.useState)(defaultOpen);
|
|
8668
9512
|
const kind = schema.kind;
|
|
8669
9513
|
if (schema.nullable) {
|
|
@@ -8685,7 +9529,7 @@ function SchemaField({ schema, value, onChange, label, depth = 0, defaultOpen =
|
|
|
8685
9529
|
}),
|
|
8686
9530
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
8687
9531
|
className: "sf-nullable-badge",
|
|
8688
|
-
children: "nullable"
|
|
9532
|
+
children: t("schema.nullable")
|
|
8689
9533
|
}),
|
|
8690
9534
|
schema.description && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
8691
9535
|
className: "sf-desc",
|
|
@@ -8696,7 +9540,7 @@ function SchemaField({ schema, value, onChange, label, depth = 0, defaultOpen =
|
|
|
8696
9540
|
className: "tiny",
|
|
8697
9541
|
disabled,
|
|
8698
9542
|
onClick: () => onChange(null),
|
|
8699
|
-
children: "
|
|
9543
|
+
children: t("schema.setNull")
|
|
8700
9544
|
}),
|
|
8701
9545
|
isNull && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
8702
9546
|
type: "button",
|
|
@@ -8706,7 +9550,7 @@ function SchemaField({ schema, value, onChange, label, depth = 0, defaultOpen =
|
|
|
8706
9550
|
...schema,
|
|
8707
9551
|
nullable: false
|
|
8708
9552
|
})),
|
|
8709
|
-
children: "
|
|
9553
|
+
children: t("schema.fillValue")
|
|
8710
9554
|
})
|
|
8711
9555
|
]
|
|
8712
9556
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
@@ -8760,7 +9604,7 @@ function SchemaField({ schema, value, onChange, label, depth = 0, defaultOpen =
|
|
|
8760
9604
|
})]
|
|
8761
9605
|
});
|
|
8762
9606
|
if (kind === "union") {
|
|
8763
|
-
const options = Array.isArray(schema.
|
|
9607
|
+
const options = Array.isArray(schema.options) ? schema.options.filter(isSchema$1) : [];
|
|
8764
9608
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
8765
9609
|
className: "sf-node sf-row",
|
|
8766
9610
|
style: { paddingLeft: depth * 14 },
|
|
@@ -8843,6 +9687,7 @@ function isScalarKind(kind) {
|
|
|
8843
9687
|
return kind === "string" || kind === "number" || kind === "boolean" || kind === "enum" || kind === "literal" || kind === "null";
|
|
8844
9688
|
}
|
|
8845
9689
|
function ScalarInput({ schema, value, onChange, disabled }) {
|
|
9690
|
+
const t = useT();
|
|
8846
9691
|
switch (schema.kind) {
|
|
8847
9692
|
case "boolean": return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", {
|
|
8848
9693
|
className: "sf-scalar",
|
|
@@ -8880,7 +9725,7 @@ function ScalarInput({ schema, value, onChange, disabled }) {
|
|
|
8880
9725
|
children: JSON.stringify(schema.constraints?.value ?? null)
|
|
8881
9726
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
8882
9727
|
className: "hint",
|
|
8883
|
-
children: "
|
|
9728
|
+
children: t("schema.fixedValue")
|
|
8884
9729
|
})]
|
|
8885
9730
|
});
|
|
8886
9731
|
case "null": return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
@@ -8890,7 +9735,7 @@ function ScalarInput({ schema, value, onChange, disabled }) {
|
|
|
8890
9735
|
children: "null"
|
|
8891
9736
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
8892
9737
|
className: "hint",
|
|
8893
|
-
children: "
|
|
9738
|
+
children: t("schema.fixedValue")
|
|
8894
9739
|
})]
|
|
8895
9740
|
});
|
|
8896
9741
|
default: return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
|
|
@@ -8903,11 +9748,12 @@ function ScalarInput({ schema, value, onChange, disabled }) {
|
|
|
8903
9748
|
}
|
|
8904
9749
|
}
|
|
8905
9750
|
function UnionField({ options, value, onChange, depth, disabled }) {
|
|
9751
|
+
const t = useT();
|
|
8906
9752
|
const [selected, setSelected] = (0, import_react.useState)(0);
|
|
8907
9753
|
const active = options[selected];
|
|
8908
9754
|
if (!active) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
8909
9755
|
className: "hint",
|
|
8910
|
-
children: "
|
|
9756
|
+
children: t("schema.unionNoBranch")
|
|
8911
9757
|
});
|
|
8912
9758
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
8913
9759
|
style: { paddingLeft: depth * 14 },
|
|
@@ -8926,9 +9772,8 @@ function UnionField({ options, value, onChange, depth, disabled }) {
|
|
|
8926
9772
|
children: options.map((opt, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("option", {
|
|
8927
9773
|
value: i,
|
|
8928
9774
|
children: [
|
|
8929
|
-
"
|
|
8930
|
-
|
|
8931
|
-
"] — ",
|
|
9775
|
+
t("schema.optionIndex", { index: i }),
|
|
9776
|
+
" — ",
|
|
8932
9777
|
opt.kind
|
|
8933
9778
|
]
|
|
8934
9779
|
}, i))
|
|
@@ -8944,12 +9789,12 @@ function UnionField({ options, value, onChange, depth, disabled }) {
|
|
|
8944
9789
|
});
|
|
8945
9790
|
}
|
|
8946
9791
|
function ContainerChildren({ schema, value, onChange, depth, disabled }) {
|
|
8947
|
-
const
|
|
9792
|
+
const t = useT();
|
|
8948
9793
|
if (schema.kind === "array") {
|
|
8949
|
-
const itemSchema = isSchema$1(
|
|
9794
|
+
const itemSchema = isSchema$1(schema.element) ? schema.element : void 0;
|
|
8950
9795
|
if (!itemSchema) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
8951
9796
|
className: "hint",
|
|
8952
|
-
children: "
|
|
9797
|
+
children: t("schema.arrayNoItem")
|
|
8953
9798
|
});
|
|
8954
9799
|
const arr = Array.isArray(value) ? value : [];
|
|
8955
9800
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [arr.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
@@ -8971,18 +9816,18 @@ function ContainerChildren({ schema, value, onChange, depth, disabled }) {
|
|
|
8971
9816
|
className: "tiny",
|
|
8972
9817
|
disabled,
|
|
8973
9818
|
onClick: () => onChange(arr.filter((_, j) => j !== i)),
|
|
8974
|
-
children: "
|
|
9819
|
+
children: t("common.delete")
|
|
8975
9820
|
})]
|
|
8976
9821
|
}, i)), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
8977
9822
|
type: "button",
|
|
8978
9823
|
className: "tiny",
|
|
8979
9824
|
disabled,
|
|
8980
9825
|
onClick: () => onChange([...arr, sampleFromSchema(itemSchema)]),
|
|
8981
|
-
children: "
|
|
9826
|
+
children: t("schema.addItem")
|
|
8982
9827
|
})] });
|
|
8983
9828
|
}
|
|
8984
9829
|
if (schema.kind === "tuple") {
|
|
8985
|
-
const items = Array.isArray(
|
|
9830
|
+
const items = Array.isArray(schema.elements) ? schema.elements.filter(isSchema$1) : [];
|
|
8986
9831
|
const arr = Array.isArray(value) ? value : [];
|
|
8987
9832
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: items.map((itemSchema, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaField, {
|
|
8988
9833
|
schema: itemSchema,
|
|
@@ -8999,9 +9844,9 @@ function ContainerChildren({ schema, value, onChange, depth, disabled }) {
|
|
|
8999
9844
|
}, i)) });
|
|
9000
9845
|
}
|
|
9001
9846
|
if (schema.kind === "object") {
|
|
9002
|
-
const props =
|
|
9847
|
+
const props = schema.properties ?? {};
|
|
9003
9848
|
const obj = value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
9004
|
-
const
|
|
9849
|
+
const allowUnknown = schema.constraints?.allowUnknownProps !== false;
|
|
9005
9850
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [Object.entries(props).map(([key, prop]) => {
|
|
9006
9851
|
if (!isSchema$1(prop)) return null;
|
|
9007
9852
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaField, {
|
|
@@ -9018,20 +9863,20 @@ function ContainerChildren({ schema, value, onChange, depth, disabled }) {
|
|
|
9018
9863
|
disabled,
|
|
9019
9864
|
defaultOpen: false
|
|
9020
9865
|
}, key);
|
|
9021
|
-
}),
|
|
9866
|
+
}), allowUnknown && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
9022
9867
|
className: "hint",
|
|
9023
9868
|
style: {
|
|
9024
9869
|
paddingLeft: depth * 14,
|
|
9025
9870
|
margin: "4px 0"
|
|
9026
9871
|
},
|
|
9027
|
-
children: "
|
|
9872
|
+
children: t("schema.strictHint")
|
|
9028
9873
|
})] });
|
|
9029
9874
|
}
|
|
9030
9875
|
if (schema.kind === "record") {
|
|
9031
|
-
const valueSchema = isSchema$1(
|
|
9876
|
+
const valueSchema = isSchema$1(schema.value) ? schema.value : void 0;
|
|
9032
9877
|
if (!valueSchema) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
9033
9878
|
className: "hint",
|
|
9034
|
-
children: "
|
|
9879
|
+
children: t("schema.recordNoValue")
|
|
9035
9880
|
});
|
|
9036
9881
|
const obj = value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
9037
9882
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [Object.entries(obj).map(([key, v]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
@@ -9056,7 +9901,7 @@ function ContainerChildren({ schema, value, onChange, depth, disabled }) {
|
|
|
9056
9901
|
delete next[key];
|
|
9057
9902
|
onChange(next);
|
|
9058
9903
|
},
|
|
9059
|
-
children: "
|
|
9904
|
+
children: t("common.delete")
|
|
9060
9905
|
})]
|
|
9061
9906
|
}, key)), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AddRecordKey, {
|
|
9062
9907
|
onAdd: (key, v) => onChange({
|
|
@@ -9070,12 +9915,13 @@ function ContainerChildren({ schema, value, onChange, depth, disabled }) {
|
|
|
9070
9915
|
return null;
|
|
9071
9916
|
}
|
|
9072
9917
|
function AddRecordKey({ onAdd, sample, disabled }) {
|
|
9918
|
+
const t = useT();
|
|
9073
9919
|
const [key, setKey] = (0, import_react.useState)("");
|
|
9074
9920
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
9075
9921
|
className: "sf-record-add",
|
|
9076
9922
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
|
|
9077
9923
|
className: "sf-input",
|
|
9078
|
-
placeholder: "
|
|
9924
|
+
placeholder: t("schema.recordAddPlaceholder"),
|
|
9079
9925
|
value: key,
|
|
9080
9926
|
onChange: (e) => setKey(e.target.value),
|
|
9081
9927
|
disabled
|
|
@@ -9087,11 +9933,12 @@ function AddRecordKey({ onAdd, sample, disabled }) {
|
|
|
9087
9933
|
onAdd(key, sample());
|
|
9088
9934
|
setKey("");
|
|
9089
9935
|
},
|
|
9090
|
-
children: "
|
|
9936
|
+
children: t("schema.addRecordKey")
|
|
9091
9937
|
})]
|
|
9092
9938
|
});
|
|
9093
9939
|
}
|
|
9094
9940
|
function UnknownLeaf({ schema, value, onChange, label, depth, disabled }) {
|
|
9941
|
+
const t = useT();
|
|
9095
9942
|
const [text, setText] = (0, import_react.useState)(() => JSON.stringify(value ?? null, null, 2));
|
|
9096
9943
|
const [error, setError] = (0, import_react.useState)(null);
|
|
9097
9944
|
const commit = (next) => {
|
|
@@ -9133,9 +9980,9 @@ function UnknownLeaf({ schema, value, onChange, label, depth, disabled }) {
|
|
|
9133
9980
|
value: text,
|
|
9134
9981
|
disabled,
|
|
9135
9982
|
onChange: (e) => commit(e.target.value)
|
|
9136
|
-
}), error && /* @__PURE__ */ (0, import_jsx_runtime.
|
|
9983
|
+
}), error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
9137
9984
|
className: "error small",
|
|
9138
|
-
children:
|
|
9985
|
+
children: t("test.jsonError", { error })
|
|
9139
9986
|
})]
|
|
9140
9987
|
})]
|
|
9141
9988
|
});
|
|
@@ -9149,19 +9996,27 @@ function Constraints({ schema }) {
|
|
|
9149
9996
|
}
|
|
9150
9997
|
//#endregion
|
|
9151
9998
|
//#region webui/src/components/TestPanel.tsx
|
|
9152
|
-
var COPY_OPTIONS = [{
|
|
9153
|
-
value: "curl",
|
|
9154
|
-
label: "复制 curl"
|
|
9155
|
-
}, {
|
|
9156
|
-
value: "fetch",
|
|
9157
|
-
label: "复制 fetch"
|
|
9158
|
-
}];
|
|
9159
9999
|
/** 格式化耗时:<1s 用 ms,否则用 s */
|
|
9160
10000
|
function formatElapsed(ms) {
|
|
9161
10001
|
if (ms < 1e3) return `${ms.toFixed(0)} ms`;
|
|
9162
10002
|
return `${(ms / 1e3).toFixed(2)} s`;
|
|
9163
10003
|
}
|
|
9164
10004
|
function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
10005
|
+
const t = useT();
|
|
10006
|
+
const COPY_OPTIONS = [
|
|
10007
|
+
{
|
|
10008
|
+
value: "curl",
|
|
10009
|
+
label: t("test.copyCurl")
|
|
10010
|
+
},
|
|
10011
|
+
{
|
|
10012
|
+
value: "curl-cmd",
|
|
10013
|
+
label: t("test.copyCurlCmd")
|
|
10014
|
+
},
|
|
10015
|
+
{
|
|
10016
|
+
value: "fetch",
|
|
10017
|
+
label: t("test.copyFetch")
|
|
10018
|
+
}
|
|
10019
|
+
];
|
|
9165
10020
|
const paramSchemas = (0, import_react.useMemo)(() => detail.signature.slice(1), [detail.signature]);
|
|
9166
10021
|
const isStreamReturn = detail.signature[0]?.kind === "stream";
|
|
9167
10022
|
const [values, setValues] = (0, import_react.useState)([]);
|
|
@@ -9219,8 +10074,11 @@ function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
|
9219
10074
|
setOutput(lines.join("\n"));
|
|
9220
10075
|
}
|
|
9221
10076
|
const totalAt = performance.now() - startedAt;
|
|
9222
|
-
if (idx === 0) lines.push(
|
|
9223
|
-
else lines.push(
|
|
10077
|
+
if (idx === 0) lines.push(t("test.streamEndedEmpty", { duration: formatElapsed(totalAt) }));
|
|
10078
|
+
else lines.push(t("test.streamEnded", {
|
|
10079
|
+
count: idx,
|
|
10080
|
+
duration: formatElapsed(totalAt)
|
|
10081
|
+
}));
|
|
9224
10082
|
setOutput(lines.join("\n"));
|
|
9225
10083
|
setElapsed({
|
|
9226
10084
|
total: totalAt,
|
|
@@ -9252,7 +10110,7 @@ function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
|
9252
10110
|
id: 1
|
|
9253
10111
|
};
|
|
9254
10112
|
const url = absoluteEndpoint(endpoint);
|
|
9255
|
-
code = kind === "curl" ? buildCurl(url, body) : buildFetch(url, body);
|
|
10113
|
+
code = kind === "curl" ? buildCurl(url, body) : kind === "curl-cmd" ? buildCurlCmd(url, body) : buildFetch(url, body);
|
|
9256
10114
|
} catch (e) {
|
|
9257
10115
|
setCopyError(e instanceof Error ? e.message : String(e));
|
|
9258
10116
|
return;
|
|
@@ -9262,24 +10120,20 @@ function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
|
9262
10120
|
setCopied(true);
|
|
9263
10121
|
setTimeout(() => setCopied(false), 2e3);
|
|
9264
10122
|
} catch (e) {
|
|
9265
|
-
setCopyError(
|
|
10123
|
+
setCopyError(t("common.copyFailed", { error: e instanceof Error ? e.message : String(e) }));
|
|
9266
10124
|
}
|
|
9267
10125
|
};
|
|
9268
10126
|
const canCopy = transport === "http";
|
|
9269
|
-
const currentLabel = COPY_OPTIONS.find((o) => o.value === copyKind)?.label ?? "
|
|
10127
|
+
const currentLabel = COPY_OPTIONS.find((o) => o.value === copyKind)?.label ?? t("common.copy");
|
|
9270
10128
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
9271
10129
|
className: "test",
|
|
9272
10130
|
children: [
|
|
9273
10131
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { children: [
|
|
9274
|
-
"
|
|
10132
|
+
t("test.params"),
|
|
9275
10133
|
" ",
|
|
9276
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
10134
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
9277
10135
|
className: "hint",
|
|
9278
|
-
children:
|
|
9279
|
-
"(",
|
|
9280
|
-
paramSchemas.length,
|
|
9281
|
-
" 个,按签名自动生成)"
|
|
9282
|
-
]
|
|
10136
|
+
children: t("test.paramsHint", { count: paramSchemas.length })
|
|
9283
10137
|
})
|
|
9284
10138
|
] }),
|
|
9285
10139
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaForm, {
|
|
@@ -9294,7 +10148,7 @@ function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
|
9294
10148
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
9295
10149
|
onClick: execute,
|
|
9296
10150
|
disabled: !method || running,
|
|
9297
|
-
children: running ? isStreamReturn ? "
|
|
10151
|
+
children: running ? isStreamReturn ? t("test.receiving") : t("test.executing") : isStreamReturn ? t("test.executeStream") : t("test.execute")
|
|
9298
10152
|
}),
|
|
9299
10153
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
9300
10154
|
className: "split-button",
|
|
@@ -9305,8 +10159,8 @@ function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
|
9305
10159
|
className: "split-button-main",
|
|
9306
10160
|
onClick: () => void copyAs(copyKind),
|
|
9307
10161
|
disabled: !method || !canCopy,
|
|
9308
|
-
title: canCopy ? "
|
|
9309
|
-
children: copied ? "
|
|
10162
|
+
title: canCopy ? t("test.copyTitle") : t("test.copyDisabledTitle"),
|
|
10163
|
+
children: copied ? t("common.copied") : currentLabel
|
|
9310
10164
|
}),
|
|
9311
10165
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
9312
10166
|
type: "button",
|
|
@@ -9315,7 +10169,7 @@ function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
|
9315
10169
|
disabled: !method || !canCopy,
|
|
9316
10170
|
"aria-haspopup": "menu",
|
|
9317
10171
|
"aria-expanded": menuOpen,
|
|
9318
|
-
title: "
|
|
10172
|
+
title: t("test.chooseFormat"),
|
|
9319
10173
|
children: "▾"
|
|
9320
10174
|
}),
|
|
9321
10175
|
menuOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", {
|
|
@@ -9343,7 +10197,7 @@ function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
|
9343
10197
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
9344
10198
|
onClick: () => setValues(paramSchemas.map(sampleFromSchema)),
|
|
9345
10199
|
disabled: !method,
|
|
9346
|
-
children: "
|
|
10200
|
+
children: t("test.resetToSample")
|
|
9347
10201
|
}),
|
|
9348
10202
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
9349
10203
|
onClick: () => {
|
|
@@ -9351,15 +10205,15 @@ function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
|
9351
10205
|
setElapsed(null);
|
|
9352
10206
|
},
|
|
9353
10207
|
disabled: !output && !elapsed,
|
|
9354
|
-
children: "
|
|
10208
|
+
children: t("test.clearOutput")
|
|
9355
10209
|
})
|
|
9356
10210
|
]
|
|
9357
10211
|
}),
|
|
9358
10212
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { children: [
|
|
9359
|
-
"
|
|
10213
|
+
t("test.result"),
|
|
9360
10214
|
isStreamReturn && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
9361
10215
|
className: "hint",
|
|
9362
|
-
children: "
|
|
10216
|
+
children: t("test.resultStream")
|
|
9363
10217
|
}),
|
|
9364
10218
|
elapsed && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
9365
10219
|
className: "elapsed-badge",
|
|
@@ -9371,7 +10225,9 @@ function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
|
9371
10225
|
className: "hint",
|
|
9372
10226
|
children: [
|
|
9373
10227
|
" ",
|
|
9374
|
-
"·
|
|
10228
|
+
"· ",
|
|
10229
|
+
t("test.firstFrame"),
|
|
10230
|
+
" ",
|
|
9375
10231
|
formatElapsed(elapsed.firstFrame)
|
|
9376
10232
|
]
|
|
9377
10233
|
})
|
|
@@ -9381,11 +10237,12 @@ function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
|
9381
10237
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
|
|
9382
10238
|
className: "output",
|
|
9383
10239
|
ref: outRef,
|
|
9384
|
-
children: output || "
|
|
10240
|
+
children: output || t("test.notExecuted")
|
|
9385
10241
|
})
|
|
9386
10242
|
]
|
|
9387
10243
|
});
|
|
9388
10244
|
}
|
|
10245
|
+
/** bash / POSIX sh:单引号包裹,内部单引号用 '\'' 转义;反斜杠续行。 */
|
|
9389
10246
|
function buildCurl(url, body) {
|
|
9390
10247
|
const quotedBody = `'${JSON.stringify(body, null, 2).replace(/'/g, `'\\''`)}'`;
|
|
9391
10248
|
return [
|
|
@@ -9394,6 +10251,23 @@ function buildCurl(url, body) {
|
|
|
9394
10251
|
` -d ${quotedBody}`
|
|
9395
10252
|
].join(" \\\n");
|
|
9396
10253
|
}
|
|
10254
|
+
/**
|
|
10255
|
+
* Windows CMD:双引号包裹。
|
|
10256
|
+
* - 双引号 " 用 \" 转义(curl.exe 在 cmd 下按 C 运行时规则解析)
|
|
10257
|
+
* - % 用 %% 转义(避免被 cmd 当作变量展开)
|
|
10258
|
+
* - 换行用 ^ 续行
|
|
10259
|
+
* - 其余字符原样保留
|
|
10260
|
+
*/
|
|
10261
|
+
function buildCurlCmd(url, body) {
|
|
10262
|
+
const bodyText = JSON.stringify(body);
|
|
10263
|
+
const escapeCmdDoubleQuoted = (s) => s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/%/g, "%%");
|
|
10264
|
+
const quotedBody = `"${escapeCmdDoubleQuoted(bodyText)}"`;
|
|
10265
|
+
return [
|
|
10266
|
+
`curl -X POST ${`"${escapeCmdDoubleQuoted(url)}"`} ^`,
|
|
10267
|
+
` -H "Content-Type: application/json" ^`,
|
|
10268
|
+
` -d ${quotedBody}`
|
|
10269
|
+
].join("\n");
|
|
10270
|
+
}
|
|
9397
10271
|
function buildFetch(url, body) {
|
|
9398
10272
|
const indented = JSON.stringify(body, null, 2).split("\n").map((line, i) => i === 0 ? line : " " + line).join("\n");
|
|
9399
10273
|
return [
|
|
@@ -9445,6 +10319,7 @@ function rateClass(v) {
|
|
|
9445
10319
|
return "rate-cold";
|
|
9446
10320
|
}
|
|
9447
10321
|
function MetricsPanel({ snapshot, previous, fetchedAt, loading, error, available, onRefresh, autoRefresh, onAutoRefreshChange, intervalMs, onIntervalChange }) {
|
|
10322
|
+
const t = useT();
|
|
9448
10323
|
const derived = (0, import_react.useMemo)(() => {
|
|
9449
10324
|
if (!snapshot) return [];
|
|
9450
10325
|
const dtSeconds = previous && fetchedAt ? (fetchedAt - previous.fetchedAt) / 1e3 : void 0;
|
|
@@ -9486,15 +10361,9 @@ function MetricsPanel({ snapshot, previous, fetchedAt, loading, error, available
|
|
|
9486
10361
|
}, [snapshot]);
|
|
9487
10362
|
if (!available) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
9488
10363
|
className: "metrics",
|
|
9489
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: "
|
|
10364
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: t("metrics.title") }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
9490
10365
|
className: "hint",
|
|
9491
|
-
children:
|
|
9492
|
-
"服务端未启用 ",
|
|
9493
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "system.metrics" }),
|
|
9494
|
-
"(",
|
|
9495
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "withSystemMethods: false" }),
|
|
9496
|
-
" 或未注册)。"
|
|
9497
|
-
]
|
|
10366
|
+
children: t("metrics.unavailable")
|
|
9498
10367
|
})]
|
|
9499
10368
|
});
|
|
9500
10369
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
@@ -9502,7 +10371,7 @@ function MetricsPanel({ snapshot, previous, fetchedAt, loading, error, available
|
|
|
9502
10371
|
children: [
|
|
9503
10372
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
|
|
9504
10373
|
className: "metrics-header",
|
|
9505
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: "
|
|
10374
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: t("metrics.title") }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
9506
10375
|
className: "metrics-controls",
|
|
9507
10376
|
children: [
|
|
9508
10377
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", {
|
|
@@ -9511,14 +10380,14 @@ function MetricsPanel({ snapshot, previous, fetchedAt, loading, error, available
|
|
|
9511
10380
|
type: "checkbox",
|
|
9512
10381
|
checked: autoRefresh,
|
|
9513
10382
|
onChange: (e) => onAutoRefreshChange(e.target.checked)
|
|
9514
|
-
}), "
|
|
10383
|
+
}), t("metrics.autoRefresh")]
|
|
9515
10384
|
}),
|
|
9516
10385
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
|
|
9517
10386
|
className: "sf-input",
|
|
9518
10387
|
value: intervalMs,
|
|
9519
10388
|
onChange: (e) => onIntervalChange(Number(e.target.value)),
|
|
9520
10389
|
disabled: !autoRefresh,
|
|
9521
|
-
title: "
|
|
10390
|
+
title: t("metrics.interval"),
|
|
9522
10391
|
children: [
|
|
9523
10392
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
9524
10393
|
value: 1e3,
|
|
@@ -9541,11 +10410,15 @@ function MetricsPanel({ snapshot, previous, fetchedAt, loading, error, available
|
|
|
9541
10410
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
9542
10411
|
onClick: onRefresh,
|
|
9543
10412
|
disabled: loading,
|
|
9544
|
-
children: loading ? "
|
|
10413
|
+
children: loading ? t("metrics.refreshing") : t("metrics.refreshNow")
|
|
9545
10414
|
}),
|
|
9546
10415
|
snapshot && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
9547
10416
|
className: "hint",
|
|
9548
|
-
children: [
|
|
10417
|
+
children: [
|
|
10418
|
+
t("metrics.uptime"),
|
|
10419
|
+
" ",
|
|
10420
|
+
formatDuration(snapshot.uptimeMs / 1e3)
|
|
10421
|
+
]
|
|
9549
10422
|
})
|
|
9550
10423
|
]
|
|
9551
10424
|
})]
|
|
@@ -9556,64 +10429,56 @@ function MetricsPanel({ snapshot, previous, fetchedAt, loading, error, available
|
|
|
9556
10429
|
}),
|
|
9557
10430
|
!snapshot && !error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
9558
10431
|
className: "hint",
|
|
9559
|
-
children: "
|
|
10432
|
+
children: t("metrics.loading")
|
|
9560
10433
|
}),
|
|
9561
10434
|
snapshot && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
9562
10435
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
9563
10436
|
className: "metrics-cards",
|
|
9564
10437
|
children: [
|
|
9565
10438
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MetricCard, {
|
|
9566
|
-
label: "
|
|
10439
|
+
label: t("metrics.methods"),
|
|
9567
10440
|
value: String(totals.methods)
|
|
9568
10441
|
}),
|
|
9569
10442
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MetricCard, {
|
|
9570
|
-
label: "
|
|
10443
|
+
label: t("metrics.calls"),
|
|
9571
10444
|
value: String(totals.calls)
|
|
9572
10445
|
}),
|
|
9573
10446
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MetricCard, {
|
|
9574
|
-
label: "
|
|
10447
|
+
label: t("metrics.streams"),
|
|
9575
10448
|
value: String(totals.streams)
|
|
9576
10449
|
}),
|
|
9577
10450
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MetricCard, {
|
|
9578
|
-
label: "
|
|
10451
|
+
label: t("metrics.errors"),
|
|
9579
10452
|
value: String(totals.errors),
|
|
9580
10453
|
tone: totals.errors > 0 ? "danger" : void 0
|
|
9581
10454
|
}),
|
|
9582
10455
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MetricCard, {
|
|
9583
|
-
label: "
|
|
10456
|
+
label: t("metrics.errorRate"),
|
|
9584
10457
|
value: totals.calls > 0 ? formatPercent(totals.errors / totals.calls) : "—",
|
|
9585
10458
|
tone: totals.calls > 0 && totals.errors / totals.calls > .05 ? "danger" : void 0
|
|
9586
10459
|
}),
|
|
9587
10460
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MetricCard, {
|
|
9588
|
-
label: "
|
|
10461
|
+
label: t("metrics.invalidRequests"),
|
|
9589
10462
|
value: String(snapshot.invalidRequests),
|
|
9590
10463
|
tone: snapshot.invalidRequests > 0 ? "warn" : void 0
|
|
9591
10464
|
})
|
|
9592
10465
|
]
|
|
9593
10466
|
}),
|
|
9594
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { children: ["
|
|
10467
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { children: [t("metrics.nonStreamTitle"), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
9595
10468
|
className: "hint",
|
|
9596
|
-
children: [
|
|
9597
|
-
" (",
|
|
9598
|
-
nonStreamMethods.length,
|
|
9599
|
-
")"
|
|
9600
|
-
]
|
|
10469
|
+
children: [" ", t("metrics.countHint", { count: nonStreamMethods.length })]
|
|
9601
10470
|
})] }),
|
|
9602
10471
|
nonStreamMethods.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
9603
10472
|
className: "hint",
|
|
9604
|
-
children: "
|
|
10473
|
+
children: t("metrics.noData")
|
|
9605
10474
|
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NonStreamTable, { rows: nonStreamMethods }),
|
|
9606
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { children: ["
|
|
10475
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { children: [t("metrics.streamTitle"), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
9607
10476
|
className: "hint",
|
|
9608
|
-
children: [
|
|
9609
|
-
" (",
|
|
9610
|
-
streamMethods.length,
|
|
9611
|
-
")"
|
|
9612
|
-
]
|
|
10477
|
+
children: [" ", t("metrics.countHint", { count: streamMethods.length })]
|
|
9613
10478
|
})] }),
|
|
9614
10479
|
streamMethods.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
9615
10480
|
className: "hint",
|
|
9616
|
-
children: "
|
|
10481
|
+
children: t("metrics.noStreams")
|
|
9617
10482
|
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StreamTable, { rows: streamMethods })
|
|
9618
10483
|
] })
|
|
9619
10484
|
]
|
|
@@ -9632,41 +10497,42 @@ function MetricCard({ label, value, tone }) {
|
|
|
9632
10497
|
});
|
|
9633
10498
|
}
|
|
9634
10499
|
function NonStreamTable({ rows }) {
|
|
10500
|
+
const t = useT();
|
|
9635
10501
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", {
|
|
9636
10502
|
className: "metrics-table",
|
|
9637
10503
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
9638
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "
|
|
10504
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: t("metrics.colMethod") }),
|
|
9639
10505
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9640
10506
|
className: "num",
|
|
9641
|
-
children: "
|
|
10507
|
+
children: t("metrics.colCalls")
|
|
9642
10508
|
}),
|
|
9643
10509
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9644
10510
|
className: "num",
|
|
9645
|
-
children: "
|
|
10511
|
+
children: t("metrics.colRate")
|
|
9646
10512
|
}),
|
|
9647
10513
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9648
10514
|
className: "num",
|
|
9649
|
-
children: "
|
|
10515
|
+
children: t("metrics.colErrors")
|
|
9650
10516
|
}),
|
|
9651
10517
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9652
10518
|
className: "num",
|
|
9653
|
-
children: "
|
|
10519
|
+
children: t("metrics.colErrPct")
|
|
9654
10520
|
}),
|
|
9655
10521
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9656
10522
|
className: "num",
|
|
9657
|
-
children: "
|
|
10523
|
+
children: t("metrics.colP50")
|
|
9658
10524
|
}),
|
|
9659
10525
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9660
10526
|
className: "num",
|
|
9661
|
-
children: "
|
|
10527
|
+
children: t("metrics.colP95")
|
|
9662
10528
|
}),
|
|
9663
10529
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9664
10530
|
className: "num",
|
|
9665
|
-
children: "
|
|
10531
|
+
children: t("metrics.colP99")
|
|
9666
10532
|
}),
|
|
9667
10533
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9668
10534
|
className: "num",
|
|
9669
|
-
children: "
|
|
10535
|
+
children: t("metrics.colAvg")
|
|
9670
10536
|
})
|
|
9671
10537
|
] }) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: rows.map((r) => {
|
|
9672
10538
|
const errorCount = Object.values(r.stats.errorsByCode).reduce((a, b) => a + b, 0);
|
|
@@ -9714,49 +10580,50 @@ function NonStreamTable({ rows }) {
|
|
|
9714
10580
|
});
|
|
9715
10581
|
}
|
|
9716
10582
|
function StreamTable({ rows }) {
|
|
10583
|
+
const t = useT();
|
|
9717
10584
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", {
|
|
9718
10585
|
className: "metrics-table",
|
|
9719
10586
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
9720
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: "
|
|
10587
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { children: t("metrics.colMethod") }),
|
|
9721
10588
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9722
10589
|
className: "num",
|
|
9723
|
-
children: "
|
|
10590
|
+
children: t("metrics.colOpened")
|
|
9724
10591
|
}),
|
|
9725
10592
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9726
10593
|
className: "num",
|
|
9727
|
-
children: "
|
|
10594
|
+
children: t("metrics.colCompleted")
|
|
9728
10595
|
}),
|
|
9729
10596
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9730
10597
|
className: "num",
|
|
9731
|
-
children: "
|
|
10598
|
+
children: t("metrics.colFailed")
|
|
9732
10599
|
}),
|
|
9733
10600
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9734
10601
|
className: "num",
|
|
9735
|
-
children: "
|
|
10602
|
+
children: t("metrics.colAborted")
|
|
9736
10603
|
}),
|
|
9737
10604
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9738
10605
|
className: "num",
|
|
9739
|
-
children: "
|
|
10606
|
+
children: t("metrics.colCompletePct")
|
|
9740
10607
|
}),
|
|
9741
10608
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9742
10609
|
className: "num",
|
|
9743
|
-
children: "
|
|
10610
|
+
children: t("metrics.colAbortPct")
|
|
9744
10611
|
}),
|
|
9745
10612
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9746
10613
|
className: "num",
|
|
9747
|
-
children: "
|
|
10614
|
+
children: t("metrics.colAvgChunks")
|
|
9748
10615
|
}),
|
|
9749
10616
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9750
10617
|
className: "num",
|
|
9751
|
-
children: "
|
|
10618
|
+
children: t("metrics.colTtfbP50")
|
|
9752
10619
|
}),
|
|
9753
10620
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9754
10621
|
className: "num",
|
|
9755
|
-
children: "
|
|
10622
|
+
children: t("metrics.colTtfbP95")
|
|
9756
10623
|
}),
|
|
9757
10624
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
9758
10625
|
className: "num",
|
|
9759
|
-
children: "
|
|
10626
|
+
children: t("metrics.colDurationAvg")
|
|
9760
10627
|
})
|
|
9761
10628
|
] }) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: rows.map((r) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
|
|
9762
10629
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
|
|
@@ -9808,58 +10675,88 @@ function StreamTable({ rows }) {
|
|
|
9808
10675
|
});
|
|
9809
10676
|
}
|
|
9810
10677
|
//#endregion
|
|
9811
|
-
//#region webui/src/
|
|
9812
|
-
|
|
9813
|
-
|
|
9814
|
-
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
|
|
9819
|
-
|
|
9820
|
-
|
|
9821
|
-
|
|
9822
|
-
|
|
9823
|
-
|
|
9824
|
-
|
|
10678
|
+
//#region webui/src/components/Footer.tsx
|
|
10679
|
+
var NPM_URL = "https://www.npmjs.com/package/@yuhere/js-jsonrpc2/";
|
|
10680
|
+
var GITHUB_URL = "https://github.com/yuhere/js-jsonrpc2";
|
|
10681
|
+
function Footer() {
|
|
10682
|
+
const t = useT();
|
|
10683
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("footer", {
|
|
10684
|
+
className: "footer",
|
|
10685
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
10686
|
+
className: "footer-version",
|
|
10687
|
+
title: t("footer.version"),
|
|
10688
|
+
children: ["v", "2.1.14"]
|
|
10689
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
10690
|
+
className: "footer-links",
|
|
10691
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
|
|
10692
|
+
className: "npm-link",
|
|
10693
|
+
href: NPM_URL,
|
|
10694
|
+
target: "_blank",
|
|
10695
|
+
rel: "noopener noreferrer",
|
|
10696
|
+
title: t("footer.npm"),
|
|
10697
|
+
"aria-label": t("footer.npm"),
|
|
10698
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
|
|
10699
|
+
viewBox: "0 0 18 7",
|
|
10700
|
+
width: "36",
|
|
10701
|
+
height: "14",
|
|
10702
|
+
role: "img",
|
|
10703
|
+
"aria-hidden": "true",
|
|
10704
|
+
focusable: "false",
|
|
10705
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
|
|
10706
|
+
fill: "#CB3837",
|
|
10707
|
+
d: "M0 0h18v7H9v-1.5H7.5V7H0z"
|
|
10708
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
|
|
10709
|
+
fill: "#fff",
|
|
10710
|
+
d: "M1.5 1.5h3v4h-1v-3h-1v3h-1zm4 0h3v4h-1v-3h-1v3h-1zm4 0h4v4h-1v-3h-1v3h-1v-3h-1z"
|
|
10711
|
+
})]
|
|
10712
|
+
})
|
|
10713
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
|
|
10714
|
+
className: "github-link",
|
|
10715
|
+
href: GITHUB_URL,
|
|
10716
|
+
target: "_blank",
|
|
10717
|
+
rel: "noopener noreferrer",
|
|
10718
|
+
title: t("footer.github"),
|
|
10719
|
+
"aria-label": t("footer.github"),
|
|
10720
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", {
|
|
10721
|
+
viewBox: "0 0 16 16",
|
|
10722
|
+
width: "16",
|
|
10723
|
+
height: "16",
|
|
10724
|
+
role: "img",
|
|
10725
|
+
"aria-hidden": "true",
|
|
10726
|
+
focusable: "false",
|
|
10727
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", {
|
|
10728
|
+
fill: "currentColor",
|
|
10729
|
+
d: "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"
|
|
10730
|
+
})
|
|
10731
|
+
})
|
|
10732
|
+
})]
|
|
10733
|
+
})]
|
|
10734
|
+
});
|
|
9825
10735
|
}
|
|
9826
|
-
|
|
10736
|
+
//#endregion
|
|
10737
|
+
//#region webui/src/utils/fuzzy.ts
|
|
10738
|
+
function compileFuzzyQuery(input) {
|
|
9827
10739
|
const raw = input ?? "";
|
|
9828
|
-
const
|
|
9829
|
-
if (trimmed.length === 0) return {
|
|
9830
|
-
includes: [],
|
|
9831
|
-
excludes: [],
|
|
9832
|
-
raw,
|
|
9833
|
-
passthrough: true
|
|
9834
|
-
};
|
|
9835
|
-
const includes = [];
|
|
9836
|
-
const excludes = [];
|
|
9837
|
-
for (const part of trimmed.split(",")) {
|
|
9838
|
-
const pat = part.trim();
|
|
9839
|
-
if (pat.length === 0) continue;
|
|
9840
|
-
if (pat.startsWith("!")) {
|
|
9841
|
-
const body = pat.slice(1).trim();
|
|
9842
|
-
if (body.length > 0) excludes.push(globToRegExp(body));
|
|
9843
|
-
} else includes.push(globToRegExp(pat));
|
|
9844
|
-
}
|
|
10740
|
+
const terms = raw.trim().toLowerCase().split(/\s+/).filter((t) => t.length > 0);
|
|
9845
10741
|
return {
|
|
9846
|
-
|
|
9847
|
-
excludes,
|
|
10742
|
+
terms,
|
|
9848
10743
|
raw,
|
|
9849
|
-
passthrough:
|
|
10744
|
+
passthrough: terms.length === 0
|
|
9850
10745
|
};
|
|
9851
10746
|
}
|
|
9852
|
-
function
|
|
9853
|
-
if (
|
|
9854
|
-
|
|
9855
|
-
|
|
9856
|
-
|
|
10747
|
+
function matchFuzzy(query, method) {
|
|
10748
|
+
if (query.passthrough) return true;
|
|
10749
|
+
const target = method.toLowerCase();
|
|
10750
|
+
return query.terms.every((t) => target.includes(t));
|
|
10751
|
+
}
|
|
10752
|
+
function filterFuzzyMethods(query, methods) {
|
|
10753
|
+
if (query.passthrough) return methods;
|
|
10754
|
+
return methods.filter((m) => matchFuzzy(query, m));
|
|
9857
10755
|
}
|
|
9858
|
-
|
|
9859
|
-
|
|
9860
|
-
if (filter.passthrough) return methods;
|
|
10756
|
+
function filterFuzzySnapshotMethods(query, methods) {
|
|
10757
|
+
if (query.passthrough) return methods;
|
|
9861
10758
|
const out = {};
|
|
9862
|
-
for (const [method, stats] of Object.entries(methods)) if (
|
|
10759
|
+
for (const [method, stats] of Object.entries(methods)) if (matchFuzzy(query, method)) out[method] = stats;
|
|
9863
10760
|
return out;
|
|
9864
10761
|
}
|
|
9865
10762
|
//#endregion
|
|
@@ -9894,6 +10791,13 @@ async function collectApiDoc(rpc, methods, onProgress) {
|
|
|
9894
10791
|
methods: out
|
|
9895
10792
|
};
|
|
9896
10793
|
}
|
|
10794
|
+
/**
|
|
10795
|
+
* 树状渲染 schema。
|
|
10796
|
+
* - array / record / stream:直接展开子节点,不挂 element / value / inner 标签
|
|
10797
|
+
* - object:属性名作标签
|
|
10798
|
+
* - union:option[i]
|
|
10799
|
+
* - tuple:[i]
|
|
10800
|
+
*/
|
|
9897
10801
|
function renderSchemaTree(schema, indent = 0) {
|
|
9898
10802
|
const pad = " ".repeat(indent);
|
|
9899
10803
|
const lines = [];
|
|
@@ -9906,26 +10810,57 @@ function renderSchemaTree(schema, indent = 0) {
|
|
|
9906
10810
|
if (parts.length) head += ` \`{ ${parts.join(", ")} }\``;
|
|
9907
10811
|
}
|
|
9908
10812
|
lines.push(head);
|
|
9909
|
-
|
|
9910
|
-
const
|
|
10813
|
+
/** 带标签的子节点(object 属性 / union 分支 / tuple 位) */
|
|
10814
|
+
const pushLabeled = (label, child) => {
|
|
9911
10815
|
const sub = renderSchemaTree(child, indent + 1);
|
|
9912
10816
|
if (sub.length) {
|
|
9913
10817
|
sub[0] = `${" ".repeat(indent + 1)}- **${label}**: ${sub[0].trim().replace(/^- /, "")}`;
|
|
9914
10818
|
lines.push(...sub);
|
|
9915
10819
|
}
|
|
9916
10820
|
};
|
|
9917
|
-
|
|
9918
|
-
|
|
9919
|
-
|
|
9920
|
-
}
|
|
9921
|
-
|
|
9922
|
-
|
|
9923
|
-
|
|
9924
|
-
|
|
9925
|
-
|
|
9926
|
-
|
|
10821
|
+
/** 无标签,直接展开(array element / record value / stream inner) */
|
|
10822
|
+
const pushPlain = (child) => {
|
|
10823
|
+
lines.push(...renderSchemaTree(child, indent + 1));
|
|
10824
|
+
};
|
|
10825
|
+
switch (schema.kind) {
|
|
10826
|
+
case "array": {
|
|
10827
|
+
const element = schema.element;
|
|
10828
|
+
if (isSchema(element)) pushPlain(element);
|
|
10829
|
+
break;
|
|
10830
|
+
}
|
|
10831
|
+
case "record": {
|
|
10832
|
+
const value = schema.value;
|
|
10833
|
+
if (isSchema(value)) pushPlain(value);
|
|
10834
|
+
break;
|
|
10835
|
+
}
|
|
10836
|
+
case "tuple": {
|
|
10837
|
+
const elements = schema.elements;
|
|
10838
|
+
if (Array.isArray(elements)) elements.forEach((it, i) => {
|
|
10839
|
+
if (isSchema(it)) pushLabeled(`[${i}]`, it);
|
|
10840
|
+
});
|
|
10841
|
+
break;
|
|
10842
|
+
}
|
|
10843
|
+
case "union": {
|
|
10844
|
+
const options = schema.options;
|
|
10845
|
+
if (Array.isArray(options)) options.forEach((opt, i) => {
|
|
10846
|
+
if (isSchema(opt)) pushLabeled(`option[${i}]`, opt);
|
|
10847
|
+
});
|
|
10848
|
+
break;
|
|
10849
|
+
}
|
|
10850
|
+
case "object": {
|
|
10851
|
+
const props = schema.properties;
|
|
10852
|
+
if (props && typeof props === "object" && !Array.isArray(props)) {
|
|
10853
|
+
for (const [k, v] of Object.entries(props)) if (isSchema(v)) pushLabeled(k, v);
|
|
10854
|
+
}
|
|
10855
|
+
break;
|
|
10856
|
+
}
|
|
10857
|
+
case "stream": {
|
|
10858
|
+
const any = schema;
|
|
10859
|
+
const inner = isSchema(any.inner) ? any.inner : isSchema(any.children?.inner) ? any.children.inner : void 0;
|
|
10860
|
+
if (inner) pushPlain(inner);
|
|
10861
|
+
break;
|
|
10862
|
+
}
|
|
9927
10863
|
}
|
|
9928
|
-
if (isSchema(ch.values)) pushChild("values", ch.values);
|
|
9929
10864
|
return lines;
|
|
9930
10865
|
}
|
|
9931
10866
|
function renderMarkdown(doc) {
|
|
@@ -9962,7 +10897,7 @@ function renderMarkdown(doc) {
|
|
|
9962
10897
|
const [ret, ...params] = m.signature;
|
|
9963
10898
|
lines.push("**返回类型**");
|
|
9964
10899
|
lines.push("");
|
|
9965
|
-
lines.push(...renderSchemaTree(ret, 0));
|
|
10900
|
+
if (ret) lines.push(...renderSchemaTree(ret, 0));
|
|
9966
10901
|
lines.push("");
|
|
9967
10902
|
lines.push(`**参数**(${params.length} 个)`);
|
|
9968
10903
|
lines.push("");
|
|
@@ -9980,7 +10915,6 @@ function renderMarkdown(doc) {
|
|
|
9980
10915
|
}
|
|
9981
10916
|
return lines.join("\n");
|
|
9982
10917
|
}
|
|
9983
|
-
/** 触发浏览器下载 */
|
|
9984
10918
|
function downloadText(filename, text, mime = "text/plain") {
|
|
9985
10919
|
const blob = new Blob([text], { type: `${mime};charset=utf-8` });
|
|
9986
10920
|
const url = URL.createObjectURL(blob);
|
|
@@ -9996,12 +10930,16 @@ function downloadText(filename, text, mime = "text/plain") {
|
|
|
9996
10930
|
//#region webui/src/App.tsx
|
|
9997
10931
|
var ENDPOINT = "";
|
|
9998
10932
|
function App() {
|
|
10933
|
+
const { t } = useI18n();
|
|
9999
10934
|
const [transport, setTransport] = (0, import_react.useState)("http");
|
|
10000
10935
|
const [selected, setSelected] = (0, import_react.useState)("");
|
|
10001
10936
|
const [generatingDocs, setGeneratingDocs] = (0, import_react.useState)(false);
|
|
10002
10937
|
const [view, setView] = (0, import_react.useState)("methods");
|
|
10003
|
-
const [
|
|
10004
|
-
const
|
|
10938
|
+
const [methodSearch, setMethodSearch] = (0, import_react.useState)("");
|
|
10939
|
+
const [metricsSearch, setMetricsSearch] = (0, import_react.useState)("");
|
|
10940
|
+
const debouncedMethodSearch = useDebouncedValue(methodSearch, 250);
|
|
10941
|
+
const debouncedMetricsSearch = useDebouncedValue(metricsSearch, 250);
|
|
10942
|
+
const rpc = (0, import_react.useMemo)(() => createRPC({
|
|
10005
10943
|
transport,
|
|
10006
10944
|
endpoint: ENDPOINT
|
|
10007
10945
|
}), [transport]);
|
|
@@ -10009,18 +10947,20 @@ function App() {
|
|
|
10009
10947
|
const { methods, loading, error, refresh } = useMethods(rpc);
|
|
10010
10948
|
const detail = useMethodDetail(rpc, selected);
|
|
10011
10949
|
const metrics = useMetrics(rpc, view === "metrics");
|
|
10012
|
-
const
|
|
10013
|
-
const
|
|
10950
|
+
const methodQuery = (0, import_react.useMemo)(() => compileFuzzyQuery(debouncedMethodSearch), [debouncedMethodSearch]);
|
|
10951
|
+
const metricsQuery = (0, import_react.useMemo)(() => compileFuzzyQuery(debouncedMetricsSearch), [debouncedMetricsSearch]);
|
|
10952
|
+
const filteredMethods = (0, import_react.useMemo)(() => filterFuzzyMethods(methodQuery, methods), [methodQuery, methods]);
|
|
10953
|
+
const filteredMetrics = (0, import_react.useMemo)(() => {
|
|
10014
10954
|
if (!metrics.snapshot) return void 0;
|
|
10015
|
-
if (
|
|
10955
|
+
if (metricsQuery.passthrough) return metrics.snapshot;
|
|
10016
10956
|
return {
|
|
10017
10957
|
...metrics.snapshot,
|
|
10018
|
-
methods:
|
|
10958
|
+
methods: filterFuzzySnapshotMethods(metricsQuery, metrics.snapshot.methods)
|
|
10019
10959
|
};
|
|
10020
|
-
}, [metrics.snapshot,
|
|
10960
|
+
}, [metrics.snapshot, metricsQuery]);
|
|
10021
10961
|
const generateDocs = (0, import_react.useCallback)(async () => {
|
|
10022
10962
|
if (methods.length === 0) {
|
|
10023
|
-
alert("
|
|
10963
|
+
alert(t("alerts.emptyMethods"));
|
|
10024
10964
|
return;
|
|
10025
10965
|
}
|
|
10026
10966
|
setGeneratingDocs(true);
|
|
@@ -10028,131 +10968,137 @@ function App() {
|
|
|
10028
10968
|
const md = renderMarkdown(await collectApiDoc(rpc, methods));
|
|
10029
10969
|
downloadText(`jsonrpc-api-doc-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19)}.md`, md, "text/markdown");
|
|
10030
10970
|
} catch (e) {
|
|
10031
|
-
alert(
|
|
10971
|
+
alert(t("alerts.docsFailed", { error: e instanceof Error ? e.message : String(e) }));
|
|
10032
10972
|
} finally {
|
|
10033
10973
|
setGeneratingDocs(false);
|
|
10034
10974
|
}
|
|
10035
|
-
}, [
|
|
10975
|
+
}, [
|
|
10976
|
+
rpc,
|
|
10977
|
+
methods,
|
|
10978
|
+
t
|
|
10979
|
+
]);
|
|
10036
10980
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
10037
10981
|
className: "app",
|
|
10038
|
-
children: [
|
|
10039
|
-
|
|
10040
|
-
onTransportChange: setTransport,
|
|
10041
|
-
onRefresh: refresh,
|
|
10042
|
-
loading,
|
|
10043
|
-
error,
|
|
10044
|
-
onGenerateDocs: generateDocs,
|
|
10045
|
-
generatingDocs
|
|
10046
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
|
|
10047
|
-
className: "sidebar",
|
|
10048
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
10049
|
-
className: "view-switch segmented",
|
|
10050
|
-
role: "group",
|
|
10051
|
-
"aria-label": "视图",
|
|
10052
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
10053
|
-
type: "button",
|
|
10054
|
-
className: view === "methods" ? "active" : "",
|
|
10055
|
-
onClick: () => setView("methods"),
|
|
10056
|
-
children: "Methods"
|
|
10057
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
10058
|
-
type: "button",
|
|
10059
|
-
className: view === "metrics" ? "active" : "",
|
|
10060
|
-
onClick: () => setView("metrics"),
|
|
10061
|
-
children: "Metrics"
|
|
10062
|
-
})]
|
|
10063
|
-
}), view === "methods" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: "Methods" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MethodTree, {
|
|
10064
|
-
methods,
|
|
10065
|
-
selected,
|
|
10066
|
-
onSelect: setSelected
|
|
10067
|
-
})] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
10068
|
-
className: "metrics-sidebar",
|
|
10069
|
-
children: [
|
|
10070
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: "Metrics" }),
|
|
10071
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
10072
|
-
className: "hint",
|
|
10073
|
-
style: { margin: "0 0 8px" },
|
|
10074
|
-
children: "📊 服务端 RPC 调用统计。"
|
|
10075
|
-
}),
|
|
10076
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", {
|
|
10077
|
-
className: "metrics-filter",
|
|
10078
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
10079
|
-
className: "metrics-filter-label",
|
|
10080
|
-
children: "Filter"
|
|
10081
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
|
|
10082
|
-
className: "sf-input",
|
|
10083
|
-
type: "text",
|
|
10084
|
-
placeholder: "user.*, !system.*",
|
|
10085
|
-
value: methodFilter,
|
|
10086
|
-
onChange: (e) => setMethodFilter(e.target.value),
|
|
10087
|
-
spellCheck: false
|
|
10088
|
-
})]
|
|
10089
|
-
}),
|
|
10090
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
|
|
10091
|
-
className: "hint metrics-filter-help",
|
|
10092
|
-
children: [
|
|
10093
|
-
"支持 ",
|
|
10094
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "*" }),
|
|
10095
|
-
" / ",
|
|
10096
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "?" }),
|
|
10097
|
-
" / ",
|
|
10098
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "!" }),
|
|
10099
|
-
",多个模式用 ",
|
|
10100
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "," }),
|
|
10101
|
-
" 分隔。",
|
|
10102
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("br", {}),
|
|
10103
|
-
"例:",
|
|
10104
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "user.*" }),
|
|
10105
|
-
"、",
|
|
10106
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "*.get" }),
|
|
10107
|
-
"、",
|
|
10108
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "!system.*" }),
|
|
10109
|
-
"、",
|
|
10110
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "user.*,!user.secret" })
|
|
10111
|
-
]
|
|
10112
|
-
}),
|
|
10113
|
-
metrics.snapshot && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
|
|
10114
|
-
className: "hint metrics-filter-stat",
|
|
10115
|
-
children: [
|
|
10116
|
-
"匹配 ",
|
|
10117
|
-
Object.keys(filteredSnapshot?.methods ?? {}).length,
|
|
10118
|
-
" /",
|
|
10119
|
-
" ",
|
|
10120
|
-
Object.keys(metrics.snapshot.methods).length,
|
|
10121
|
-
" 个方法"
|
|
10122
|
-
]
|
|
10123
|
-
})
|
|
10124
|
-
]
|
|
10125
|
-
})]
|
|
10126
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
10127
|
-
className: "content",
|
|
10128
|
-
children: view === "methods" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MethodDetail, {
|
|
10129
|
-
method: selected,
|
|
10130
|
-
detail
|
|
10131
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TestPanel, {
|
|
10132
|
-
method: selected,
|
|
10133
|
-
detail,
|
|
10134
|
-
rpc,
|
|
10982
|
+
children: [
|
|
10983
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Toolbar, {
|
|
10135
10984
|
transport,
|
|
10136
|
-
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
|
|
10142
|
-
|
|
10143
|
-
|
|
10144
|
-
|
|
10145
|
-
|
|
10146
|
-
|
|
10147
|
-
|
|
10148
|
-
|
|
10149
|
-
|
|
10150
|
-
|
|
10985
|
+
onTransportChange: setTransport,
|
|
10986
|
+
onRefresh: refresh,
|
|
10987
|
+
loading,
|
|
10988
|
+
error,
|
|
10989
|
+
onGenerateDocs: generateDocs,
|
|
10990
|
+
generatingDocs
|
|
10991
|
+
}),
|
|
10992
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
|
|
10993
|
+
className: "sidebar",
|
|
10994
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
10995
|
+
className: "view-switch segmented",
|
|
10996
|
+
role: "group",
|
|
10997
|
+
"aria-label": t("view.label"),
|
|
10998
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
10999
|
+
type: "button",
|
|
11000
|
+
className: view === "methods" ? "active" : "",
|
|
11001
|
+
onClick: () => setView("methods"),
|
|
11002
|
+
children: t("view.methods")
|
|
11003
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
11004
|
+
type: "button",
|
|
11005
|
+
className: view === "metrics" ? "active" : "",
|
|
11006
|
+
onClick: () => setView("metrics"),
|
|
11007
|
+
children: t("view.metrics")
|
|
11008
|
+
})]
|
|
11009
|
+
}), view === "methods" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11010
|
+
className: "metrics-sidebar",
|
|
11011
|
+
children: [
|
|
11012
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: t("sidebar.methods") }),
|
|
11013
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", {
|
|
11014
|
+
className: "metrics-filter",
|
|
11015
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
11016
|
+
className: "metrics-filter-label",
|
|
11017
|
+
children: t("sidebar.search")
|
|
11018
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
|
|
11019
|
+
className: "sf-input",
|
|
11020
|
+
type: "text",
|
|
11021
|
+
placeholder: t("sidebar.searchPlaceholder"),
|
|
11022
|
+
value: methodSearch,
|
|
11023
|
+
onChange: (e) => setMethodSearch(e.target.value),
|
|
11024
|
+
spellCheck: false
|
|
11025
|
+
})]
|
|
11026
|
+
}),
|
|
11027
|
+
!methodQuery.passthrough && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
11028
|
+
className: "hint metrics-filter-stat",
|
|
11029
|
+
children: t("sidebar.matchCount", {
|
|
11030
|
+
matched: filteredMethods.length,
|
|
11031
|
+
total: methods.length
|
|
11032
|
+
})
|
|
11033
|
+
}),
|
|
11034
|
+
filteredMethods.length === 0 && methods.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
11035
|
+
className: "empty",
|
|
11036
|
+
children: t("sidebar.noMatch")
|
|
11037
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MethodTree, {
|
|
11038
|
+
methods: filteredMethods,
|
|
11039
|
+
selected,
|
|
11040
|
+
onSelect: setSelected
|
|
11041
|
+
})
|
|
11042
|
+
]
|
|
11043
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
11044
|
+
className: "metrics-sidebar",
|
|
11045
|
+
children: [
|
|
11046
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: t("sidebar.metrics") }),
|
|
11047
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", {
|
|
11048
|
+
className: "metrics-filter",
|
|
11049
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
11050
|
+
className: "metrics-filter-label",
|
|
11051
|
+
children: t("sidebar.search")
|
|
11052
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
|
|
11053
|
+
className: "sf-input",
|
|
11054
|
+
type: "text",
|
|
11055
|
+
placeholder: t("sidebar.searchPlaceholder"),
|
|
11056
|
+
value: metricsSearch,
|
|
11057
|
+
onChange: (e) => setMetricsSearch(e.target.value),
|
|
11058
|
+
spellCheck: false
|
|
11059
|
+
})]
|
|
11060
|
+
}),
|
|
11061
|
+
metrics.snapshot && !metricsQuery.passthrough && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
11062
|
+
className: "hint metrics-filter-stat",
|
|
11063
|
+
children: t("sidebar.matchCount", {
|
|
11064
|
+
matched: Object.keys(filteredMetrics?.methods ?? {}).length,
|
|
11065
|
+
total: Object.keys(metrics.snapshot.methods).length
|
|
11066
|
+
})
|
|
11067
|
+
})
|
|
11068
|
+
]
|
|
11069
|
+
})]
|
|
11070
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
11071
|
+
className: "content",
|
|
11072
|
+
children: view === "methods" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(MethodDetail, {
|
|
11073
|
+
method: selected,
|
|
11074
|
+
detail
|
|
11075
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TestPanel, {
|
|
11076
|
+
method: selected,
|
|
11077
|
+
detail,
|
|
11078
|
+
rpc,
|
|
11079
|
+
transport,
|
|
11080
|
+
endpoint: ENDPOINT
|
|
11081
|
+
})] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MetricsPanel, {
|
|
11082
|
+
snapshot: filteredMetrics,
|
|
11083
|
+
previous: metrics.previous,
|
|
11084
|
+
fetchedAt: metrics.fetchedAt,
|
|
11085
|
+
loading: metrics.loading,
|
|
11086
|
+
error: metrics.error,
|
|
11087
|
+
available: metrics.available,
|
|
11088
|
+
onRefresh: () => void metrics.refresh(),
|
|
11089
|
+
autoRefresh: metrics.autoRefresh,
|
|
11090
|
+
onAutoRefreshChange: metrics.setAutoRefresh,
|
|
11091
|
+
intervalMs: metrics.intervalMs,
|
|
11092
|
+
onIntervalChange: metrics.setIntervalMs
|
|
11093
|
+
})
|
|
11094
|
+
})] }),
|
|
11095
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Footer, {})
|
|
11096
|
+
]
|
|
10151
11097
|
});
|
|
10152
11098
|
}
|
|
10153
11099
|
//#endregion
|
|
10154
11100
|
//#region webui/src/main.tsx
|
|
10155
|
-
import_client.createRoot(document.getElementById("root")).render(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.StrictMode, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(App, {}) }) }));
|
|
11101
|
+
import_client.createRoot(document.getElementById("root")).render(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.StrictMode, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(I18nProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(App, {}) }) }) }));
|
|
10156
11102
|
//#endregion
|
|
10157
11103
|
|
|
10158
|
-
//# sourceMappingURL=index-
|
|
11104
|
+
//# sourceMappingURL=index-mYqtDOwe.js.map
|