third-audience-mdx 1.0.0 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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.d.mts CHANGED
@@ -42,20 +42,16 @@ interface ThirdAudienceConfig {
42
42
  declare function withThirdAudience(options?: ThirdAudienceConfig, nextConfig?: NextConfig): NextConfig;
43
43
 
44
44
  /**
45
- * Third Audience middleware.
45
+ * Third Audience middleware — Edge-runtime compatible (no Node.js crypto).
46
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
47
+ * Auth guard uses cookie presence only; HMAC verification happens in the
48
+ * route handler (Node.js runtime) where crypto is available.
53
49
  *
54
50
  * Wire up in middleware.ts:
55
51
  * export { thirdAudienceMiddleware as middleware } from 'third-audience-mdx'
56
52
  * export const config = { matcher: ['/((?!_next|api).*)'] }
57
53
  */
58
- declare function thirdAudienceMiddleware(req: NextRequest): Promise<NextResponse>;
54
+ declare function thirdAudienceMiddleware(req: NextRequest): NextResponse | null;
59
55
 
60
56
  interface BotDetectionResult {
61
57
  isBot: boolean;
package/dist/index.d.ts CHANGED
@@ -42,20 +42,16 @@ interface ThirdAudienceConfig {
42
42
  declare function withThirdAudience(options?: ThirdAudienceConfig, nextConfig?: NextConfig): NextConfig;
43
43
 
44
44
  /**
45
- * Third Audience middleware.
45
+ * Third Audience middleware — Edge-runtime compatible (no Node.js crypto).
46
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
47
+ * Auth guard uses cookie presence only; HMAC verification happens in the
48
+ * route handler (Node.js runtime) where crypto is available.
53
49
  *
54
50
  * Wire up in middleware.ts:
55
51
  * export { thirdAudienceMiddleware as middleware } from 'third-audience-mdx'
56
52
  * export const config = { matcher: ['/((?!_next|api).*)'] }
57
53
  */
58
- declare function thirdAudienceMiddleware(req: NextRequest): Promise<NextResponse>;
54
+ declare function thirdAudienceMiddleware(req: NextRequest): NextResponse | null;
59
55
 
60
56
  interface BotDetectionResult {
61
57
  isBot: boolean;