feat(api-docs): generate response examples from Go structs; fix SS2022 PSK regen (#4996)

Stop hand-writing OpenAPI response examples, which kept drifting from the real payloads (clients/traffic missing fields, inbounds/list exposing userId which is json:"-", the fictional inbound-443 tag instead of the real in-<port>-<transport> form).

tools/openapigen now emits frontend/src/generated/examples.ts: a per-struct example instance built from type defaults, validate oneof/min bounds, and example: struct tags, with nested-ref expansion and a cycle guard. build-openapi.mjs composes the {success,obj} envelope from it for any endpoint annotated with responseSchema (+ responseSchemaArray for lists); the hand-written response is dropped for those. Service DTOs InboundOption/ApiTokenView/ProbeResultUI are added to the walker.

#4996: client password regeneration now produces a valid Shadowsocks 2022 PSK (correct base64 length per cipher) when an SS2022 inbound is attached, in both the single and bulk client forms; backend surfaces ssMethod on /inbounds/options so the UI can pick the right length.

Also: Swagger UI persists the Authorization token across reloads (persistAuthorization).
This commit is contained in:
MHSanaei
2026-06-06 14:58:15 +02:00
parent 483952cfa0
commit 83799d71b0
22 changed files with 924 additions and 143 deletions
+9 -1
View File
@@ -4,6 +4,7 @@ import { join, dirname } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { sections } from '../src/pages/api-docs/endpoints.ts';
import { EXAMPLES } from '../src/generated/examples.ts';
const __dirname = dirname(fileURLToPath(import.meta.url));
const outPath = join(__dirname, '..', 'public', 'openapi.json');
@@ -128,7 +129,14 @@ function buildOperation(ep, tag) {
}
const responses = {};
const successExample = tryParseJson(ep.response);
let successExample = tryParseJson(ep.response);
if (successExample === undefined && ep.responseSchema) {
const obj = EXAMPLES[ep.responseSchema];
if (obj === undefined) {
throw new Error(`${ep.method} ${ep.path}: responseSchema "${ep.responseSchema}" has no generated example`);
}
successExample = { success: true, obj: ep.responseSchemaArray ? [obj] : obj };
}
responses['200'] = {
description: 'Successful response',
content: {