shokupan 0.10.1 → 0.10.3
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/index.cjs +292 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +292 -0
- package/dist/index.js.map +1 -1
- package/dist/plugins/application/api-explorer/plugin.d.ts +7 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3567,6 +3567,297 @@ function Event(eventName) {
|
|
|
3567
3567
|
function RateLimit(options) {
|
|
3568
3568
|
return Use(RateLimitMiddleware(options));
|
|
3569
3569
|
}
|
|
3570
|
+
function ApiExplorerApp({ spec, asyncSpec, config }) {
|
|
3571
|
+
const hierarchy = /* @__PURE__ */ new Map();
|
|
3572
|
+
const addRoute = (groupKey, route) => {
|
|
3573
|
+
if (!hierarchy.has(groupKey)) {
|
|
3574
|
+
hierarchy.set(groupKey, []);
|
|
3575
|
+
}
|
|
3576
|
+
hierarchy.get(groupKey).push(route);
|
|
3577
|
+
};
|
|
3578
|
+
const getGroupKey = (op, source) => {
|
|
3579
|
+
if (op.tags && op.tags.length > 0) {
|
|
3580
|
+
const tag = typeof op.tags[0] === "string" ? op.tags[0] : op.tags[0].name;
|
|
3581
|
+
if (!tag.startsWith("/")) return tag;
|
|
3582
|
+
}
|
|
3583
|
+
if (source?.className) return source.className;
|
|
3584
|
+
if (source?.file) {
|
|
3585
|
+
const parts = source.file.split("/");
|
|
3586
|
+
const filename = parts[parts.length - 1].replace(/\.(ts|js)$/, "");
|
|
3587
|
+
return filename.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
3588
|
+
}
|
|
3589
|
+
if (op.tags && op.tags.length > 0) {
|
|
3590
|
+
const tag = typeof op.tags[0] === "string" ? op.tags[0] : op.tags[0].name;
|
|
3591
|
+
return tag;
|
|
3592
|
+
}
|
|
3593
|
+
return "Ungrouped";
|
|
3594
|
+
};
|
|
3595
|
+
const createSubgroups = (routes, depth = 0) => {
|
|
3596
|
+
if (routes.length < 3 || depth > 5) {
|
|
3597
|
+
return routes.map((route) => ({
|
|
3598
|
+
name: route.path,
|
|
3599
|
+
type: "route",
|
|
3600
|
+
path: route.path,
|
|
3601
|
+
routes: [route]
|
|
3602
|
+
}));
|
|
3603
|
+
}
|
|
3604
|
+
const pathSegments = routes.map((r) => {
|
|
3605
|
+
const cleaned = r.path.replace(/^\/|\/$/g, "");
|
|
3606
|
+
return cleaned.split("/");
|
|
3607
|
+
});
|
|
3608
|
+
const prefixGroups = /* @__PURE__ */ new Map();
|
|
3609
|
+
const ungrouped = [];
|
|
3610
|
+
routes.forEach((route, idx) => {
|
|
3611
|
+
const segments = pathSegments[idx];
|
|
3612
|
+
if (segments.length <= depth) {
|
|
3613
|
+
ungrouped.push(route);
|
|
3614
|
+
return;
|
|
3615
|
+
}
|
|
3616
|
+
const prefix = segments.slice(0, depth + 1).join("/");
|
|
3617
|
+
if (!prefixGroups.has(prefix)) {
|
|
3618
|
+
prefixGroups.set(prefix, []);
|
|
3619
|
+
}
|
|
3620
|
+
prefixGroups.get(prefix).push(route);
|
|
3621
|
+
});
|
|
3622
|
+
const result = [];
|
|
3623
|
+
prefixGroups.forEach((groupRoutes, prefix) => {
|
|
3624
|
+
if (groupRoutes.length >= 3) {
|
|
3625
|
+
const prefixName = prefix.split("/").pop() || prefix;
|
|
3626
|
+
result.push({
|
|
3627
|
+
name: prefixName,
|
|
3628
|
+
type: "subgroup",
|
|
3629
|
+
path: "/" + prefix,
|
|
3630
|
+
children: createSubgroups(groupRoutes, depth + 1)
|
|
3631
|
+
});
|
|
3632
|
+
} else {
|
|
3633
|
+
ungrouped.push(...groupRoutes);
|
|
3634
|
+
}
|
|
3635
|
+
});
|
|
3636
|
+
ungrouped.forEach((route) => {
|
|
3637
|
+
result.push({
|
|
3638
|
+
name: route.path,
|
|
3639
|
+
type: "route",
|
|
3640
|
+
path: route.path,
|
|
3641
|
+
routes: [route]
|
|
3642
|
+
});
|
|
3643
|
+
});
|
|
3644
|
+
result.sort((a, b) => {
|
|
3645
|
+
if (a.type === "subgroup" && b.type !== "subgroup") return -1;
|
|
3646
|
+
if (a.type !== "subgroup" && b.type === "subgroup") return 1;
|
|
3647
|
+
return a.name.localeCompare(b.name);
|
|
3648
|
+
});
|
|
3649
|
+
return result;
|
|
3650
|
+
};
|
|
3651
|
+
Object.entries(spec.paths || {}).forEach(([path2, methods]) => {
|
|
3652
|
+
Object.entries(methods).forEach(([method, op]) => {
|
|
3653
|
+
if (!op.operationId) {
|
|
3654
|
+
op.operationId = `${method}-${path2.replace(/\//g, "-").replace(/[{}:]/g, "")}`;
|
|
3655
|
+
}
|
|
3656
|
+
const route = { method, path: path2, op };
|
|
3657
|
+
const source = op["x-shokupan-source"];
|
|
3658
|
+
const groupKey = getGroupKey(op, source);
|
|
3659
|
+
addRoute(groupKey, route);
|
|
3660
|
+
});
|
|
3661
|
+
});
|
|
3662
|
+
Object.entries(asyncSpec?.channels || {}).forEach(([name, ch]) => {
|
|
3663
|
+
const operations = [];
|
|
3664
|
+
if (ch.publish) operations.push({ method: "recv", op: ch.publish });
|
|
3665
|
+
if (ch.subscribe) operations.push({ method: "send", op: ch.subscribe });
|
|
3666
|
+
operations.forEach(({ method, op }) => {
|
|
3667
|
+
if (!op.operationId) op.operationId = `${method}-${name.replace(/[^a-zA-Z0-9]/g, "-")}`;
|
|
3668
|
+
const route = { method, path: name, op };
|
|
3669
|
+
const source = op["x-shokupan-source"] || op["x-source-info"];
|
|
3670
|
+
const groupKey = getGroupKey(op, source);
|
|
3671
|
+
addRoute(groupKey, route);
|
|
3672
|
+
});
|
|
3673
|
+
});
|
|
3674
|
+
const hierarchicalGroups = Array.from(hierarchy.entries()).map(([name, routes]) => {
|
|
3675
|
+
routes.sort((a, b) => a.path.localeCompare(b.path));
|
|
3676
|
+
const children = createSubgroups(routes);
|
|
3677
|
+
return {
|
|
3678
|
+
name,
|
|
3679
|
+
type: "group",
|
|
3680
|
+
children
|
|
3681
|
+
};
|
|
3682
|
+
}).sort((a, b) => {
|
|
3683
|
+
if (a.name === "Ungrouped") return 1;
|
|
3684
|
+
if (b.name === "Ungrouped") return -1;
|
|
3685
|
+
return a.name.localeCompare(b.name);
|
|
3686
|
+
});
|
|
3687
|
+
const allRoutes = Array.from(hierarchy.values()).flat();
|
|
3688
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("html", { lang: "en", children: [
|
|
3689
|
+
/* @__PURE__ */ jsxRuntime.jsxs("head", { children: [
|
|
3690
|
+
/* @__PURE__ */ jsxRuntime.jsx("meta", { charSet: "UTF-8" }),
|
|
3691
|
+
/* @__PURE__ */ jsxRuntime.jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1.0" }),
|
|
3692
|
+
/* @__PURE__ */ jsxRuntime.jsx("title", { children: spec.info?.title || "API Explorer" }),
|
|
3693
|
+
/* @__PURE__ */ jsxRuntime.jsx("link", { rel: "stylesheet", href: "style.css" }),
|
|
3694
|
+
/* @__PURE__ */ jsxRuntime.jsx("link", { rel: "stylesheet", href: "theme.css" }),
|
|
3695
|
+
/* @__PURE__ */ jsxRuntime.jsx("script", { src: "https://cdn.jsdelivr.net/npm/marked@4.3.0/marked.min.js" }),
|
|
3696
|
+
/* @__PURE__ */ jsxRuntime.jsx("script", { src: "https://cdn.jsdelivr.net/npm/monaco-editor@0.45.0/min/vs/loader.js" }),
|
|
3697
|
+
/* @__PURE__ */ jsxRuntime.jsx("script", { dangerouslySetInnerHTML: {
|
|
3698
|
+
__html: `
|
|
3699
|
+
(function() {
|
|
3700
|
+
if (!window.location.pathname.endsWith('/') && !window.location.pathname.split('/').pop().includes('.')) {
|
|
3701
|
+
var newUrl = window.location.pathname + '/' + window.location.search + window.location.hash;
|
|
3702
|
+
window.history.replaceState(null, null, newUrl);
|
|
3703
|
+
window.location.reload();
|
|
3704
|
+
}
|
|
3705
|
+
})();
|
|
3706
|
+
`
|
|
3707
|
+
} })
|
|
3708
|
+
] }),
|
|
3709
|
+
/* @__PURE__ */ jsxRuntime.jsxs("body", { class: "dark-theme", children: [
|
|
3710
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { id: "app", children: [
|
|
3711
|
+
/* @__PURE__ */ jsxRuntime.jsx(Sidebar$1, { spec, hierarchicalGroups }),
|
|
3712
|
+
/* @__PURE__ */ jsxRuntime.jsx(MainContent$1, { allRoutes, config, spec })
|
|
3713
|
+
] }),
|
|
3714
|
+
/* @__PURE__ */ jsxRuntime.jsx("script", { src: "explorer-client.mjs", type: "module" })
|
|
3715
|
+
] })
|
|
3716
|
+
] });
|
|
3717
|
+
}
|
|
3718
|
+
function Sidebar$1({ spec, hierarchicalGroups }) {
|
|
3719
|
+
const renderNavNode = (node, depth = 0) => {
|
|
3720
|
+
if (node.type === "route") {
|
|
3721
|
+
const route = node.routes[0];
|
|
3722
|
+
const source = route.op["x-shokupan-source"] || route.op["x-source-info"];
|
|
3723
|
+
const isRuntime = route.op["x-source-info"]?.isRuntime;
|
|
3724
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { class: "nav-item-wrapper", style: `padding-left: ${depth * 12}px;`, children: [
|
|
3725
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3726
|
+
"a",
|
|
3727
|
+
{
|
|
3728
|
+
href: `#${route.op.operationId}`,
|
|
3729
|
+
class: "nav-item",
|
|
3730
|
+
"data-id": route.op.operationId,
|
|
3731
|
+
title: route.path,
|
|
3732
|
+
children: [
|
|
3733
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { class: `badge badge-${route.method.toUpperCase()}`, children: route.method.toUpperCase() }),
|
|
3734
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { class: "nav-label", children: node.name }),
|
|
3735
|
+
isRuntime && /* @__PURE__ */ jsxRuntime.jsx("span", { class: "nav-warning", title: "Static Analysis Failed", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", children: [
|
|
3736
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }),
|
|
3737
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
|
|
3738
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
|
|
3739
|
+
] }) })
|
|
3740
|
+
]
|
|
3741
|
+
},
|
|
3742
|
+
route.op.operationId
|
|
3743
|
+
),
|
|
3744
|
+
source?.file && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3745
|
+
"a",
|
|
3746
|
+
{
|
|
3747
|
+
href: `vscode://file/${source.file}:${source.line || 1}`,
|
|
3748
|
+
class: "nav-source-link",
|
|
3749
|
+
title: `${source.file}:${source.line || 1}`,
|
|
3750
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", children: [
|
|
3751
|
+
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "16 18 22 12 16 6" }),
|
|
3752
|
+
/* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "8 6 2 12 8 18" })
|
|
3753
|
+
] })
|
|
3754
|
+
}
|
|
3755
|
+
)
|
|
3756
|
+
] });
|
|
3757
|
+
} else if (node.type === "subgroup") {
|
|
3758
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { class: "nav-subgroup collapsed", style: `padding-left: ${depth * 12}px;`, children: [
|
|
3759
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { class: "nav-subgroup-title", children: [
|
|
3760
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { class: "chevron", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "9 18 15 12 9 6" }) }) }),
|
|
3761
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: node.name })
|
|
3762
|
+
] }),
|
|
3763
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { class: "nav-subgroup-items", children: node.children?.map((child) => renderNavNode(child, depth + 1)) })
|
|
3764
|
+
] });
|
|
3765
|
+
}
|
|
3766
|
+
};
|
|
3767
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("aside", { class: "sidebar", children: [
|
|
3768
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { class: "resize-handle" }),
|
|
3769
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { class: "sidebar-header", children: [
|
|
3770
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { class: "toggle-sidebar", children: "☰" }),
|
|
3771
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { children: spec.info?.title }),
|
|
3772
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { class: "version", children: spec.info?.version })
|
|
3773
|
+
] }),
|
|
3774
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { class: "sidebar-collapse-trigger", children: "➔" }),
|
|
3775
|
+
/* @__PURE__ */ jsxRuntime.jsx("nav", { class: "nav-groups", children: hierarchicalGroups.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("div", { class: "nav-group collapsed", children: [
|
|
3776
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { class: "nav-group-title", children: [
|
|
3777
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { class: "chevron", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "9 18 15 12 9 6" }) }) }),
|
|
3778
|
+
" ",
|
|
3779
|
+
group.name
|
|
3780
|
+
] }),
|
|
3781
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { class: "nav-items", children: group.children?.map((child) => renderNavNode(child, 0)) })
|
|
3782
|
+
] }, group.name)) })
|
|
3783
|
+
] });
|
|
3784
|
+
}
|
|
3785
|
+
function MainContent$1({ allRoutes, config, spec }) {
|
|
3786
|
+
const explorerData = JSON.stringify({
|
|
3787
|
+
routes: allRoutes,
|
|
3788
|
+
config,
|
|
3789
|
+
info: spec.info
|
|
3790
|
+
});
|
|
3791
|
+
const safeJson = explorerData.replace(/<\/script>/g, "<\\/script>");
|
|
3792
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("main", { class: "content", id: "main-content", children: [
|
|
3793
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { id: "ide-container", children: /* @__PURE__ */ jsxRuntime.jsx("div", { class: "empty-state", children: "Select a request to view details" }) }),
|
|
3794
|
+
/* @__PURE__ */ jsxRuntime.jsx("script", { id: "explorer-data", type: "application/json", dangerouslySetInnerHTML: { __html: safeJson } })
|
|
3795
|
+
] });
|
|
3796
|
+
}
|
|
3797
|
+
class ApiExplorerPlugin extends ShokupanRouter {
|
|
3798
|
+
constructor(pluginOptions = {}) {
|
|
3799
|
+
super({ renderer: renderToString });
|
|
3800
|
+
this.pluginOptions = pluginOptions;
|
|
3801
|
+
pluginOptions.path ??= "/explorer";
|
|
3802
|
+
}
|
|
3803
|
+
onInit(app, options) {
|
|
3804
|
+
const path2 = this.pluginOptions.path || options?.path || "/apiexplorer";
|
|
3805
|
+
app.mount(path2, this);
|
|
3806
|
+
if (app.applicationConfig.enableOpenApiGen !== true) {
|
|
3807
|
+
console.warn("ApiExplorerPlugin: enableOpenApiGen is disabled. ApiExplorerPlugin will not generate spec.");
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3810
|
+
static getBasePath() {
|
|
3811
|
+
const dir = path$1.dirname(node_url.fileURLToPath(typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("index.cjs", document.baseURI).href));
|
|
3812
|
+
if (dir.endsWith("dist")) {
|
|
3813
|
+
return dir + "/plugins/application/api-explorer";
|
|
3814
|
+
}
|
|
3815
|
+
return dir;
|
|
3816
|
+
}
|
|
3817
|
+
init() {
|
|
3818
|
+
const serveFile = async (ctx, file, type) => {
|
|
3819
|
+
const content = await promises$1.readFile(path$1.join(ApiExplorerPlugin.getBasePath(), "static", file), "utf-8");
|
|
3820
|
+
ctx.set("Content-Type", type);
|
|
3821
|
+
return ctx.send(content);
|
|
3822
|
+
};
|
|
3823
|
+
const stripSourceCode = (spec) => {
|
|
3824
|
+
if (!spec || !spec.paths) return spec;
|
|
3825
|
+
Object.values(spec.paths).forEach((methods) => {
|
|
3826
|
+
Object.values(methods).forEach((op) => {
|
|
3827
|
+
if (op["x-source-info"]?.snippet) {
|
|
3828
|
+
delete op["x-source-info"].snippet;
|
|
3829
|
+
}
|
|
3830
|
+
if (op["x-shokupan-source"]?.code) {
|
|
3831
|
+
delete op["x-shokupan-source"].code;
|
|
3832
|
+
}
|
|
3833
|
+
});
|
|
3834
|
+
});
|
|
3835
|
+
return spec;
|
|
3836
|
+
};
|
|
3837
|
+
this.get("/style.css", (ctx) => serveFile(ctx, "style.css", "text/css"));
|
|
3838
|
+
this.get("/theme.css", (ctx) => serveFile(ctx, "theme.css", "text/css"));
|
|
3839
|
+
this.get("/explorer-client.mjs", (ctx) => serveFile(ctx, "explorer-client.mjs", "application/javascript"));
|
|
3840
|
+
this.get("/_source", async (ctx) => {
|
|
3841
|
+
const file = ctx.query["file"];
|
|
3842
|
+
if (!file) return ctx.text("Missing file parameter", 400);
|
|
3843
|
+
try {
|
|
3844
|
+
const content = await promises$1.readFile(file, "utf-8");
|
|
3845
|
+
return ctx.text(content);
|
|
3846
|
+
} catch (err) {
|
|
3847
|
+
return ctx.text("File not found", 404);
|
|
3848
|
+
}
|
|
3849
|
+
});
|
|
3850
|
+
this.get("/openapi.json", async (ctx) => {
|
|
3851
|
+
const spec = this.root.openApiSpec ? structuredClone(this.root.openApiSpec) : await (this.root || this).generateApiSpec();
|
|
3852
|
+
return ctx.json(stripSourceCode(spec));
|
|
3853
|
+
});
|
|
3854
|
+
this.get("/", async (ctx) => {
|
|
3855
|
+
const spec = this.root.openApiSpec ? structuredClone(this.root.openApiSpec) : await (this.root || this).generateApiSpec();
|
|
3856
|
+
const asyncSpec = ctx.app.asyncApiSpec;
|
|
3857
|
+
return ctx.jsx(ApiExplorerApp({ spec: stripSourceCode(spec), asyncSpec }));
|
|
3858
|
+
});
|
|
3859
|
+
}
|
|
3860
|
+
}
|
|
3570
3861
|
function AsyncApiApp({ spec, serverUrl, base, disableSourceView, navTree }) {
|
|
3571
3862
|
return /* @__PURE__ */ jsxRuntime.jsxs("html", { lang: "en", children: [
|
|
3572
3863
|
/* @__PURE__ */ jsxRuntime.jsxs("head", { children: [
|
|
@@ -6407,6 +6698,7 @@ exports.$socket = $socket;
|
|
|
6407
6698
|
exports.$url = $url;
|
|
6408
6699
|
exports.$ws = $ws;
|
|
6409
6700
|
exports.All = All;
|
|
6701
|
+
exports.ApiExplorerPlugin = ApiExplorerPlugin;
|
|
6410
6702
|
exports.AsyncApiPlugin = AsyncApiPlugin;
|
|
6411
6703
|
exports.AuthPlugin = AuthPlugin;
|
|
6412
6704
|
exports.Body = Body;
|