third-audience-mdx 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/CLAUDE.md +41 -0
  2. package/INSTALLATION.md +367 -0
  3. package/README.md +303 -0
  4. package/WORKLOG.md +162 -0
  5. package/dist/cli/index.d.mts +1 -0
  6. package/dist/cli/index.d.ts +1 -0
  7. package/dist/cli/index.js +208 -0
  8. package/dist/cli/index.js.map +1 -0
  9. package/dist/cli/index.mjs +185 -0
  10. package/dist/cli/index.mjs.map +1 -0
  11. package/dist/dashboard/auth.d.mts +16 -0
  12. package/dist/dashboard/auth.d.ts +16 -0
  13. package/dist/dashboard/auth.js +123 -0
  14. package/dist/dashboard/auth.js.map +1 -0
  15. package/dist/dashboard/auth.mjs +87 -0
  16. package/dist/dashboard/auth.mjs.map +1 -0
  17. package/dist/dashboard/routes/analytics-api-route.d.mts +6 -0
  18. package/dist/dashboard/routes/analytics-api-route.d.ts +6 -0
  19. package/dist/dashboard/routes/analytics-api-route.js +180 -0
  20. package/dist/dashboard/routes/analytics-api-route.js.map +1 -0
  21. package/dist/dashboard/routes/analytics-api-route.mjs +145 -0
  22. package/dist/dashboard/routes/analytics-api-route.mjs.map +1 -0
  23. package/dist/dashboard/routes/api-key-route.d.mts +8 -0
  24. package/dist/dashboard/routes/api-key-route.d.ts +8 -0
  25. package/dist/dashboard/routes/api-key-route.js +173 -0
  26. package/dist/dashboard/routes/api-key-route.js.map +1 -0
  27. package/dist/dashboard/routes/api-key-route.mjs +137 -0
  28. package/dist/dashboard/routes/api-key-route.mjs.map +1 -0
  29. package/dist/dashboard/routes/citation-route.d.mts +14 -0
  30. package/dist/dashboard/routes/citation-route.d.ts +14 -0
  31. package/dist/dashboard/routes/citation-route.js +202 -0
  32. package/dist/dashboard/routes/citation-route.js.map +1 -0
  33. package/dist/dashboard/routes/citation-route.mjs +166 -0
  34. package/dist/dashboard/routes/citation-route.mjs.map +1 -0
  35. package/dist/dashboard/routes/llms-txt-route.d.mts +6 -0
  36. package/dist/dashboard/routes/llms-txt-route.d.ts +6 -0
  37. package/dist/dashboard/routes/llms-txt-route.js +119 -0
  38. package/dist/dashboard/routes/llms-txt-route.js.map +1 -0
  39. package/dist/dashboard/routes/llms-txt-route.mjs +84 -0
  40. package/dist/dashboard/routes/llms-txt-route.mjs.map +1 -0
  41. package/dist/dashboard/routes/login-route.d.mts +6 -0
  42. package/dist/dashboard/routes/login-route.d.ts +6 -0
  43. package/dist/dashboard/routes/login-route.js +313 -0
  44. package/dist/dashboard/routes/login-route.js.map +1 -0
  45. package/dist/dashboard/routes/login-route.mjs +284 -0
  46. package/dist/dashboard/routes/login-route.mjs.map +1 -0
  47. package/dist/dashboard/routes/markdown-route.d.mts +15 -0
  48. package/dist/dashboard/routes/markdown-route.d.ts +15 -0
  49. package/dist/dashboard/routes/markdown-route.js +239 -0
  50. package/dist/dashboard/routes/markdown-route.js.map +1 -0
  51. package/dist/dashboard/routes/markdown-route.mjs +204 -0
  52. package/dist/dashboard/routes/markdown-route.mjs.map +1 -0
  53. package/dist/dashboard/routes/okf-route.d.mts +13 -0
  54. package/dist/dashboard/routes/okf-route.d.ts +13 -0
  55. package/dist/dashboard/routes/okf-route.js +184 -0
  56. package/dist/dashboard/routes/okf-route.js.map +1 -0
  57. package/dist/dashboard/routes/okf-route.mjs +149 -0
  58. package/dist/dashboard/routes/okf-route.mjs.map +1 -0
  59. package/dist/dashboard/routes/sitemap-ai-route.d.mts +6 -0
  60. package/dist/dashboard/routes/sitemap-ai-route.d.ts +6 -0
  61. package/dist/dashboard/routes/sitemap-ai-route.js +134 -0
  62. package/dist/dashboard/routes/sitemap-ai-route.js.map +1 -0
  63. package/dist/dashboard/routes/sitemap-ai-route.mjs +99 -0
  64. package/dist/dashboard/routes/sitemap-ai-route.mjs.map +1 -0
  65. package/dist/dashboard/ui/components/Sidebar.d.mts +5 -0
  66. package/dist/dashboard/ui/components/Sidebar.d.ts +5 -0
  67. package/dist/dashboard/ui/components/Sidebar.js +102 -0
  68. package/dist/dashboard/ui/components/Sidebar.js.map +1 -0
  69. package/dist/dashboard/ui/components/Sidebar.mjs +68 -0
  70. package/dist/dashboard/ui/components/Sidebar.mjs.map +1 -0
  71. package/dist/dashboard/ui/globals.css +175 -0
  72. package/dist/dashboard/ui/pages/BotAnalyticsPage.d.mts +5 -0
  73. package/dist/dashboard/ui/pages/BotAnalyticsPage.d.ts +5 -0
  74. package/dist/dashboard/ui/pages/BotAnalyticsPage.js +269 -0
  75. package/dist/dashboard/ui/pages/BotAnalyticsPage.js.map +1 -0
  76. package/dist/dashboard/ui/pages/BotAnalyticsPage.mjs +232 -0
  77. package/dist/dashboard/ui/pages/BotAnalyticsPage.mjs.map +1 -0
  78. package/dist/dashboard/ui/pages/BotManagementPage.d.mts +13 -0
  79. package/dist/dashboard/ui/pages/BotManagementPage.d.ts +13 -0
  80. package/dist/dashboard/ui/pages/BotManagementPage.js +177 -0
  81. package/dist/dashboard/ui/pages/BotManagementPage.js.map +1 -0
  82. package/dist/dashboard/ui/pages/BotManagementPage.mjs +153 -0
  83. package/dist/dashboard/ui/pages/BotManagementPage.mjs.map +1 -0
  84. package/dist/dashboard/ui/pages/LlmTrafficPage.d.mts +5 -0
  85. package/dist/dashboard/ui/pages/LlmTrafficPage.d.ts +5 -0
  86. package/dist/dashboard/ui/pages/LlmTrafficPage.js +203 -0
  87. package/dist/dashboard/ui/pages/LlmTrafficPage.js.map +1 -0
  88. package/dist/dashboard/ui/pages/LlmTrafficPage.mjs +168 -0
  89. package/dist/dashboard/ui/pages/LlmTrafficPage.mjs.map +1 -0
  90. package/dist/dashboard/ui/pages/SettingsPage.d.mts +8 -0
  91. package/dist/dashboard/ui/pages/SettingsPage.d.ts +8 -0
  92. package/dist/dashboard/ui/pages/SettingsPage.js +181 -0
  93. package/dist/dashboard/ui/pages/SettingsPage.js.map +1 -0
  94. package/dist/dashboard/ui/pages/SettingsPage.mjs +157 -0
  95. package/dist/dashboard/ui/pages/SettingsPage.mjs.map +1 -0
  96. package/dist/dashboard/ui/pages/SystemHealthPage.d.mts +5 -0
  97. package/dist/dashboard/ui/pages/SystemHealthPage.d.ts +5 -0
  98. package/dist/dashboard/ui/pages/SystemHealthPage.js +183 -0
  99. package/dist/dashboard/ui/pages/SystemHealthPage.js.map +1 -0
  100. package/dist/dashboard/ui/pages/SystemHealthPage.mjs +148 -0
  101. package/dist/dashboard/ui/pages/SystemHealthPage.mjs.map +1 -0
  102. package/dist/index.d.mts +84 -0
  103. package/dist/index.d.ts +84 -0
  104. package/dist/index.js +372 -0
  105. package/dist/index.js.map +1 -0
  106. package/dist/index.mjs +346 -0
  107. package/dist/index.mjs.map +1 -0
  108. package/package.json +125 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/dashboard/ui/pages/LlmTrafficPage.tsx","../../../../src/dashboard/ui/components/Card.tsx","../../../../src/dashboard/ui/components/HeroCard.tsx"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport { Card } from '../components/Card.js'\nimport { HeroCard } from '../components/HeroCard.js'\nimport type { CitationRecord } from '../../../citations/citation-tracker.js'\n\nconst PLATFORM_COLORS: Record<string, string> = {\n ChatGPT: 'green', Perplexity: 'blue', Claude: 'orange',\n Gemini: 'teal', Copilot: 'blue', default: 'gray',\n}\n\nfunction loadCitations(days = 30): CitationRecord[] {\n const dataDir = process.env.TA_DATA_DIR ?? 'data'\n const filePath = path.join(process.cwd(), dataDir, 'ta-citations.jsonl')\n if (!fs.existsSync(filePath)) return []\n\n const cutoff = new Date()\n cutoff.setDate(cutoff.getDate() - days)\n const cutoffStr = cutoff.toISOString()\n\n return fs.readFileSync(filePath, 'utf-8')\n .split('\\n').filter(Boolean)\n .map(l => { try { return JSON.parse(l) as CitationRecord } catch { return null } })\n .filter((r): r is CitationRecord => r !== null && r.timestamp >= cutoffStr)\n}\n\nfunction groupBy<T>(arr: T[], key: (item: T) => string): Array<{ name: string; count: number }> {\n const map = new Map<string, number>()\n for (const item of arr) {\n const k = key(item)\n map.set(k, (map.get(k) ?? 0) + 1)\n }\n return [...map.entries()]\n .sort((a, b) => b[1] - a[1])\n .map(([name, count]) => ({ name, count }))\n}\n\nexport async function LlmTrafficPage() {\n const records = loadCitations(30)\n\n const today = new Date().toISOString().slice(0, 10)\n const todayCount = records.filter(r => r.timestamp.startsWith(today)).length\n\n const byPlatform = groupBy(records, r => r.platform)\n const byPage = groupBy(records, r => r.url)\n const byQuery = groupBy(records.filter(r => r.query), r => r.query!).slice(0, 10)\n\n return (\n <div>\n <h1 className=\"ta-page-title\">LLM Traffic</h1>\n <p className=\"ta-page-subtitle\">Citation clicks from AI platforms (last 30 days)</p>\n\n <div className=\"ta-hero-grid\">\n <HeroCard\n label=\"Total Citations\"\n value={records.length.toLocaleString()}\n meta={`${todayCount} today`}\n color=\"blue\"\n icon={<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}><path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/></svg>}\n />\n <HeroCard\n label=\"AI Platforms\"\n value={byPlatform.length}\n meta=\"distinct sources\"\n color=\"green\"\n icon={<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}><circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"2\" y1=\"12\" x2=\"22\" y2=\"12\"/><path d=\"M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z\"/></svg>}\n />\n <HeroCard\n label=\"Pages Cited\"\n value={byPage.length}\n meta=\"unique URLs cited\"\n color=\"orange\"\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=\"Top Platform\"\n value={byPlatform[0]?.name ?? '—'}\n meta={byPlatform[0] ? `${byPlatform[0].count} citations` : 'no data yet'}\n color=\"teal\"\n icon={<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}><polygon points=\"12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2\"/></svg>}\n />\n </div>\n\n <div className=\"ta-grid-2\">\n <Card title=\"By Platform\">\n {byPlatform.length === 0 ? (\n <div className=\"ta-empty\"><p>No citation data yet. Make sure citation-tracker.js is included in your layout.</p></div>\n ) : (\n <table className=\"ta-table\">\n <thead><tr><th>Platform</th><th>Citations</th><th>Share</th></tr></thead>\n <tbody>\n {byPlatform.map(p => {\n const pct = records.length > 0 ? ((p.count / records.length) * 100).toFixed(1) : '0'\n const color = PLATFORM_COLORS[p.name] ?? PLATFORM_COLORS.default\n return (\n <tr key={p.name}>\n <td><span className={`ta-badge ta-badge--${color}`}>{p.name}</span></td>\n <td><strong>{p.count}</strong></td>\n <td style={{ fontSize: 12, color: 'var(--ta-gray-600)' }}>{pct}%</td>\n </tr>\n )\n })}\n </tbody>\n </table>\n )}\n </Card>\n\n <Card title=\"Top Queries\">\n {byQuery.length === 0 ? (\n <div className=\"ta-empty\"><p>No query data yet. Queries are captured when AI platforms include a search term in the referrer URL.</p></div>\n ) : (\n <table className=\"ta-table\">\n <thead><tr><th>Query</th><th>Citations</th></tr></thead>\n <tbody>\n {byQuery.map(q => (\n <tr key={q.name}>\n <td style={{ fontFamily: 'var(--ta-font-mono)', fontSize: 12 }}>{q.name}</td>\n <td><strong>{q.count}</strong></td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </Card>\n </div>\n\n <Card title=\"Top Cited Pages\">\n {byPage.length === 0 ? (\n <div className=\"ta-empty\"><p>No pages cited yet.</p></div>\n ) : (\n <table className=\"ta-table\">\n <thead><tr><th>Page</th><th>Citations</th></tr></thead>\n <tbody>\n {byPage.slice(0, 20).map(p => (\n <tr key={p.name}>\n <td>\n <a href={p.name} target=\"_blank\" rel=\"noreferrer\" style={{ fontFamily: 'var(--ta-font-mono)', fontSize: 12 }}>\n {p.name}\n </a>\n </td>\n <td><strong>{p.count}</strong></td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </Card>\n </div>\n )\n}\n","import type { ReactNode } from 'react'\n\ninterface CardProps {\n title: string\n action?: ReactNode\n children: ReactNode\n}\n\nexport function Card({ title, action, children }: CardProps) {\n return (\n <div className=\"ta-card ta-section\">\n <div className=\"ta-card-header\">\n <h2>{title}</h2>\n {action}\n </div>\n <div className=\"ta-card-body\">{children}</div>\n </div>\n )\n}\n","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"]}
@@ -0,0 +1,8 @@
1
+ import * as react from 'react';
2
+
3
+ interface SettingsPageProps {
4
+ maskedKey: string | null;
5
+ }
6
+ declare function SettingsPage({ maskedKey: initialMasked }: SettingsPageProps): react.JSX.Element;
7
+
8
+ export { SettingsPage };
@@ -0,0 +1,8 @@
1
+ import * as react from 'react';
2
+
3
+ interface SettingsPageProps {
4
+ maskedKey: string | null;
5
+ }
6
+ declare function SettingsPage({ maskedKey: initialMasked }: SettingsPageProps): react.JSX.Element;
7
+
8
+ export { SettingsPage };
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/dashboard/ui/pages/SettingsPage.tsx
22
+ var SettingsPage_exports = {};
23
+ __export(SettingsPage_exports, {
24
+ SettingsPage: () => SettingsPage
25
+ });
26
+ module.exports = __toCommonJS(SettingsPage_exports);
27
+ var import_react = require("react");
28
+ var import_jsx_runtime = require("react/jsx-runtime");
29
+ function SettingsPage({ maskedKey: initialMasked }) {
30
+ const [masked, setMasked] = (0, import_react.useState)(initialMasked);
31
+ const [revealed, setRevealed] = (0, import_react.useState)(null);
32
+ const [rotating, setRotating] = (0, import_react.useState)(false);
33
+ const [copied, setCopied] = (0, import_react.useState)(false);
34
+ const [error, setError] = (0, import_react.useState)(null);
35
+ async function handleRotate() {
36
+ if (!confirm("Rotate the API key? All existing integrations using the current key will stop working immediately.")) return;
37
+ setRotating(true);
38
+ setError(null);
39
+ setRevealed(null);
40
+ try {
41
+ const res = await fetch("/api/third-audience/api-key", {
42
+ method: "POST",
43
+ headers: { "Content-Type": "application/json" },
44
+ body: JSON.stringify({ action: "rotate" })
45
+ });
46
+ const data = await res.json();
47
+ if (!res.ok) throw new Error(data.error ?? "Failed");
48
+ setRevealed(data.key ?? null);
49
+ setMasked(null);
50
+ } catch (e) {
51
+ setError(e instanceof Error ? e.message : "Unknown error");
52
+ } finally {
53
+ setRotating(false);
54
+ }
55
+ }
56
+ async function handleCopy(text) {
57
+ try {
58
+ await navigator.clipboard.writeText(text);
59
+ setCopied(true);
60
+ setTimeout(() => setCopied(false), 2e3);
61
+ } catch {
62
+ setError("Copy failed \u2014 please copy manually.");
63
+ }
64
+ }
65
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ta-page", children: [
66
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-page-header", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "ta-page-title", children: "Settings" }) }),
67
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ta-card", style: { maxWidth: 640 }, children: [
68
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-card-header", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "ta-card-title", children: "API Key" }) }),
69
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ta-card-body", children: [
70
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: { fontSize: 14, color: "var(--ta-secondary)", marginBottom: 20 }, children: [
71
+ "Use this key to authenticate headless or external API calls via the",
72
+ " ",
73
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "X-TA-Api-Key" }),
74
+ " request header. Keep it secret."
75
+ ] }),
76
+ revealed && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: {
77
+ background: "#f0fff4",
78
+ border: "1.5px solid #34c759",
79
+ borderRadius: 10,
80
+ padding: "14px 16px",
81
+ marginBottom: 16
82
+ }, children: [
83
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 12, fontWeight: 600, color: "#1a7f37", marginBottom: 8 }, children: "New API key \u2014 copy it now, it will not be shown again" }),
84
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", gap: 10, alignItems: "center" }, children: [
85
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { style: {
86
+ flex: 1,
87
+ fontFamily: "monospace",
88
+ fontSize: 13,
89
+ wordBreak: "break-all",
90
+ background: "#fff",
91
+ padding: "8px 12px",
92
+ borderRadius: 8,
93
+ border: "1px solid #d2d2d7"
94
+ }, children: revealed }),
95
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
96
+ "button",
97
+ {
98
+ className: "ta-btn ta-btn-secondary",
99
+ onClick: () => handleCopy(revealed),
100
+ style: { whiteSpace: "nowrap" },
101
+ children: copied ? "\u2713 Copied" : "Copy"
102
+ }
103
+ )
104
+ ] })
105
+ ] }),
106
+ !revealed && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", gap: 10, alignItems: "center", marginBottom: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
107
+ "input",
108
+ {
109
+ readOnly: true,
110
+ value: masked ?? "(no key generated)",
111
+ style: {
112
+ flex: 1,
113
+ fontFamily: "monospace",
114
+ fontSize: 13,
115
+ padding: "9px 12px",
116
+ border: "1.5px solid #d2d2d7",
117
+ borderRadius: 10,
118
+ background: "#f5f5f7",
119
+ color: "#1d1d1f"
120
+ }
121
+ }
122
+ ) }),
123
+ error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: {
124
+ background: "#fff2f2",
125
+ border: "1px solid #ffbaba",
126
+ borderRadius: 8,
127
+ padding: "10px 14px",
128
+ fontSize: 13,
129
+ color: "#c0392b",
130
+ marginBottom: 16
131
+ }, children: error }),
132
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
133
+ "button",
134
+ {
135
+ className: "ta-btn ta-btn-danger",
136
+ onClick: handleRotate,
137
+ disabled: rotating,
138
+ children: rotating ? "Rotating\u2026" : "Rotate API key"
139
+ }
140
+ ),
141
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: 12, color: "var(--ta-secondary)", marginTop: 10 }, children: "Rotating generates a new key immediately. The old key stops working at once." })
142
+ ] })
143
+ ] }),
144
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ta-card", style: { maxWidth: 640, marginTop: 20 }, children: [
145
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-card-header", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "ta-card-title", children: "Usage" }) }),
146
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ta-card-body", children: [
147
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: { fontSize: 14, color: "var(--ta-secondary)", marginBottom: 12 }, children: [
148
+ "Include the key in the ",
149
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "X-TA-Api-Key" }),
150
+ " header on any API request:"
151
+ ] }),
152
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", { style: {
153
+ background: "#1d1d1f",
154
+ color: "#f5f5f7",
155
+ borderRadius: 10,
156
+ padding: "14px 16px",
157
+ fontSize: 13,
158
+ overflowX: "auto"
159
+ }, children: `curl https://yoursite.com/api/third-audience/analytics \\
160
+ -H "X-TA-Api-Key: ta_your_key_here"` }),
161
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: { fontSize: 13, color: "var(--ta-secondary)", marginTop: 12 }, children: [
162
+ "Or use ",
163
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: "Authorization: Bearer ta_your_key_here" }),
164
+ " if your HTTP client does not support custom headers."
165
+ ] })
166
+ ] })
167
+ ] }),
168
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ta-card", style: { maxWidth: 640, marginTop: 20 }, children: [
169
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-card-header", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "ta-card-title", children: "Dashboard password" }) }),
170
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ta-card-body", children: [
171
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: 14, color: "var(--ta-secondary)", marginBottom: 16 }, children: "Change the password used to log in to this dashboard." }),
172
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: "/third-audience/login?reset=1", className: "ta-btn ta-btn-secondary", children: "Change password" })
173
+ ] })
174
+ ] })
175
+ ] });
176
+ }
177
+ // Annotate the CommonJS export names for ESM import in node:
178
+ 0 && (module.exports = {
179
+ SettingsPage
180
+ });
181
+ //# sourceMappingURL=SettingsPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/dashboard/ui/pages/SettingsPage.tsx"],"sourcesContent":["'use client'\n\nimport { useState } from 'react'\n\ninterface SettingsPageProps {\n maskedKey: string | null\n}\n\nexport function SettingsPage({ maskedKey: initialMasked }: SettingsPageProps) {\n const [masked, setMasked] = useState(initialMasked)\n const [revealed, setRevealed] = useState<string | null>(null)\n const [rotating, setRotating] = useState(false)\n const [copied, setCopied] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n async function handleRotate() {\n if (!confirm('Rotate the API key? All existing integrations using the current key will stop working immediately.')) return\n setRotating(true)\n setError(null)\n setRevealed(null)\n try {\n const res = await fetch('/api/third-audience/api-key', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ action: 'rotate' }),\n })\n const data = await res.json() as { key?: string; error?: string }\n if (!res.ok) throw new Error(data.error ?? 'Failed')\n setRevealed(data.key ?? null)\n setMasked(null) // hide masked while showing full key\n } catch (e) {\n setError(e instanceof Error ? e.message : 'Unknown error')\n } finally {\n setRotating(false)\n }\n }\n\n async function handleCopy(text: string) {\n try {\n await navigator.clipboard.writeText(text)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch {\n setError('Copy failed — please copy manually.')\n }\n }\n\n return (\n <div className=\"ta-page\">\n <div className=\"ta-page-header\">\n <h1 className=\"ta-page-title\">Settings</h1>\n </div>\n\n {/* API Key section — mirrors WP plugin's settings page */}\n <div className=\"ta-card\" style={{ maxWidth: 640 }}>\n <div className=\"ta-card-header\">\n <h2 className=\"ta-card-title\">API Key</h2>\n </div>\n <div className=\"ta-card-body\">\n <p style={{ fontSize: 14, color: 'var(--ta-secondary)', marginBottom: 20 }}>\n Use this key to authenticate headless or external API calls via the{' '}\n <code>X-TA-Api-Key</code> request header. Keep it secret.\n </p>\n\n {/* Revealed key (shown once after rotate) */}\n {revealed && (\n <div style={{\n background: '#f0fff4',\n border: '1.5px solid #34c759',\n borderRadius: 10,\n padding: '14px 16px',\n marginBottom: 16,\n }}>\n <div style={{ fontSize: 12, fontWeight: 600, color: '#1a7f37', marginBottom: 8 }}>\n New API key — copy it now, it will not be shown again\n </div>\n <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>\n <code style={{\n flex: 1,\n fontFamily: 'monospace',\n fontSize: 13,\n wordBreak: 'break-all',\n background: '#fff',\n padding: '8px 12px',\n borderRadius: 8,\n border: '1px solid #d2d2d7',\n }}>{revealed}</code>\n <button\n className=\"ta-btn ta-btn-secondary\"\n onClick={() => handleCopy(revealed)}\n style={{ whiteSpace: 'nowrap' }}\n >\n {copied ? '✓ Copied' : 'Copy'}\n </button>\n </div>\n </div>\n )}\n\n {/* Masked key display */}\n {!revealed && (\n <div style={{ display: 'flex', gap: 10, alignItems: 'center', marginBottom: 16 }}>\n <input\n readOnly\n value={masked ?? '(no key generated)'}\n style={{\n flex: 1,\n fontFamily: 'monospace',\n fontSize: 13,\n padding: '9px 12px',\n border: '1.5px solid #d2d2d7',\n borderRadius: 10,\n background: '#f5f5f7',\n color: '#1d1d1f',\n }}\n />\n </div>\n )}\n\n {error && (\n <div style={{\n background: '#fff2f2',\n border: '1px solid #ffbaba',\n borderRadius: 8,\n padding: '10px 14px',\n fontSize: 13,\n color: '#c0392b',\n marginBottom: 16,\n }}>{error}</div>\n )}\n\n <button\n className=\"ta-btn ta-btn-danger\"\n onClick={handleRotate}\n disabled={rotating}\n >\n {rotating ? 'Rotating…' : 'Rotate API key'}\n </button>\n <p style={{ fontSize: 12, color: 'var(--ta-secondary)', marginTop: 10 }}>\n Rotating generates a new key immediately. The old key stops working at once.\n </p>\n </div>\n </div>\n\n {/* Usage example */}\n <div className=\"ta-card\" style={{ maxWidth: 640, marginTop: 20 }}>\n <div className=\"ta-card-header\">\n <h2 className=\"ta-card-title\">Usage</h2>\n </div>\n <div className=\"ta-card-body\">\n <p style={{ fontSize: 14, color: 'var(--ta-secondary)', marginBottom: 12 }}>\n Include the key in the <code>X-TA-Api-Key</code> header on any API request:\n </p>\n <pre style={{\n background: '#1d1d1f',\n color: '#f5f5f7',\n borderRadius: 10,\n padding: '14px 16px',\n fontSize: 13,\n overflowX: 'auto',\n }}>{`curl https://yoursite.com/api/third-audience/analytics \\\\\n -H \"X-TA-Api-Key: ta_your_key_here\"`}</pre>\n <p style={{ fontSize: 13, color: 'var(--ta-secondary)', marginTop: 12 }}>\n Or use <code>Authorization: Bearer ta_your_key_here</code> if your HTTP client\n does not support custom headers.\n </p>\n </div>\n </div>\n\n {/* Change password */}\n <div className=\"ta-card\" style={{ maxWidth: 640, marginTop: 20 }}>\n <div className=\"ta-card-header\">\n <h2 className=\"ta-card-title\">Dashboard password</h2>\n </div>\n <div className=\"ta-card-body\">\n <p style={{ fontSize: 14, color: 'var(--ta-secondary)', marginBottom: 16 }}>\n Change the password used to log in to this dashboard.\n </p>\n <a href=\"/third-audience/login?reset=1\" className=\"ta-btn ta-btn-secondary\">\n Change password\n </a>\n </div>\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,157 @@
1
+ "use client";
2
+
3
+ // src/dashboard/ui/pages/SettingsPage.tsx
4
+ import { useState } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ function SettingsPage({ maskedKey: initialMasked }) {
7
+ const [masked, setMasked] = useState(initialMasked);
8
+ const [revealed, setRevealed] = useState(null);
9
+ const [rotating, setRotating] = useState(false);
10
+ const [copied, setCopied] = useState(false);
11
+ const [error, setError] = useState(null);
12
+ async function handleRotate() {
13
+ if (!confirm("Rotate the API key? All existing integrations using the current key will stop working immediately.")) return;
14
+ setRotating(true);
15
+ setError(null);
16
+ setRevealed(null);
17
+ try {
18
+ const res = await fetch("/api/third-audience/api-key", {
19
+ method: "POST",
20
+ headers: { "Content-Type": "application/json" },
21
+ body: JSON.stringify({ action: "rotate" })
22
+ });
23
+ const data = await res.json();
24
+ if (!res.ok) throw new Error(data.error ?? "Failed");
25
+ setRevealed(data.key ?? null);
26
+ setMasked(null);
27
+ } catch (e) {
28
+ setError(e instanceof Error ? e.message : "Unknown error");
29
+ } finally {
30
+ setRotating(false);
31
+ }
32
+ }
33
+ async function handleCopy(text) {
34
+ try {
35
+ await navigator.clipboard.writeText(text);
36
+ setCopied(true);
37
+ setTimeout(() => setCopied(false), 2e3);
38
+ } catch {
39
+ setError("Copy failed \u2014 please copy manually.");
40
+ }
41
+ }
42
+ return /* @__PURE__ */ jsxs("div", { className: "ta-page", children: [
43
+ /* @__PURE__ */ jsx("div", { className: "ta-page-header", children: /* @__PURE__ */ jsx("h1", { className: "ta-page-title", children: "Settings" }) }),
44
+ /* @__PURE__ */ jsxs("div", { className: "ta-card", style: { maxWidth: 640 }, children: [
45
+ /* @__PURE__ */ jsx("div", { className: "ta-card-header", children: /* @__PURE__ */ jsx("h2", { className: "ta-card-title", children: "API Key" }) }),
46
+ /* @__PURE__ */ jsxs("div", { className: "ta-card-body", children: [
47
+ /* @__PURE__ */ jsxs("p", { style: { fontSize: 14, color: "var(--ta-secondary)", marginBottom: 20 }, children: [
48
+ "Use this key to authenticate headless or external API calls via the",
49
+ " ",
50
+ /* @__PURE__ */ jsx("code", { children: "X-TA-Api-Key" }),
51
+ " request header. Keep it secret."
52
+ ] }),
53
+ revealed && /* @__PURE__ */ jsxs("div", { style: {
54
+ background: "#f0fff4",
55
+ border: "1.5px solid #34c759",
56
+ borderRadius: 10,
57
+ padding: "14px 16px",
58
+ marginBottom: 16
59
+ }, children: [
60
+ /* @__PURE__ */ jsx("div", { style: { fontSize: 12, fontWeight: 600, color: "#1a7f37", marginBottom: 8 }, children: "New API key \u2014 copy it now, it will not be shown again" }),
61
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 10, alignItems: "center" }, children: [
62
+ /* @__PURE__ */ jsx("code", { style: {
63
+ flex: 1,
64
+ fontFamily: "monospace",
65
+ fontSize: 13,
66
+ wordBreak: "break-all",
67
+ background: "#fff",
68
+ padding: "8px 12px",
69
+ borderRadius: 8,
70
+ border: "1px solid #d2d2d7"
71
+ }, children: revealed }),
72
+ /* @__PURE__ */ jsx(
73
+ "button",
74
+ {
75
+ className: "ta-btn ta-btn-secondary",
76
+ onClick: () => handleCopy(revealed),
77
+ style: { whiteSpace: "nowrap" },
78
+ children: copied ? "\u2713 Copied" : "Copy"
79
+ }
80
+ )
81
+ ] })
82
+ ] }),
83
+ !revealed && /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 10, alignItems: "center", marginBottom: 16 }, children: /* @__PURE__ */ jsx(
84
+ "input",
85
+ {
86
+ readOnly: true,
87
+ value: masked ?? "(no key generated)",
88
+ style: {
89
+ flex: 1,
90
+ fontFamily: "monospace",
91
+ fontSize: 13,
92
+ padding: "9px 12px",
93
+ border: "1.5px solid #d2d2d7",
94
+ borderRadius: 10,
95
+ background: "#f5f5f7",
96
+ color: "#1d1d1f"
97
+ }
98
+ }
99
+ ) }),
100
+ error && /* @__PURE__ */ jsx("div", { style: {
101
+ background: "#fff2f2",
102
+ border: "1px solid #ffbaba",
103
+ borderRadius: 8,
104
+ padding: "10px 14px",
105
+ fontSize: 13,
106
+ color: "#c0392b",
107
+ marginBottom: 16
108
+ }, children: error }),
109
+ /* @__PURE__ */ jsx(
110
+ "button",
111
+ {
112
+ className: "ta-btn ta-btn-danger",
113
+ onClick: handleRotate,
114
+ disabled: rotating,
115
+ children: rotating ? "Rotating\u2026" : "Rotate API key"
116
+ }
117
+ ),
118
+ /* @__PURE__ */ jsx("p", { style: { fontSize: 12, color: "var(--ta-secondary)", marginTop: 10 }, children: "Rotating generates a new key immediately. The old key stops working at once." })
119
+ ] })
120
+ ] }),
121
+ /* @__PURE__ */ jsxs("div", { className: "ta-card", style: { maxWidth: 640, marginTop: 20 }, children: [
122
+ /* @__PURE__ */ jsx("div", { className: "ta-card-header", children: /* @__PURE__ */ jsx("h2", { className: "ta-card-title", children: "Usage" }) }),
123
+ /* @__PURE__ */ jsxs("div", { className: "ta-card-body", children: [
124
+ /* @__PURE__ */ jsxs("p", { style: { fontSize: 14, color: "var(--ta-secondary)", marginBottom: 12 }, children: [
125
+ "Include the key in the ",
126
+ /* @__PURE__ */ jsx("code", { children: "X-TA-Api-Key" }),
127
+ " header on any API request:"
128
+ ] }),
129
+ /* @__PURE__ */ jsx("pre", { style: {
130
+ background: "#1d1d1f",
131
+ color: "#f5f5f7",
132
+ borderRadius: 10,
133
+ padding: "14px 16px",
134
+ fontSize: 13,
135
+ overflowX: "auto"
136
+ }, children: `curl https://yoursite.com/api/third-audience/analytics \\
137
+ -H "X-TA-Api-Key: ta_your_key_here"` }),
138
+ /* @__PURE__ */ jsxs("p", { style: { fontSize: 13, color: "var(--ta-secondary)", marginTop: 12 }, children: [
139
+ "Or use ",
140
+ /* @__PURE__ */ jsx("code", { children: "Authorization: Bearer ta_your_key_here" }),
141
+ " if your HTTP client does not support custom headers."
142
+ ] })
143
+ ] })
144
+ ] }),
145
+ /* @__PURE__ */ jsxs("div", { className: "ta-card", style: { maxWidth: 640, marginTop: 20 }, children: [
146
+ /* @__PURE__ */ jsx("div", { className: "ta-card-header", children: /* @__PURE__ */ jsx("h2", { className: "ta-card-title", children: "Dashboard password" }) }),
147
+ /* @__PURE__ */ jsxs("div", { className: "ta-card-body", children: [
148
+ /* @__PURE__ */ jsx("p", { style: { fontSize: 14, color: "var(--ta-secondary)", marginBottom: 16 }, children: "Change the password used to log in to this dashboard." }),
149
+ /* @__PURE__ */ jsx("a", { href: "/third-audience/login?reset=1", className: "ta-btn ta-btn-secondary", children: "Change password" })
150
+ ] })
151
+ ] })
152
+ ] });
153
+ }
154
+ export {
155
+ SettingsPage
156
+ };
157
+ //# sourceMappingURL=SettingsPage.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/dashboard/ui/pages/SettingsPage.tsx"],"sourcesContent":["'use client'\n\nimport { useState } from 'react'\n\ninterface SettingsPageProps {\n maskedKey: string | null\n}\n\nexport function SettingsPage({ maskedKey: initialMasked }: SettingsPageProps) {\n const [masked, setMasked] = useState(initialMasked)\n const [revealed, setRevealed] = useState<string | null>(null)\n const [rotating, setRotating] = useState(false)\n const [copied, setCopied] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n async function handleRotate() {\n if (!confirm('Rotate the API key? All existing integrations using the current key will stop working immediately.')) return\n setRotating(true)\n setError(null)\n setRevealed(null)\n try {\n const res = await fetch('/api/third-audience/api-key', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ action: 'rotate' }),\n })\n const data = await res.json() as { key?: string; error?: string }\n if (!res.ok) throw new Error(data.error ?? 'Failed')\n setRevealed(data.key ?? null)\n setMasked(null) // hide masked while showing full key\n } catch (e) {\n setError(e instanceof Error ? e.message : 'Unknown error')\n } finally {\n setRotating(false)\n }\n }\n\n async function handleCopy(text: string) {\n try {\n await navigator.clipboard.writeText(text)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch {\n setError('Copy failed — please copy manually.')\n }\n }\n\n return (\n <div className=\"ta-page\">\n <div className=\"ta-page-header\">\n <h1 className=\"ta-page-title\">Settings</h1>\n </div>\n\n {/* API Key section — mirrors WP plugin's settings page */}\n <div className=\"ta-card\" style={{ maxWidth: 640 }}>\n <div className=\"ta-card-header\">\n <h2 className=\"ta-card-title\">API Key</h2>\n </div>\n <div className=\"ta-card-body\">\n <p style={{ fontSize: 14, color: 'var(--ta-secondary)', marginBottom: 20 }}>\n Use this key to authenticate headless or external API calls via the{' '}\n <code>X-TA-Api-Key</code> request header. Keep it secret.\n </p>\n\n {/* Revealed key (shown once after rotate) */}\n {revealed && (\n <div style={{\n background: '#f0fff4',\n border: '1.5px solid #34c759',\n borderRadius: 10,\n padding: '14px 16px',\n marginBottom: 16,\n }}>\n <div style={{ fontSize: 12, fontWeight: 600, color: '#1a7f37', marginBottom: 8 }}>\n New API key — copy it now, it will not be shown again\n </div>\n <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>\n <code style={{\n flex: 1,\n fontFamily: 'monospace',\n fontSize: 13,\n wordBreak: 'break-all',\n background: '#fff',\n padding: '8px 12px',\n borderRadius: 8,\n border: '1px solid #d2d2d7',\n }}>{revealed}</code>\n <button\n className=\"ta-btn ta-btn-secondary\"\n onClick={() => handleCopy(revealed)}\n style={{ whiteSpace: 'nowrap' }}\n >\n {copied ? '✓ Copied' : 'Copy'}\n </button>\n </div>\n </div>\n )}\n\n {/* Masked key display */}\n {!revealed && (\n <div style={{ display: 'flex', gap: 10, alignItems: 'center', marginBottom: 16 }}>\n <input\n readOnly\n value={masked ?? '(no key generated)'}\n style={{\n flex: 1,\n fontFamily: 'monospace',\n fontSize: 13,\n padding: '9px 12px',\n border: '1.5px solid #d2d2d7',\n borderRadius: 10,\n background: '#f5f5f7',\n color: '#1d1d1f',\n }}\n />\n </div>\n )}\n\n {error && (\n <div style={{\n background: '#fff2f2',\n border: '1px solid #ffbaba',\n borderRadius: 8,\n padding: '10px 14px',\n fontSize: 13,\n color: '#c0392b',\n marginBottom: 16,\n }}>{error}</div>\n )}\n\n <button\n className=\"ta-btn ta-btn-danger\"\n onClick={handleRotate}\n disabled={rotating}\n >\n {rotating ? 'Rotating…' : 'Rotate API key'}\n </button>\n <p style={{ fontSize: 12, color: 'var(--ta-secondary)', marginTop: 10 }}>\n Rotating generates a new key immediately. The old key stops working at once.\n </p>\n </div>\n </div>\n\n {/* Usage example */}\n <div className=\"ta-card\" style={{ maxWidth: 640, marginTop: 20 }}>\n <div className=\"ta-card-header\">\n <h2 className=\"ta-card-title\">Usage</h2>\n </div>\n <div className=\"ta-card-body\">\n <p style={{ fontSize: 14, color: 'var(--ta-secondary)', marginBottom: 12 }}>\n Include the key in the <code>X-TA-Api-Key</code> header on any API request:\n </p>\n <pre style={{\n background: '#1d1d1f',\n color: '#f5f5f7',\n borderRadius: 10,\n padding: '14px 16px',\n fontSize: 13,\n overflowX: 'auto',\n }}>{`curl https://yoursite.com/api/third-audience/analytics \\\\\n -H \"X-TA-Api-Key: ta_your_key_here\"`}</pre>\n <p style={{ fontSize: 13, color: 'var(--ta-secondary)', marginTop: 12 }}>\n Or use <code>Authorization: Bearer ta_your_key_here</code> if your HTTP client\n does not support custom headers.\n </p>\n </div>\n </div>\n\n {/* Change password */}\n <div className=\"ta-card\" style={{ maxWidth: 640, marginTop: 20 }}>\n <div className=\"ta-card-header\">\n <h2 className=\"ta-card-title\">Dashboard password</h2>\n </div>\n <div className=\"ta-card-body\">\n <p style={{ fontSize: 14, color: 'var(--ta-secondary)', marginBottom: 16 }}>\n Change the password used to log in to this dashboard.\n </p>\n <a href=\"/third-audience/login?reset=1\" className=\"ta-btn ta-btn-secondary\">\n Change password\n </a>\n </div>\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,5 @@
1
+ import * as react from 'react';
2
+
3
+ declare function SystemHealthPage(): Promise<react.JSX.Element>;
4
+
5
+ export { SystemHealthPage };
@@ -0,0 +1,5 @@
1
+ import * as react from 'react';
2
+
3
+ declare function SystemHealthPage(): Promise<react.JSX.Element>;
4
+
5
+ export { SystemHealthPage };