flowdoc-gen 0.1.4 → 0.1.6
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/bin.js +2 -2
- package/dist/{chunk-ZJCRRUX7.js → chunk-KSXE5LV4.js} +68 -1
- package/dist/{generate-4NMSVNJF.js → generate-TGEAHUE2.js} +1 -1
- package/dist/index.cjs +79 -5
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +79 -5
- package/dist/{serve-AD6IWZXI.js → serve-M5UPSOY5.js} +1 -1
- package/package.json +1 -1
- package/ui-assets/index.css +1 -1
- package/ui-assets/ui.js +10 -10
package/dist/bin.js
CHANGED
|
@@ -13,11 +13,11 @@ program.command("init").description("Scaffold a flowdoc.config.ts in the current
|
|
|
13
13
|
init();
|
|
14
14
|
});
|
|
15
15
|
program.command("generate").description("Parse your routes and write docs to the output folder").option("-c, --config <path>", "Path to flowdoc config file").option("-o, --output <path>", "Override output directory").option("-q, --quiet", "Suppress output").action(async (opts) => {
|
|
16
|
-
const { generate } = await import("./generate-
|
|
16
|
+
const { generate } = await import("./generate-TGEAHUE2.js");
|
|
17
17
|
await generate(opts);
|
|
18
18
|
});
|
|
19
19
|
program.command("serve").description("Generate docs and serve them locally").option("-c, --config <path>", "Path to flowdoc config file").option("-o, --output <path>", "Override output directory").option("-p, --port <number>", "Port to serve on (default: 4000)", "4000").option("-w, --watch", "Re-generate docs on source file changes").option("--no-open", "Don't open browser automatically").action(async (opts) => {
|
|
20
|
-
const { serve } = await import("./serve-
|
|
20
|
+
const { serve } = await import("./serve-M5UPSOY5.js");
|
|
21
21
|
const serveOpts = {
|
|
22
22
|
port: opts.port ? parseInt(opts.port, 10) : 4e3,
|
|
23
23
|
noOpen: !opts.open,
|
|
@@ -885,14 +885,23 @@ var tryExtractRoute = (call, ctx) => {
|
|
|
885
885
|
const { requestBody, parameters } = extractFromMiddleware(middlewareArgs, ctx);
|
|
886
886
|
const pathParams = extractPathParameters(path);
|
|
887
887
|
const handlerInfo = extractHandlerInfo(handlerArg);
|
|
888
|
+
const responseSchemas = extractResponseSchemas(handlerArg);
|
|
888
889
|
const allParameters = mergeParameters(parameters, pathParams);
|
|
889
890
|
const tags = inferTags(path);
|
|
891
|
+
const responses = buildDefaultResponses(method);
|
|
892
|
+
for (const [code, schema] of Object.entries(responseSchemas)) {
|
|
893
|
+
const existing = responses[code] ?? { description: `HTTP ${code}` };
|
|
894
|
+
responses[code] = {
|
|
895
|
+
...existing,
|
|
896
|
+
content: { "application/json": { schema } }
|
|
897
|
+
};
|
|
898
|
+
}
|
|
890
899
|
const route = {
|
|
891
900
|
method,
|
|
892
901
|
path,
|
|
893
902
|
tags,
|
|
894
903
|
parameters: allParameters,
|
|
895
|
-
responses
|
|
904
|
+
responses,
|
|
896
905
|
middleware: middlewareArgs.map((m) => m.getText())
|
|
897
906
|
};
|
|
898
907
|
if (handlerInfo.summary !== void 0) route.summary = handlerInfo.summary;
|
|
@@ -951,6 +960,64 @@ var extractPathParameters = (path) => {
|
|
|
951
960
|
}
|
|
952
961
|
return params;
|
|
953
962
|
};
|
|
963
|
+
var extractResponseSchemas = (handler) => {
|
|
964
|
+
const result = {};
|
|
965
|
+
const calls = handler.getDescendantsOfKind(SyntaxKind3.CallExpression);
|
|
966
|
+
for (const call of calls) {
|
|
967
|
+
const expr = call.getExpression();
|
|
968
|
+
if (!Node5.isPropertyAccessExpression(expr)) continue;
|
|
969
|
+
const methodName = expr.getName();
|
|
970
|
+
if (methodName !== "json" && methodName !== "send") continue;
|
|
971
|
+
let statusCode = "200";
|
|
972
|
+
const callee = expr.getExpression();
|
|
973
|
+
if (Node5.isCallExpression(callee)) {
|
|
974
|
+
const statusExpr = callee.getExpression();
|
|
975
|
+
if (Node5.isPropertyAccessExpression(statusExpr) && statusExpr.getName() === "status") {
|
|
976
|
+
const statusArg = callee.getArguments()[0];
|
|
977
|
+
if (statusArg && Node5.isNumericLiteral(statusArg)) {
|
|
978
|
+
statusCode = statusArg.getText();
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
const args = call.getArguments();
|
|
983
|
+
if (args.length === 0) continue;
|
|
984
|
+
const arg = args[0];
|
|
985
|
+
if (!arg || !Node5.isObjectLiteralExpression(arg)) continue;
|
|
986
|
+
const schema = schemaFromObjectLiteral(arg);
|
|
987
|
+
if (schema && Object.keys(schema.properties ?? {}).length > 0) {
|
|
988
|
+
if (!result[statusCode]) result[statusCode] = schema;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
return result;
|
|
992
|
+
};
|
|
993
|
+
var schemaFromObjectLiteral = (obj) => {
|
|
994
|
+
const properties = {};
|
|
995
|
+
for (const prop of obj.getProperties()) {
|
|
996
|
+
if (!Node5.isPropertyAssignment(prop)) continue;
|
|
997
|
+
const name = prop.getNameNode().getText().replace(/['"]/g, "");
|
|
998
|
+
const init = prop.getInitializer();
|
|
999
|
+
if (!init) continue;
|
|
1000
|
+
properties[name] = schemaFromValue(init);
|
|
1001
|
+
}
|
|
1002
|
+
return { type: "object", properties };
|
|
1003
|
+
};
|
|
1004
|
+
var schemaFromValue = (expr) => {
|
|
1005
|
+
if (Node5.isStringLiteral(expr) || Node5.isTemplateExpression(expr) || Node5.isNoSubstitutionTemplateLiteral(expr))
|
|
1006
|
+
return { type: "string", example: Node5.isStringLiteral(expr) ? expr.getLiteralValue() : void 0 };
|
|
1007
|
+
if (Node5.isNumericLiteral(expr))
|
|
1008
|
+
return { type: "number", example: Number(expr.getLiteralValue()) };
|
|
1009
|
+
if (expr.getKind() === SyntaxKind3.TrueKeyword || expr.getKind() === SyntaxKind3.FalseKeyword)
|
|
1010
|
+
return { type: "boolean", example: expr.getKind() === SyntaxKind3.TrueKeyword };
|
|
1011
|
+
if (Node5.isNullLiteral(expr))
|
|
1012
|
+
return { type: "null" };
|
|
1013
|
+
if (Node5.isArrayLiteralExpression(expr)) {
|
|
1014
|
+
const items = expr.getElements()[0];
|
|
1015
|
+
return { type: "array", items: items ? schemaFromValue(items) : {} };
|
|
1016
|
+
}
|
|
1017
|
+
if (Node5.isObjectLiteralExpression(expr))
|
|
1018
|
+
return schemaFromObjectLiteral(expr);
|
|
1019
|
+
return {};
|
|
1020
|
+
};
|
|
954
1021
|
var extractHandlerInfo = (handler) => {
|
|
955
1022
|
const leadingComments = handler.getLeadingCommentRanges();
|
|
956
1023
|
if (leadingComments.length === 0) return {};
|
package/dist/index.cjs
CHANGED
|
@@ -925,14 +925,23 @@ var tryExtractRoute = (call, ctx) => {
|
|
|
925
925
|
const { requestBody, parameters } = extractFromMiddleware(middlewareArgs, ctx);
|
|
926
926
|
const pathParams = extractPathParameters(path);
|
|
927
927
|
const handlerInfo = extractHandlerInfo(handlerArg);
|
|
928
|
+
const responseSchemas = extractResponseSchemas(handlerArg);
|
|
928
929
|
const allParameters = mergeParameters(parameters, pathParams);
|
|
929
930
|
const tags = inferTags(path);
|
|
931
|
+
const responses = buildDefaultResponses(method);
|
|
932
|
+
for (const [code, schema] of Object.entries(responseSchemas)) {
|
|
933
|
+
const existing = responses[code] ?? { description: `HTTP ${code}` };
|
|
934
|
+
responses[code] = {
|
|
935
|
+
...existing,
|
|
936
|
+
content: { "application/json": { schema } }
|
|
937
|
+
};
|
|
938
|
+
}
|
|
930
939
|
const route = {
|
|
931
940
|
method,
|
|
932
941
|
path,
|
|
933
942
|
tags,
|
|
934
943
|
parameters: allParameters,
|
|
935
|
-
responses
|
|
944
|
+
responses,
|
|
936
945
|
middleware: middlewareArgs.map((m) => m.getText())
|
|
937
946
|
};
|
|
938
947
|
if (handlerInfo.summary !== void 0) route.summary = handlerInfo.summary;
|
|
@@ -991,6 +1000,64 @@ var extractPathParameters = (path) => {
|
|
|
991
1000
|
}
|
|
992
1001
|
return params;
|
|
993
1002
|
};
|
|
1003
|
+
var extractResponseSchemas = (handler) => {
|
|
1004
|
+
const result = {};
|
|
1005
|
+
const calls = handler.getDescendantsOfKind(import_ts_morph.SyntaxKind.CallExpression);
|
|
1006
|
+
for (const call of calls) {
|
|
1007
|
+
const expr = call.getExpression();
|
|
1008
|
+
if (!import_ts_morph.Node.isPropertyAccessExpression(expr)) continue;
|
|
1009
|
+
const methodName = expr.getName();
|
|
1010
|
+
if (methodName !== "json" && methodName !== "send") continue;
|
|
1011
|
+
let statusCode = "200";
|
|
1012
|
+
const callee = expr.getExpression();
|
|
1013
|
+
if (import_ts_morph.Node.isCallExpression(callee)) {
|
|
1014
|
+
const statusExpr = callee.getExpression();
|
|
1015
|
+
if (import_ts_morph.Node.isPropertyAccessExpression(statusExpr) && statusExpr.getName() === "status") {
|
|
1016
|
+
const statusArg = callee.getArguments()[0];
|
|
1017
|
+
if (statusArg && import_ts_morph.Node.isNumericLiteral(statusArg)) {
|
|
1018
|
+
statusCode = statusArg.getText();
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
const args = call.getArguments();
|
|
1023
|
+
if (args.length === 0) continue;
|
|
1024
|
+
const arg = args[0];
|
|
1025
|
+
if (!arg || !import_ts_morph.Node.isObjectLiteralExpression(arg)) continue;
|
|
1026
|
+
const schema = schemaFromObjectLiteral(arg);
|
|
1027
|
+
if (schema && Object.keys(schema.properties ?? {}).length > 0) {
|
|
1028
|
+
if (!result[statusCode]) result[statusCode] = schema;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
return result;
|
|
1032
|
+
};
|
|
1033
|
+
var schemaFromObjectLiteral = (obj) => {
|
|
1034
|
+
const properties = {};
|
|
1035
|
+
for (const prop of obj.getProperties()) {
|
|
1036
|
+
if (!import_ts_morph.Node.isPropertyAssignment(prop)) continue;
|
|
1037
|
+
const name = prop.getNameNode().getText().replace(/['"]/g, "");
|
|
1038
|
+
const init2 = prop.getInitializer();
|
|
1039
|
+
if (!init2) continue;
|
|
1040
|
+
properties[name] = schemaFromValue(init2);
|
|
1041
|
+
}
|
|
1042
|
+
return { type: "object", properties };
|
|
1043
|
+
};
|
|
1044
|
+
var schemaFromValue = (expr) => {
|
|
1045
|
+
if (import_ts_morph.Node.isStringLiteral(expr) || import_ts_morph.Node.isTemplateExpression(expr) || import_ts_morph.Node.isNoSubstitutionTemplateLiteral(expr))
|
|
1046
|
+
return { type: "string", example: import_ts_morph.Node.isStringLiteral(expr) ? expr.getLiteralValue() : void 0 };
|
|
1047
|
+
if (import_ts_morph.Node.isNumericLiteral(expr))
|
|
1048
|
+
return { type: "number", example: Number(expr.getLiteralValue()) };
|
|
1049
|
+
if (expr.getKind() === import_ts_morph.SyntaxKind.TrueKeyword || expr.getKind() === import_ts_morph.SyntaxKind.FalseKeyword)
|
|
1050
|
+
return { type: "boolean", example: expr.getKind() === import_ts_morph.SyntaxKind.TrueKeyword };
|
|
1051
|
+
if (import_ts_morph.Node.isNullLiteral(expr))
|
|
1052
|
+
return { type: "null" };
|
|
1053
|
+
if (import_ts_morph.Node.isArrayLiteralExpression(expr)) {
|
|
1054
|
+
const items = expr.getElements()[0];
|
|
1055
|
+
return { type: "array", items: items ? schemaFromValue(items) : {} };
|
|
1056
|
+
}
|
|
1057
|
+
if (import_ts_morph.Node.isObjectLiteralExpression(expr))
|
|
1058
|
+
return schemaFromObjectLiteral(expr);
|
|
1059
|
+
return {};
|
|
1060
|
+
};
|
|
994
1061
|
var extractHandlerInfo = (handler) => {
|
|
995
1062
|
const leadingComments = handler.getLeadingCommentRanges();
|
|
996
1063
|
if (leadingComments.length === 0) return {};
|
|
@@ -1333,6 +1400,7 @@ var MIME = {
|
|
|
1333
1400
|
".json": "application/json"
|
|
1334
1401
|
};
|
|
1335
1402
|
var flowdoc = (opts = {}) => {
|
|
1403
|
+
const disabled = opts.disabled ?? process.env.NODE_ENV === "production";
|
|
1336
1404
|
const cwd = process.cwd();
|
|
1337
1405
|
let outputDir = null;
|
|
1338
1406
|
let ready = false;
|
|
@@ -1361,6 +1429,10 @@ var flowdoc = (opts = {}) => {
|
|
|
1361
1429
|
}
|
|
1362
1430
|
})();
|
|
1363
1431
|
return async (req, res, next) => {
|
|
1432
|
+
if (disabled) {
|
|
1433
|
+
res.status(403).send("API docs are not available in this environment.");
|
|
1434
|
+
return;
|
|
1435
|
+
}
|
|
1364
1436
|
await init2;
|
|
1365
1437
|
if (initError || !outputDir) {
|
|
1366
1438
|
res.status(500).send(`flowdoc init failed: ${initError}`);
|
|
@@ -1370,8 +1442,9 @@ var flowdoc = (opts = {}) => {
|
|
|
1370
1442
|
if (urlPath === "/index.html") {
|
|
1371
1443
|
const brand = "#6366f1";
|
|
1372
1444
|
const baseUrl = `${req.protocol}://${req.get("host")}`;
|
|
1445
|
+
const docsBase = req.baseUrl || "";
|
|
1373
1446
|
res.setHeader("Content-Type", "text/html");
|
|
1374
|
-
res.send(buildHtml({ baseUrl, brand }));
|
|
1447
|
+
res.send(buildHtml({ baseUrl, brand, docsBase }));
|
|
1375
1448
|
return;
|
|
1376
1449
|
}
|
|
1377
1450
|
const filePath = (0, import_path6.join)(outputDir, urlPath);
|
|
@@ -1384,7 +1457,7 @@ var flowdoc = (opts = {}) => {
|
|
|
1384
1457
|
(0, import_fs6.createReadStream)(filePath).pipe(res);
|
|
1385
1458
|
};
|
|
1386
1459
|
};
|
|
1387
|
-
var buildHtml = ({ baseUrl, brand }) => `<!DOCTYPE html>
|
|
1460
|
+
var buildHtml = ({ baseUrl, brand, docsBase }) => `<!DOCTYPE html>
|
|
1388
1461
|
<html lang="en" class="dark">
|
|
1389
1462
|
<head>
|
|
1390
1463
|
<meta charset="UTF-8" />
|
|
@@ -1393,9 +1466,10 @@ var buildHtml = ({ baseUrl, brand }) => `<!DOCTYPE html>
|
|
|
1393
1466
|
<script>
|
|
1394
1467
|
window.__FLOWDOC_BRAND__ = "${brand}";
|
|
1395
1468
|
window.__FLOWDOC_BASE_URL__ = "${baseUrl}";
|
|
1469
|
+
window.__FLOWDOC_DOCS_BASE__ = "${docsBase}";
|
|
1396
1470
|
</script>
|
|
1397
|
-
<script type="module" crossorigin src="
|
|
1398
|
-
<link rel="stylesheet" href="
|
|
1471
|
+
<script type="module" crossorigin src="${docsBase}/assets/ui.js"></script>
|
|
1472
|
+
<link rel="stylesheet" href="${docsBase}/assets/index.css" />
|
|
1399
1473
|
</head>
|
|
1400
1474
|
<body><div id="root"></div></body>
|
|
1401
1475
|
</html>`;
|
package/dist/index.d.cts
CHANGED
|
@@ -131,6 +131,13 @@ interface FlowDocMiddlewareOptions {
|
|
|
131
131
|
config?: string;
|
|
132
132
|
/** Route prefix the middleware is mounted at — used only for the HTML shell */
|
|
133
133
|
path?: string;
|
|
134
|
+
/**
|
|
135
|
+
* Disable the docs endpoint. Useful for production environments.
|
|
136
|
+
* Defaults to `process.env.NODE_ENV === "production"` when not set,
|
|
137
|
+
* meaning docs are served in development and blocked in production.
|
|
138
|
+
* Pass `false` to explicitly enable in production; `true` to always block.
|
|
139
|
+
*/
|
|
140
|
+
disabled?: boolean;
|
|
134
141
|
}
|
|
135
142
|
/**
|
|
136
143
|
* Express middleware that serves flowdoc docs at whatever route you mount it on.
|
package/dist/index.d.ts
CHANGED
|
@@ -131,6 +131,13 @@ interface FlowDocMiddlewareOptions {
|
|
|
131
131
|
config?: string;
|
|
132
132
|
/** Route prefix the middleware is mounted at — used only for the HTML shell */
|
|
133
133
|
path?: string;
|
|
134
|
+
/**
|
|
135
|
+
* Disable the docs endpoint. Useful for production environments.
|
|
136
|
+
* Defaults to `process.env.NODE_ENV === "production"` when not set,
|
|
137
|
+
* meaning docs are served in development and blocked in production.
|
|
138
|
+
* Pass `false` to explicitly enable in production; `true` to always block.
|
|
139
|
+
*/
|
|
140
|
+
disabled?: boolean;
|
|
134
141
|
}
|
|
135
142
|
/**
|
|
136
143
|
* Express middleware that serves flowdoc docs at whatever route you mount it on.
|
package/dist/index.js
CHANGED
|
@@ -885,14 +885,23 @@ var tryExtractRoute = (call, ctx) => {
|
|
|
885
885
|
const { requestBody, parameters } = extractFromMiddleware(middlewareArgs, ctx);
|
|
886
886
|
const pathParams = extractPathParameters(path);
|
|
887
887
|
const handlerInfo = extractHandlerInfo(handlerArg);
|
|
888
|
+
const responseSchemas = extractResponseSchemas(handlerArg);
|
|
888
889
|
const allParameters = mergeParameters(parameters, pathParams);
|
|
889
890
|
const tags = inferTags(path);
|
|
891
|
+
const responses = buildDefaultResponses(method);
|
|
892
|
+
for (const [code, schema] of Object.entries(responseSchemas)) {
|
|
893
|
+
const existing = responses[code] ?? { description: `HTTP ${code}` };
|
|
894
|
+
responses[code] = {
|
|
895
|
+
...existing,
|
|
896
|
+
content: { "application/json": { schema } }
|
|
897
|
+
};
|
|
898
|
+
}
|
|
890
899
|
const route = {
|
|
891
900
|
method,
|
|
892
901
|
path,
|
|
893
902
|
tags,
|
|
894
903
|
parameters: allParameters,
|
|
895
|
-
responses
|
|
904
|
+
responses,
|
|
896
905
|
middleware: middlewareArgs.map((m) => m.getText())
|
|
897
906
|
};
|
|
898
907
|
if (handlerInfo.summary !== void 0) route.summary = handlerInfo.summary;
|
|
@@ -951,6 +960,64 @@ var extractPathParameters = (path) => {
|
|
|
951
960
|
}
|
|
952
961
|
return params;
|
|
953
962
|
};
|
|
963
|
+
var extractResponseSchemas = (handler) => {
|
|
964
|
+
const result = {};
|
|
965
|
+
const calls = handler.getDescendantsOfKind(SyntaxKind3.CallExpression);
|
|
966
|
+
for (const call of calls) {
|
|
967
|
+
const expr = call.getExpression();
|
|
968
|
+
if (!Node5.isPropertyAccessExpression(expr)) continue;
|
|
969
|
+
const methodName = expr.getName();
|
|
970
|
+
if (methodName !== "json" && methodName !== "send") continue;
|
|
971
|
+
let statusCode = "200";
|
|
972
|
+
const callee = expr.getExpression();
|
|
973
|
+
if (Node5.isCallExpression(callee)) {
|
|
974
|
+
const statusExpr = callee.getExpression();
|
|
975
|
+
if (Node5.isPropertyAccessExpression(statusExpr) && statusExpr.getName() === "status") {
|
|
976
|
+
const statusArg = callee.getArguments()[0];
|
|
977
|
+
if (statusArg && Node5.isNumericLiteral(statusArg)) {
|
|
978
|
+
statusCode = statusArg.getText();
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
const args = call.getArguments();
|
|
983
|
+
if (args.length === 0) continue;
|
|
984
|
+
const arg = args[0];
|
|
985
|
+
if (!arg || !Node5.isObjectLiteralExpression(arg)) continue;
|
|
986
|
+
const schema = schemaFromObjectLiteral(arg);
|
|
987
|
+
if (schema && Object.keys(schema.properties ?? {}).length > 0) {
|
|
988
|
+
if (!result[statusCode]) result[statusCode] = schema;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
return result;
|
|
992
|
+
};
|
|
993
|
+
var schemaFromObjectLiteral = (obj) => {
|
|
994
|
+
const properties = {};
|
|
995
|
+
for (const prop of obj.getProperties()) {
|
|
996
|
+
if (!Node5.isPropertyAssignment(prop)) continue;
|
|
997
|
+
const name = prop.getNameNode().getText().replace(/['"]/g, "");
|
|
998
|
+
const init2 = prop.getInitializer();
|
|
999
|
+
if (!init2) continue;
|
|
1000
|
+
properties[name] = schemaFromValue(init2);
|
|
1001
|
+
}
|
|
1002
|
+
return { type: "object", properties };
|
|
1003
|
+
};
|
|
1004
|
+
var schemaFromValue = (expr) => {
|
|
1005
|
+
if (Node5.isStringLiteral(expr) || Node5.isTemplateExpression(expr) || Node5.isNoSubstitutionTemplateLiteral(expr))
|
|
1006
|
+
return { type: "string", example: Node5.isStringLiteral(expr) ? expr.getLiteralValue() : void 0 };
|
|
1007
|
+
if (Node5.isNumericLiteral(expr))
|
|
1008
|
+
return { type: "number", example: Number(expr.getLiteralValue()) };
|
|
1009
|
+
if (expr.getKind() === SyntaxKind3.TrueKeyword || expr.getKind() === SyntaxKind3.FalseKeyword)
|
|
1010
|
+
return { type: "boolean", example: expr.getKind() === SyntaxKind3.TrueKeyword };
|
|
1011
|
+
if (Node5.isNullLiteral(expr))
|
|
1012
|
+
return { type: "null" };
|
|
1013
|
+
if (Node5.isArrayLiteralExpression(expr)) {
|
|
1014
|
+
const items = expr.getElements()[0];
|
|
1015
|
+
return { type: "array", items: items ? schemaFromValue(items) : {} };
|
|
1016
|
+
}
|
|
1017
|
+
if (Node5.isObjectLiteralExpression(expr))
|
|
1018
|
+
return schemaFromObjectLiteral(expr);
|
|
1019
|
+
return {};
|
|
1020
|
+
};
|
|
954
1021
|
var extractHandlerInfo = (handler) => {
|
|
955
1022
|
const leadingComments = handler.getLeadingCommentRanges();
|
|
956
1023
|
if (leadingComments.length === 0) return {};
|
|
@@ -1293,6 +1360,7 @@ var MIME = {
|
|
|
1293
1360
|
".json": "application/json"
|
|
1294
1361
|
};
|
|
1295
1362
|
var flowdoc = (opts = {}) => {
|
|
1363
|
+
const disabled = opts.disabled ?? process.env.NODE_ENV === "production";
|
|
1296
1364
|
const cwd = process.cwd();
|
|
1297
1365
|
let outputDir = null;
|
|
1298
1366
|
let ready = false;
|
|
@@ -1321,6 +1389,10 @@ var flowdoc = (opts = {}) => {
|
|
|
1321
1389
|
}
|
|
1322
1390
|
})();
|
|
1323
1391
|
return async (req, res, next) => {
|
|
1392
|
+
if (disabled) {
|
|
1393
|
+
res.status(403).send("API docs are not available in this environment.");
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1324
1396
|
await init2;
|
|
1325
1397
|
if (initError || !outputDir) {
|
|
1326
1398
|
res.status(500).send(`flowdoc init failed: ${initError}`);
|
|
@@ -1330,8 +1402,9 @@ var flowdoc = (opts = {}) => {
|
|
|
1330
1402
|
if (urlPath === "/index.html") {
|
|
1331
1403
|
const brand = "#6366f1";
|
|
1332
1404
|
const baseUrl = `${req.protocol}://${req.get("host")}`;
|
|
1405
|
+
const docsBase = req.baseUrl || "";
|
|
1333
1406
|
res.setHeader("Content-Type", "text/html");
|
|
1334
|
-
res.send(buildHtml({ baseUrl, brand }));
|
|
1407
|
+
res.send(buildHtml({ baseUrl, brand, docsBase }));
|
|
1335
1408
|
return;
|
|
1336
1409
|
}
|
|
1337
1410
|
const filePath = join5(outputDir, urlPath);
|
|
@@ -1344,7 +1417,7 @@ var flowdoc = (opts = {}) => {
|
|
|
1344
1417
|
createReadStream2(filePath).pipe(res);
|
|
1345
1418
|
};
|
|
1346
1419
|
};
|
|
1347
|
-
var buildHtml = ({ baseUrl, brand }) => `<!DOCTYPE html>
|
|
1420
|
+
var buildHtml = ({ baseUrl, brand, docsBase }) => `<!DOCTYPE html>
|
|
1348
1421
|
<html lang="en" class="dark">
|
|
1349
1422
|
<head>
|
|
1350
1423
|
<meta charset="UTF-8" />
|
|
@@ -1353,9 +1426,10 @@ var buildHtml = ({ baseUrl, brand }) => `<!DOCTYPE html>
|
|
|
1353
1426
|
<script>
|
|
1354
1427
|
window.__FLOWDOC_BRAND__ = "${brand}";
|
|
1355
1428
|
window.__FLOWDOC_BASE_URL__ = "${baseUrl}";
|
|
1429
|
+
window.__FLOWDOC_DOCS_BASE__ = "${docsBase}";
|
|
1356
1430
|
</script>
|
|
1357
|
-
<script type="module" crossorigin src="
|
|
1358
|
-
<link rel="stylesheet" href="
|
|
1431
|
+
<script type="module" crossorigin src="${docsBase}/assets/ui.js"></script>
|
|
1432
|
+
<link rel="stylesheet" href="${docsBase}/assets/index.css" />
|
|
1359
1433
|
</head>
|
|
1360
1434
|
<body><div id="root"></div></body>
|
|
1361
1435
|
</html>`;
|
package/package.json
CHANGED
package/ui-assets/index.css
CHANGED
|
@@ -1 +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:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";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}.sticky{position:sticky}.top-0{top:0}.mx-auto{margin-left:auto;margin-right:auto}.-mb-px{margin-bottom:-1px}.mb-1{margin-bottom:.25rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.h-12{height:3rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-96{max-height:24rem}.w-10{width:2.5rem}.w-12{width:3rem}.w-24{width:6rem}.w-64{width:16rem}.w-full{width:100%}.min-w-0{min-width:0px}.min-w-\[42px\]{min-width:42px}.min-w-\[52px\]{min-width:52px}.max-w-3xl{max-width:48rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.resize-y{resize:vertical}.grid-cols-\[1fr_auto_1fr\]{grid-template-columns:1fr auto 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.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))}.self-start{align-self:flex-start}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-\[var\(--brand\)\]{border-color:var(--brand)}.border-red-900\/50{border-color:#7f1d1d80}.border-slate-700{--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity, 1))}.border-slate-800{--tw-border-opacity: 1;border-color:rgb(30 41 59 / var(--tw-border-opacity, 1))}.bg-\[var\(--brand\)\]{background-color:var(--brand)}.bg-amber-500\/15{background-color:#f59e0b26}.bg-blue-500\/15{background-color:#3b82f626}.bg-emerald-500\/15{background-color:#10b98126}.bg-orange-500\/15{background-color:#f9731626}.bg-purple-500\/15{background-color:#a855f726}.bg-red-500\/15{background-color:#ef444426}.bg-red-950\/40{background-color:#450a0a66}.bg-slate-500\/15{background-color:#64748b26}.bg-slate-800{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.bg-slate-900{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity, 1))}.bg-slate-950{--tw-bg-opacity: 1;background-color:rgb(2 6 23 / var(--tw-bg-opacity, 1))}.p-3{padding:.75rem}.p-4{padding:1rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pl-0{padding-left:0}.pl-3{padding-left:.75rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.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}.leading-relaxed{line-height:1.625}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-\[var\(--brand\)\]{color:var(--brand)}.text-amber-400{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity, 1))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.text-orange-400{--tw-text-opacity: 1;color:rgb(251 146 60 / var(--tw-text-opacity, 1))}.text-purple-400{--tw-text-opacity: 1;color:rgb(192 132 252 / var(--tw-text-opacity, 1))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-slate-100{--tw-text-opacity: 1;color:rgb(241 245 249 / 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-slate-600{--tw-text-opacity: 1;color:rgb(71 85 105 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-inset{--tw-ring-inset: inset}.ring-amber-500\/20{--tw-ring-color: rgb(245 158 11 / .2)}.ring-blue-500\/20{--tw-ring-color: rgb(59 130 246 / .2)}.ring-emerald-500\/20{--tw-ring-color: rgb(16 185 129 / .2)}.ring-orange-500\/20{--tw-ring-color: rgb(249 115 22 / .2)}.ring-purple-500\/20{--tw-ring-color: rgb(168 85 247 / .2)}.ring-red-500\/20{--tw-ring-color: rgb(239 68 68 / .2)}.ring-slate-500\/20{--tw-ring-color: rgb(100 116 139 / .2)}.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-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}:root{--brand: #6366f1}*{box-sizing:border-box}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Inter,Segoe UI,sans-serif;-webkit-font-smoothing:antialiased}::-webkit-scrollbar{width:4px;height:4px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:#334155;border-radius:2px}.placeholder\:text-slate-600::-moz-placeholder{--tw-text-opacity: 1;color:rgb(71 85 105 / var(--tw-text-opacity, 1))}.placeholder\:text-slate-600::placeholder{--tw-text-opacity: 1;color:rgb(71 85 105 / var(--tw-text-opacity, 1))}.hover\:bg-slate-800\/50:hover{background-color:#1e293b80}.hover\:text-slate-200:hover{--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity, 1))}.hover\:text-slate-300:hover{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1))}.hover\:opacity-90:hover{opacity:.9}.focus\:border-\[var\(--brand\)\]:focus{border-color:var(--brand)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.disabled\:opacity-50:disabled{opacity:.5}
|
|
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:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";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}.sticky{position:sticky}.top-0{top:0}.mx-auto{margin-left:auto;margin-right:auto}.-mb-px{margin-bottom:-1px}.mb-1{margin-bottom:.25rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.h-12{height:3rem}.h-full{height:100%}.h-screen{height:100vh}.max-h-96{max-height:24rem}.w-10{width:2.5rem}.w-12{width:3rem}.w-24{width:6rem}.w-64{width:16rem}.w-full{width:100%}.min-w-0{min-width:0px}.min-w-\[42px\]{min-width:42px}.min-w-\[52px\]{min-width:52px}.max-w-3xl{max-width:48rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.resize-y{resize:vertical}.grid-cols-\[1fr_auto_1fr\]{grid-template-columns:1fr auto 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.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))}.self-start{align-self:flex-start}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-\[var\(--brand\)\]{border-color:var(--brand)}.border-red-900\/50{border-color:#7f1d1d80}.border-slate-700{--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity, 1))}.border-slate-800{--tw-border-opacity: 1;border-color:rgb(30 41 59 / var(--tw-border-opacity, 1))}.bg-\[var\(--brand\)\]{background-color:var(--brand)}.bg-amber-500\/15{background-color:#f59e0b26}.bg-blue-500\/15{background-color:#3b82f626}.bg-emerald-500\/15{background-color:#10b98126}.bg-orange-500\/15{background-color:#f9731626}.bg-purple-500\/15{background-color:#a855f726}.bg-red-500\/15{background-color:#ef444426}.bg-red-950\/40{background-color:#450a0a66}.bg-slate-500\/15{background-color:#64748b26}.bg-slate-800{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity, 1))}.bg-slate-900{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity, 1))}.bg-slate-950{--tw-bg-opacity: 1;background-color:rgb(2 6 23 / var(--tw-bg-opacity, 1))}.p-3{padding:.75rem}.p-4{padding:1rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pl-0{padding-left:0}.pl-1{padding-left:.25rem}.pl-3{padding-left:.75rem}.pt-2{padding-top:.5rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.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}.leading-relaxed{line-height:1.625}.tracking-tight{letter-spacing:-.025em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-\[var\(--brand\)\]{color:var(--brand)}.text-amber-400{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity, 1))}.text-green-400{--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity, 1))}.text-orange-400{--tw-text-opacity: 1;color:rgb(251 146 60 / var(--tw-text-opacity, 1))}.text-purple-400{--tw-text-opacity: 1;color:rgb(192 132 252 / var(--tw-text-opacity, 1))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-slate-100{--tw-text-opacity: 1;color:rgb(241 245 249 / 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-slate-600{--tw-text-opacity: 1;color:rgb(71 85 105 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-inset{--tw-ring-inset: inset}.ring-amber-500\/20{--tw-ring-color: rgb(245 158 11 / .2)}.ring-blue-500\/20{--tw-ring-color: rgb(59 130 246 / .2)}.ring-emerald-500\/20{--tw-ring-color: rgb(16 185 129 / .2)}.ring-orange-500\/20{--tw-ring-color: rgb(249 115 22 / .2)}.ring-purple-500\/20{--tw-ring-color: rgb(168 85 247 / .2)}.ring-red-500\/20{--tw-ring-color: rgb(239 68 68 / .2)}.ring-slate-500\/20{--tw-ring-color: rgb(100 116 139 / .2)}.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-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}:root{--brand: #6366f1}*{box-sizing:border-box}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Inter,Segoe UI,sans-serif;-webkit-font-smoothing:antialiased}::-webkit-scrollbar{width:4px;height:4px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:#334155;border-radius:2px}.placeholder\:text-slate-600::-moz-placeholder{--tw-text-opacity: 1;color:rgb(71 85 105 / var(--tw-text-opacity, 1))}.placeholder\:text-slate-600::placeholder{--tw-text-opacity: 1;color:rgb(71 85 105 / var(--tw-text-opacity, 1))}.hover\:bg-slate-800\/50:hover{background-color:#1e293b80}.hover\:text-slate-200:hover{--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity, 1))}.hover\:text-slate-300:hover{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity, 1))}.hover\:opacity-90:hover{opacity:.9}.focus\:border-\[var\(--brand\)\]:focus{border-color:var(--brand)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.disabled\:opacity-50:disabled{opacity:.5}
|