third-audience-mdx 1.0.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/CLAUDE.md +41 -0
- package/INSTALLATION.md +367 -0
- package/README.md +303 -0
- package/WORKLOG.md +162 -0
- package/dist/cli/index.d.mts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +208 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/index.mjs +185 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/dashboard/auth.d.mts +16 -0
- package/dist/dashboard/auth.d.ts +16 -0
- package/dist/dashboard/auth.js +123 -0
- package/dist/dashboard/auth.js.map +1 -0
- package/dist/dashboard/auth.mjs +87 -0
- package/dist/dashboard/auth.mjs.map +1 -0
- package/dist/dashboard/routes/analytics-api-route.d.mts +6 -0
- package/dist/dashboard/routes/analytics-api-route.d.ts +6 -0
- package/dist/dashboard/routes/analytics-api-route.js +180 -0
- package/dist/dashboard/routes/analytics-api-route.js.map +1 -0
- package/dist/dashboard/routes/analytics-api-route.mjs +145 -0
- package/dist/dashboard/routes/analytics-api-route.mjs.map +1 -0
- package/dist/dashboard/routes/api-key-route.d.mts +8 -0
- package/dist/dashboard/routes/api-key-route.d.ts +8 -0
- package/dist/dashboard/routes/api-key-route.js +173 -0
- package/dist/dashboard/routes/api-key-route.js.map +1 -0
- package/dist/dashboard/routes/api-key-route.mjs +137 -0
- package/dist/dashboard/routes/api-key-route.mjs.map +1 -0
- package/dist/dashboard/routes/citation-route.d.mts +14 -0
- package/dist/dashboard/routes/citation-route.d.ts +14 -0
- package/dist/dashboard/routes/citation-route.js +202 -0
- package/dist/dashboard/routes/citation-route.js.map +1 -0
- package/dist/dashboard/routes/citation-route.mjs +166 -0
- package/dist/dashboard/routes/citation-route.mjs.map +1 -0
- package/dist/dashboard/routes/llms-txt-route.d.mts +6 -0
- package/dist/dashboard/routes/llms-txt-route.d.ts +6 -0
- package/dist/dashboard/routes/llms-txt-route.js +119 -0
- package/dist/dashboard/routes/llms-txt-route.js.map +1 -0
- package/dist/dashboard/routes/llms-txt-route.mjs +84 -0
- package/dist/dashboard/routes/llms-txt-route.mjs.map +1 -0
- package/dist/dashboard/routes/login-route.d.mts +6 -0
- package/dist/dashboard/routes/login-route.d.ts +6 -0
- package/dist/dashboard/routes/login-route.js +313 -0
- package/dist/dashboard/routes/login-route.js.map +1 -0
- package/dist/dashboard/routes/login-route.mjs +284 -0
- package/dist/dashboard/routes/login-route.mjs.map +1 -0
- package/dist/dashboard/routes/markdown-route.d.mts +15 -0
- package/dist/dashboard/routes/markdown-route.d.ts +15 -0
- package/dist/dashboard/routes/markdown-route.js +239 -0
- package/dist/dashboard/routes/markdown-route.js.map +1 -0
- package/dist/dashboard/routes/markdown-route.mjs +204 -0
- package/dist/dashboard/routes/markdown-route.mjs.map +1 -0
- package/dist/dashboard/routes/okf-route.d.mts +13 -0
- package/dist/dashboard/routes/okf-route.d.ts +13 -0
- package/dist/dashboard/routes/okf-route.js +184 -0
- package/dist/dashboard/routes/okf-route.js.map +1 -0
- package/dist/dashboard/routes/okf-route.mjs +149 -0
- package/dist/dashboard/routes/okf-route.mjs.map +1 -0
- package/dist/dashboard/routes/sitemap-ai-route.d.mts +6 -0
- package/dist/dashboard/routes/sitemap-ai-route.d.ts +6 -0
- package/dist/dashboard/routes/sitemap-ai-route.js +134 -0
- package/dist/dashboard/routes/sitemap-ai-route.js.map +1 -0
- package/dist/dashboard/routes/sitemap-ai-route.mjs +99 -0
- package/dist/dashboard/routes/sitemap-ai-route.mjs.map +1 -0
- package/dist/dashboard/ui/components/Sidebar.d.mts +5 -0
- package/dist/dashboard/ui/components/Sidebar.d.ts +5 -0
- package/dist/dashboard/ui/components/Sidebar.js +102 -0
- package/dist/dashboard/ui/components/Sidebar.js.map +1 -0
- package/dist/dashboard/ui/components/Sidebar.mjs +68 -0
- package/dist/dashboard/ui/components/Sidebar.mjs.map +1 -0
- package/dist/dashboard/ui/globals.css +175 -0
- package/dist/dashboard/ui/pages/BotAnalyticsPage.d.mts +5 -0
- package/dist/dashboard/ui/pages/BotAnalyticsPage.d.ts +5 -0
- package/dist/dashboard/ui/pages/BotAnalyticsPage.js +269 -0
- package/dist/dashboard/ui/pages/BotAnalyticsPage.js.map +1 -0
- package/dist/dashboard/ui/pages/BotAnalyticsPage.mjs +232 -0
- package/dist/dashboard/ui/pages/BotAnalyticsPage.mjs.map +1 -0
- package/dist/dashboard/ui/pages/BotManagementPage.d.mts +13 -0
- package/dist/dashboard/ui/pages/BotManagementPage.d.ts +13 -0
- package/dist/dashboard/ui/pages/BotManagementPage.js +177 -0
- package/dist/dashboard/ui/pages/BotManagementPage.js.map +1 -0
- package/dist/dashboard/ui/pages/BotManagementPage.mjs +153 -0
- package/dist/dashboard/ui/pages/BotManagementPage.mjs.map +1 -0
- package/dist/dashboard/ui/pages/LlmTrafficPage.d.mts +5 -0
- package/dist/dashboard/ui/pages/LlmTrafficPage.d.ts +5 -0
- package/dist/dashboard/ui/pages/LlmTrafficPage.js +203 -0
- package/dist/dashboard/ui/pages/LlmTrafficPage.js.map +1 -0
- package/dist/dashboard/ui/pages/LlmTrafficPage.mjs +168 -0
- package/dist/dashboard/ui/pages/LlmTrafficPage.mjs.map +1 -0
- package/dist/dashboard/ui/pages/SettingsPage.d.mts +8 -0
- package/dist/dashboard/ui/pages/SettingsPage.d.ts +8 -0
- package/dist/dashboard/ui/pages/SettingsPage.js +181 -0
- package/dist/dashboard/ui/pages/SettingsPage.js.map +1 -0
- package/dist/dashboard/ui/pages/SettingsPage.mjs +157 -0
- package/dist/dashboard/ui/pages/SettingsPage.mjs.map +1 -0
- package/dist/dashboard/ui/pages/SystemHealthPage.d.mts +5 -0
- package/dist/dashboard/ui/pages/SystemHealthPage.d.ts +5 -0
- package/dist/dashboard/ui/pages/SystemHealthPage.js +183 -0
- package/dist/dashboard/ui/pages/SystemHealthPage.js.map +1 -0
- package/dist/dashboard/ui/pages/SystemHealthPage.mjs +148 -0
- package/dist/dashboard/ui/pages/SystemHealthPage.mjs.map +1 -0
- package/dist/index.d.mts +84 -0
- package/dist/index.d.ts +84 -0
- package/dist/index.js +372 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +346 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +125 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/dashboard/ui/pages/SystemHealthPage.tsx
|
|
31
|
+
var SystemHealthPage_exports = {};
|
|
32
|
+
__export(SystemHealthPage_exports, {
|
|
33
|
+
SystemHealthPage: () => SystemHealthPage
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(SystemHealthPage_exports);
|
|
36
|
+
var import_fs = __toESM(require("fs"));
|
|
37
|
+
var import_path = __toESM(require("path"));
|
|
38
|
+
|
|
39
|
+
// src/dashboard/ui/components/Card.tsx
|
|
40
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
41
|
+
function Card({ title, action, children }) {
|
|
42
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ta-card ta-section", children: [
|
|
43
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ta-card-header", children: [
|
|
44
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: title }),
|
|
45
|
+
action
|
|
46
|
+
] }),
|
|
47
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-card-body", children })
|
|
48
|
+
] });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/dashboard/ui/pages/SystemHealthPage.tsx
|
|
52
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
53
|
+
function runHealthChecks() {
|
|
54
|
+
const cwd = process.cwd();
|
|
55
|
+
const checks = [];
|
|
56
|
+
const [major] = process.versions.node.split(".").map(Number);
|
|
57
|
+
checks.push({
|
|
58
|
+
label: `Node.js ${process.versions.node}`,
|
|
59
|
+
status: major >= 18 ? "ok" : "error",
|
|
60
|
+
note: major < 18 ? "Requires Node 18+" : void 0
|
|
61
|
+
});
|
|
62
|
+
const contentDir = process.env.TA_CONTENT_DIR ?? "content";
|
|
63
|
+
const contentPath = import_path.default.join(cwd, contentDir);
|
|
64
|
+
const contentExists = import_fs.default.existsSync(contentPath);
|
|
65
|
+
let mdxCount = 0;
|
|
66
|
+
if (contentExists) {
|
|
67
|
+
let countMdx2 = function(dir) {
|
|
68
|
+
let n = 0;
|
|
69
|
+
for (const e of import_fs.default.readdirSync(dir, { withFileTypes: true })) {
|
|
70
|
+
if (e.isDirectory()) n += countMdx2(import_path.default.join(dir, e.name));
|
|
71
|
+
else if (e.name.endsWith(".mdx") || e.name.endsWith(".md")) n++;
|
|
72
|
+
}
|
|
73
|
+
return n;
|
|
74
|
+
};
|
|
75
|
+
var countMdx = countMdx2;
|
|
76
|
+
mdxCount = countMdx2(contentPath);
|
|
77
|
+
}
|
|
78
|
+
checks.push({
|
|
79
|
+
label: `Content directory (${contentDir})`,
|
|
80
|
+
status: contentExists ? "ok" : "warning",
|
|
81
|
+
note: contentExists ? `${mdxCount} MDX files` : "Not found \u2014 set TA_CONTENT_DIR"
|
|
82
|
+
});
|
|
83
|
+
const dataDir = process.env.TA_DATA_DIR ?? "data";
|
|
84
|
+
const dataPath = import_path.default.join(cwd, dataDir);
|
|
85
|
+
checks.push({
|
|
86
|
+
label: `Data directory (${dataDir})`,
|
|
87
|
+
status: import_fs.default.existsSync(dataPath) ? "ok" : "warning",
|
|
88
|
+
note: !import_fs.default.existsSync(dataPath) ? "Run `npx third-audience init`" : void 0
|
|
89
|
+
});
|
|
90
|
+
const visitsPath = import_path.default.join(cwd, dataDir, "ta-visits.jsonl");
|
|
91
|
+
const citPath = import_path.default.join(cwd, dataDir, "ta-citations.jsonl");
|
|
92
|
+
const visitLines = import_fs.default.existsSync(visitsPath) ? import_fs.default.readFileSync(visitsPath, "utf-8").split("\n").filter(Boolean).length : 0;
|
|
93
|
+
const citLines = import_fs.default.existsSync(citPath) ? import_fs.default.readFileSync(citPath, "utf-8").split("\n").filter(Boolean).length : 0;
|
|
94
|
+
checks.push({ label: "ta-visits.jsonl", status: "ok", note: `${visitLines.toLocaleString()} records` });
|
|
95
|
+
checks.push({ label: "ta-citations.jsonl", status: "ok", note: `${citLines.toLocaleString()} records` });
|
|
96
|
+
const cachePath = import_path.default.join(cwd, dataDir, "ta-cache");
|
|
97
|
+
const cacheExists = import_fs.default.existsSync(cachePath);
|
|
98
|
+
const cacheFiles = cacheExists ? import_fs.default.readdirSync(cachePath).filter((f) => f.endsWith(".json")).length : 0;
|
|
99
|
+
checks.push({ label: "Cache directory", status: "ok", note: `${cacheFiles} entries` });
|
|
100
|
+
checks.push({
|
|
101
|
+
label: "THIRD_AUDIENCE_SECRET",
|
|
102
|
+
status: process.env.THIRD_AUDIENCE_SECRET ? "ok" : "warning",
|
|
103
|
+
note: !process.env.THIRD_AUDIENCE_SECRET ? "Not set \u2014 dashboard is open to anyone" : "Set"
|
|
104
|
+
});
|
|
105
|
+
const middlewarePath = import_path.default.join(cwd, "middleware.ts");
|
|
106
|
+
checks.push({
|
|
107
|
+
label: "middleware.ts",
|
|
108
|
+
status: import_fs.default.existsSync(middlewarePath) ? "ok" : "warning",
|
|
109
|
+
note: !import_fs.default.existsSync(middlewarePath) ? "Not found \u2014 .md URLs and /llms.txt may not route correctly" : void 0
|
|
110
|
+
});
|
|
111
|
+
const hasErrors = checks.some((c) => c.status === "error");
|
|
112
|
+
const hasWarnings = checks.some((c) => c.status === "warning");
|
|
113
|
+
const overall = hasErrors ? "error" : hasWarnings ? "warning" : "ok";
|
|
114
|
+
return { checks, overall };
|
|
115
|
+
}
|
|
116
|
+
var STATUS_ICON = { ok: "\u2705", warning: "\u26A0\uFE0F", error: "\u274C" };
|
|
117
|
+
var STATUS_COLOR = {
|
|
118
|
+
ok: "var(--ta-green)",
|
|
119
|
+
warning: "var(--ta-orange)",
|
|
120
|
+
error: "var(--ta-red)"
|
|
121
|
+
};
|
|
122
|
+
var OVERALL_MSG = {
|
|
123
|
+
ok: "All systems operational",
|
|
124
|
+
warning: "Some optional features may be limited",
|
|
125
|
+
error: "Action required: system requirements not met"
|
|
126
|
+
};
|
|
127
|
+
async function SystemHealthPage() {
|
|
128
|
+
const { checks, overall } = runHealthChecks();
|
|
129
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
130
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { className: "ta-page-title", children: "System Health" }),
|
|
131
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "ta-page-subtitle", children: "Diagnostics and configuration status" }),
|
|
132
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ta-card ta-section", style: { borderLeft: `4px solid ${STATUS_COLOR[overall]}` }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ta-card-body", style: { display: "flex", alignItems: "center", gap: 14 }, children: [
|
|
133
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: 28 }, children: STATUS_ICON[overall] }),
|
|
134
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
135
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontWeight: 600, fontSize: 15 }, children: OVERALL_MSG[overall] }),
|
|
136
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { color: "var(--ta-gray-600)", fontSize: 13 }, children: [
|
|
137
|
+
checks.filter((c) => c.status === "ok").length,
|
|
138
|
+
"/",
|
|
139
|
+
checks.length,
|
|
140
|
+
" checks passing"
|
|
141
|
+
] })
|
|
142
|
+
] })
|
|
143
|
+
] }) }),
|
|
144
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card, { title: "System Checks", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { className: "ta-table", children: [
|
|
145
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
|
|
146
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: "Check" }),
|
|
147
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: "Status" }),
|
|
148
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { children: "Notes" })
|
|
149
|
+
] }) }),
|
|
150
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: checks.map((c) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
|
|
151
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: { fontWeight: 500 }, children: c.label }),
|
|
152
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: `ta-badge ta-badge--${c.status === "ok" ? "green" : c.status === "warning" ? "orange" : "red"}`, children: c.status }) }),
|
|
153
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: { color: "var(--ta-gray-600)", fontSize: 13 }, children: c.note ?? "\u2014" })
|
|
154
|
+
] }, c.label)) })
|
|
155
|
+
] }) }),
|
|
156
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card, { title: "Package Info", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "grid", gridTemplateColumns: "160px 1fr", gap: "8px 0", fontSize: 13 }, children: [
|
|
157
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "var(--ta-gray-600)" }, children: "Package" }),
|
|
158
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: "third-audience-mdx" }) }),
|
|
159
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "var(--ta-gray-600)" }, children: "Node.js" }),
|
|
160
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: process.versions.node }) }),
|
|
161
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "var(--ta-gray-600)" }, children: "Content dir" }),
|
|
162
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: process.env.TA_CONTENT_DIR ?? "content" }) }),
|
|
163
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "var(--ta-gray-600)" }, children: "Data dir" }),
|
|
164
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: process.env.TA_DATA_DIR ?? "data" }) }),
|
|
165
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "var(--ta-gray-600)" }, children: "Dashboard" }),
|
|
166
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: "/third-audience/" }) })
|
|
167
|
+
] }) }),
|
|
168
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card, { title: "Quick Links", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 10 }, children: [
|
|
169
|
+
{ href: "/llms.txt", label: "/llms.txt" },
|
|
170
|
+
{ href: "/sitemap-ai.xml", label: "/sitemap-ai.xml" },
|
|
171
|
+
{ href: "/okf/", label: "/okf/" },
|
|
172
|
+
{ href: "/okf/index.md", label: "/okf/index.md" }
|
|
173
|
+
].map((link) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("a", { href: link.href, target: "_blank", rel: "noreferrer", className: "ta-btn ta-btn--ghost", children: [
|
|
174
|
+
link.label,
|
|
175
|
+
" \u2197"
|
|
176
|
+
] }, link.href)) }) })
|
|
177
|
+
] });
|
|
178
|
+
}
|
|
179
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
180
|
+
0 && (module.exports = {
|
|
181
|
+
SystemHealthPage
|
|
182
|
+
});
|
|
183
|
+
//# sourceMappingURL=SystemHealthPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/dashboard/ui/pages/SystemHealthPage.tsx","../../../../src/dashboard/ui/components/Card.tsx"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport { Card } from '../components/Card.js'\n\ninterface HealthCheck {\n label: string\n status: 'ok' | 'warning' | 'error'\n note?: string\n}\n\nfunction runHealthChecks(): { checks: HealthCheck[]; overall: 'ok' | 'warning' | 'error' } {\n const cwd = process.cwd()\n const checks: HealthCheck[] = []\n\n // Node version\n const [major] = process.versions.node.split('.').map(Number)\n checks.push({\n label: `Node.js ${process.versions.node}`,\n status: major >= 18 ? 'ok' : 'error',\n note: major < 18 ? 'Requires Node 18+' : undefined,\n })\n\n // Content dir\n const contentDir = process.env.TA_CONTENT_DIR ?? 'content'\n const contentPath = path.join(cwd, contentDir)\n const contentExists = fs.existsSync(contentPath)\n let mdxCount = 0\n if (contentExists) {\n function countMdx(dir: string): number {\n let n = 0\n for (const e of fs.readdirSync(dir, { withFileTypes: true })) {\n if (e.isDirectory()) n += countMdx(path.join(dir, e.name))\n else if (e.name.endsWith('.mdx') || e.name.endsWith('.md')) n++\n }\n return n\n }\n mdxCount = countMdx(contentPath)\n }\n checks.push({\n label: `Content directory (${contentDir})`,\n status: contentExists ? 'ok' : 'warning',\n note: contentExists ? `${mdxCount} MDX files` : 'Not found — set TA_CONTENT_DIR',\n })\n\n // Data dir\n const dataDir = process.env.TA_DATA_DIR ?? 'data'\n const dataPath = path.join(cwd, dataDir)\n checks.push({\n label: `Data directory (${dataDir})`,\n status: fs.existsSync(dataPath) ? 'ok' : 'warning',\n note: !fs.existsSync(dataPath) ? 'Run `npx third-audience init`' : undefined,\n })\n\n // JSONL files\n const visitsPath = path.join(cwd, dataDir, 'ta-visits.jsonl')\n const citPath = path.join(cwd, dataDir, 'ta-citations.jsonl')\n const visitLines = fs.existsSync(visitsPath) ? fs.readFileSync(visitsPath, 'utf-8').split('\\n').filter(Boolean).length : 0\n const citLines = fs.existsSync(citPath) ? fs.readFileSync(citPath, 'utf-8').split('\\n').filter(Boolean).length : 0\n checks.push({ label: 'ta-visits.jsonl', status: 'ok', note: `${visitLines.toLocaleString()} records` })\n checks.push({ label: 'ta-citations.jsonl', status: 'ok', note: `${citLines.toLocaleString()} records` })\n\n // Cache dir\n const cachePath = path.join(cwd, dataDir, 'ta-cache')\n const cacheExists = fs.existsSync(cachePath)\n const cacheFiles = cacheExists ? fs.readdirSync(cachePath).filter(f => f.endsWith('.json')).length : 0\n checks.push({ label: 'Cache directory', status: 'ok', note: `${cacheFiles} entries` })\n\n // Dashboard secret\n checks.push({\n label: 'THIRD_AUDIENCE_SECRET',\n status: process.env.THIRD_AUDIENCE_SECRET ? 'ok' : 'warning',\n note: !process.env.THIRD_AUDIENCE_SECRET ? 'Not set — dashboard is open to anyone' : 'Set',\n })\n\n // Middleware\n const middlewarePath = path.join(cwd, 'middleware.ts')\n checks.push({\n label: 'middleware.ts',\n status: fs.existsSync(middlewarePath) ? 'ok' : 'warning',\n note: !fs.existsSync(middlewarePath) ? 'Not found — .md URLs and /llms.txt may not route correctly' : undefined,\n })\n\n const hasErrors = checks.some(c => c.status === 'error')\n const hasWarnings = checks.some(c => c.status === 'warning')\n const overall = hasErrors ? 'error' : hasWarnings ? 'warning' : 'ok'\n\n return { checks, overall }\n}\n\nconst STATUS_ICON: Record<string, string> = { ok: '✅', warning: '⚠️', error: '❌' }\nconst STATUS_COLOR: Record<string, string> = {\n ok: 'var(--ta-green)', warning: 'var(--ta-orange)', error: 'var(--ta-red)',\n}\nconst OVERALL_MSG: Record<string, string> = {\n ok: 'All systems operational',\n warning: 'Some optional features may be limited',\n error: 'Action required: system requirements not met',\n}\n\nexport async function SystemHealthPage() {\n const { checks, overall } = runHealthChecks()\n\n return (\n <div>\n <h1 className=\"ta-page-title\">System Health</h1>\n <p className=\"ta-page-subtitle\">Diagnostics and configuration status</p>\n\n {/* Overall status banner */}\n <div className=\"ta-card ta-section\" style={{ borderLeft: `4px solid ${STATUS_COLOR[overall]}` }}>\n <div className=\"ta-card-body\" style={{ display: 'flex', alignItems: 'center', gap: 14 }}>\n <span style={{ fontSize: 28 }}>{STATUS_ICON[overall]}</span>\n <div>\n <div style={{ fontWeight: 600, fontSize: 15 }}>{OVERALL_MSG[overall]}</div>\n <div style={{ color: 'var(--ta-gray-600)', fontSize: 13 }}>\n {checks.filter(c => c.status === 'ok').length}/{checks.length} checks passing\n </div>\n </div>\n </div>\n </div>\n\n <Card title=\"System Checks\">\n <table className=\"ta-table\">\n <thead><tr><th>Check</th><th>Status</th><th>Notes</th></tr></thead>\n <tbody>\n {checks.map(c => (\n <tr key={c.label}>\n <td style={{ fontWeight: 500 }}>{c.label}</td>\n <td>\n <span className={`ta-badge ta-badge--${c.status === 'ok' ? 'green' : c.status === 'warning' ? 'orange' : 'red'}`}>\n {c.status}\n </span>\n </td>\n <td style={{ color: 'var(--ta-gray-600)', fontSize: 13 }}>{c.note ?? '—'}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </Card>\n\n <Card title=\"Package Info\">\n <div style={{ display: 'grid', gridTemplateColumns: '160px 1fr', gap: '8px 0', fontSize: 13 }}>\n <span style={{ color: 'var(--ta-gray-600)' }}>Package</span>\n <span><code>third-audience-mdx</code></span>\n <span style={{ color: 'var(--ta-gray-600)' }}>Node.js</span>\n <span><code>{process.versions.node}</code></span>\n <span style={{ color: 'var(--ta-gray-600)' }}>Content dir</span>\n <span><code>{process.env.TA_CONTENT_DIR ?? 'content'}</code></span>\n <span style={{ color: 'var(--ta-gray-600)' }}>Data dir</span>\n <span><code>{process.env.TA_DATA_DIR ?? 'data'}</code></span>\n <span style={{ color: 'var(--ta-gray-600)' }}>Dashboard</span>\n <span><code>/third-audience/</code></span>\n </div>\n </Card>\n\n <Card title=\"Quick Links\">\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>\n {[\n { href: '/llms.txt', label: '/llms.txt' },\n { href: '/sitemap-ai.xml', label: '/sitemap-ai.xml' },\n { href: '/okf/', label: '/okf/' },\n { href: '/okf/index.md', label: '/okf/index.md' },\n ].map(link => (\n <a key={link.href} href={link.href} target=\"_blank\" rel=\"noreferrer\" className=\"ta-btn ta-btn--ghost\">\n {link.label} ↗\n </a>\n ))}\n </div>\n </Card>\n </div>\n )\n}\n","import type { ReactNode } from 'react'\n\ninterface CardProps {\n title: string\n action?: ReactNode\n children: ReactNode\n}\n\nexport function Card({ title, action, children }: CardProps) {\n return (\n <div className=\"ta-card ta-section\">\n <div className=\"ta-card-header\">\n <h2>{title}</h2>\n {action}\n </div>\n <div className=\"ta-card-body\">{children}</div>\n </div>\n )\n}\n"],"mappings":"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","names":["import_jsx_runtime","path","fs","countMdx"]}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// src/dashboard/ui/pages/SystemHealthPage.tsx
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
// src/dashboard/ui/components/Card.tsx
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
function Card({ title, action, children }) {
|
|
8
|
+
return /* @__PURE__ */ jsxs("div", { className: "ta-card ta-section", children: [
|
|
9
|
+
/* @__PURE__ */ jsxs("div", { className: "ta-card-header", children: [
|
|
10
|
+
/* @__PURE__ */ jsx("h2", { children: title }),
|
|
11
|
+
action
|
|
12
|
+
] }),
|
|
13
|
+
/* @__PURE__ */ jsx("div", { className: "ta-card-body", children })
|
|
14
|
+
] });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/dashboard/ui/pages/SystemHealthPage.tsx
|
|
18
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
19
|
+
function runHealthChecks() {
|
|
20
|
+
const cwd = process.cwd();
|
|
21
|
+
const checks = [];
|
|
22
|
+
const [major] = process.versions.node.split(".").map(Number);
|
|
23
|
+
checks.push({
|
|
24
|
+
label: `Node.js ${process.versions.node}`,
|
|
25
|
+
status: major >= 18 ? "ok" : "error",
|
|
26
|
+
note: major < 18 ? "Requires Node 18+" : void 0
|
|
27
|
+
});
|
|
28
|
+
const contentDir = process.env.TA_CONTENT_DIR ?? "content";
|
|
29
|
+
const contentPath = path.join(cwd, contentDir);
|
|
30
|
+
const contentExists = fs.existsSync(contentPath);
|
|
31
|
+
let mdxCount = 0;
|
|
32
|
+
if (contentExists) {
|
|
33
|
+
let countMdx2 = function(dir) {
|
|
34
|
+
let n = 0;
|
|
35
|
+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
36
|
+
if (e.isDirectory()) n += countMdx2(path.join(dir, e.name));
|
|
37
|
+
else if (e.name.endsWith(".mdx") || e.name.endsWith(".md")) n++;
|
|
38
|
+
}
|
|
39
|
+
return n;
|
|
40
|
+
};
|
|
41
|
+
var countMdx = countMdx2;
|
|
42
|
+
mdxCount = countMdx2(contentPath);
|
|
43
|
+
}
|
|
44
|
+
checks.push({
|
|
45
|
+
label: `Content directory (${contentDir})`,
|
|
46
|
+
status: contentExists ? "ok" : "warning",
|
|
47
|
+
note: contentExists ? `${mdxCount} MDX files` : "Not found \u2014 set TA_CONTENT_DIR"
|
|
48
|
+
});
|
|
49
|
+
const dataDir = process.env.TA_DATA_DIR ?? "data";
|
|
50
|
+
const dataPath = path.join(cwd, dataDir);
|
|
51
|
+
checks.push({
|
|
52
|
+
label: `Data directory (${dataDir})`,
|
|
53
|
+
status: fs.existsSync(dataPath) ? "ok" : "warning",
|
|
54
|
+
note: !fs.existsSync(dataPath) ? "Run `npx third-audience init`" : void 0
|
|
55
|
+
});
|
|
56
|
+
const visitsPath = path.join(cwd, dataDir, "ta-visits.jsonl");
|
|
57
|
+
const citPath = path.join(cwd, dataDir, "ta-citations.jsonl");
|
|
58
|
+
const visitLines = fs.existsSync(visitsPath) ? fs.readFileSync(visitsPath, "utf-8").split("\n").filter(Boolean).length : 0;
|
|
59
|
+
const citLines = fs.existsSync(citPath) ? fs.readFileSync(citPath, "utf-8").split("\n").filter(Boolean).length : 0;
|
|
60
|
+
checks.push({ label: "ta-visits.jsonl", status: "ok", note: `${visitLines.toLocaleString()} records` });
|
|
61
|
+
checks.push({ label: "ta-citations.jsonl", status: "ok", note: `${citLines.toLocaleString()} records` });
|
|
62
|
+
const cachePath = path.join(cwd, dataDir, "ta-cache");
|
|
63
|
+
const cacheExists = fs.existsSync(cachePath);
|
|
64
|
+
const cacheFiles = cacheExists ? fs.readdirSync(cachePath).filter((f) => f.endsWith(".json")).length : 0;
|
|
65
|
+
checks.push({ label: "Cache directory", status: "ok", note: `${cacheFiles} entries` });
|
|
66
|
+
checks.push({
|
|
67
|
+
label: "THIRD_AUDIENCE_SECRET",
|
|
68
|
+
status: process.env.THIRD_AUDIENCE_SECRET ? "ok" : "warning",
|
|
69
|
+
note: !process.env.THIRD_AUDIENCE_SECRET ? "Not set \u2014 dashboard is open to anyone" : "Set"
|
|
70
|
+
});
|
|
71
|
+
const middlewarePath = path.join(cwd, "middleware.ts");
|
|
72
|
+
checks.push({
|
|
73
|
+
label: "middleware.ts",
|
|
74
|
+
status: fs.existsSync(middlewarePath) ? "ok" : "warning",
|
|
75
|
+
note: !fs.existsSync(middlewarePath) ? "Not found \u2014 .md URLs and /llms.txt may not route correctly" : void 0
|
|
76
|
+
});
|
|
77
|
+
const hasErrors = checks.some((c) => c.status === "error");
|
|
78
|
+
const hasWarnings = checks.some((c) => c.status === "warning");
|
|
79
|
+
const overall = hasErrors ? "error" : hasWarnings ? "warning" : "ok";
|
|
80
|
+
return { checks, overall };
|
|
81
|
+
}
|
|
82
|
+
var STATUS_ICON = { ok: "\u2705", warning: "\u26A0\uFE0F", error: "\u274C" };
|
|
83
|
+
var STATUS_COLOR = {
|
|
84
|
+
ok: "var(--ta-green)",
|
|
85
|
+
warning: "var(--ta-orange)",
|
|
86
|
+
error: "var(--ta-red)"
|
|
87
|
+
};
|
|
88
|
+
var OVERALL_MSG = {
|
|
89
|
+
ok: "All systems operational",
|
|
90
|
+
warning: "Some optional features may be limited",
|
|
91
|
+
error: "Action required: system requirements not met"
|
|
92
|
+
};
|
|
93
|
+
async function SystemHealthPage() {
|
|
94
|
+
const { checks, overall } = runHealthChecks();
|
|
95
|
+
return /* @__PURE__ */ jsxs2("div", { children: [
|
|
96
|
+
/* @__PURE__ */ jsx2("h1", { className: "ta-page-title", children: "System Health" }),
|
|
97
|
+
/* @__PURE__ */ jsx2("p", { className: "ta-page-subtitle", children: "Diagnostics and configuration status" }),
|
|
98
|
+
/* @__PURE__ */ jsx2("div", { className: "ta-card ta-section", style: { borderLeft: `4px solid ${STATUS_COLOR[overall]}` }, children: /* @__PURE__ */ jsxs2("div", { className: "ta-card-body", style: { display: "flex", alignItems: "center", gap: 14 }, children: [
|
|
99
|
+
/* @__PURE__ */ jsx2("span", { style: { fontSize: 28 }, children: STATUS_ICON[overall] }),
|
|
100
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
101
|
+
/* @__PURE__ */ jsx2("div", { style: { fontWeight: 600, fontSize: 15 }, children: OVERALL_MSG[overall] }),
|
|
102
|
+
/* @__PURE__ */ jsxs2("div", { style: { color: "var(--ta-gray-600)", fontSize: 13 }, children: [
|
|
103
|
+
checks.filter((c) => c.status === "ok").length,
|
|
104
|
+
"/",
|
|
105
|
+
checks.length,
|
|
106
|
+
" checks passing"
|
|
107
|
+
] })
|
|
108
|
+
] })
|
|
109
|
+
] }) }),
|
|
110
|
+
/* @__PURE__ */ jsx2(Card, { title: "System Checks", children: /* @__PURE__ */ jsxs2("table", { className: "ta-table", children: [
|
|
111
|
+
/* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsxs2("tr", { children: [
|
|
112
|
+
/* @__PURE__ */ jsx2("th", { children: "Check" }),
|
|
113
|
+
/* @__PURE__ */ jsx2("th", { children: "Status" }),
|
|
114
|
+
/* @__PURE__ */ jsx2("th", { children: "Notes" })
|
|
115
|
+
] }) }),
|
|
116
|
+
/* @__PURE__ */ jsx2("tbody", { children: checks.map((c) => /* @__PURE__ */ jsxs2("tr", { children: [
|
|
117
|
+
/* @__PURE__ */ jsx2("td", { style: { fontWeight: 500 }, children: c.label }),
|
|
118
|
+
/* @__PURE__ */ jsx2("td", { children: /* @__PURE__ */ jsx2("span", { className: `ta-badge ta-badge--${c.status === "ok" ? "green" : c.status === "warning" ? "orange" : "red"}`, children: c.status }) }),
|
|
119
|
+
/* @__PURE__ */ jsx2("td", { style: { color: "var(--ta-gray-600)", fontSize: 13 }, children: c.note ?? "\u2014" })
|
|
120
|
+
] }, c.label)) })
|
|
121
|
+
] }) }),
|
|
122
|
+
/* @__PURE__ */ jsx2(Card, { title: "Package Info", children: /* @__PURE__ */ jsxs2("div", { style: { display: "grid", gridTemplateColumns: "160px 1fr", gap: "8px 0", fontSize: 13 }, children: [
|
|
123
|
+
/* @__PURE__ */ jsx2("span", { style: { color: "var(--ta-gray-600)" }, children: "Package" }),
|
|
124
|
+
/* @__PURE__ */ jsx2("span", { children: /* @__PURE__ */ jsx2("code", { children: "third-audience-mdx" }) }),
|
|
125
|
+
/* @__PURE__ */ jsx2("span", { style: { color: "var(--ta-gray-600)" }, children: "Node.js" }),
|
|
126
|
+
/* @__PURE__ */ jsx2("span", { children: /* @__PURE__ */ jsx2("code", { children: process.versions.node }) }),
|
|
127
|
+
/* @__PURE__ */ jsx2("span", { style: { color: "var(--ta-gray-600)" }, children: "Content dir" }),
|
|
128
|
+
/* @__PURE__ */ jsx2("span", { children: /* @__PURE__ */ jsx2("code", { children: process.env.TA_CONTENT_DIR ?? "content" }) }),
|
|
129
|
+
/* @__PURE__ */ jsx2("span", { style: { color: "var(--ta-gray-600)" }, children: "Data dir" }),
|
|
130
|
+
/* @__PURE__ */ jsx2("span", { children: /* @__PURE__ */ jsx2("code", { children: process.env.TA_DATA_DIR ?? "data" }) }),
|
|
131
|
+
/* @__PURE__ */ jsx2("span", { style: { color: "var(--ta-gray-600)" }, children: "Dashboard" }),
|
|
132
|
+
/* @__PURE__ */ jsx2("span", { children: /* @__PURE__ */ jsx2("code", { children: "/third-audience/" }) })
|
|
133
|
+
] }) }),
|
|
134
|
+
/* @__PURE__ */ jsx2(Card, { title: "Quick Links", children: /* @__PURE__ */ jsx2("div", { style: { display: "flex", flexWrap: "wrap", gap: 10 }, children: [
|
|
135
|
+
{ href: "/llms.txt", label: "/llms.txt" },
|
|
136
|
+
{ href: "/sitemap-ai.xml", label: "/sitemap-ai.xml" },
|
|
137
|
+
{ href: "/okf/", label: "/okf/" },
|
|
138
|
+
{ href: "/okf/index.md", label: "/okf/index.md" }
|
|
139
|
+
].map((link) => /* @__PURE__ */ jsxs2("a", { href: link.href, target: "_blank", rel: "noreferrer", className: "ta-btn ta-btn--ghost", children: [
|
|
140
|
+
link.label,
|
|
141
|
+
" \u2197"
|
|
142
|
+
] }, link.href)) }) })
|
|
143
|
+
] });
|
|
144
|
+
}
|
|
145
|
+
export {
|
|
146
|
+
SystemHealthPage
|
|
147
|
+
};
|
|
148
|
+
//# sourceMappingURL=SystemHealthPage.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/dashboard/ui/pages/SystemHealthPage.tsx","../../../../src/dashboard/ui/components/Card.tsx"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport { Card } from '../components/Card.js'\n\ninterface HealthCheck {\n label: string\n status: 'ok' | 'warning' | 'error'\n note?: string\n}\n\nfunction runHealthChecks(): { checks: HealthCheck[]; overall: 'ok' | 'warning' | 'error' } {\n const cwd = process.cwd()\n const checks: HealthCheck[] = []\n\n // Node version\n const [major] = process.versions.node.split('.').map(Number)\n checks.push({\n label: `Node.js ${process.versions.node}`,\n status: major >= 18 ? 'ok' : 'error',\n note: major < 18 ? 'Requires Node 18+' : undefined,\n })\n\n // Content dir\n const contentDir = process.env.TA_CONTENT_DIR ?? 'content'\n const contentPath = path.join(cwd, contentDir)\n const contentExists = fs.existsSync(contentPath)\n let mdxCount = 0\n if (contentExists) {\n function countMdx(dir: string): number {\n let n = 0\n for (const e of fs.readdirSync(dir, { withFileTypes: true })) {\n if (e.isDirectory()) n += countMdx(path.join(dir, e.name))\n else if (e.name.endsWith('.mdx') || e.name.endsWith('.md')) n++\n }\n return n\n }\n mdxCount = countMdx(contentPath)\n }\n checks.push({\n label: `Content directory (${contentDir})`,\n status: contentExists ? 'ok' : 'warning',\n note: contentExists ? `${mdxCount} MDX files` : 'Not found — set TA_CONTENT_DIR',\n })\n\n // Data dir\n const dataDir = process.env.TA_DATA_DIR ?? 'data'\n const dataPath = path.join(cwd, dataDir)\n checks.push({\n label: `Data directory (${dataDir})`,\n status: fs.existsSync(dataPath) ? 'ok' : 'warning',\n note: !fs.existsSync(dataPath) ? 'Run `npx third-audience init`' : undefined,\n })\n\n // JSONL files\n const visitsPath = path.join(cwd, dataDir, 'ta-visits.jsonl')\n const citPath = path.join(cwd, dataDir, 'ta-citations.jsonl')\n const visitLines = fs.existsSync(visitsPath) ? fs.readFileSync(visitsPath, 'utf-8').split('\\n').filter(Boolean).length : 0\n const citLines = fs.existsSync(citPath) ? fs.readFileSync(citPath, 'utf-8').split('\\n').filter(Boolean).length : 0\n checks.push({ label: 'ta-visits.jsonl', status: 'ok', note: `${visitLines.toLocaleString()} records` })\n checks.push({ label: 'ta-citations.jsonl', status: 'ok', note: `${citLines.toLocaleString()} records` })\n\n // Cache dir\n const cachePath = path.join(cwd, dataDir, 'ta-cache')\n const cacheExists = fs.existsSync(cachePath)\n const cacheFiles = cacheExists ? fs.readdirSync(cachePath).filter(f => f.endsWith('.json')).length : 0\n checks.push({ label: 'Cache directory', status: 'ok', note: `${cacheFiles} entries` })\n\n // Dashboard secret\n checks.push({\n label: 'THIRD_AUDIENCE_SECRET',\n status: process.env.THIRD_AUDIENCE_SECRET ? 'ok' : 'warning',\n note: !process.env.THIRD_AUDIENCE_SECRET ? 'Not set — dashboard is open to anyone' : 'Set',\n })\n\n // Middleware\n const middlewarePath = path.join(cwd, 'middleware.ts')\n checks.push({\n label: 'middleware.ts',\n status: fs.existsSync(middlewarePath) ? 'ok' : 'warning',\n note: !fs.existsSync(middlewarePath) ? 'Not found — .md URLs and /llms.txt may not route correctly' : undefined,\n })\n\n const hasErrors = checks.some(c => c.status === 'error')\n const hasWarnings = checks.some(c => c.status === 'warning')\n const overall = hasErrors ? 'error' : hasWarnings ? 'warning' : 'ok'\n\n return { checks, overall }\n}\n\nconst STATUS_ICON: Record<string, string> = { ok: '✅', warning: '⚠️', error: '❌' }\nconst STATUS_COLOR: Record<string, string> = {\n ok: 'var(--ta-green)', warning: 'var(--ta-orange)', error: 'var(--ta-red)',\n}\nconst OVERALL_MSG: Record<string, string> = {\n ok: 'All systems operational',\n warning: 'Some optional features may be limited',\n error: 'Action required: system requirements not met',\n}\n\nexport async function SystemHealthPage() {\n const { checks, overall } = runHealthChecks()\n\n return (\n <div>\n <h1 className=\"ta-page-title\">System Health</h1>\n <p className=\"ta-page-subtitle\">Diagnostics and configuration status</p>\n\n {/* Overall status banner */}\n <div className=\"ta-card ta-section\" style={{ borderLeft: `4px solid ${STATUS_COLOR[overall]}` }}>\n <div className=\"ta-card-body\" style={{ display: 'flex', alignItems: 'center', gap: 14 }}>\n <span style={{ fontSize: 28 }}>{STATUS_ICON[overall]}</span>\n <div>\n <div style={{ fontWeight: 600, fontSize: 15 }}>{OVERALL_MSG[overall]}</div>\n <div style={{ color: 'var(--ta-gray-600)', fontSize: 13 }}>\n {checks.filter(c => c.status === 'ok').length}/{checks.length} checks passing\n </div>\n </div>\n </div>\n </div>\n\n <Card title=\"System Checks\">\n <table className=\"ta-table\">\n <thead><tr><th>Check</th><th>Status</th><th>Notes</th></tr></thead>\n <tbody>\n {checks.map(c => (\n <tr key={c.label}>\n <td style={{ fontWeight: 500 }}>{c.label}</td>\n <td>\n <span className={`ta-badge ta-badge--${c.status === 'ok' ? 'green' : c.status === 'warning' ? 'orange' : 'red'}`}>\n {c.status}\n </span>\n </td>\n <td style={{ color: 'var(--ta-gray-600)', fontSize: 13 }}>{c.note ?? '—'}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </Card>\n\n <Card title=\"Package Info\">\n <div style={{ display: 'grid', gridTemplateColumns: '160px 1fr', gap: '8px 0', fontSize: 13 }}>\n <span style={{ color: 'var(--ta-gray-600)' }}>Package</span>\n <span><code>third-audience-mdx</code></span>\n <span style={{ color: 'var(--ta-gray-600)' }}>Node.js</span>\n <span><code>{process.versions.node}</code></span>\n <span style={{ color: 'var(--ta-gray-600)' }}>Content dir</span>\n <span><code>{process.env.TA_CONTENT_DIR ?? 'content'}</code></span>\n <span style={{ color: 'var(--ta-gray-600)' }}>Data dir</span>\n <span><code>{process.env.TA_DATA_DIR ?? 'data'}</code></span>\n <span style={{ color: 'var(--ta-gray-600)' }}>Dashboard</span>\n <span><code>/third-audience/</code></span>\n </div>\n </Card>\n\n <Card title=\"Quick Links\">\n <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>\n {[\n { href: '/llms.txt', label: '/llms.txt' },\n { href: '/sitemap-ai.xml', label: '/sitemap-ai.xml' },\n { href: '/okf/', label: '/okf/' },\n { href: '/okf/index.md', label: '/okf/index.md' },\n ].map(link => (\n <a key={link.href} href={link.href} target=\"_blank\" rel=\"noreferrer\" className=\"ta-btn ta-btn--ghost\">\n {link.label} ↗\n </a>\n ))}\n </div>\n </Card>\n </div>\n )\n}\n","import type { ReactNode } from 'react'\n\ninterface CardProps {\n title: string\n action?: ReactNode\n children: ReactNode\n}\n\nexport function Card({ title, action, children }: CardProps) {\n return (\n <div className=\"ta-card ta-section\">\n <div className=\"ta-card-header\">\n <h2>{title}</h2>\n {action}\n </div>\n <div className=\"ta-card-body\">{children}</div>\n </div>\n )\n}\n"],"mappings":"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","names":["jsx","jsxs","countMdx"]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { NextConfig } from 'next';
|
|
2
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
|
|
4
|
+
interface ThirdAudienceConfig {
|
|
5
|
+
/** Directory containing .mdx files, relative to project root. Default: 'content' */
|
|
6
|
+
contentDir?: string;
|
|
7
|
+
/** Directory for JSONL data files. Default: 'data' */
|
|
8
|
+
dataDir?: string;
|
|
9
|
+
/** Mount the /third-audience/ dashboard. Default: true */
|
|
10
|
+
dashboard?: boolean;
|
|
11
|
+
/** Secret for dashboard access (HTTP Basic or bearer). Required when dashboard: true */
|
|
12
|
+
dashboardSecret?: string;
|
|
13
|
+
notifications?: {
|
|
14
|
+
email?: {
|
|
15
|
+
smtp: string;
|
|
16
|
+
to: string;
|
|
17
|
+
from?: string;
|
|
18
|
+
};
|
|
19
|
+
slack?: {
|
|
20
|
+
webhookUrl: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
bots?: {
|
|
24
|
+
allowlist?: string[];
|
|
25
|
+
blocklist?: string[];
|
|
26
|
+
};
|
|
27
|
+
cache?: {
|
|
28
|
+
/** Cache TTL in seconds. Default: 3600 */
|
|
29
|
+
ttl?: number;
|
|
30
|
+
/** Max in-memory entries. Default: 500 */
|
|
31
|
+
maxMemoryEntries?: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Wraps next.config.ts to inject Third Audience rewrites and headers.
|
|
37
|
+
*
|
|
38
|
+
* Usage:
|
|
39
|
+
* import { withThirdAudience } from 'third-audience-mdx'
|
|
40
|
+
* export default withThirdAudience({ contentDir: 'content' })
|
|
41
|
+
*/
|
|
42
|
+
declare function withThirdAudience(options?: ThirdAudienceConfig, nextConfig?: NextConfig): NextConfig;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Third Audience middleware.
|
|
46
|
+
*
|
|
47
|
+
* Handles:
|
|
48
|
+
* - Dashboard auth: /third-audience/* requires valid session cookie
|
|
49
|
+
* - .md URL requests → serve Markdown of matching MDX file
|
|
50
|
+
* - Accept: text/markdown header → serve Markdown of current page
|
|
51
|
+
* - Bot visit tracking (non-blocking, fire-and-forget)
|
|
52
|
+
* - Citation detection via Referer header
|
|
53
|
+
*
|
|
54
|
+
* Wire up in middleware.ts:
|
|
55
|
+
* export { thirdAudienceMiddleware as middleware } from 'third-audience-mdx'
|
|
56
|
+
* export const config = { matcher: ['/((?!_next|api).*)'] }
|
|
57
|
+
*/
|
|
58
|
+
declare function thirdAudienceMiddleware(req: NextRequest): Promise<NextResponse>;
|
|
59
|
+
|
|
60
|
+
interface BotDetectionResult {
|
|
61
|
+
isBot: boolean;
|
|
62
|
+
botName: string | null;
|
|
63
|
+
confidence: 'high' | 'medium' | 'low';
|
|
64
|
+
detectionMethod: 'known_pattern' | 'heuristic' | 'auto_learned' | 'none';
|
|
65
|
+
category: 'ai_crawler' | 'search_engine' | 'unknown_bot' | 'human';
|
|
66
|
+
rawUserAgent: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface DetectBotInput {
|
|
70
|
+
userAgent: string;
|
|
71
|
+
/** Optional: headers map for heuristic checks */
|
|
72
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
73
|
+
/** Optional: IP address */
|
|
74
|
+
ip?: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Three-layer bot detection pipeline:
|
|
78
|
+
* 1. Known pattern matching (O(n) UA string match)
|
|
79
|
+
* 2. Heuristic signals (missing headers, headless indicators)
|
|
80
|
+
* 3. Auto-learner flag (unknown UAs that behave bot-like)
|
|
81
|
+
*/
|
|
82
|
+
declare function detectBot(input: DetectBotInput): BotDetectionResult;
|
|
83
|
+
|
|
84
|
+
export { type BotDetectionResult, type ThirdAudienceConfig, detectBot, thirdAudienceMiddleware, withThirdAudience };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { NextConfig } from 'next';
|
|
2
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
|
|
4
|
+
interface ThirdAudienceConfig {
|
|
5
|
+
/** Directory containing .mdx files, relative to project root. Default: 'content' */
|
|
6
|
+
contentDir?: string;
|
|
7
|
+
/** Directory for JSONL data files. Default: 'data' */
|
|
8
|
+
dataDir?: string;
|
|
9
|
+
/** Mount the /third-audience/ dashboard. Default: true */
|
|
10
|
+
dashboard?: boolean;
|
|
11
|
+
/** Secret for dashboard access (HTTP Basic or bearer). Required when dashboard: true */
|
|
12
|
+
dashboardSecret?: string;
|
|
13
|
+
notifications?: {
|
|
14
|
+
email?: {
|
|
15
|
+
smtp: string;
|
|
16
|
+
to: string;
|
|
17
|
+
from?: string;
|
|
18
|
+
};
|
|
19
|
+
slack?: {
|
|
20
|
+
webhookUrl: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
bots?: {
|
|
24
|
+
allowlist?: string[];
|
|
25
|
+
blocklist?: string[];
|
|
26
|
+
};
|
|
27
|
+
cache?: {
|
|
28
|
+
/** Cache TTL in seconds. Default: 3600 */
|
|
29
|
+
ttl?: number;
|
|
30
|
+
/** Max in-memory entries. Default: 500 */
|
|
31
|
+
maxMemoryEntries?: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Wraps next.config.ts to inject Third Audience rewrites and headers.
|
|
37
|
+
*
|
|
38
|
+
* Usage:
|
|
39
|
+
* import { withThirdAudience } from 'third-audience-mdx'
|
|
40
|
+
* export default withThirdAudience({ contentDir: 'content' })
|
|
41
|
+
*/
|
|
42
|
+
declare function withThirdAudience(options?: ThirdAudienceConfig, nextConfig?: NextConfig): NextConfig;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Third Audience middleware.
|
|
46
|
+
*
|
|
47
|
+
* Handles:
|
|
48
|
+
* - Dashboard auth: /third-audience/* requires valid session cookie
|
|
49
|
+
* - .md URL requests → serve Markdown of matching MDX file
|
|
50
|
+
* - Accept: text/markdown header → serve Markdown of current page
|
|
51
|
+
* - Bot visit tracking (non-blocking, fire-and-forget)
|
|
52
|
+
* - Citation detection via Referer header
|
|
53
|
+
*
|
|
54
|
+
* Wire up in middleware.ts:
|
|
55
|
+
* export { thirdAudienceMiddleware as middleware } from 'third-audience-mdx'
|
|
56
|
+
* export const config = { matcher: ['/((?!_next|api).*)'] }
|
|
57
|
+
*/
|
|
58
|
+
declare function thirdAudienceMiddleware(req: NextRequest): Promise<NextResponse>;
|
|
59
|
+
|
|
60
|
+
interface BotDetectionResult {
|
|
61
|
+
isBot: boolean;
|
|
62
|
+
botName: string | null;
|
|
63
|
+
confidence: 'high' | 'medium' | 'low';
|
|
64
|
+
detectionMethod: 'known_pattern' | 'heuristic' | 'auto_learned' | 'none';
|
|
65
|
+
category: 'ai_crawler' | 'search_engine' | 'unknown_bot' | 'human';
|
|
66
|
+
rawUserAgent: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface DetectBotInput {
|
|
70
|
+
userAgent: string;
|
|
71
|
+
/** Optional: headers map for heuristic checks */
|
|
72
|
+
headers?: Record<string, string | string[] | undefined>;
|
|
73
|
+
/** Optional: IP address */
|
|
74
|
+
ip?: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Three-layer bot detection pipeline:
|
|
78
|
+
* 1. Known pattern matching (O(n) UA string match)
|
|
79
|
+
* 2. Heuristic signals (missing headers, headless indicators)
|
|
80
|
+
* 3. Auto-learner flag (unknown UAs that behave bot-like)
|
|
81
|
+
*/
|
|
82
|
+
declare function detectBot(input: DetectBotInput): BotDetectionResult;
|
|
83
|
+
|
|
84
|
+
export { type BotDetectionResult, type ThirdAudienceConfig, detectBot, thirdAudienceMiddleware, withThirdAudience };
|