third-audience-mdx 1.0.2 → 1.0.4
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/dashboard/routes/bots-config-route.d.mts +8 -0
- package/dist/dashboard/routes/bots-config-route.d.ts +8 -0
- package/dist/dashboard/routes/bots-config-route.js +149 -0
- package/dist/dashboard/routes/bots-config-route.js.map +1 -0
- package/dist/dashboard/routes/bots-config-route.mjs +113 -0
- package/dist/dashboard/routes/bots-config-route.mjs.map +1 -0
- package/dist/dashboard/routes/okf-graph-route.d.mts +6 -0
- package/dist/dashboard/routes/okf-graph-route.d.ts +6 -0
- package/dist/dashboard/routes/okf-graph-route.js +266 -0
- package/dist/dashboard/routes/okf-graph-route.js.map +1 -0
- package/dist/dashboard/routes/okf-graph-route.mjs +231 -0
- package/dist/dashboard/routes/okf-graph-route.mjs.map +1 -0
- package/dist/dashboard/routes/okf-route.js +1 -1
- package/dist/dashboard/routes/okf-route.js.map +1 -1
- package/dist/dashboard/routes/okf-route.mjs +1 -1
- package/dist/dashboard/routes/okf-route.mjs.map +1 -1
- package/dist/dashboard/ui/components/Sidebar.js +15 -0
- package/dist/dashboard/ui/components/Sidebar.js.map +1 -1
- package/dist/dashboard/ui/components/Sidebar.mjs +15 -0
- package/dist/dashboard/ui/components/Sidebar.mjs.map +1 -1
- package/dist/dashboard/ui/pages/OkfPage.d.mts +5 -0
- package/dist/dashboard/ui/pages/OkfPage.d.ts +5 -0
- package/dist/dashboard/ui/pages/OkfPage.js +438 -0
- package/dist/dashboard/ui/pages/OkfPage.js.map +1 -0
- package/dist/dashboard/ui/pages/OkfPage.mjs +414 -0
- package/dist/dashboard/ui/pages/OkfPage.mjs.map +1 -0
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -1
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/dashboard/ui/pages/OkfPage.tsx
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
5
|
+
|
|
6
|
+
// src/dashboard/ui/components/Card.tsx
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
function Card({ title, action, children }) {
|
|
9
|
+
return /* @__PURE__ */ jsxs("div", { className: "ta-card ta-section", children: [
|
|
10
|
+
/* @__PURE__ */ jsxs("div", { className: "ta-card-header", children: [
|
|
11
|
+
/* @__PURE__ */ jsx("h2", { children: title }),
|
|
12
|
+
action
|
|
13
|
+
] }),
|
|
14
|
+
/* @__PURE__ */ jsx("div", { className: "ta-card-body", children })
|
|
15
|
+
] });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/dashboard/ui/components/HeroCard.tsx
|
|
19
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
20
|
+
function HeroCard({ label, value, meta, color = "blue", icon }) {
|
|
21
|
+
return /* @__PURE__ */ jsxs2("div", { className: `ta-hero-card ta-hero-card--${color}`, children: [
|
|
22
|
+
/* @__PURE__ */ jsx2("div", { className: "ta-hero-icon", children: icon }),
|
|
23
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
24
|
+
/* @__PURE__ */ jsx2("div", { className: "ta-hero-label", children: label }),
|
|
25
|
+
/* @__PURE__ */ jsx2("div", { className: "ta-hero-value", children: value }),
|
|
26
|
+
meta && /* @__PURE__ */ jsx2("div", { className: "ta-hero-meta", children: meta })
|
|
27
|
+
] })
|
|
28
|
+
] });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/dashboard/ui/pages/OkfPage.tsx
|
|
32
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
33
|
+
function OkfGraph({ data }) {
|
|
34
|
+
const svgRef = useRef(null);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const svg = svgRef.current;
|
|
37
|
+
if (!svg || !data.nodes.length) return;
|
|
38
|
+
const NS = "http://www.w3.org/2000/svg";
|
|
39
|
+
svg.innerHTML = "";
|
|
40
|
+
const rect = svg.getBoundingClientRect();
|
|
41
|
+
const W = Math.max(320, Math.round(rect.width)) || 900;
|
|
42
|
+
const H = Math.max(360, Math.round(rect.height)) || 560;
|
|
43
|
+
svg.setAttribute("viewBox", `0 0 ${W} ${H}`);
|
|
44
|
+
const showLabels = data.nodes.length <= 40;
|
|
45
|
+
const spread = Math.min(W, H) * 0.42;
|
|
46
|
+
const nodes = data.nodes.map((n, i) => {
|
|
47
|
+
const ang = i / data.nodes.length * Math.PI * 2;
|
|
48
|
+
return { ...n, x: W / 2 + Math.cos(ang) * spread, y: H / 2 + Math.sin(ang) * spread, vx: 0, vy: 0, deg: 0, fixed: false, moved: false };
|
|
49
|
+
});
|
|
50
|
+
const byId = {};
|
|
51
|
+
nodes.forEach((n) => {
|
|
52
|
+
byId[n.id] = n;
|
|
53
|
+
});
|
|
54
|
+
const edges = data.edges.filter((e) => byId[e.source] && byId[e.target] && e.source !== e.target);
|
|
55
|
+
edges.forEach((e) => {
|
|
56
|
+
byId[e.source].deg++;
|
|
57
|
+
byId[e.target].deg++;
|
|
58
|
+
});
|
|
59
|
+
const radius = (n) => 6 + Math.min(10, n.deg * 1.7);
|
|
60
|
+
function tick() {
|
|
61
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
62
|
+
const a = nodes[i];
|
|
63
|
+
for (let j = i + 1; j < nodes.length; j++) {
|
|
64
|
+
const b = nodes[j];
|
|
65
|
+
const dx = a.x - b.x, dy = a.y - b.y;
|
|
66
|
+
const d2 = dx * dx + dy * dy || 0.01, d = Math.sqrt(d2);
|
|
67
|
+
const f = 9e3 / d2, fx = f * dx / d, fy = f * dy / d;
|
|
68
|
+
a.vx += fx;
|
|
69
|
+
a.vy += fy;
|
|
70
|
+
b.vx -= fx;
|
|
71
|
+
b.vy -= fy;
|
|
72
|
+
}
|
|
73
|
+
a.vx += (W / 2 - a.x) * 5e-3;
|
|
74
|
+
a.vy += (H / 2 - a.y) * 5e-3;
|
|
75
|
+
}
|
|
76
|
+
for (const e of edges) {
|
|
77
|
+
const a = byId[e.source], b = byId[e.target];
|
|
78
|
+
const dx = b.x - a.x, dy = b.y - a.y;
|
|
79
|
+
const d = Math.sqrt(dx * dx + dy * dy) || 0.01;
|
|
80
|
+
const f = (d - 150) * 0.012, fx = f * dx / d, fy = f * dy / d;
|
|
81
|
+
a.vx += fx;
|
|
82
|
+
a.vy += fy;
|
|
83
|
+
b.vx -= fx;
|
|
84
|
+
b.vy -= fy;
|
|
85
|
+
}
|
|
86
|
+
for (const a of nodes) {
|
|
87
|
+
if (a.fixed) {
|
|
88
|
+
a.vx = 0;
|
|
89
|
+
a.vy = 0;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
a.vx *= 0.86;
|
|
93
|
+
a.vy *= 0.86;
|
|
94
|
+
a.x += Math.max(-12, Math.min(12, a.vx));
|
|
95
|
+
a.y += Math.max(-12, Math.min(12, a.vy));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const view = document.createElementNS(NS, "g");
|
|
99
|
+
svg.appendChild(view);
|
|
100
|
+
const gE = document.createElementNS(NS, "g");
|
|
101
|
+
const gN = document.createElementNS(NS, "g");
|
|
102
|
+
view.appendChild(gE);
|
|
103
|
+
view.appendChild(gN);
|
|
104
|
+
let tx = 0, ty = 0, sc = 1;
|
|
105
|
+
const applyView = () => view.setAttribute("transform", `translate(${tx},${ty}) scale(${sc})`);
|
|
106
|
+
const edgeEls = edges.map(() => {
|
|
107
|
+
const ln = document.createElementNS(NS, "line");
|
|
108
|
+
ln.setAttribute("stroke", "rgba(130,175,230,0.10)");
|
|
109
|
+
ln.setAttribute("stroke-width", "0.7");
|
|
110
|
+
gE.appendChild(ln);
|
|
111
|
+
return ln;
|
|
112
|
+
});
|
|
113
|
+
nodes.forEach((n) => {
|
|
114
|
+
const g = document.createElementNS(NS, "g");
|
|
115
|
+
g.setAttribute("cursor", n.url ? "pointer" : "grab");
|
|
116
|
+
const c = document.createElementNS(NS, "circle");
|
|
117
|
+
c.setAttribute("r", String(radius(n)));
|
|
118
|
+
c.setAttribute("fill", n.type === "WebPage" || n.type === "Page" ? "#8ab4e8" : "#5291d7");
|
|
119
|
+
c.setAttribute("stroke", "#0f1115");
|
|
120
|
+
c.setAttribute("stroke-width", "1.5");
|
|
121
|
+
const t = document.createElementNS(NS, "text");
|
|
122
|
+
t.textContent = n.title.length > 26 ? n.title.slice(0, 24) + "\u2026" : n.title;
|
|
123
|
+
t.setAttribute("fill", "#c9d4e0");
|
|
124
|
+
t.setAttribute("font-size", "11");
|
|
125
|
+
t.setAttribute("text-anchor", "middle");
|
|
126
|
+
t.setAttribute("pointer-events", "none");
|
|
127
|
+
t.setAttribute("opacity", showLabels ? "1" : "0");
|
|
128
|
+
const ti = document.createElementNS(NS, "title");
|
|
129
|
+
ti.textContent = n.title;
|
|
130
|
+
g.appendChild(c);
|
|
131
|
+
g.appendChild(t);
|
|
132
|
+
g.appendChild(ti);
|
|
133
|
+
g.addEventListener("mouseenter", () => highlight(n));
|
|
134
|
+
g.addEventListener("mouseleave", clearHi);
|
|
135
|
+
if (n.url) {
|
|
136
|
+
g.addEventListener("click", () => {
|
|
137
|
+
if (n.moved) {
|
|
138
|
+
n.moved = false;
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
window.open(n.url, "_blank", "noopener");
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
gN.appendChild(g);
|
|
145
|
+
n.g = g;
|
|
146
|
+
n.c = c;
|
|
147
|
+
n.t = t;
|
|
148
|
+
});
|
|
149
|
+
function highlight(node) {
|
|
150
|
+
const on = { [node.id]: true };
|
|
151
|
+
edges.forEach((e, i) => {
|
|
152
|
+
const hit = e.source === node.id || e.target === node.id;
|
|
153
|
+
edgeEls[i].setAttribute("stroke", hit ? "rgba(146,190,240,0.95)" : "rgba(130,175,230,0.07)");
|
|
154
|
+
if (hit) {
|
|
155
|
+
on[e.source] = true;
|
|
156
|
+
on[e.target] = true;
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
nodes.forEach((m) => {
|
|
160
|
+
m.g.setAttribute("opacity", on[m.id] ? "1" : "0.22");
|
|
161
|
+
m.t.setAttribute("opacity", on[m.id] ? "1" : showLabels ? "1" : "0");
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
function clearHi() {
|
|
165
|
+
edgeEls.forEach((el) => el.setAttribute("stroke", "rgba(130,175,230,0.10)"));
|
|
166
|
+
nodes.forEach((m) => {
|
|
167
|
+
m.g.setAttribute("opacity", "1");
|
|
168
|
+
if (!showLabels) m.t.setAttribute("opacity", "0");
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
function paint() {
|
|
172
|
+
edges.forEach((e, i) => {
|
|
173
|
+
const a = byId[e.source], b = byId[e.target];
|
|
174
|
+
edgeEls[i].setAttribute("x1", String(a.x));
|
|
175
|
+
edgeEls[i].setAttribute("y1", String(a.y));
|
|
176
|
+
edgeEls[i].setAttribute("x2", String(b.x));
|
|
177
|
+
edgeEls[i].setAttribute("y2", String(b.y));
|
|
178
|
+
});
|
|
179
|
+
nodes.forEach((n) => {
|
|
180
|
+
n.c.setAttribute("cx", String(n.x));
|
|
181
|
+
n.c.setAttribute("cy", String(n.y));
|
|
182
|
+
n.t.setAttribute("x", String(n.x));
|
|
183
|
+
n.t.setAttribute("y", String(n.y - radius(n) - 5));
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
function pt(el, ev) {
|
|
187
|
+
const m = el.getScreenCTM();
|
|
188
|
+
if (!m) return { x: ev.clientX, y: ev.clientY };
|
|
189
|
+
const inv = m.inverse();
|
|
190
|
+
return { x: inv.a * ev.clientX + inv.c * ev.clientY + inv.e, y: inv.b * ev.clientX + inv.d * ev.clientY + inv.f };
|
|
191
|
+
}
|
|
192
|
+
const state = { drag: null, pan: null };
|
|
193
|
+
svg.addEventListener("mousedown", (ev) => {
|
|
194
|
+
const p = pt(view, ev);
|
|
195
|
+
let best = 900;
|
|
196
|
+
let hit = null;
|
|
197
|
+
nodes.forEach((n) => {
|
|
198
|
+
const dx = n.x - p.x, dy = n.y - p.y, dd = dx * dx + dy * dy;
|
|
199
|
+
if (dd < best) {
|
|
200
|
+
best = dd;
|
|
201
|
+
hit = n;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
if (hit !== null) {
|
|
205
|
+
state.drag = hit;
|
|
206
|
+
state.drag.fixed = true;
|
|
207
|
+
state.drag.moved = false;
|
|
208
|
+
} else {
|
|
209
|
+
const r = pt(svg, ev);
|
|
210
|
+
state.pan = { x: r.x, y: r.y, tx, ty };
|
|
211
|
+
svg.style.cursor = "grabbing";
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
const onMouseMove = (ev) => {
|
|
215
|
+
if (state.drag !== null) {
|
|
216
|
+
const p = pt(view, ev);
|
|
217
|
+
state.drag.x = p.x;
|
|
218
|
+
state.drag.y = p.y;
|
|
219
|
+
state.drag.moved = true;
|
|
220
|
+
tick();
|
|
221
|
+
state.drag.x = p.x;
|
|
222
|
+
state.drag.y = p.y;
|
|
223
|
+
paint();
|
|
224
|
+
} else if (state.pan !== null) {
|
|
225
|
+
const r = pt(svg, ev);
|
|
226
|
+
tx = state.pan.tx + (r.x - state.pan.x);
|
|
227
|
+
ty = state.pan.ty + (r.y - state.pan.y);
|
|
228
|
+
applyView();
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
const onMouseUp = () => {
|
|
232
|
+
if (state.drag !== null) {
|
|
233
|
+
state.drag.fixed = false;
|
|
234
|
+
state.drag = null;
|
|
235
|
+
let f = 0;
|
|
236
|
+
(function r() {
|
|
237
|
+
tick();
|
|
238
|
+
paint();
|
|
239
|
+
if (f++ < 60) requestAnimationFrame(r);
|
|
240
|
+
})();
|
|
241
|
+
}
|
|
242
|
+
if (state.pan !== null) {
|
|
243
|
+
state.pan = null;
|
|
244
|
+
svg.style.cursor = "";
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
window.addEventListener("mousemove", onMouseMove);
|
|
248
|
+
window.addEventListener("mouseup", onMouseUp);
|
|
249
|
+
svg.addEventListener("wheel", (ev) => {
|
|
250
|
+
ev.preventDefault();
|
|
251
|
+
const r = pt(svg, ev), lx = (r.x - tx) / sc, ly = (r.y - ty) / sc;
|
|
252
|
+
sc = Math.max(0.15, Math.min(4, sc * (ev.deltaY < 0 ? 1.12 : 1 / 1.12)));
|
|
253
|
+
tx = r.x - lx * sc;
|
|
254
|
+
ty = r.y - ly * sc;
|
|
255
|
+
applyView();
|
|
256
|
+
}, { passive: false });
|
|
257
|
+
function fitView() {
|
|
258
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
259
|
+
nodes.forEach((n) => {
|
|
260
|
+
const r = radius(n) + 24;
|
|
261
|
+
if (n.x - r < minX) minX = n.x - r;
|
|
262
|
+
if (n.y - r < minY) minY = n.y - r;
|
|
263
|
+
if (n.x + r > maxX) maxX = n.x + r;
|
|
264
|
+
if (n.y + r > maxY) maxY = n.y + r;
|
|
265
|
+
});
|
|
266
|
+
const bw = Math.max(1, maxX - minX), bh = Math.max(1, maxY - minY), pad = 30;
|
|
267
|
+
sc = Math.max(0.15, Math.min(2, Math.min((W - pad * 2) / bw, (H - pad * 2) / bh)));
|
|
268
|
+
tx = (W - bw * sc) / 2 - minX * sc;
|
|
269
|
+
ty = (H - bh * sc) / 2 - minY * sc;
|
|
270
|
+
applyView();
|
|
271
|
+
}
|
|
272
|
+
for (let k = 0; k < 500; k++) tick();
|
|
273
|
+
paint();
|
|
274
|
+
fitView();
|
|
275
|
+
return () => {
|
|
276
|
+
window.removeEventListener("mousemove", onMouseMove);
|
|
277
|
+
window.removeEventListener("mouseup", onMouseUp);
|
|
278
|
+
};
|
|
279
|
+
}, [data]);
|
|
280
|
+
return /* @__PURE__ */ jsx3(
|
|
281
|
+
"svg",
|
|
282
|
+
{
|
|
283
|
+
ref: svgRef,
|
|
284
|
+
style: { width: "100%", height: "72vh", minHeight: 560, display: "block", background: "#0f1115", borderRadius: 8, cursor: "grab", touchAction: "none" },
|
|
285
|
+
role: "img",
|
|
286
|
+
"aria-label": "Knowledge graph of your content"
|
|
287
|
+
}
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
function OkfPage() {
|
|
291
|
+
const [state, setState] = useState({ data: null, loading: true, error: null });
|
|
292
|
+
useEffect(() => {
|
|
293
|
+
fetch("/api/third-audience/okf-graph").then((r) => r.ok ? r.json() : r.json().then((e) => Promise.reject(e.error ?? "Failed"))).then((data2) => setState({ data: data2, loading: false, error: null })).catch((e) => setState({ data: null, loading: false, error: String(e) }));
|
|
294
|
+
}, []);
|
|
295
|
+
if (state.loading) return /* @__PURE__ */ jsx3("div", { style: { padding: 48, color: "var(--ta-gray-500)", textAlign: "center" }, children: "Loading knowledge graph\u2026" });
|
|
296
|
+
if (state.error) return /* @__PURE__ */ jsx3("div", { style: { padding: 48, color: "var(--ta-red)", textAlign: "center" }, children: state.error });
|
|
297
|
+
if (!state.data) return null;
|
|
298
|
+
const { data } = state;
|
|
299
|
+
return /* @__PURE__ */ jsxs3("div", { children: [
|
|
300
|
+
/* @__PURE__ */ jsx3("h1", { className: "ta-page-title", children: "OKF Bundle" }),
|
|
301
|
+
/* @__PURE__ */ jsx3("p", { className: "ta-page-subtitle", children: "Open Knowledge Format \u2014 your content as clean Markdown for AI crawlers" }),
|
|
302
|
+
/* @__PURE__ */ jsxs3("div", { className: "ta-hero-grid", children: [
|
|
303
|
+
/* @__PURE__ */ jsx3(
|
|
304
|
+
HeroCard,
|
|
305
|
+
{
|
|
306
|
+
label: "Total Pages",
|
|
307
|
+
value: data.stats.pages,
|
|
308
|
+
meta: "in content directory",
|
|
309
|
+
color: "blue",
|
|
310
|
+
icon: /* @__PURE__ */ jsxs3("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: [
|
|
311
|
+
/* @__PURE__ */ jsx3("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
|
|
312
|
+
/* @__PURE__ */ jsx3("polyline", { points: "14 2 14 8 20 8" })
|
|
313
|
+
] })
|
|
314
|
+
}
|
|
315
|
+
),
|
|
316
|
+
/* @__PURE__ */ jsx3(
|
|
317
|
+
HeroCard,
|
|
318
|
+
{
|
|
319
|
+
label: "Graph Nodes",
|
|
320
|
+
value: data.stats.nodes,
|
|
321
|
+
meta: "top connected pages",
|
|
322
|
+
color: "teal",
|
|
323
|
+
icon: /* @__PURE__ */ jsxs3("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: [
|
|
324
|
+
/* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "3" }),
|
|
325
|
+
/* @__PURE__ */ jsx3("circle", { cx: "3", cy: "6", r: "2" }),
|
|
326
|
+
/* @__PURE__ */ jsx3("circle", { cx: "21", cy: "6", r: "2" }),
|
|
327
|
+
/* @__PURE__ */ jsx3("circle", { cx: "3", cy: "18", r: "2" }),
|
|
328
|
+
/* @__PURE__ */ jsx3("circle", { cx: "21", cy: "18", r: "2" }),
|
|
329
|
+
/* @__PURE__ */ jsx3("line", { x1: "5", y1: "6", x2: "10", y2: "11" }),
|
|
330
|
+
/* @__PURE__ */ jsx3("line", { x1: "19", y1: "6", x2: "14", y2: "11" }),
|
|
331
|
+
/* @__PURE__ */ jsx3("line", { x1: "5", y1: "18", x2: "10", y2: "13" }),
|
|
332
|
+
/* @__PURE__ */ jsx3("line", { x1: "19", y1: "18", x2: "14", y2: "13" })
|
|
333
|
+
] })
|
|
334
|
+
}
|
|
335
|
+
),
|
|
336
|
+
/* @__PURE__ */ jsx3(
|
|
337
|
+
HeroCard,
|
|
338
|
+
{
|
|
339
|
+
label: "Internal Links",
|
|
340
|
+
value: data.stats.edges,
|
|
341
|
+
meta: "edges in graph",
|
|
342
|
+
color: "green",
|
|
343
|
+
icon: /* @__PURE__ */ jsxs3("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: [
|
|
344
|
+
/* @__PURE__ */ jsx3("path", { d: "M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" }),
|
|
345
|
+
/* @__PURE__ */ jsx3("path", { d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" })
|
|
346
|
+
] })
|
|
347
|
+
}
|
|
348
|
+
),
|
|
349
|
+
/* @__PURE__ */ jsx3(
|
|
350
|
+
HeroCard,
|
|
351
|
+
{
|
|
352
|
+
label: "Bundle Index",
|
|
353
|
+
value: "View",
|
|
354
|
+
meta: data.indexUrl.replace(/^https?:\/\/[^/]+/, ""),
|
|
355
|
+
color: "orange",
|
|
356
|
+
icon: /* @__PURE__ */ jsxs3("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: [
|
|
357
|
+
/* @__PURE__ */ jsx3("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }),
|
|
358
|
+
/* @__PURE__ */ jsx3("polyline", { points: "15 3 21 3 21 9" }),
|
|
359
|
+
/* @__PURE__ */ jsx3("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
|
|
360
|
+
] })
|
|
361
|
+
}
|
|
362
|
+
)
|
|
363
|
+
] }),
|
|
364
|
+
/* @__PURE__ */ jsx3("div", { style: { marginBottom: 24 }, children: /* @__PURE__ */ jsxs3(Card, { title: "Knowledge Graph", children: [
|
|
365
|
+
/* @__PURE__ */ jsxs3("p", { style: { fontSize: 13, color: "var(--ta-gray-500)", marginBottom: 16 }, children: [
|
|
366
|
+
"Drag nodes \xB7 scroll to zoom \xB7 drag background to pan \xB7 click a node to open the page",
|
|
367
|
+
data.graph.nodes.length > 40 && " \xB7 hover a node to reveal its labels"
|
|
368
|
+
] }),
|
|
369
|
+
/* @__PURE__ */ jsx3(OkfGraph, { data: data.graph })
|
|
370
|
+
] }) }),
|
|
371
|
+
/* @__PURE__ */ jsxs3("div", { className: "ta-grid-2", children: [
|
|
372
|
+
/* @__PURE__ */ jsx3(Card, { title: "Bundle URLs", children: /* @__PURE__ */ jsxs3("table", { className: "ta-table", children: [
|
|
373
|
+
/* @__PURE__ */ jsx3("thead", { children: /* @__PURE__ */ jsxs3("tr", { children: [
|
|
374
|
+
/* @__PURE__ */ jsx3("th", { children: "Resource" }),
|
|
375
|
+
/* @__PURE__ */ jsx3("th", { children: "URL" })
|
|
376
|
+
] }) }),
|
|
377
|
+
/* @__PURE__ */ jsxs3("tbody", { children: [
|
|
378
|
+
/* @__PURE__ */ jsxs3("tr", { children: [
|
|
379
|
+
/* @__PURE__ */ jsx3("td", { children: "Index" }),
|
|
380
|
+
/* @__PURE__ */ jsx3("td", { children: /* @__PURE__ */ jsx3("a", { href: "/okf", target: "_blank", rel: "noreferrer", style: { fontFamily: "var(--ta-font-mono)", fontSize: 12 }, children: "/okf" }) })
|
|
381
|
+
] }),
|
|
382
|
+
/* @__PURE__ */ jsxs3("tr", { children: [
|
|
383
|
+
/* @__PURE__ */ jsx3("td", { children: "AI Sitemap" }),
|
|
384
|
+
/* @__PURE__ */ jsx3("td", { children: /* @__PURE__ */ jsx3("a", { href: "/sitemap-ai.xml", target: "_blank", rel: "noreferrer", style: { fontFamily: "var(--ta-font-mono)", fontSize: 12 }, children: "/sitemap-ai.xml" }) })
|
|
385
|
+
] }),
|
|
386
|
+
/* @__PURE__ */ jsxs3("tr", { children: [
|
|
387
|
+
/* @__PURE__ */ jsx3("td", { children: "LLMs.txt" }),
|
|
388
|
+
/* @__PURE__ */ jsx3("td", { children: /* @__PURE__ */ jsx3("a", { href: "/llms.txt", target: "_blank", rel: "noreferrer", style: { fontFamily: "var(--ta-font-mono)", fontSize: 12 }, children: "/llms.txt" }) })
|
|
389
|
+
] })
|
|
390
|
+
] })
|
|
391
|
+
] }) }),
|
|
392
|
+
/* @__PURE__ */ jsx3(Card, { title: "How AI Crawlers Use OKF", children: /* @__PURE__ */ jsxs3("div", { style: { fontSize: 13, color: "var(--ta-gray-600)", lineHeight: 1.7 }, children: [
|
|
393
|
+
/* @__PURE__ */ jsxs3("p", { style: { marginBottom: 10 }, children: [
|
|
394
|
+
"Each page on your site is available as clean Markdown at ",
|
|
395
|
+
/* @__PURE__ */ jsx3("code", { style: { fontFamily: "var(--ta-font-mono)", background: "var(--ta-gray-100)", padding: "1px 5px", borderRadius: 4 }, children: "/okf/slug.md" })
|
|
396
|
+
] }),
|
|
397
|
+
/* @__PURE__ */ jsxs3("p", { style: { marginBottom: 10 }, children: [
|
|
398
|
+
"Internal links are rewritten to point to sibling ",
|
|
399
|
+
/* @__PURE__ */ jsx3("code", { style: { fontFamily: "var(--ta-font-mono)", background: "var(--ta-gray-100)", padding: "1px 5px", borderRadius: 4 }, children: ".md" }),
|
|
400
|
+
" files so crawlers can follow the full knowledge graph."
|
|
401
|
+
] }),
|
|
402
|
+
/* @__PURE__ */ jsxs3("p", { children: [
|
|
403
|
+
"The index at ",
|
|
404
|
+
/* @__PURE__ */ jsx3("code", { style: { fontFamily: "var(--ta-font-mono)", background: "var(--ta-gray-100)", padding: "1px 5px", borderRadius: 4 }, children: "/okf" }),
|
|
405
|
+
" lists every page with title and description \u2014 a complete sitemap in natural language."
|
|
406
|
+
] })
|
|
407
|
+
] }) })
|
|
408
|
+
] })
|
|
409
|
+
] });
|
|
410
|
+
}
|
|
411
|
+
export {
|
|
412
|
+
OkfPage
|
|
413
|
+
};
|
|
414
|
+
//# sourceMappingURL=OkfPage.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/dashboard/ui/pages/OkfPage.tsx","../../../../src/dashboard/ui/components/Card.tsx","../../../../src/dashboard/ui/components/HeroCard.tsx"],"sourcesContent":["'use client'\n\nimport { useEffect, useRef, useState } from 'react'\nimport { Card } from '../components/Card.js'\nimport { HeroCard } from '../components/HeroCard.js'\n\ninterface GraphNode { id: string; title: string; type: string; url: string }\ninterface GraphEdge { source: string; target: string }\ninterface GraphData { nodes: GraphNode[]; edges: GraphEdge[] }\ninterface OkfData {\n graph: GraphData\n stats: { pages: number; nodes: number; edges: number }\n indexUrl: string\n}\n\nfunction OkfGraph({ data }: { data: GraphData }) {\n const svgRef = useRef<SVGSVGElement>(null)\n\n useEffect(() => {\n const svg = svgRef.current\n if (!svg || !data.nodes.length) return\n const NS = 'http://www.w3.org/2000/svg'\n svg.innerHTML = ''\n\n const rect = svg.getBoundingClientRect()\n const W = Math.max(320, Math.round(rect.width)) || 900\n const H = Math.max(360, Math.round(rect.height)) || 560\n svg.setAttribute('viewBox', `0 0 ${W} ${H}`)\n\n const showLabels = data.nodes.length <= 40\n const spread = Math.min(W, H) * 0.42\n\n type SimNode = GraphNode & { x: number; y: number; vx: number; vy: number; deg: number; fixed: boolean; moved: boolean; g?: SVGGElement; c?: SVGCircleElement; t?: SVGTextElement }\n const nodes: SimNode[] = data.nodes.map((n, i) => {\n const ang = (i / data.nodes.length) * Math.PI * 2\n return { ...n, x: W / 2 + Math.cos(ang) * spread, y: H / 2 + Math.sin(ang) * spread, vx: 0, vy: 0, deg: 0, fixed: false, moved: false }\n })\n\n const byId: Record<string, SimNode> = {}\n nodes.forEach(n => { byId[n.id] = n })\n\n const edges = data.edges.filter(e => byId[e.source] && byId[e.target] && e.source !== e.target)\n edges.forEach(e => { byId[e.source].deg++; byId[e.target].deg++ })\n\n const radius = (n: SimNode) => 6 + Math.min(10, n.deg * 1.7)\n\n function tick() {\n for (let i = 0; i < nodes.length; i++) {\n const a = nodes[i]\n for (let j = i + 1; j < nodes.length; j++) {\n const b = nodes[j]\n const dx = a.x - b.x, dy = a.y - b.y\n const d2 = dx * dx + dy * dy || 0.01, d = Math.sqrt(d2)\n const f = 9000 / d2, fx = f * dx / d, fy = f * dy / d\n a.vx += fx; a.vy += fy; b.vx -= fx; b.vy -= fy\n }\n a.vx += (W / 2 - a.x) * 0.005\n a.vy += (H / 2 - a.y) * 0.005\n }\n for (const e of edges) {\n const a = byId[e.source], b = byId[e.target]\n const dx = b.x - a.x, dy = b.y - a.y\n const d = Math.sqrt(dx * dx + dy * dy) || 0.01\n const f = (d - 150) * 0.012, fx = f * dx / d, fy = f * dy / d\n a.vx += fx; a.vy += fy; b.vx -= fx; b.vy -= fy\n }\n for (const a of nodes) {\n if (a.fixed) { a.vx = 0; a.vy = 0; continue }\n a.vx *= 0.86; a.vy *= 0.86\n a.x += Math.max(-12, Math.min(12, a.vx))\n a.y += Math.max(-12, Math.min(12, a.vy))\n }\n }\n\n const view = document.createElementNS(NS, 'g')\n svg.appendChild(view)\n const gE = document.createElementNS(NS, 'g')\n const gN = document.createElementNS(NS, 'g')\n view.appendChild(gE); view.appendChild(gN)\n\n let tx = 0, ty = 0, sc = 1\n const applyView = () => view.setAttribute('transform', `translate(${tx},${ty}) scale(${sc})`)\n\n const edgeEls = edges.map(() => {\n const ln = document.createElementNS(NS, 'line')\n ln.setAttribute('stroke', 'rgba(130,175,230,0.10)')\n ln.setAttribute('stroke-width', '0.7')\n gE.appendChild(ln); return ln\n })\n\n nodes.forEach(n => {\n const g = document.createElementNS(NS, 'g')\n g.setAttribute('cursor', n.url ? 'pointer' : 'grab')\n const c = document.createElementNS(NS, 'circle')\n c.setAttribute('r', String(radius(n)))\n c.setAttribute('fill', n.type === 'WebPage' || n.type === 'Page' ? '#8ab4e8' : '#5291d7')\n c.setAttribute('stroke', '#0f1115'); c.setAttribute('stroke-width', '1.5')\n const t = document.createElementNS(NS, 'text')\n t.textContent = n.title.length > 26 ? n.title.slice(0, 24) + '…' : n.title\n t.setAttribute('fill', '#c9d4e0'); t.setAttribute('font-size', '11')\n t.setAttribute('text-anchor', 'middle'); t.setAttribute('pointer-events', 'none')\n t.setAttribute('opacity', showLabels ? '1' : '0')\n const ti = document.createElementNS(NS, 'title'); ti.textContent = n.title\n g.appendChild(c); g.appendChild(t); g.appendChild(ti)\n g.addEventListener('mouseenter', () => highlight(n))\n g.addEventListener('mouseleave', clearHi)\n if (n.url) {\n g.addEventListener('click', () => { if (n.moved) { n.moved = false; return } window.open(n.url, '_blank', 'noopener') })\n }\n gN.appendChild(g); n.g = g; n.c = c; n.t = t\n })\n\n function highlight(node: SimNode) {\n const on: Record<string, boolean> = { [node.id]: true }\n edges.forEach((e, i) => {\n const hit = e.source === node.id || e.target === node.id\n edgeEls[i].setAttribute('stroke', hit ? 'rgba(146,190,240,0.95)' : 'rgba(130,175,230,0.07)')\n if (hit) { on[e.source] = true; on[e.target] = true }\n })\n nodes.forEach(m => {\n m.g!.setAttribute('opacity', on[m.id] ? '1' : '0.22')\n m.t!.setAttribute('opacity', on[m.id] ? '1' : showLabels ? '1' : '0')\n })\n }\n\n function clearHi() {\n edgeEls.forEach(el => el.setAttribute('stroke', 'rgba(130,175,230,0.10)'))\n nodes.forEach(m => {\n m.g!.setAttribute('opacity', '1')\n if (!showLabels) m.t!.setAttribute('opacity', '0')\n })\n }\n\n function paint() {\n edges.forEach((e, i) => {\n const a = byId[e.source], b = byId[e.target]\n edgeEls[i].setAttribute('x1', String(a.x)); edgeEls[i].setAttribute('y1', String(a.y))\n edgeEls[i].setAttribute('x2', String(b.x)); edgeEls[i].setAttribute('y2', String(b.y))\n })\n nodes.forEach(n => {\n n.c!.setAttribute('cx', String(n.x)); n.c!.setAttribute('cy', String(n.y))\n n.t!.setAttribute('x', String(n.x)); n.t!.setAttribute('y', String(n.y - radius(n) - 5))\n })\n }\n\n function pt(el: SVGGraphicsElement, ev: MouseEvent) {\n const m = el.getScreenCTM(); if (!m) return { x: ev.clientX, y: ev.clientY }\n const inv = m.inverse()\n return { x: inv.a * ev.clientX + inv.c * ev.clientY + inv.e, y: inv.b * ev.clientX + inv.d * ev.clientY + inv.f }\n }\n\n const state: { drag: SimNode | null; pan: { x: number; y: number; tx: number; ty: number } | null } = { drag: null, pan: null }\n\n svg.addEventListener('mousedown', ev => {\n const p = pt(view as SVGGraphicsElement, ev)\n let best = 900\n let hit: SimNode | null = null\n nodes.forEach(n => { const dx = n.x - p.x, dy = n.y - p.y, dd = dx * dx + dy * dy; if (dd < best) { best = dd; hit = n } })\n if (hit !== null) { state.drag = hit; (state.drag as SimNode).fixed = true; (state.drag as SimNode).moved = false }\n else { const r = pt(svg as SVGGraphicsElement, ev); state.pan = { x: r.x, y: r.y, tx, ty }; svg.style.cursor = 'grabbing' }\n })\n const onMouseMove = (ev: MouseEvent) => {\n if (state.drag !== null) { const p = pt(view as SVGGraphicsElement, ev); state.drag.x = p.x; state.drag.y = p.y; state.drag.moved = true; tick(); state.drag.x = p.x; state.drag.y = p.y; paint() }\n else if (state.pan !== null) { const r = pt(svg as SVGGraphicsElement, ev); tx = state.pan.tx + (r.x - state.pan.x); ty = state.pan.ty + (r.y - state.pan.y); applyView() }\n }\n const onMouseUp = () => {\n if (state.drag !== null) {\n state.drag.fixed = false; state.drag = null\n let f = 0;(function r() { tick(); paint(); if (f++ < 60) requestAnimationFrame(r) })()\n }\n if (state.pan !== null) { state.pan = null; svg.style.cursor = '' }\n }\n window.addEventListener('mousemove', onMouseMove)\n window.addEventListener('mouseup', onMouseUp)\n svg.addEventListener('wheel', ev => {\n ev.preventDefault()\n const r = pt(svg as SVGGraphicsElement, ev), lx = (r.x - tx) / sc, ly = (r.y - ty) / sc\n sc = Math.max(0.15, Math.min(4, sc * (ev.deltaY < 0 ? 1.12 : 1 / 1.12)))\n tx = r.x - lx * sc; ty = r.y - ly * sc; applyView()\n }, { passive: false })\n\n function fitView() {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity\n nodes.forEach(n => {\n const r = radius(n) + 24\n if (n.x - r < minX) minX = n.x - r; if (n.y - r < minY) minY = n.y - r\n if (n.x + r > maxX) maxX = n.x + r; if (n.y + r > maxY) maxY = n.y + r\n })\n const bw = Math.max(1, maxX - minX), bh = Math.max(1, maxY - minY), pad = 30\n sc = Math.max(0.15, Math.min(2, Math.min((W - pad * 2) / bw, (H - pad * 2) / bh)))\n tx = (W - bw * sc) / 2 - minX * sc; ty = (H - bh * sc) / 2 - minY * sc; applyView()\n }\n\n for (let k = 0; k < 500; k++) tick()\n paint(); fitView()\n\n return () => {\n window.removeEventListener('mousemove', onMouseMove)\n window.removeEventListener('mouseup', onMouseUp)\n }\n }, [data])\n\n return (\n <svg\n ref={svgRef}\n style={{ width: '100%', height: '72vh', minHeight: 560, display: 'block', background: '#0f1115', borderRadius: 8, cursor: 'grab', touchAction: 'none' }}\n role=\"img\"\n aria-label=\"Knowledge graph of your content\"\n />\n )\n}\n\nexport function OkfPage() {\n const [state, setState] = useState<{ data: OkfData | null; loading: boolean; error: string | null }>({ data: null, loading: true, error: null })\n\n useEffect(() => {\n fetch('/api/third-audience/okf-graph')\n .then(r => r.ok ? r.json() : r.json().then((e: { error?: string }) => Promise.reject(e.error ?? 'Failed')))\n .then((data: OkfData) => setState({ data, loading: false, error: null }))\n .catch((e: unknown) => setState({ data: null, loading: false, error: String(e) }))\n }, [])\n\n if (state.loading) return <div style={{ padding: 48, color: 'var(--ta-gray-500)', textAlign: 'center' }}>Loading knowledge graph…</div>\n if (state.error) return <div style={{ padding: 48, color: 'var(--ta-red)', textAlign: 'center' }}>{state.error}</div>\n if (!state.data) return null\n\n const { data } = state\n\n return (\n <div>\n <h1 className=\"ta-page-title\">OKF Bundle</h1>\n <p className=\"ta-page-subtitle\">Open Knowledge Format — your content as clean Markdown for AI crawlers</p>\n\n <div className=\"ta-hero-grid\">\n <HeroCard\n label=\"Total Pages\"\n value={data.stats.pages}\n meta=\"in content directory\"\n color=\"blue\"\n icon={<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}><path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"/><polyline points=\"14 2 14 8 20 8\"/></svg>}\n />\n <HeroCard\n label=\"Graph Nodes\"\n value={data.stats.nodes}\n meta=\"top connected pages\"\n color=\"teal\"\n icon={<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}><circle cx=\"12\" cy=\"12\" r=\"3\"/><circle cx=\"3\" cy=\"6\" r=\"2\"/><circle cx=\"21\" cy=\"6\" r=\"2\"/><circle cx=\"3\" cy=\"18\" r=\"2\"/><circle cx=\"21\" cy=\"18\" r=\"2\"/><line x1=\"5\" y1=\"6\" x2=\"10\" y2=\"11\"/><line x1=\"19\" y1=\"6\" x2=\"14\" y2=\"11\"/><line x1=\"5\" y1=\"18\" x2=\"10\" y2=\"13\"/><line x1=\"19\" y1=\"18\" x2=\"14\" y2=\"13\"/></svg>}\n />\n <HeroCard\n label=\"Internal Links\"\n value={data.stats.edges}\n meta=\"edges in graph\"\n color=\"green\"\n icon={<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}><path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\"/><path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\"/></svg>}\n />\n <HeroCard\n label=\"Bundle Index\"\n value=\"View\"\n meta={data.indexUrl.replace(/^https?:\\/\\/[^/]+/, '')}\n color=\"orange\"\n icon={<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}><path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\"/><polyline points=\"15 3 21 3 21 9\"/><line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\"/></svg>}\n />\n </div>\n\n <div style={{ marginBottom: 24 }}>\n <Card title=\"Knowledge Graph\">\n <p style={{ fontSize: 13, color: 'var(--ta-gray-500)', marginBottom: 16 }}>\n Drag nodes · scroll to zoom · drag background to pan · click a node to open the page\n {data.graph.nodes.length > 40 && ' · hover a node to reveal its labels'}\n </p>\n <OkfGraph data={data.graph} />\n </Card>\n </div>\n\n <div className=\"ta-grid-2\">\n <Card title=\"Bundle URLs\">\n <table className=\"ta-table\">\n <thead><tr><th>Resource</th><th>URL</th></tr></thead>\n <tbody>\n <tr>\n <td>Index</td>\n <td><a href=\"/okf\" target=\"_blank\" rel=\"noreferrer\" style={{ fontFamily: 'var(--ta-font-mono)', fontSize: 12 }}>/okf</a></td>\n </tr>\n <tr>\n <td>AI Sitemap</td>\n <td><a href=\"/sitemap-ai.xml\" target=\"_blank\" rel=\"noreferrer\" style={{ fontFamily: 'var(--ta-font-mono)', fontSize: 12 }}>/sitemap-ai.xml</a></td>\n </tr>\n <tr>\n <td>LLMs.txt</td>\n <td><a href=\"/llms.txt\" target=\"_blank\" rel=\"noreferrer\" style={{ fontFamily: 'var(--ta-font-mono)', fontSize: 12 }}>/llms.txt</a></td>\n </tr>\n </tbody>\n </table>\n </Card>\n <Card title=\"How AI Crawlers Use OKF\">\n <div style={{ fontSize: 13, color: 'var(--ta-gray-600)', lineHeight: 1.7 }}>\n <p style={{ marginBottom: 10 }}>Each page on your site is available as clean Markdown at <code style={{ fontFamily: 'var(--ta-font-mono)', background: 'var(--ta-gray-100)', padding: '1px 5px', borderRadius: 4 }}>/okf/slug.md</code></p>\n <p style={{ marginBottom: 10 }}>Internal links are rewritten to point to sibling <code style={{ fontFamily: 'var(--ta-font-mono)', background: 'var(--ta-gray-100)', padding: '1px 5px', borderRadius: 4 }}>.md</code> files so crawlers can follow the full knowledge graph.</p>\n <p>The index at <code style={{ fontFamily: 'var(--ta-font-mono)', background: 'var(--ta-gray-100)', padding: '1px 5px', borderRadius: 4 }}>/okf</code> lists every page with title and description — a complete sitemap in natural language.</p>\n </div>\n </Card>\n </div>\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","import type { ReactNode } from 'react'\n\ninterface HeroCardProps {\n label: string\n value: string | number\n meta?: string\n color?: 'blue' | 'green' | 'orange' | 'teal'\n icon: ReactNode\n}\n\nexport function HeroCard({ label, value, meta, color = 'blue', icon }: HeroCardProps) {\n return (\n <div className={`ta-hero-card ta-hero-card--${color}`}>\n <div className=\"ta-hero-icon\">{icon}</div>\n <div>\n <div className=\"ta-hero-label\">{label}</div>\n <div className=\"ta-hero-value\">{value}</div>\n {meta && <div className=\"ta-hero-meta\">{meta}</div>}\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["jsx","jsxs","jsx","jsxs","data"]}
|
package/dist/index.js
CHANGED
|
@@ -121,7 +121,8 @@ function thirdAudienceMiddleware(req) {
|
|
|
121
121
|
}
|
|
122
122
|
if (pathname.startsWith("/okf")) {
|
|
123
123
|
const url = req.nextUrl.clone();
|
|
124
|
-
|
|
124
|
+
const rest = pathname.slice(4);
|
|
125
|
+
url.pathname = `/api/third-audience/okf${rest || "/index"}`;
|
|
125
126
|
return import_server.NextResponse.rewrite(url);
|
|
126
127
|
}
|
|
127
128
|
if (pathname === "/llms.txt") {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/core/config.ts","../src/core/with-third-audience.ts","../src/core/middleware.ts","../src/detection/known-patterns.ts","../src/detection/bot-detection-pipeline.ts"],"sourcesContent":["/**\n * third-audience-mdx\n * Public API surface for the package.\n */\n\nexport { withThirdAudience } from './core/with-third-audience.js'\nexport { thirdAudienceMiddleware } from './core/middleware.js'\nexport { detectBot } from './detection/bot-detection-pipeline.js'\nexport type { ThirdAudienceConfig } from './core/config.js'\nexport type { BotDetectionResult } from './detection/bot-detection-result.js'\n","export interface ThirdAudienceConfig {\n /** Directory containing .mdx files, relative to project root. Default: 'content' */\n contentDir?: string\n /** Directory for JSONL data files. Default: 'data' */\n dataDir?: string\n /** Mount the /third-audience/ dashboard. Default: true */\n dashboard?: boolean\n /** Secret for dashboard access (HTTP Basic or bearer). Required when dashboard: true */\n dashboardSecret?: string\n notifications?: {\n email?: { smtp: string; to: string; from?: string }\n slack?: { webhookUrl: string }\n }\n bots?: {\n allowlist?: string[]\n blocklist?: string[]\n }\n cache?: {\n /** Cache TTL in seconds. Default: 3600 */\n ttl?: number\n /** Max in-memory entries. Default: 500 */\n maxMemoryEntries?: number\n }\n}\n\nexport const defaultConfig: Required<ThirdAudienceConfig> = {\n contentDir: 'content',\n dataDir: 'data',\n dashboard: true,\n dashboardSecret: '',\n notifications: {},\n bots: { allowlist: [], blocklist: [] },\n cache: { ttl: 3600, maxMemoryEntries: 500 },\n}\n\nexport function resolveConfig(partial: ThirdAudienceConfig = {}): Required<ThirdAudienceConfig> {\n return {\n ...defaultConfig,\n ...partial,\n bots: { ...defaultConfig.bots, ...partial.bots },\n cache: { ...defaultConfig.cache, ...partial.cache },\n notifications: { ...defaultConfig.notifications, ...partial.notifications },\n }\n}\n","import type { NextConfig } from 'next'\nimport { resolveConfig, type ThirdAudienceConfig } from './config.js'\n\n/**\n * Wraps next.config.ts to inject Third Audience rewrites and headers.\n *\n * Usage:\n * import { withThirdAudience } from 'third-audience-mdx'\n * export default withThirdAudience({ contentDir: 'content' })\n */\nexport function withThirdAudience(\n options: ThirdAudienceConfig = {},\n nextConfig: NextConfig = {}\n): NextConfig {\n const config = resolveConfig(options)\n\n return {\n ...nextConfig,\n async headers() {\n const existing = await nextConfig.headers?.() ?? []\n return [\n ...existing,\n {\n source: '/:path*.md',\n headers: [{ key: 'Content-Type', value: 'text/markdown; charset=utf-8' }],\n },\n {\n source: '/llms.txt',\n headers: [{ key: 'Content-Type', value: 'text/plain; charset=utf-8' }],\n },\n {\n source: '/okf/:path*',\n headers: [{ key: 'Content-Type', value: 'text/markdown; charset=utf-8' }],\n },\n ]\n },\n env: {\n ...nextConfig.env,\n TA_CONTENT_DIR: config.contentDir,\n TA_DATA_DIR: config.dataDir,\n TA_DASHBOARD_ENABLED: String(config.dashboard),\n },\n }\n}\n","import { NextResponse, type NextRequest } from 'next/server'\n\nconst COOKIE_NAME = 'ta_session'\nconst RESET_COOKIE = 'ta_session_reset'\n\n/**\n * Third Audience middleware — Edge-runtime compatible (no Node.js crypto).\n *\n * Auth guard uses cookie presence only; HMAC verification happens in the\n * route handler (Node.js runtime) where crypto is available.\n *\n * Wire up in middleware.ts:\n * export { thirdAudienceMiddleware as middleware } from 'third-audience-mdx'\n * export const config = { matcher: ['/((?!_next|api).*)'] }\n */\nexport function thirdAudienceMiddleware(req: NextRequest): NextResponse | null {\n const { pathname } = req.nextUrl\n const accept = req.headers.get('accept') ?? ''\n\n // Dashboard auth guard — cookie presence check (HMAC verified in route handler)\n if (pathname.startsWith('/third-audience') && !pathname.startsWith('/third-audience/login')) {\n const session = req.cookies.get(COOKIE_NAME)?.value\n if (!session) {\n const loginUrl = req.nextUrl.clone()\n loginUrl.pathname = '/third-audience/login'\n return NextResponse.redirect(loginUrl)\n }\n }\n\n // Password reset guard — /third-audience/login?reset=1 requires reset or session cookie\n if (pathname === '/third-audience/login' && req.nextUrl.searchParams.get('reset') === '1') {\n const resetCookie = req.cookies.get(RESET_COOKIE)?.value\n const sessionCookie = req.cookies.get(COOKIE_NAME)?.value\n if (!resetCookie && !sessionCookie) {\n const loginUrl = req.nextUrl.clone()\n loginUrl.pathname = '/third-audience/login'\n loginUrl.search = ''\n return NextResponse.redirect(loginUrl)\n }\n }\n\n // /third-audience/login → rewrite to login route handler (GET/POST)\n if (pathname === '/third-audience/login') {\n const url = req.nextUrl.clone()\n url.pathname = '/api/third-audience/login'\n return NextResponse.rewrite(url)\n }\n\n // .md URL → rewrite to our internal markdown route handler\n if (pathname.endsWith('.md')) {\n const slug = pathname.slice(0, -3) // strip .md\n const url = req.nextUrl.clone()\n url.pathname = `/api/third-audience/markdown${slug}`\n return NextResponse.rewrite(url)\n }\n\n // Accept: text/markdown header → rewrite to markdown route\n if (accept.includes('text/markdown')) {\n const url = req.nextUrl.clone()\n url.pathname = `/api/third-audience/markdown${pathname}`\n return NextResponse.rewrite(url)\n }\n\n // /okf/ → rewrite to OKF bundle handler\n if (pathname.startsWith('/okf')) {\n const url = req.nextUrl.clone()\n url.pathname = `/api/third-audience/okf${pathname.slice(4)}`\n return NextResponse.rewrite(url)\n }\n\n // /llms.txt → rewrite to discovery handler\n if (pathname === '/llms.txt') {\n const url = req.nextUrl.clone()\n url.pathname = '/api/third-audience/llms-txt'\n return NextResponse.rewrite(url)\n }\n\n // /sitemap-ai.xml → rewrite to AI sitemap handler\n if (pathname === '/sitemap-ai.xml') {\n const url = req.nextUrl.clone()\n url.pathname = '/api/third-audience/sitemap-ai'\n return NextResponse.rewrite(url)\n }\n\n // No match — let the caller's middleware chain continue\n return null\n}\n\n","/** Known AI crawler and search engine user-agent patterns. */\nexport interface KnownBot {\n name: string\n category: 'ai_crawler' | 'search_engine'\n patterns: RegExp[]\n}\n\nexport const KNOWN_BOTS: KnownBot[] = [\n // AI Crawlers\n { name: 'ClaudeBot', category: 'ai_crawler', patterns: [/claudebot/i, /claude-web/i] },\n { name: 'GPTBot', category: 'ai_crawler', patterns: [/gptbot/i] },\n { name: 'ChatGPT-User', category: 'ai_crawler', patterns: [/chatgpt-user/i] },\n { name: 'PerplexityBot', category: 'ai_crawler', patterns: [/perplexitybot/i] },\n { name: 'Googlebot-AI', category: 'ai_crawler', patterns: [/google-extended/i, /googleother/i] },\n { name: 'FacebookBot', category: 'ai_crawler', patterns: [/facebookbot/i] },\n { name: 'Applebot-Extended',category: 'ai_crawler', patterns: [/applebot-extended/i] },\n { name: 'YouBot', category: 'ai_crawler', patterns: [/youbot/i] },\n { name: 'CCBot', category: 'ai_crawler', patterns: [/ccbot/i] },\n { name: 'CohereCrawler', category: 'ai_crawler', patterns: [/cohere-ai/i] },\n { name: 'AI2Bot', category: 'ai_crawler', patterns: [/ai2bot/i] },\n { name: 'Bytespider', category: 'ai_crawler', patterns: [/bytespider/i] },\n { name: 'Diffbot', category: 'ai_crawler', patterns: [/diffbot/i] },\n\n // Search Engines\n { name: 'Googlebot', category: 'search_engine', patterns: [/googlebot/i] },\n { name: 'Bingbot', category: 'search_engine', patterns: [/bingbot/i, /msnbot/i] },\n { name: 'DuckDuckBot', category: 'search_engine', patterns: [/duckduckbot/i] },\n { name: 'Baiduspider', category: 'search_engine', patterns: [/baiduspider/i] },\n { name: 'YandexBot', category: 'search_engine', patterns: [/yandexbot/i] },\n { name: 'Sogou', category: 'search_engine', patterns: [/sogou/i] },\n { name: 'Exabot', category: 'search_engine', patterns: [/exabot/i] },\n { name: 'ia_archiver', category: 'search_engine', patterns: [/ia_archiver/i] },\n]\n","import type { BotDetectionResult } from './bot-detection-result.js'\nimport { KNOWN_BOTS } from './known-patterns.js'\n\nexport interface DetectBotInput {\n userAgent: string\n /** Optional: headers map for heuristic checks */\n headers?: Record<string, string | string[] | undefined>\n /** Optional: IP address */\n ip?: string\n}\n\n/**\n * Three-layer bot detection pipeline:\n * 1. Known pattern matching (O(n) UA string match)\n * 2. Heuristic signals (missing headers, headless indicators)\n * 3. Auto-learner flag (unknown UAs that behave bot-like)\n */\nexport function detectBot(input: DetectBotInput): BotDetectionResult {\n const ua = input.userAgent ?? ''\n\n // Layer 1: known pattern match\n for (const bot of KNOWN_BOTS) {\n for (const pattern of bot.patterns) {\n if (pattern.test(ua)) {\n return {\n isBot: true,\n botName: bot.name,\n confidence: 'high',\n detectionMethod: 'known_pattern',\n category: bot.category,\n rawUserAgent: ua,\n }\n }\n }\n }\n\n // Layer 2: heuristics\n const heuristicResult = checkHeuristics(ua, input.headers ?? {})\n if (heuristicResult) return { ...heuristicResult, rawUserAgent: ua }\n\n // Layer 3: auto-learner — flag suspicious unknown UAs for review\n if (looksLikeBotUa(ua)) {\n return {\n isBot: true,\n botName: null,\n confidence: 'low',\n detectionMethod: 'auto_learned',\n category: 'unknown_bot',\n rawUserAgent: ua,\n }\n }\n\n return {\n isBot: false,\n botName: null,\n confidence: 'high',\n detectionMethod: 'none',\n category: 'human',\n rawUserAgent: ua,\n }\n}\n\nfunction checkHeuristics(\n ua: string,\n headers: Record<string, string | string[] | undefined>\n): Omit<BotDetectionResult, 'rawUserAgent'> | null {\n // Headless Chrome signals\n if (/headlesschrome/i.test(ua)) {\n return { isBot: true, botName: 'HeadlessChrome', confidence: 'medium', detectionMethod: 'heuristic', category: 'unknown_bot' }\n }\n if (/phantomjs/i.test(ua)) {\n return { isBot: true, botName: 'PhantomJS', confidence: 'high', detectionMethod: 'heuristic', category: 'unknown_bot' }\n }\n if (/selenium/i.test(ua)) {\n return { isBot: true, botName: 'Selenium', confidence: 'high', detectionMethod: 'heuristic', category: 'unknown_bot' }\n }\n\n // Empty or very short UA is suspicious\n if (ua.trim().length < 10) {\n return { isBot: true, botName: null, confidence: 'low', detectionMethod: 'heuristic', category: 'unknown_bot' }\n }\n\n // Missing typical browser headers\n const hasAcceptLang = !!headers['accept-language']\n const hasAcceptEncoding = !!headers['accept-encoding']\n if (!hasAcceptLang && !hasAcceptEncoding) {\n return { isBot: true, botName: null, confidence: 'low', detectionMethod: 'heuristic', category: 'unknown_bot' }\n }\n\n return null\n}\n\nfunction looksLikeBotUa(ua: string): boolean {\n return (\n /bot|crawler|spider|scraper|fetch|http|python|curl|java|ruby|go-http|node/i.test(ua) &&\n !/chrome|firefox|safari|edge|opera/i.test(ua)\n )\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/core/config.ts","../src/core/with-third-audience.ts","../src/core/middleware.ts","../src/detection/known-patterns.ts","../src/detection/bot-detection-pipeline.ts"],"sourcesContent":["/**\n * third-audience-mdx\n * Public API surface for the package.\n */\n\nexport { withThirdAudience } from './core/with-third-audience.js'\nexport { thirdAudienceMiddleware } from './core/middleware.js'\nexport { detectBot } from './detection/bot-detection-pipeline.js'\nexport type { ThirdAudienceConfig } from './core/config.js'\nexport type { BotDetectionResult } from './detection/bot-detection-result.js'\n","export interface ThirdAudienceConfig {\n /** Directory containing .mdx files, relative to project root. Default: 'content' */\n contentDir?: string\n /** Directory for JSONL data files. Default: 'data' */\n dataDir?: string\n /** Mount the /third-audience/ dashboard. Default: true */\n dashboard?: boolean\n /** Secret for dashboard access (HTTP Basic or bearer). Required when dashboard: true */\n dashboardSecret?: string\n notifications?: {\n email?: { smtp: string; to: string; from?: string }\n slack?: { webhookUrl: string }\n }\n bots?: {\n allowlist?: string[]\n blocklist?: string[]\n }\n cache?: {\n /** Cache TTL in seconds. Default: 3600 */\n ttl?: number\n /** Max in-memory entries. Default: 500 */\n maxMemoryEntries?: number\n }\n}\n\nexport const defaultConfig: Required<ThirdAudienceConfig> = {\n contentDir: 'content',\n dataDir: 'data',\n dashboard: true,\n dashboardSecret: '',\n notifications: {},\n bots: { allowlist: [], blocklist: [] },\n cache: { ttl: 3600, maxMemoryEntries: 500 },\n}\n\nexport function resolveConfig(partial: ThirdAudienceConfig = {}): Required<ThirdAudienceConfig> {\n return {\n ...defaultConfig,\n ...partial,\n bots: { ...defaultConfig.bots, ...partial.bots },\n cache: { ...defaultConfig.cache, ...partial.cache },\n notifications: { ...defaultConfig.notifications, ...partial.notifications },\n }\n}\n","import type { NextConfig } from 'next'\nimport { resolveConfig, type ThirdAudienceConfig } from './config.js'\n\n/**\n * Wraps next.config.ts to inject Third Audience rewrites and headers.\n *\n * Usage:\n * import { withThirdAudience } from 'third-audience-mdx'\n * export default withThirdAudience({ contentDir: 'content' })\n */\nexport function withThirdAudience(\n options: ThirdAudienceConfig = {},\n nextConfig: NextConfig = {}\n): NextConfig {\n const config = resolveConfig(options)\n\n return {\n ...nextConfig,\n async headers() {\n const existing = await nextConfig.headers?.() ?? []\n return [\n ...existing,\n {\n source: '/:path*.md',\n headers: [{ key: 'Content-Type', value: 'text/markdown; charset=utf-8' }],\n },\n {\n source: '/llms.txt',\n headers: [{ key: 'Content-Type', value: 'text/plain; charset=utf-8' }],\n },\n {\n source: '/okf/:path*',\n headers: [{ key: 'Content-Type', value: 'text/markdown; charset=utf-8' }],\n },\n ]\n },\n env: {\n ...nextConfig.env,\n TA_CONTENT_DIR: config.contentDir,\n TA_DATA_DIR: config.dataDir,\n TA_DASHBOARD_ENABLED: String(config.dashboard),\n },\n }\n}\n","import { NextResponse, type NextRequest } from 'next/server'\n\nconst COOKIE_NAME = 'ta_session'\nconst RESET_COOKIE = 'ta_session_reset'\n\n/**\n * Third Audience middleware — Edge-runtime compatible (no Node.js crypto).\n *\n * Auth guard uses cookie presence only; HMAC verification happens in the\n * route handler (Node.js runtime) where crypto is available.\n *\n * Wire up in middleware.ts:\n * export { thirdAudienceMiddleware as middleware } from 'third-audience-mdx'\n * export const config = { matcher: ['/((?!_next|api).*)'] }\n */\nexport function thirdAudienceMiddleware(req: NextRequest): NextResponse | null {\n const { pathname } = req.nextUrl\n const accept = req.headers.get('accept') ?? ''\n\n // Dashboard auth guard — cookie presence check (HMAC verified in route handler)\n if (pathname.startsWith('/third-audience') && !pathname.startsWith('/third-audience/login')) {\n const session = req.cookies.get(COOKIE_NAME)?.value\n if (!session) {\n const loginUrl = req.nextUrl.clone()\n loginUrl.pathname = '/third-audience/login'\n return NextResponse.redirect(loginUrl)\n }\n }\n\n // Password reset guard — /third-audience/login?reset=1 requires reset or session cookie\n if (pathname === '/third-audience/login' && req.nextUrl.searchParams.get('reset') === '1') {\n const resetCookie = req.cookies.get(RESET_COOKIE)?.value\n const sessionCookie = req.cookies.get(COOKIE_NAME)?.value\n if (!resetCookie && !sessionCookie) {\n const loginUrl = req.nextUrl.clone()\n loginUrl.pathname = '/third-audience/login'\n loginUrl.search = ''\n return NextResponse.redirect(loginUrl)\n }\n }\n\n // /third-audience/login → rewrite to login route handler (GET/POST)\n if (pathname === '/third-audience/login') {\n const url = req.nextUrl.clone()\n url.pathname = '/api/third-audience/login'\n return NextResponse.rewrite(url)\n }\n\n // .md URL → rewrite to our internal markdown route handler\n if (pathname.endsWith('.md')) {\n const slug = pathname.slice(0, -3) // strip .md\n const url = req.nextUrl.clone()\n url.pathname = `/api/third-audience/markdown${slug}`\n return NextResponse.rewrite(url)\n }\n\n // Accept: text/markdown header → rewrite to markdown route\n if (accept.includes('text/markdown')) {\n const url = req.nextUrl.clone()\n url.pathname = `/api/third-audience/markdown${pathname}`\n return NextResponse.rewrite(url)\n }\n\n // /okf or /okf/* → rewrite to OKF bundle handler\n // [...path] catch-all requires at least one segment, so /okf → /okf/index\n if (pathname.startsWith('/okf')) {\n const url = req.nextUrl.clone()\n const rest = pathname.slice(4) // '' or '/something'\n url.pathname = `/api/third-audience/okf${rest || '/index'}`\n return NextResponse.rewrite(url)\n }\n\n // /llms.txt → rewrite to discovery handler\n if (pathname === '/llms.txt') {\n const url = req.nextUrl.clone()\n url.pathname = '/api/third-audience/llms-txt'\n return NextResponse.rewrite(url)\n }\n\n // /sitemap-ai.xml → rewrite to AI sitemap handler\n if (pathname === '/sitemap-ai.xml') {\n const url = req.nextUrl.clone()\n url.pathname = '/api/third-audience/sitemap-ai'\n return NextResponse.rewrite(url)\n }\n\n // No match — let the caller's middleware chain continue\n return null\n}\n\n","/** Known AI crawler and search engine user-agent patterns. */\nexport interface KnownBot {\n name: string\n category: 'ai_crawler' | 'search_engine'\n patterns: RegExp[]\n}\n\nexport const KNOWN_BOTS: KnownBot[] = [\n // AI Crawlers\n { name: 'ClaudeBot', category: 'ai_crawler', patterns: [/claudebot/i, /claude-web/i] },\n { name: 'GPTBot', category: 'ai_crawler', patterns: [/gptbot/i] },\n { name: 'ChatGPT-User', category: 'ai_crawler', patterns: [/chatgpt-user/i] },\n { name: 'PerplexityBot', category: 'ai_crawler', patterns: [/perplexitybot/i] },\n { name: 'Googlebot-AI', category: 'ai_crawler', patterns: [/google-extended/i, /googleother/i] },\n { name: 'FacebookBot', category: 'ai_crawler', patterns: [/facebookbot/i] },\n { name: 'Applebot-Extended',category: 'ai_crawler', patterns: [/applebot-extended/i] },\n { name: 'YouBot', category: 'ai_crawler', patterns: [/youbot/i] },\n { name: 'CCBot', category: 'ai_crawler', patterns: [/ccbot/i] },\n { name: 'CohereCrawler', category: 'ai_crawler', patterns: [/cohere-ai/i] },\n { name: 'AI2Bot', category: 'ai_crawler', patterns: [/ai2bot/i] },\n { name: 'Bytespider', category: 'ai_crawler', patterns: [/bytespider/i] },\n { name: 'Diffbot', category: 'ai_crawler', patterns: [/diffbot/i] },\n\n // Search Engines\n { name: 'Googlebot', category: 'search_engine', patterns: [/googlebot/i] },\n { name: 'Bingbot', category: 'search_engine', patterns: [/bingbot/i, /msnbot/i] },\n { name: 'DuckDuckBot', category: 'search_engine', patterns: [/duckduckbot/i] },\n { name: 'Baiduspider', category: 'search_engine', patterns: [/baiduspider/i] },\n { name: 'YandexBot', category: 'search_engine', patterns: [/yandexbot/i] },\n { name: 'Sogou', category: 'search_engine', patterns: [/sogou/i] },\n { name: 'Exabot', category: 'search_engine', patterns: [/exabot/i] },\n { name: 'ia_archiver', category: 'search_engine', patterns: [/ia_archiver/i] },\n]\n","import type { BotDetectionResult } from './bot-detection-result.js'\nimport { KNOWN_BOTS } from './known-patterns.js'\n\nexport interface DetectBotInput {\n userAgent: string\n /** Optional: headers map for heuristic checks */\n headers?: Record<string, string | string[] | undefined>\n /** Optional: IP address */\n ip?: string\n}\n\n/**\n * Three-layer bot detection pipeline:\n * 1. Known pattern matching (O(n) UA string match)\n * 2. Heuristic signals (missing headers, headless indicators)\n * 3. Auto-learner flag (unknown UAs that behave bot-like)\n */\nexport function detectBot(input: DetectBotInput): BotDetectionResult {\n const ua = input.userAgent ?? ''\n\n // Layer 1: known pattern match\n for (const bot of KNOWN_BOTS) {\n for (const pattern of bot.patterns) {\n if (pattern.test(ua)) {\n return {\n isBot: true,\n botName: bot.name,\n confidence: 'high',\n detectionMethod: 'known_pattern',\n category: bot.category,\n rawUserAgent: ua,\n }\n }\n }\n }\n\n // Layer 2: heuristics\n const heuristicResult = checkHeuristics(ua, input.headers ?? {})\n if (heuristicResult) return { ...heuristicResult, rawUserAgent: ua }\n\n // Layer 3: auto-learner — flag suspicious unknown UAs for review\n if (looksLikeBotUa(ua)) {\n return {\n isBot: true,\n botName: null,\n confidence: 'low',\n detectionMethod: 'auto_learned',\n category: 'unknown_bot',\n rawUserAgent: ua,\n }\n }\n\n return {\n isBot: false,\n botName: null,\n confidence: 'high',\n detectionMethod: 'none',\n category: 'human',\n rawUserAgent: ua,\n }\n}\n\nfunction checkHeuristics(\n ua: string,\n headers: Record<string, string | string[] | undefined>\n): Omit<BotDetectionResult, 'rawUserAgent'> | null {\n // Headless Chrome signals\n if (/headlesschrome/i.test(ua)) {\n return { isBot: true, botName: 'HeadlessChrome', confidence: 'medium', detectionMethod: 'heuristic', category: 'unknown_bot' }\n }\n if (/phantomjs/i.test(ua)) {\n return { isBot: true, botName: 'PhantomJS', confidence: 'high', detectionMethod: 'heuristic', category: 'unknown_bot' }\n }\n if (/selenium/i.test(ua)) {\n return { isBot: true, botName: 'Selenium', confidence: 'high', detectionMethod: 'heuristic', category: 'unknown_bot' }\n }\n\n // Empty or very short UA is suspicious\n if (ua.trim().length < 10) {\n return { isBot: true, botName: null, confidence: 'low', detectionMethod: 'heuristic', category: 'unknown_bot' }\n }\n\n // Missing typical browser headers\n const hasAcceptLang = !!headers['accept-language']\n const hasAcceptEncoding = !!headers['accept-encoding']\n if (!hasAcceptLang && !hasAcceptEncoding) {\n return { isBot: true, botName: null, confidence: 'low', detectionMethod: 'heuristic', category: 'unknown_bot' }\n }\n\n return null\n}\n\nfunction looksLikeBotUa(ua: string): boolean {\n return (\n /bot|crawler|spider|scraper|fetch|http|python|curl|java|ruby|go-http|node/i.test(ua) &&\n !/chrome|firefox|safari|edge|opera/i.test(ua)\n )\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -93,7 +93,8 @@ function thirdAudienceMiddleware(req) {
|
|
|
93
93
|
}
|
|
94
94
|
if (pathname.startsWith("/okf")) {
|
|
95
95
|
const url = req.nextUrl.clone();
|
|
96
|
-
|
|
96
|
+
const rest = pathname.slice(4);
|
|
97
|
+
url.pathname = `/api/third-audience/okf${rest || "/index"}`;
|
|
97
98
|
return NextResponse.rewrite(url);
|
|
98
99
|
}
|
|
99
100
|
if (pathname === "/llms.txt") {
|