@api-doc-tor/express 0.1.0
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/chat-proxy.d.ts +12 -0
- package/dist/chat-proxy.d.ts.map +1 -0
- package/dist/chat-proxy.js +44 -0
- package/dist/chat-proxy.js.map +1 -0
- package/dist/docs-access-express.d.ts +16 -0
- package/dist/docs-access-express.d.ts.map +1 -0
- package/dist/docs-access-express.js +187 -0
- package/dist/docs-access-express.js.map +1 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +134 -0
- package/dist/index.js.map +1 -0
- package/package.json +36 -0
- package/static/assets/index-2Nv3pxOm.css +1 -0
- package/static/assets/index-6tehJlKh.js +214 -0
- package/static/assets/index-B148KlKZ.js +247 -0
- package/static/assets/index-B7AxOqhh.js +247 -0
- package/static/assets/index-BAVM9zLs.css +1 -0
- package/static/assets/index-BD4qyClR.js +216 -0
- package/static/assets/index-BZaQe_xi.css +1 -0
- package/static/assets/index-BjWlpH_h.js +216 -0
- package/static/assets/index-BmiFV0rx.css +1 -0
- package/static/assets/index-BqIvYIJT.js +247 -0
- package/static/assets/index-BwOiuEB4.js +216 -0
- package/static/assets/index-C372jkHK.js +214 -0
- package/static/assets/index-C9S9wEor.js +217 -0
- package/static/assets/index-Cd9PPQz6.css +1 -0
- package/static/assets/index-Cf2mt1FM.css +1 -0
- package/static/assets/index-Cfn42GaL.css +1 -0
- package/static/assets/index-Ckm4kbAk.css +1 -0
- package/static/assets/index-CzGmm9SR.css +1 -0
- package/static/assets/index-D0jOSazL.js +187 -0
- package/static/assets/index-D3-lCeHu.js +214 -0
- package/static/assets/index-DDRNEd4n.js +247 -0
- package/static/assets/index-DOyViYzn.js +247 -0
- package/static/assets/index-DZsbTHIg.js +214 -0
- package/static/assets/index-DaYbWEw0.js +190 -0
- package/static/assets/index-Djqsib7P.css +1 -0
- package/static/assets/index-Ds4IYSZ4.css +1 -0
- package/static/assets/index-Dzo0Xwn5.css +1 -0
- package/static/assets/index-L47Yb4hH.js +187 -0
- package/static/assets/index-NKfaEJl0.css +1 -0
- package/static/assets/index-U9Pdo8dD.js +214 -0
- package/static/assets/index-UVEGH1D3.css +1 -0
- package/static/assets/index-mZYiGRwU.css +1 -0
- package/static/assets/index-pOjZ5m-I.js +247 -0
- package/static/assets/index-rCcLuTWw.js +216 -0
- package/static/index.html +21 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Request, type RequestHandler, type Response, type Router } from "express";
|
|
2
|
+
export type { ChatProvider, ChatMessage } from "@api-doc-tor/core";
|
|
3
|
+
/**
|
|
4
|
+
* Proxy LLM: el cliente envía la clave del usuario en `X-API-Doc-Tor-LLM-Key` (no se persiste en servidor).
|
|
5
|
+
*/
|
|
6
|
+
export declare function handleChatProxy(req: Request, res: Response): Promise<void>;
|
|
7
|
+
export declare const chatProxyJsonMiddleware: RequestHandler;
|
|
8
|
+
/** POST `__chat` — acceso público (sin docsAccess). */
|
|
9
|
+
export declare function registerChatRoutes(router: Router): void;
|
|
10
|
+
/** POST `__chat` — solo si `check(req)` es true (p. ej. sesión docsAccess). */
|
|
11
|
+
export declare function registerChatRoutesProtected(router: Router, check: (req: Request) => boolean): void;
|
|
12
|
+
//# sourceMappingURL=chat-proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-proxy.d.ts","sourceRoot":"","sources":["../src/chat-proxy.ts"],"names":[],"mappings":"AACA,OAAgB,EAAE,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjG,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAQnE;;GAEG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAehF;AAED,eAAO,MAAM,uBAAuB,EAAE,cAA+C,CAAC;AAEtF,uDAAuD;AACvD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,+EAA+E;AAC/E,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,IAAI,CAYlG"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { runLlmProxy, LLM_KEY_HEADER } from "@api-doc-tor/core";
|
|
2
|
+
import express from "express";
|
|
3
|
+
function getApiKey(req) {
|
|
4
|
+
const h = req.headers[LLM_KEY_HEADER];
|
|
5
|
+
if (typeof h === "string" && h.trim())
|
|
6
|
+
return h.trim();
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Proxy LLM: el cliente envía la clave del usuario en `X-API-Doc-Tor-LLM-Key` (no se persiste en servidor).
|
|
11
|
+
*/
|
|
12
|
+
export async function handleChatProxy(req, res) {
|
|
13
|
+
const apiKey = getApiKey(req);
|
|
14
|
+
if (!apiKey) {
|
|
15
|
+
res.status(401).type("application/json").send(JSON.stringify({
|
|
16
|
+
error: "missing_api_key",
|
|
17
|
+
message: "Cabecera X-API-Doc-Tor-LLM-Key requerida",
|
|
18
|
+
}));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const body = req.body;
|
|
22
|
+
const result = await runLlmProxy(apiKey, body);
|
|
23
|
+
res.status(result.status).type("application/json").send(result.body);
|
|
24
|
+
}
|
|
25
|
+
export const chatProxyJsonMiddleware = express.json({ limit: "4mb" });
|
|
26
|
+
/** POST `__chat` — acceso público (sin docsAccess). */
|
|
27
|
+
export function registerChatRoutes(router) {
|
|
28
|
+
router.post("/__chat", chatProxyJsonMiddleware, (req, res) => void handleChatProxy(req, res));
|
|
29
|
+
}
|
|
30
|
+
/** POST `__chat` — solo si `check(req)` es true (p. ej. sesión docsAccess). */
|
|
31
|
+
export function registerChatRoutesProtected(router, check) {
|
|
32
|
+
router.post("/__chat", chatProxyJsonMiddleware, (req, res) => {
|
|
33
|
+
if (!check(req)) {
|
|
34
|
+
const base = req.baseUrl || "/";
|
|
35
|
+
res
|
|
36
|
+
.status(401)
|
|
37
|
+
.type("application/json")
|
|
38
|
+
.send(JSON.stringify({ error: "unauthorized", loginPath: `${base}/__auth/login` }));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
void handleChatProxy(req, res);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=chat-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-proxy.js","sourceRoot":"","sources":["../src/chat-proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA4B,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC1F,OAAO,OAA0E,MAAM,SAAS,CAAC;AAIjG,SAAS,SAAS,CAAC,GAAY;IAC7B,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACtC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE;QAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACvD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAY,EAAE,GAAa;IAC/D,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAC3C,IAAI,CAAC,SAAS,CAAC;YACb,KAAK,EAAE,iBAAiB;YACxB,OAAO,EAAE,0CAA0C;SACpD,CAAC,CACH,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,GAAG,CAAC,IAA2B,CAAC;IAC7C,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC/C,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAmB,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;AAEtF,uDAAuD;AACvD,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,uBAAuB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,KAAK,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAChG,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,2BAA2B,CAAC,MAAc,EAAE,KAAgC;IAC1F,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,uBAAuB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC3D,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;YAChB,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC;YAChC,GAAG;iBACA,MAAM,CAAC,GAAG,CAAC;iBACX,IAAI,CAAC,kBAAkB,CAAC;iBACxB,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,GAAG,IAAI,eAAe,EAAE,CAAC,CAAC,CAAC;YACtF,OAAO;QACT,CAAC;QACD,KAAK,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type DocsAccessConfig } from "@api-doc-tor/core/docs-access";
|
|
2
|
+
import type { OpenAPIV3 } from "openapi-types";
|
|
3
|
+
import { type Router } from "express";
|
|
4
|
+
export declare function attachDocsAccessToRouter(router: Router, options: {
|
|
5
|
+
document: OpenAPIV3.Document;
|
|
6
|
+
docsAccess: DocsAccessConfig;
|
|
7
|
+
branding?: import("@api-doc-tor/core/ui-branding").ApiDocTorUiBranding;
|
|
8
|
+
buildUiConfigJson: (branding?: import("@api-doc-tor/core/ui-branding").ApiDocTorUiBranding) => unknown;
|
|
9
|
+
presetBundle?: unknown;
|
|
10
|
+
specName: string;
|
|
11
|
+
presetName: string;
|
|
12
|
+
uiConfigName: string;
|
|
13
|
+
hasPreset: boolean;
|
|
14
|
+
staticRoot: string;
|
|
15
|
+
}): void;
|
|
16
|
+
//# sourceMappingURL=docs-access-express.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs-access-express.d.ts","sourceRoot":"","sources":["../src/docs-access-express.ts"],"names":[],"mappings":"AACA,OAAO,EAML,KAAK,gBAAgB,EAEtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAgB,EAA+B,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAwC5E,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IACP,QAAQ,EAAE,SAAS,CAAC,QAAQ,CAAC;IAC7B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,+BAA+B,EAAE,mBAAmB,CAAC;IACvE,iBAAiB,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,+BAA+B,EAAE,mBAAmB,KAAK,OAAO,CAAC;IACvG,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,GACA,IAAI,CAmKN"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { assertOpenAPI3 } from "@api-doc-tor/core";
|
|
2
|
+
import { filterOpenAPIDocumentForUser, findDocsUser, resolveSessionSecret, signDocsSession, verifyDocsSession, } from "@api-doc-tor/core/docs-access";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import express from "express";
|
|
5
|
+
import { registerChatRoutesProtected } from "./chat-proxy.js";
|
|
6
|
+
const COOKIE_DEFAULT = "api_doc_tor_session";
|
|
7
|
+
function escapeHtml(s) {
|
|
8
|
+
return s
|
|
9
|
+
.replace(/&/g, "&")
|
|
10
|
+
.replace(/</g, "<")
|
|
11
|
+
.replace(/>/g, ">")
|
|
12
|
+
.replace(/"/g, """);
|
|
13
|
+
}
|
|
14
|
+
function getCookie(req, name) {
|
|
15
|
+
const raw = req.headers.cookie;
|
|
16
|
+
if (!raw)
|
|
17
|
+
return undefined;
|
|
18
|
+
for (const part of raw.split(";")) {
|
|
19
|
+
const i = part.indexOf("=");
|
|
20
|
+
if (i === -1)
|
|
21
|
+
continue;
|
|
22
|
+
const k = part.slice(0, i).trim();
|
|
23
|
+
if (k !== name)
|
|
24
|
+
continue;
|
|
25
|
+
return decodeURIComponent(part.slice(i + 1).trim());
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
function getUserFromRequest(req, cfg, secret, cookieName) {
|
|
30
|
+
const token = getCookie(req, cookieName);
|
|
31
|
+
if (!token)
|
|
32
|
+
return null;
|
|
33
|
+
const v = verifyDocsSession(token, secret);
|
|
34
|
+
if (!v)
|
|
35
|
+
return null;
|
|
36
|
+
const u = cfg.users.find((x) => x.username === v.username);
|
|
37
|
+
return u ?? null;
|
|
38
|
+
}
|
|
39
|
+
export function attachDocsAccessToRouter(router, options) {
|
|
40
|
+
const cfg = options.docsAccess;
|
|
41
|
+
const { secret } = resolveSessionSecret(cfg.sessionSecret);
|
|
42
|
+
const cookieName = cfg.sessionCookieName ?? COOKIE_DEFAULT;
|
|
43
|
+
const maxAge = cfg.sessionMaxAgeSec ?? 60 * 60 * 24 * 7;
|
|
44
|
+
const loginTitle = cfg.loginTitle ?? "Acceso a la documentación";
|
|
45
|
+
const parseLogin = [
|
|
46
|
+
express.json(),
|
|
47
|
+
express.urlencoded({ extended: false }),
|
|
48
|
+
];
|
|
49
|
+
router.post("/__auth/login", ...parseLogin, (req, res) => {
|
|
50
|
+
const body = req.body;
|
|
51
|
+
const username = typeof body.username === "string" ? body.username : "";
|
|
52
|
+
const password = typeof body.password === "string" ? body.password : "";
|
|
53
|
+
const redirectRaw = typeof body.redirect === "string" ? body.redirect : "";
|
|
54
|
+
const user = findDocsUser(cfg, username, password);
|
|
55
|
+
if (!user) {
|
|
56
|
+
if (req.is("application/json")) {
|
|
57
|
+
res.status(401).type("application/json").send(JSON.stringify({ error: "invalid_credentials" }));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
res.status(401).type("text/html")
|
|
61
|
+
.send(`<!DOCTYPE html><html><head><meta charset="utf-8"><title>Error</title></head><body>
|
|
62
|
+
<p>Credenciales inválidas.</p><p><a href="${req.baseUrl}/__auth/login">Volver</a></p></body></html>`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const token = signDocsSession(user.username, secret, maxAge);
|
|
66
|
+
const base = req.baseUrl || "/";
|
|
67
|
+
res.cookie(cookieName, token, {
|
|
68
|
+
httpOnly: true,
|
|
69
|
+
sameSite: "lax",
|
|
70
|
+
path: base,
|
|
71
|
+
maxAge: maxAge * 1000,
|
|
72
|
+
});
|
|
73
|
+
let target = `${base}/`;
|
|
74
|
+
if (redirectRaw.startsWith("/") && (redirectRaw.startsWith(base) || redirectRaw.startsWith(`${base}/`))) {
|
|
75
|
+
target = redirectRaw;
|
|
76
|
+
}
|
|
77
|
+
else if (redirectRaw.startsWith("/") && !redirectRaw.includes("..")) {
|
|
78
|
+
target = redirectRaw;
|
|
79
|
+
}
|
|
80
|
+
if (req.is("application/json")) {
|
|
81
|
+
res.type("application/json").send(JSON.stringify({ ok: true, username: user.username }));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
res.redirect(302, target);
|
|
85
|
+
});
|
|
86
|
+
router.get("/__auth/login", (req, res) => {
|
|
87
|
+
if (getUserFromRequest(req, cfg, secret, cookieName)) {
|
|
88
|
+
const q = typeof req.query.redirect === "string" ? req.query.redirect : "";
|
|
89
|
+
const base = req.baseUrl || "/";
|
|
90
|
+
const safe = q.startsWith("/") && !q.includes("..") ? q : `${base}/`;
|
|
91
|
+
res.redirect(302, safe);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const redirect = typeof req.query.redirect === "string" ? escapeHtml(req.query.redirect) : `${req.baseUrl}/`;
|
|
95
|
+
const html = `<!DOCTYPE html>
|
|
96
|
+
<html lang="es">
|
|
97
|
+
<head>
|
|
98
|
+
<meta charset="utf-8"/>
|
|
99
|
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
100
|
+
<title>${escapeHtml(loginTitle)}</title>
|
|
101
|
+
<style>
|
|
102
|
+
body { font-family: system-ui, sans-serif; background: #0f172a; color: #e2e8f0; margin: 0; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
|
|
103
|
+
form { background: #1e293b; padding: 1.5rem; border-radius: 12px; min-width: 280px; }
|
|
104
|
+
label { display: block; margin-bottom: 0.5rem; font-size: 0.875rem; }
|
|
105
|
+
input { width: 100%; box-sizing: border-box; padding: 0.5rem; margin-bottom: 1rem; border-radius: 8px; border: 1px solid #475569; background: #0f172a; color: inherit; }
|
|
106
|
+
button { width: 100%; padding: 0.6rem; border-radius: 8px; border: none; background: #38bdf8; color: #0f172a; font-weight: 600; cursor: pointer; }
|
|
107
|
+
h1 { font-size: 1.125rem; margin: 0 0 1rem; }
|
|
108
|
+
</style>
|
|
109
|
+
</head>
|
|
110
|
+
<body>
|
|
111
|
+
<form method="post" action="${req.baseUrl}/__auth/login">
|
|
112
|
+
<h1>${escapeHtml(loginTitle)}</h1>
|
|
113
|
+
<input type="hidden" name="redirect" value="${redirect}"/>
|
|
114
|
+
<label>Usuario<input name="username" autocomplete="username" required/></label>
|
|
115
|
+
<label>Contraseña<input name="password" type="password" autocomplete="current-password" required/></label>
|
|
116
|
+
<button type="submit">Entrar</button>
|
|
117
|
+
</form>
|
|
118
|
+
</body>
|
|
119
|
+
</html>`;
|
|
120
|
+
res.type("text/html").send(html);
|
|
121
|
+
});
|
|
122
|
+
router.post("/__auth/logout", (req, res) => {
|
|
123
|
+
const base = req.baseUrl || "/";
|
|
124
|
+
res.clearCookie(cookieName, { path: base });
|
|
125
|
+
if (req.is("application/json")) {
|
|
126
|
+
res.type("application/json").send(JSON.stringify({ ok: true }));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
res.redirect(302, `${base}/__auth/login`);
|
|
130
|
+
});
|
|
131
|
+
router.get("/__auth/session", (req, res) => {
|
|
132
|
+
const user = getUserFromRequest(req, cfg, secret, cookieName);
|
|
133
|
+
if (!user) {
|
|
134
|
+
res.status(401).type("application/json").send(JSON.stringify({ error: "unauthorized" }));
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
res.type("application/json").send(JSON.stringify({
|
|
138
|
+
username: user.username,
|
|
139
|
+
allowedTags: user.allowedTags ?? null,
|
|
140
|
+
allowedPathPrefixes: user.allowedPathPrefixes ?? null,
|
|
141
|
+
}));
|
|
142
|
+
});
|
|
143
|
+
registerChatRoutesProtected(router, (req) => !!getUserFromRequest(req, cfg, secret, cookieName));
|
|
144
|
+
router.use((req, res, next) => {
|
|
145
|
+
const user = getUserFromRequest(req, cfg, secret, cookieName);
|
|
146
|
+
if (user) {
|
|
147
|
+
req.docsAccessUser = user;
|
|
148
|
+
return next();
|
|
149
|
+
}
|
|
150
|
+
const wantsJson = req.path.endsWith(".json") ||
|
|
151
|
+
(req.accepts("json") && !req.accepts("html")) ||
|
|
152
|
+
(req.path.includes("/assets/") && !req.accepts("html"));
|
|
153
|
+
if (wantsJson) {
|
|
154
|
+
res.status(401).type("application/json").send(JSON.stringify({ error: "unauthorized", loginPath: `${req.baseUrl}/__auth/login` }));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const here = req.originalUrl.split("?")[0] ?? "";
|
|
158
|
+
res.redirect(302, `${req.baseUrl}/__auth/login?redirect=${encodeURIComponent(here)}`);
|
|
159
|
+
});
|
|
160
|
+
router.get(`/${options.specName}`, (req, res) => {
|
|
161
|
+
const user = req.docsAccessUser;
|
|
162
|
+
const doc = filterOpenAPIDocumentForUser(options.document, user);
|
|
163
|
+
assertOpenAPI3(doc);
|
|
164
|
+
res.type("application/json").send(JSON.stringify(doc, null, 2));
|
|
165
|
+
});
|
|
166
|
+
if (options.hasPreset) {
|
|
167
|
+
router.get(`/${options.presetName}`, (_req, res) => {
|
|
168
|
+
res.type("application/json").send(JSON.stringify(options.presetBundle, null, 2));
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
router.get(`/${options.uiConfigName}`, (_req, res) => {
|
|
172
|
+
const cfgJson = options.buildUiConfigJson(options.branding);
|
|
173
|
+
res.type("application/json").send(JSON.stringify({ ...cfgJson, docsAuthRequired: true }, null, 2));
|
|
174
|
+
});
|
|
175
|
+
router.use(express.static(options.staticRoot, { index: false }));
|
|
176
|
+
router.get(/.*/, (req, res) => {
|
|
177
|
+
if (req.path.includes("/assets/")) {
|
|
178
|
+
res.status(404).send("Not Found");
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
res.sendFile(join(options.staticRoot, "index.html"), (err) => {
|
|
182
|
+
if (err)
|
|
183
|
+
res.status(500).send(err.message);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=docs-access-express.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs-access-express.js","sourceRoot":"","sources":["../src/docs-access-express.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type DocsAccessConfig } from "@api-doc-tor/core/docs-access";
|
|
2
|
+
import { type ApiDocTorPresetInput } from "@api-doc-tor/core/preset";
|
|
3
|
+
import { type ApiDocTorUiBranding } from "@api-doc-tor/core/ui-branding";
|
|
4
|
+
import type { OpenAPIV3 } from "openapi-types";
|
|
5
|
+
import type { Server } from "node:http";
|
|
6
|
+
import { type Application, type Router } from "express";
|
|
7
|
+
export type { ApiDocTorPresetInput } from "@api-doc-tor/core/preset";
|
|
8
|
+
export type { ApiDocTorUiBranding } from "@api-doc-tor/core/ui-branding";
|
|
9
|
+
export type { DocsAccessConfig, DocsAccessUser } from "@api-doc-tor/core/docs-access";
|
|
10
|
+
export interface ApiDocTorExpressOptions {
|
|
11
|
+
document: OpenAPIV3.Document;
|
|
12
|
+
/**
|
|
13
|
+
* URL base de la API real (p. ej. producción). Se inyecta como primer `servers[].url`
|
|
14
|
+
* en el OpenAPI servido para “Probar”, codegen y exports contra un backend existente.
|
|
15
|
+
*/
|
|
16
|
+
publicUrl?: string;
|
|
17
|
+
path?: string;
|
|
18
|
+
specFileName?: string;
|
|
19
|
+
uiConfigFileName?: string;
|
|
20
|
+
branding?: ApiDocTorUiBranding;
|
|
21
|
+
presetFileName?: string;
|
|
22
|
+
preset?: ApiDocTorPresetInput;
|
|
23
|
+
/**
|
|
24
|
+
* Acceso a la documentación por usuario/contraseña (JSON).
|
|
25
|
+
* Si está activo, `openapi.json` y la SPA quedan protegidos; cada usuario puede filtrar por tags/prefijos de ruta.
|
|
26
|
+
*/
|
|
27
|
+
docsAccess?: DocsAccessConfig;
|
|
28
|
+
staticRoot?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function apiDocTorRouter(options: ApiDocTorExpressOptions): Router;
|
|
31
|
+
export declare function setupApiDocTorExpress(app: Application, options: ApiDocTorExpressOptions): void;
|
|
32
|
+
/**
|
|
33
|
+
* Crea una aplicación Express que **solo** monta la documentación (OpenAPI + SPA).
|
|
34
|
+
* Úsala cuando no tengas otra app: `createApiDocTorApp(opts).listen(3333)`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createApiDocTorApp(options: ApiDocTorExpressOptions): Application;
|
|
37
|
+
/** Opciones extra para arrancar el servidor sin configurar `listen` a mano. */
|
|
38
|
+
export type ListenApiDocTorStandaloneOptions = ApiDocTorExpressOptions & {
|
|
39
|
+
/** Puerto; por defecto `process.env.PORT` o `3333`. */
|
|
40
|
+
port?: number;
|
|
41
|
+
/** Host; por defecto `process.env.HOST` o `0.0.0.0`. */
|
|
42
|
+
host?: string;
|
|
43
|
+
};
|
|
44
|
+
export type ListenApiDocTorStandaloneResult = {
|
|
45
|
+
app: Application;
|
|
46
|
+
server: Server;
|
|
47
|
+
port: number;
|
|
48
|
+
host: string;
|
|
49
|
+
/** URL típica para abrir el navegador (path de docs incluido). */
|
|
50
|
+
docsUrl: string;
|
|
51
|
+
/** Igual que `publicUrl` en opciones, normalizada; solo si se pasó. */
|
|
52
|
+
apiPublicUrl?: string;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Crea la app, escucha en puerto/host y resuelve cuando el servidor está listo.
|
|
56
|
+
* Pensado para “solo documentación”: no hace falta otra aplicación Express.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* await listenApiDocTorStandalone({ document: myOpenApi, path: "/docs" });
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare function listenApiDocTorStandalone(options: ListenApiDocTorStandaloneOptions): Promise<ListenApiDocTorStandaloneResult>;
|
|
64
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAC3F,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAqB,KAAK,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAC5F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAgB,EAAE,KAAK,WAAW,EAA+B,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAS9F,YAAY,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACrE,YAAY,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACzE,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAEtF,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,SAAS,CAAC,QAAQ,CAAC;IAC7B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,mBAAmB,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B;;;OAGG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AASD,wBAAgB,eAAe,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAyDxE;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,uBAAuB,GAAG,IAAI,CAG9F;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,uBAAuB,GAAG,WAAW,CAIhF;AAED,+EAA+E;AAC/E,MAAM,MAAM,gCAAgC,GAAG,uBAAuB,GAAG;IACvE,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,GAAG,EAAE,WAAW,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAiBF;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,gCAAgC,GACxC,OAAO,CAAC,+BAA+B,CAAC,CAyB1C"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { applyPublicUrlToDocument, assertOpenAPI3 } from "@api-doc-tor/core";
|
|
2
|
+
import { isDocsAccessEnabled } from "@api-doc-tor/core/docs-access";
|
|
3
|
+
import { createExportBundleFromPreset, isPresetNonEmpty, } from "@api-doc-tor/core/preset";
|
|
4
|
+
import { buildUiConfigJson } from "@api-doc-tor/core/ui-branding";
|
|
5
|
+
import express from "express";
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { registerChatRoutes } from "./chat-proxy.js";
|
|
10
|
+
import { attachDocsAccessToRouter } from "./docs-access-express.js";
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
function resolveStaticRoot(custom) {
|
|
13
|
+
if (custom)
|
|
14
|
+
return custom;
|
|
15
|
+
const pkgStatic = join(__dirname, "..", "static");
|
|
16
|
+
if (existsSync(join(pkgStatic, "index.html")))
|
|
17
|
+
return pkgStatic;
|
|
18
|
+
return join(__dirname, "..", "..", "ui", "dist");
|
|
19
|
+
}
|
|
20
|
+
export function apiDocTorRouter(options) {
|
|
21
|
+
const document = applyPublicUrlToDocument(options.document, options.publicUrl);
|
|
22
|
+
const specName = options.specFileName ?? "openapi.json";
|
|
23
|
+
const presetName = options.presetFileName ?? "preset.json";
|
|
24
|
+
const uiConfigName = options.uiConfigFileName ?? "ui-config.json";
|
|
25
|
+
const staticRoot = resolveStaticRoot(options.staticRoot);
|
|
26
|
+
const router = express.Router();
|
|
27
|
+
const hasPreset = isPresetNonEmpty(options.preset);
|
|
28
|
+
const presetBundle = hasPreset ? createExportBundleFromPreset(options.preset) : undefined;
|
|
29
|
+
if (isDocsAccessEnabled(options.docsAccess)) {
|
|
30
|
+
attachDocsAccessToRouter(router, {
|
|
31
|
+
document,
|
|
32
|
+
docsAccess: options.docsAccess,
|
|
33
|
+
branding: options.branding,
|
|
34
|
+
buildUiConfigJson: (b) => buildUiConfigJson(b),
|
|
35
|
+
presetBundle,
|
|
36
|
+
specName,
|
|
37
|
+
presetName,
|
|
38
|
+
uiConfigName,
|
|
39
|
+
hasPreset,
|
|
40
|
+
staticRoot,
|
|
41
|
+
});
|
|
42
|
+
return router;
|
|
43
|
+
}
|
|
44
|
+
registerChatRoutes(router);
|
|
45
|
+
router.get(`/${specName}`, (_req, res) => {
|
|
46
|
+
assertOpenAPI3(document);
|
|
47
|
+
res.type("application/json").send(JSON.stringify(document, null, 2));
|
|
48
|
+
});
|
|
49
|
+
if (hasPreset) {
|
|
50
|
+
router.get(`/${presetName}`, (_req, res) => {
|
|
51
|
+
res.type("application/json").send(JSON.stringify(presetBundle, null, 2));
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
router.get(`/${uiConfigName}`, (_req, res) => {
|
|
55
|
+
const cfg = buildUiConfigJson(options.branding);
|
|
56
|
+
res.type("application/json").send(JSON.stringify(cfg, null, 2));
|
|
57
|
+
});
|
|
58
|
+
router.use(express.static(staticRoot, { index: false }));
|
|
59
|
+
router.get(/.*/, (req, res) => {
|
|
60
|
+
if (req.path.includes("/assets/")) {
|
|
61
|
+
res.status(404).send("Not Found");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
res.sendFile(join(staticRoot, "index.html"), (err) => {
|
|
65
|
+
if (err)
|
|
66
|
+
res.status(500).send(err.message);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
return router;
|
|
70
|
+
}
|
|
71
|
+
export function setupApiDocTorExpress(app, options) {
|
|
72
|
+
const base = options.path ?? "/docs";
|
|
73
|
+
app.use(base, apiDocTorRouter(options));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Crea una aplicación Express que **solo** monta la documentación (OpenAPI + SPA).
|
|
77
|
+
* Úsala cuando no tengas otra app: `createApiDocTorApp(opts).listen(3333)`.
|
|
78
|
+
*/
|
|
79
|
+
export function createApiDocTorApp(options) {
|
|
80
|
+
const app = express();
|
|
81
|
+
setupApiDocTorExpress(app, options);
|
|
82
|
+
return app;
|
|
83
|
+
}
|
|
84
|
+
function resolveListenPort(opts) {
|
|
85
|
+
if (opts.port != null && Number.isFinite(opts.port))
|
|
86
|
+
return opts.port;
|
|
87
|
+
const env = process.env.PORT;
|
|
88
|
+
if (env != null && env !== "") {
|
|
89
|
+
const n = Number(env);
|
|
90
|
+
if (Number.isFinite(n))
|
|
91
|
+
return n;
|
|
92
|
+
}
|
|
93
|
+
return 3333;
|
|
94
|
+
}
|
|
95
|
+
function resolveListenHost(opts) {
|
|
96
|
+
if (opts.host != null && opts.host !== "")
|
|
97
|
+
return opts.host;
|
|
98
|
+
return process.env.HOST != null && process.env.HOST !== "" ? process.env.HOST : "0.0.0.0";
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Crea la app, escucha en puerto/host y resuelve cuando el servidor está listo.
|
|
102
|
+
* Pensado para “solo documentación”: no hace falta otra aplicación Express.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* await listenApiDocTorStandalone({ document: myOpenApi, path: "/docs" });
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export function listenApiDocTorStandalone(options) {
|
|
110
|
+
const app = createApiDocTorApp(options);
|
|
111
|
+
const port = resolveListenPort(options);
|
|
112
|
+
const host = resolveListenHost(options);
|
|
113
|
+
const path = options.path ?? "/docs";
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
const server = app.listen(port, host, () => {
|
|
116
|
+
const addr = server.address();
|
|
117
|
+
const realPort = typeof addr === "object" && addr && "port" in addr ? addr.port : port;
|
|
118
|
+
const displayHost = host === "0.0.0.0" || host === "::" ? "127.0.0.1" : host;
|
|
119
|
+
const docsUrl = `http://${displayHost}:${realPort}${path.endsWith("/") ? path.slice(0, -1) : path}`;
|
|
120
|
+
const rawPu = options.publicUrl?.trim();
|
|
121
|
+
const apiPublicUrl = rawPu ? rawPu.replace(/\/$/, "") : undefined;
|
|
122
|
+
resolve({
|
|
123
|
+
app,
|
|
124
|
+
server,
|
|
125
|
+
port: realPort,
|
|
126
|
+
host,
|
|
127
|
+
docsUrl,
|
|
128
|
+
...(apiPublicUrl != null ? { apiPublicUrl } : {}),
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
server.once("error", reject);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@api-doc-tor/express",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"static"
|
|
16
|
+
],
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"express": "^4.21.1",
|
|
19
|
+
"openapi-types": "^12.1.3",
|
|
20
|
+
"@api-doc-tor/core": "0.1.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/express": "^5.0.0",
|
|
24
|
+
"@types/node": "^22.10.0",
|
|
25
|
+
"tsx": "^4.19.2",
|
|
26
|
+
"typescript": "^5.7.2"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"express": "^4 || ^5"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"prebuild": "pnpm --filter @api-doc-tor/ui run build && node scripts/copy-ui.mjs",
|
|
33
|
+
"build": "tsc -p tsconfig.json",
|
|
34
|
+
"test": "node --import tsx/esm --test test/setup.test.ts"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:DM Sans,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.mb-2{margin-bottom:.5rem}.ml-2{margin-left:.5rem}.mt-1{margin-top:.25rem}.mt-4{margin-top:1rem}.block{display:block}.flex{display:flex}.hidden{display:none}.h-32{height:8rem}.max-h-64{max-height:16rem}.max-h-96{max-height:24rem}.min-h-0{min-height:0px}.min-h-screen{min-height:100vh}.w-12{width:3rem}.w-16{width:4rem}.w-20{width:5rem}.w-24{width:6rem}.w-64{width:16rem}.w-full{width:100%}.min-w-\[120px\]{min-width:120px}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.cursor-pointer{cursor:pointer}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-x-auto{overflow-x:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-lg{border-radius:.5rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-l-2{border-left-width:2px}.border-t{border-top-width:1px}.border-accent{--tw-border-opacity: 1;border-color:rgb(56 189 248 / var(--tw-border-opacity, 1))}.border-red-500\/30{border-color:#ef44444d}.border-surface-700{--tw-border-opacity: 1;border-color:rgb(36 48 68 / var(--tw-border-opacity, 1))}.bg-accent{--tw-bg-opacity: 1;background-color:rgb(56 189 248 / var(--tw-bg-opacity, 1))}.bg-accent\/20{background-color:#38bdf833}.bg-accent\/30{background-color:#38bdf84d}.bg-surface-700{--tw-bg-opacity: 1;background-color:rgb(36 48 68 / var(--tw-bg-opacity, 1))}.bg-surface-800{--tw-bg-opacity: 1;background-color:rgb(26 34 48 / var(--tw-bg-opacity, 1))}.bg-surface-900{--tw-bg-opacity: 1;background-color:rgb(18 23 31 / var(--tw-bg-opacity, 1))}.bg-surface-900\/50{background-color:#12171f80}.bg-surface-900\/80{background-color:#12171fcc}.bg-surface-950{--tw-bg-opacity: 1;background-color:rgb(12 15 20 / var(--tw-bg-opacity, 1))}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.text-left{text-align:left}.text-center{text-align:center}.font-display{font-family:Outfit,system-ui,sans-serif}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.text-accent{--tw-text-opacity: 1;color:rgb(56 189 248 / var(--tw-text-opacity, 1))}.text-emerald-300\/90{color:#6ee7b7e6}.text-red-200{--tw-text-opacity: 1;color:rgb(254 202 202 / var(--tw-text-opacity, 1))}.text-slate-200{--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity, 1))}.text-slate-300{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1))}.text-slate-400{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity, 1))}.text-slate-500{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity, 1))}.text-surface-950{--tw-text-opacity: 1;color:rgb(12 15 20 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-90{opacity:.9}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}body{margin:0}.hover\:bg-surface-700:hover{--tw-bg-opacity: 1;background-color:rgb(36 48 68 / var(--tw-bg-opacity, 1))}.hover\:bg-surface-800:hover{--tw-bg-opacity: 1;background-color:rgb(26 34 48 / var(--tw-bg-opacity, 1))}@media(min-width:768px){.md\:w-64{width:16rem}.md\:flex-row{flex-direction:row}.md\:flex-col{flex-direction:column}.md\:border-b-0{border-bottom-width:0px}.md\:border-r{border-right-width:1px}}@media(min-width:1024px){.lg\:max-h-none{max-height:none}.lg\:w-72{width:18rem}.lg\:flex-row{flex-direction:row}.lg\:border-b-0{border-bottom-width:0px}.lg\:border-r{border-right-width:1px}}
|