@yuhere/js-jsonrpc2 2.1.2 → 2.1.4
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.js +4 -4
- package/dist/cli/demo-methods.d.ts +1 -1
- package/dist/cli/demo-methods.js +1 -1
- package/dist/cli/express.js +2 -2
- package/dist/cli/stdio.js +1 -1
- package/dist/core/Repository.d.ts +2 -2
- package/dist/core/Repository.js +9 -9
- package/dist/core/convert.d.ts +2 -2
- package/dist/core/convert.js +2 -2
- package/dist/core/descriptor.d.ts +3 -3
- package/dist/core/descriptor.js +3 -3
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.js +2 -2
- package/dist/core/permission.d.ts +2 -2
- package/dist/core/permission.js +2 -2
- package/dist/core/spec-check.d.ts +1 -1
- package/dist/core/spec-check.js +3 -3
- package/dist/core/system-methods.d.ts +1 -1
- package/dist/core/system-methods.js +4 -4
- package/dist/errors/{RpcError.d.ts → RPCError.d.ts} +1 -1
- package/dist/errors/index.d.ts +2 -2
- package/dist/errors/index.js +2 -2
- package/dist/index.d.ts +11 -11
- package/dist/index.js +8 -8
- package/dist/schema/json/index.d.ts +16 -16
- package/dist/schema/json/index.js +4 -4
- package/dist/schema/json/marker.d.ts +1 -1
- package/dist/schema/z/protocol.d.ts +5 -5
- package/dist/schema/z/protocol.js +1 -1
- package/dist/schema/z/register.d.ts +1 -1
- package/dist/schema/z/register.js +1 -1
- package/dist/transport/express/body.js +2 -2
- package/dist/transport/express/index.d.ts +2 -2
- package/dist/transport/express/index.js +1 -1
- package/dist/transport/express/middleware.d.ts +2 -2
- package/dist/transport/express/middleware.js +5 -5
- package/dist/transport/express/respond.d.ts +1 -1
- package/dist/transport/express/respond.js +1 -1
- package/dist/transport/stdio/index.d.ts +1 -1
- package/dist/transport/stdio/index.js +1 -1
- package/dist/transport/stdio/middleware.d.ts +2 -2
- package/dist/transport/stdio/middleware.js +4 -4
- package/dist/transport/ws/index.d.ts +2 -2
- package/dist/transport/ws/index.js +2 -2
- package/dist/transport/ws/middleware.d.ts +2 -2
- package/dist/transport/ws/middleware.js +3 -3
- package/dist/transport/ws/standalone.d.ts +1 -1
- package/dist/transport/ws/standalone.js +2 -2
- package/dist/types.d.ts +4 -4
- package/htdoc/assets/{index-hcP2-9jw.css → index-BAZmvr5x.css} +13 -0
- package/htdoc/assets/{index-CQr-lnlD.js → index-sVQlhxjI.js} +223 -32
- package/htdoc/assets/index-sVQlhxjI.js.map +1 -0
- package/htdoc/index.html +2 -2
- package/package.json +5 -4
- package/webui/src/App.tsx +30 -3
- package/webui/src/api/docGen.ts +188 -0
- package/webui/src/components/SchemaForm.tsx +0 -1
- package/webui/src/components/TestPanel.tsx +53 -10
- package/webui/src/components/Toolbar.tsx +13 -1
- package/webui/src/styles/geek.css +13 -0
- package/dist/schema/index.d.ts +0 -4
- package/dist/schema/index.d.ts.map +0 -1
- package/dist/schema/index.js +0 -4
- package/dist/schema/index.js.map +0 -1
- package/dist/schema/primitives.d.ts +0 -25
- package/dist/schema/primitives.d.ts.map +0 -1
- package/dist/schema/primitives.js +0 -153
- package/dist/schema/primitives.js.map +0 -1
- package/dist/schema/rpc.d.ts +0 -21
- package/dist/schema/rpc.d.ts.map +0 -1
- package/dist/schema/rpc.js +0 -17
- package/dist/schema/rpc.js.map +0 -1
- package/dist/stream/index.d.ts +0 -3
- package/dist/stream/index.d.ts.map +0 -1
- package/dist/stream/index.js +0 -2
- package/dist/stream/index.js.map +0 -1
- package/dist/stream/stringify.d.ts +0 -19
- package/dist/stream/stringify.d.ts.map +0 -1
- package/dist/stream/stringify.js +0 -217
- package/dist/stream/stringify.js.map +0 -1
- package/htdoc/assets/index-CQr-lnlD.js.map +0 -1
- /package/dist/errors/{RpcError.d.ts.map → RPCError.d.ts.map} +0 -0
- /package/dist/errors/{RpcError.js → RPCError.js} +0 -0
- /package/dist/errors/{RpcError.js.map → RPCError.js.map} +0 -0
|
@@ -8129,7 +8129,7 @@ var THEME_OPTIONS = [
|
|
|
8129
8129
|
label: "暗"
|
|
8130
8130
|
}
|
|
8131
8131
|
];
|
|
8132
|
-
function Toolbar({ transport, onTransportChange, onRefresh, loading, error }) {
|
|
8132
|
+
function Toolbar({ transport, onTransportChange, onRefresh, loading, error, onGenerateDocs, generatingDocs }) {
|
|
8133
8133
|
const { mode, setMode } = useTheme();
|
|
8134
8134
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", {
|
|
8135
8135
|
className: "toolbar",
|
|
@@ -8156,6 +8156,12 @@ function Toolbar({ transport, onTransportChange, onRefresh, loading, error }) {
|
|
|
8156
8156
|
disabled: loading,
|
|
8157
8157
|
children: loading ? "刷新中…" : "刷新方法列表"
|
|
8158
8158
|
}),
|
|
8159
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
8160
|
+
onClick: onGenerateDocs,
|
|
8161
|
+
disabled: generatingDocs || loading || loading,
|
|
8162
|
+
title: "拉取所有方法的帮助与签名,生成 Markdown 文档并下载",
|
|
8163
|
+
children: generatingDocs ? "生成中…" : "生成文档 ⬇"
|
|
8164
|
+
}),
|
|
8159
8165
|
error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
8160
8166
|
className: "error",
|
|
8161
8167
|
children: error
|
|
@@ -8446,7 +8452,7 @@ function MethodDetail({ method, detail }) {
|
|
|
8446
8452
|
//#endregion
|
|
8447
8453
|
//#region webui/src/api/paramForm.ts
|
|
8448
8454
|
/** 判断是否为合法 schema 描述(kind 为字符串) */
|
|
8449
|
-
function isSchema(v) {
|
|
8455
|
+
function isSchema$1(v) {
|
|
8450
8456
|
return !!v && typeof v === "object" && typeof v.kind === "string";
|
|
8451
8457
|
}
|
|
8452
8458
|
/**
|
|
@@ -8470,20 +8476,20 @@ function sampleFromSchema(schema) {
|
|
|
8470
8476
|
const values = schema.constraints?.values;
|
|
8471
8477
|
return Array.isArray(values) && values.length > 0 ? values[0] : "";
|
|
8472
8478
|
}
|
|
8473
|
-
case "nullable": return isSchema(c.inner) ? sampleFromSchema(c.inner) : null;
|
|
8474
|
-
case "array": return [isSchema(c.items) ? sampleFromSchema(c.items) : null];
|
|
8475
|
-
case "tuple": return (Array.isArray(c.items) ? c.items : []).map((it) => isSchema(it) ? sampleFromSchema(it) : null);
|
|
8479
|
+
case "nullable": return isSchema$1(c.inner) ? sampleFromSchema(c.inner) : null;
|
|
8480
|
+
case "array": return [isSchema$1(c.items) ? sampleFromSchema(c.items) : null];
|
|
8481
|
+
case "tuple": return (Array.isArray(c.items) ? c.items : []).map((it) => isSchema$1(it) ? sampleFromSchema(it) : null);
|
|
8476
8482
|
case "union": {
|
|
8477
8483
|
const options = Array.isArray(c.options) ? c.options : [];
|
|
8478
|
-
return options.length > 0 && isSchema(options[0]) ? sampleFromSchema(options[0]) : null;
|
|
8484
|
+
return options.length > 0 && isSchema$1(options[0]) ? sampleFromSchema(options[0]) : null;
|
|
8479
8485
|
}
|
|
8480
8486
|
case "object": {
|
|
8481
8487
|
const props = c.properties ?? {};
|
|
8482
8488
|
const out = {};
|
|
8483
|
-
for (const [k, v] of Object.entries(props)) if (isSchema(v)) out[k] = sampleFromSchema(v);
|
|
8489
|
+
for (const [k, v] of Object.entries(props)) if (isSchema$1(v)) out[k] = sampleFromSchema(v);
|
|
8484
8490
|
return out;
|
|
8485
8491
|
}
|
|
8486
|
-
case "record": return { key: isSchema(c.values) ? sampleFromSchema(c.values) : null };
|
|
8492
|
+
case "record": return { key: isSchema$1(c.values) ? sampleFromSchema(c.values) : null };
|
|
8487
8493
|
default: return null;
|
|
8488
8494
|
}
|
|
8489
8495
|
}
|
|
@@ -8531,7 +8537,7 @@ function SchemaField({ schema, value, onChange, label, depth = 0, defaultOpen =
|
|
|
8531
8537
|
const [open, setOpen] = (0, import_react.useState)(defaultOpen);
|
|
8532
8538
|
const kind = schema.kind;
|
|
8533
8539
|
if (kind === "nullable") {
|
|
8534
|
-
const inner = schema.children && isSchema(schema.children.inner) ? schema.children.inner : void 0;
|
|
8540
|
+
const inner = schema.children && isSchema$1(schema.children.inner) ? schema.children.inner : void 0;
|
|
8535
8541
|
if (!inner) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnknownLeaf, {
|
|
8536
8542
|
schema,
|
|
8537
8543
|
value,
|
|
@@ -8556,10 +8562,6 @@ function SchemaField({ schema, value, onChange, label, depth = 0, defaultOpen =
|
|
|
8556
8562
|
style: { color: colorOf("nullable") },
|
|
8557
8563
|
children: "nullable"
|
|
8558
8564
|
}),
|
|
8559
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
8560
|
-
className: "sf-nullable",
|
|
8561
|
-
children: "| null"
|
|
8562
|
-
}),
|
|
8563
8565
|
!isNull && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
8564
8566
|
type: "button",
|
|
8565
8567
|
className: "tiny",
|
|
@@ -8623,7 +8625,7 @@ function SchemaField({ schema, value, onChange, label, depth = 0, defaultOpen =
|
|
|
8623
8625
|
})]
|
|
8624
8626
|
});
|
|
8625
8627
|
if (kind === "union") {
|
|
8626
|
-
const options = Array.isArray(schema.children?.options) ? schema.children.options.filter(isSchema) : [];
|
|
8628
|
+
const options = Array.isArray(schema.children?.options) ? schema.children.options.filter(isSchema$1) : [];
|
|
8627
8629
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
8628
8630
|
className: "sf-node sf-row",
|
|
8629
8631
|
style: { paddingLeft: depth * 14 },
|
|
@@ -8799,7 +8801,7 @@ function UnionField({ options, value, onChange, depth, disabled }) {
|
|
|
8799
8801
|
function ContainerChildren({ schema, value, onChange, depth, disabled }) {
|
|
8800
8802
|
const c = schema.children ?? {};
|
|
8801
8803
|
if (schema.kind === "array") {
|
|
8802
|
-
const itemSchema = isSchema(c.items) ? c.items : void 0;
|
|
8804
|
+
const itemSchema = isSchema$1(c.items) ? c.items : void 0;
|
|
8803
8805
|
if (!itemSchema) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
8804
8806
|
className: "hint",
|
|
8805
8807
|
children: "(数组无 item schema)"
|
|
@@ -8835,7 +8837,7 @@ function ContainerChildren({ schema, value, onChange, depth, disabled }) {
|
|
|
8835
8837
|
})] });
|
|
8836
8838
|
}
|
|
8837
8839
|
if (schema.kind === "tuple") {
|
|
8838
|
-
const items = Array.isArray(c.items) ? c.items.filter(isSchema) : [];
|
|
8840
|
+
const items = Array.isArray(c.items) ? c.items.filter(isSchema$1) : [];
|
|
8839
8841
|
const arr = Array.isArray(value) ? value : [];
|
|
8840
8842
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: items.map((itemSchema, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaField, {
|
|
8841
8843
|
schema: itemSchema,
|
|
@@ -8856,7 +8858,7 @@ function ContainerChildren({ schema, value, onChange, depth, disabled }) {
|
|
|
8856
8858
|
const obj = value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
8857
8859
|
const strict = Boolean(schema.constraints?.strict);
|
|
8858
8860
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [Object.entries(props).map(([key, prop]) => {
|
|
8859
|
-
if (!isSchema(prop)) return null;
|
|
8861
|
+
if (!isSchema$1(prop)) return null;
|
|
8860
8862
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SchemaField, {
|
|
8861
8863
|
schema: prop,
|
|
8862
8864
|
value: obj[key],
|
|
@@ -8881,7 +8883,7 @@ function ContainerChildren({ schema, value, onChange, depth, disabled }) {
|
|
|
8881
8883
|
})] });
|
|
8882
8884
|
}
|
|
8883
8885
|
if (schema.kind === "record") {
|
|
8884
|
-
const valueSchema = isSchema(c.values) ? c.values : void 0;
|
|
8886
|
+
const valueSchema = isSchema$1(c.values) ? c.values : void 0;
|
|
8885
8887
|
if (!valueSchema) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
8886
8888
|
className: "hint",
|
|
8887
8889
|
children: "(record 无 value schema)"
|
|
@@ -9009,11 +9011,17 @@ var COPY_OPTIONS = [{
|
|
|
9009
9011
|
value: "fetch",
|
|
9010
9012
|
label: "复制 fetch"
|
|
9011
9013
|
}];
|
|
9014
|
+
/** 格式化耗时:<1s 用 ms,否则用 s */
|
|
9015
|
+
function formatElapsed(ms) {
|
|
9016
|
+
if (ms < 1e3) return `${ms.toFixed(0)} ms`;
|
|
9017
|
+
return `${(ms / 1e3).toFixed(2)} s`;
|
|
9018
|
+
}
|
|
9012
9019
|
function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
9013
9020
|
const paramSchemas = (0, import_react.useMemo)(() => detail.signature.slice(1), [detail.signature]);
|
|
9014
9021
|
const isStreamReturn = detail.signature[0]?.kind === "stream";
|
|
9015
9022
|
const [values, setValues] = (0, import_react.useState)([]);
|
|
9016
9023
|
const [output, setOutput] = (0, import_react.useState)("");
|
|
9024
|
+
const [elapsed, setElapsed] = (0, import_react.useState)(null);
|
|
9017
9025
|
const [running, setRunning] = (0, import_react.useState)(false);
|
|
9018
9026
|
const [copyKind, setCopyKind] = (0, import_react.useState)("curl");
|
|
9019
9027
|
const [copied, setCopied] = (0, import_react.useState)(false);
|
|
@@ -9025,6 +9033,7 @@ function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
|
9025
9033
|
if (!method) return;
|
|
9026
9034
|
setValues(paramSchemas.map(sampleFromSchema));
|
|
9027
9035
|
setOutput("");
|
|
9036
|
+
setElapsed(null);
|
|
9028
9037
|
}, [method, paramSchemas]);
|
|
9029
9038
|
(0, import_react.useEffect)(() => {
|
|
9030
9039
|
setCopied(false);
|
|
@@ -9050,25 +9059,37 @@ function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
|
9050
9059
|
if (!method) return;
|
|
9051
9060
|
setRunning(true);
|
|
9052
9061
|
setOutput("");
|
|
9062
|
+
setElapsed(null);
|
|
9063
|
+
const startedAt = performance.now();
|
|
9053
9064
|
try {
|
|
9054
9065
|
const result = await rpc.call(method, ...values);
|
|
9066
|
+
const firstFrameAt = performance.now() - startedAt;
|
|
9055
9067
|
if (isStreamResult(result)) {
|
|
9056
9068
|
let idx = 0;
|
|
9057
9069
|
const lines = [];
|
|
9058
9070
|
for await (const value of result) {
|
|
9059
|
-
|
|
9071
|
+
const now = performance.now() - startedAt;
|
|
9072
|
+
lines.push(`[${idx}] (+${formatElapsed(now)}) ${JSON.stringify(value, null, 2)}`);
|
|
9060
9073
|
idx++;
|
|
9061
9074
|
setOutput(lines.join("\n"));
|
|
9062
9075
|
}
|
|
9063
|
-
|
|
9064
|
-
|
|
9065
|
-
|
|
9066
|
-
|
|
9067
|
-
|
|
9076
|
+
const totalAt = performance.now() - startedAt;
|
|
9077
|
+
if (idx === 0) lines.push(`(流已结束,无数据,总耗时 ${formatElapsed(totalAt)})`);
|
|
9078
|
+
else lines.push(`(流已结束,共 ${idx} 帧,总耗时 ${formatElapsed(totalAt)})`);
|
|
9079
|
+
setOutput(lines.join("\n"));
|
|
9080
|
+
setElapsed({
|
|
9081
|
+
total: totalAt,
|
|
9082
|
+
firstFrame: firstFrameAt
|
|
9083
|
+
});
|
|
9084
|
+
} else {
|
|
9085
|
+
const totalAt = performance.now() - startedAt;
|
|
9068
9086
|
setOutput(JSON.stringify(result, null, 2));
|
|
9087
|
+
setElapsed({ total: totalAt });
|
|
9069
9088
|
}
|
|
9070
9089
|
} catch (e) {
|
|
9090
|
+
const totalAt = performance.now() - startedAt;
|
|
9071
9091
|
setOutput(formatError(e));
|
|
9092
|
+
setElapsed({ total: totalAt });
|
|
9072
9093
|
} finally {
|
|
9073
9094
|
setRunning(false);
|
|
9074
9095
|
requestAnimationFrame(() => outRef.current?.scrollIntoView({ block: "nearest" }));
|
|
@@ -9180,16 +9201,38 @@ function TestPanel({ method, detail, rpc, transport, endpoint }) {
|
|
|
9180
9201
|
children: "重置为示例"
|
|
9181
9202
|
}),
|
|
9182
9203
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
9183
|
-
onClick: () =>
|
|
9184
|
-
|
|
9204
|
+
onClick: () => {
|
|
9205
|
+
setOutput("");
|
|
9206
|
+
setElapsed(null);
|
|
9207
|
+
},
|
|
9208
|
+
disabled: !output && !elapsed,
|
|
9185
9209
|
children: "清空输出"
|
|
9186
9210
|
})
|
|
9187
9211
|
]
|
|
9188
9212
|
}),
|
|
9189
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { children: [
|
|
9190
|
-
|
|
9191
|
-
|
|
9192
|
-
|
|
9213
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", { children: [
|
|
9214
|
+
"结果",
|
|
9215
|
+
isStreamReturn && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
9216
|
+
className: "hint",
|
|
9217
|
+
children: "(流式)"
|
|
9218
|
+
}),
|
|
9219
|
+
elapsed && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
9220
|
+
className: "elapsed-badge",
|
|
9221
|
+
children: [
|
|
9222
|
+
" ",
|
|
9223
|
+
"⏱ ",
|
|
9224
|
+
formatElapsed(elapsed.total),
|
|
9225
|
+
elapsed.firstFrame !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
9226
|
+
className: "hint",
|
|
9227
|
+
children: [
|
|
9228
|
+
" ",
|
|
9229
|
+
"· 首帧 ",
|
|
9230
|
+
formatElapsed(elapsed.firstFrame)
|
|
9231
|
+
]
|
|
9232
|
+
})
|
|
9233
|
+
]
|
|
9234
|
+
})
|
|
9235
|
+
] }),
|
|
9193
9236
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
|
|
9194
9237
|
className: "output",
|
|
9195
9238
|
ref: outRef,
|
|
@@ -9232,11 +9275,142 @@ function formatError(e) {
|
|
|
9232
9275
|
return `Error: ${e instanceof Error ? e.message : String(e)}`;
|
|
9233
9276
|
}
|
|
9234
9277
|
//#endregion
|
|
9278
|
+
//#region webui/src/api/docGen.ts
|
|
9279
|
+
function isSchema(v) {
|
|
9280
|
+
return !!v && typeof v === "object" && typeof v.kind === "string";
|
|
9281
|
+
}
|
|
9282
|
+
/** 逐个方法拉取 help + signature */
|
|
9283
|
+
async function collectApiDoc(rpc, methods, onProgress) {
|
|
9284
|
+
const out = [];
|
|
9285
|
+
for (let i = 0; i < methods.length; i++) {
|
|
9286
|
+
const name = methods[i];
|
|
9287
|
+
try {
|
|
9288
|
+
const [help, sig] = await Promise.all([rpc.call("system.methodHelp", name).catch(() => ""), rpc.call("system.methodSignature", name).catch(() => [])]);
|
|
9289
|
+
out.push({
|
|
9290
|
+
name,
|
|
9291
|
+
help: typeof help === "string" ? help : "",
|
|
9292
|
+
signature: Array.isArray(sig) ? sig.filter(isSchema) : []
|
|
9293
|
+
});
|
|
9294
|
+
} catch (e) {
|
|
9295
|
+
out.push({
|
|
9296
|
+
name,
|
|
9297
|
+
help: "",
|
|
9298
|
+
signature: [],
|
|
9299
|
+
error: e instanceof Error ? e.message : String(e)
|
|
9300
|
+
});
|
|
9301
|
+
}
|
|
9302
|
+
onProgress?.(i + 1, methods.length);
|
|
9303
|
+
}
|
|
9304
|
+
return {
|
|
9305
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9306
|
+
methods: out
|
|
9307
|
+
};
|
|
9308
|
+
}
|
|
9309
|
+
function renderSchemaTree(schema, indent = 0) {
|
|
9310
|
+
const pad = " ".repeat(indent);
|
|
9311
|
+
const lines = [];
|
|
9312
|
+
let head = `${pad}- \`${schema.kind}\``;
|
|
9313
|
+
if (schema.nullable) head += " _(nullable)_";
|
|
9314
|
+
if (schema.description) head += ` — ${schema.description}`;
|
|
9315
|
+
const c = schema.constraints;
|
|
9316
|
+
if (c && Object.keys(c).length > 0) {
|
|
9317
|
+
const parts = Object.entries(c).filter(([, v]) => v !== void 0).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
|
|
9318
|
+
if (parts.length) head += ` \`{ ${parts.join(", ")} }\``;
|
|
9319
|
+
}
|
|
9320
|
+
lines.push(head);
|
|
9321
|
+
const ch = schema.children ?? {};
|
|
9322
|
+
const pushChild = (label, child) => {
|
|
9323
|
+
const sub = renderSchemaTree(child, indent + 1);
|
|
9324
|
+
if (sub.length) {
|
|
9325
|
+
sub[0] = `${" ".repeat(indent + 1)}- **${label}**: ${sub[0].trim().replace(/^- /, "")}`;
|
|
9326
|
+
lines.push(...sub);
|
|
9327
|
+
}
|
|
9328
|
+
};
|
|
9329
|
+
if (isSchema(ch.inner)) pushChild("inner", ch.inner);
|
|
9330
|
+
if (Array.isArray(ch.items)) ch.items.forEach((it, i) => {
|
|
9331
|
+
if (isSchema(it)) pushChild(`[${i}]`, it);
|
|
9332
|
+
});
|
|
9333
|
+
else if (isSchema(ch.items)) pushChild("items", ch.items);
|
|
9334
|
+
if (Array.isArray(ch.options)) ch.options.forEach((opt, i) => {
|
|
9335
|
+
if (isSchema(opt)) pushChild(`option[${i}]`, opt);
|
|
9336
|
+
});
|
|
9337
|
+
if (ch.properties && typeof ch.properties === "object") {
|
|
9338
|
+
for (const [k, v] of Object.entries(ch.properties)) if (isSchema(v)) pushChild(k, v);
|
|
9339
|
+
}
|
|
9340
|
+
if (isSchema(ch.values)) pushChild("values", ch.values);
|
|
9341
|
+
return lines;
|
|
9342
|
+
}
|
|
9343
|
+
function renderMarkdown(doc) {
|
|
9344
|
+
const lines = [];
|
|
9345
|
+
lines.push("# JSON-RPC API 文档");
|
|
9346
|
+
lines.push("");
|
|
9347
|
+
lines.push(`> 生成时间:${doc.generatedAt}`);
|
|
9348
|
+
lines.push(`> 方法总数:${doc.methods.length}`);
|
|
9349
|
+
lines.push("");
|
|
9350
|
+
lines.push("## 目录");
|
|
9351
|
+
lines.push("");
|
|
9352
|
+
for (const m of doc.methods) {
|
|
9353
|
+
const anchor = m.name.toLowerCase().replace(/[^\w]+/g, "-");
|
|
9354
|
+
lines.push(`- [\`${m.name}\`](#${anchor})`);
|
|
9355
|
+
}
|
|
9356
|
+
lines.push("");
|
|
9357
|
+
for (const m of doc.methods) {
|
|
9358
|
+
lines.push(`## \`${m.name}\``);
|
|
9359
|
+
lines.push("");
|
|
9360
|
+
if (m.error) {
|
|
9361
|
+
lines.push(`> ⚠️ 获取失败:${m.error}`);
|
|
9362
|
+
lines.push("");
|
|
9363
|
+
continue;
|
|
9364
|
+
}
|
|
9365
|
+
lines.push("**帮助**");
|
|
9366
|
+
lines.push("");
|
|
9367
|
+
lines.push(m.help ? m.help : "_(无帮助信息)_");
|
|
9368
|
+
lines.push("");
|
|
9369
|
+
if (m.signature.length === 0) {
|
|
9370
|
+
lines.push("**签名**:_(无)_");
|
|
9371
|
+
lines.push("");
|
|
9372
|
+
continue;
|
|
9373
|
+
}
|
|
9374
|
+
const [ret, ...params] = m.signature;
|
|
9375
|
+
lines.push("**返回类型**");
|
|
9376
|
+
lines.push("");
|
|
9377
|
+
lines.push(...renderSchemaTree(ret, 0));
|
|
9378
|
+
lines.push("");
|
|
9379
|
+
lines.push(`**参数**(${params.length} 个)`);
|
|
9380
|
+
lines.push("");
|
|
9381
|
+
if (params.length === 0) lines.push("_(无参数)_");
|
|
9382
|
+
else params.forEach((p, i) => {
|
|
9383
|
+
const sub = renderSchemaTree(p, 0);
|
|
9384
|
+
if (sub.length) {
|
|
9385
|
+
sub[0] = `- **参数 [${i}]**: ${sub[0].trim().replace(/^- /, "")}`;
|
|
9386
|
+
lines.push(...sub);
|
|
9387
|
+
}
|
|
9388
|
+
});
|
|
9389
|
+
lines.push("");
|
|
9390
|
+
lines.push("---");
|
|
9391
|
+
lines.push("");
|
|
9392
|
+
}
|
|
9393
|
+
return lines.join("\n");
|
|
9394
|
+
}
|
|
9395
|
+
/** 触发浏览器下载 */
|
|
9396
|
+
function downloadText(filename, text, mime = "text/plain") {
|
|
9397
|
+
const blob = new Blob([text], { type: `${mime};charset=utf-8` });
|
|
9398
|
+
const url = URL.createObjectURL(blob);
|
|
9399
|
+
const a = document.createElement("a");
|
|
9400
|
+
a.href = url;
|
|
9401
|
+
a.download = filename;
|
|
9402
|
+
document.body.appendChild(a);
|
|
9403
|
+
a.click();
|
|
9404
|
+
document.body.removeChild(a);
|
|
9405
|
+
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
9406
|
+
}
|
|
9407
|
+
//#endregion
|
|
9235
9408
|
//#region webui/src/App.tsx
|
|
9236
9409
|
var ENDPOINT = "";
|
|
9237
9410
|
function App() {
|
|
9238
9411
|
const [transport, setTransport] = (0, import_react.useState)("http");
|
|
9239
9412
|
const [selected, setSelected] = (0, import_react.useState)("");
|
|
9413
|
+
const [generatingDocs, setGeneratingDocs] = (0, import_react.useState)(false);
|
|
9240
9414
|
const rpc = (0, import_react.useMemo)(() => {
|
|
9241
9415
|
return createRpc({
|
|
9242
9416
|
transport,
|
|
@@ -9248,6 +9422,21 @@ function App() {
|
|
|
9248
9422
|
}, [rpc]);
|
|
9249
9423
|
const { methods, loading, error, refresh } = useMethods(rpc);
|
|
9250
9424
|
const detail = useMethodDetail(rpc, selected);
|
|
9425
|
+
const generateDocs = (0, import_react.useCallback)(async () => {
|
|
9426
|
+
if (methods.length === 0) {
|
|
9427
|
+
alert("方法列表为空,请先刷新方法列表。");
|
|
9428
|
+
return;
|
|
9429
|
+
}
|
|
9430
|
+
setGeneratingDocs(true);
|
|
9431
|
+
try {
|
|
9432
|
+
const md = renderMarkdown(await collectApiDoc(rpc, methods));
|
|
9433
|
+
downloadText(`jsonrpc-api-doc-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19)}.md`, md, "text/markdown");
|
|
9434
|
+
} catch (e) {
|
|
9435
|
+
alert(`生成文档失败:${e instanceof Error ? e.message : String(e)}`);
|
|
9436
|
+
} finally {
|
|
9437
|
+
setGeneratingDocs(false);
|
|
9438
|
+
}
|
|
9439
|
+
}, [rpc, methods]);
|
|
9251
9440
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
9252
9441
|
className: "app",
|
|
9253
9442
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Toolbar, {
|
|
@@ -9255,7 +9444,9 @@ function App() {
|
|
|
9255
9444
|
onTransportChange: setTransport,
|
|
9256
9445
|
onRefresh: refresh,
|
|
9257
9446
|
loading,
|
|
9258
|
-
error
|
|
9447
|
+
error,
|
|
9448
|
+
onGenerateDocs: generateDocs,
|
|
9449
|
+
generatingDocs
|
|
9259
9450
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
|
|
9260
9451
|
className: "sidebar",
|
|
9261
9452
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: "Methods" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MethodTree, {
|
|
@@ -9283,4 +9474,4 @@ function App() {
|
|
|
9283
9474
|
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, {}) }) }));
|
|
9284
9475
|
//#endregion
|
|
9285
9476
|
|
|
9286
|
-
//# sourceMappingURL=index-
|
|
9477
|
+
//# sourceMappingURL=index-sVQlhxjI.js.map
|