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,175 @@
1
+ /* Third Audience Dashboard — Apple-inspired design system */
2
+
3
+ :root {
4
+ --ta-blue: #007aff;
5
+ --ta-green: #34c759;
6
+ --ta-orange: #ff9500;
7
+ --ta-red: #ff3b30;
8
+ --ta-purple: #af52de;
9
+ --ta-teal: #5ac8fa;
10
+
11
+ --ta-gray-50: #fafafa;
12
+ --ta-gray-100: #f5f5f7;
13
+ --ta-gray-200: #e5e5ea;
14
+ --ta-gray-300: #d1d1d6;
15
+ --ta-gray-400: #c7c7cc;
16
+ --ta-gray-500: #aeaeb2;
17
+ --ta-gray-600: #8e8e93;
18
+ --ta-gray-700: #636366;
19
+ --ta-gray-800: #3a3a3c;
20
+ --ta-gray-900: #1c1c1e;
21
+
22
+ --ta-bg: #f5f5f7;
23
+ --ta-surface: #ffffff;
24
+ --ta-border: rgba(0,0,0,0.08);
25
+
26
+ --ta-radius-sm: 8px;
27
+ --ta-radius-md: 12px;
28
+ --ta-radius-lg: 16px;
29
+ --ta-radius-xl: 20px;
30
+
31
+ --ta-shadow-sm: 0 2px 4px rgba(0,0,0,0.06);
32
+ --ta-shadow-md: 0 4px 12px rgba(0,0,0,0.08);
33
+ --ta-shadow-lg: 0 8px 24px rgba(0,0,0,0.12);
34
+
35
+ --ta-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
36
+ --ta-font-mono: "SF Mono", Monaco, "Cascadia Code", Consolas, monospace;
37
+ }
38
+
39
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
40
+
41
+ body {
42
+ font-family: var(--ta-font);
43
+ background: var(--ta-bg);
44
+ color: var(--ta-gray-900);
45
+ font-size: 14px;
46
+ line-height: 1.5;
47
+ -webkit-font-smoothing: antialiased;
48
+ }
49
+
50
+ a { color: var(--ta-blue); text-decoration: none; }
51
+ a:hover { text-decoration: underline; }
52
+
53
+ /* Layout */
54
+ .ta-layout { display: flex; min-height: 100vh; }
55
+ .ta-sidebar {
56
+ width: 220px; flex-shrink: 0;
57
+ background: var(--ta-surface);
58
+ border-right: 1px solid var(--ta-border);
59
+ padding: 24px 0;
60
+ position: sticky; top: 0; height: 100vh; overflow-y: auto;
61
+ }
62
+ .ta-main { flex: 1; padding: 32px; max-width: 1200px; }
63
+
64
+ /* Sidebar */
65
+ .ta-sidebar-brand {
66
+ display: flex; align-items: center; gap: 10px;
67
+ padding: 0 20px 24px;
68
+ border-bottom: 1px solid var(--ta-border);
69
+ margin-bottom: 16px;
70
+ }
71
+ .ta-sidebar-brand svg { width: 28px; height: 28px; }
72
+ .ta-sidebar-brand span { font-weight: 700; font-size: 15px; letter-spacing: -0.3px; }
73
+ .ta-nav-item {
74
+ display: flex; align-items: center; gap: 10px;
75
+ padding: 10px 20px; color: var(--ta-gray-700);
76
+ font-size: 14px; font-weight: 500;
77
+ border-radius: 0; transition: all 0.15s;
78
+ cursor: pointer; text-decoration: none;
79
+ }
80
+ .ta-nav-item:hover { background: var(--ta-gray-100); color: var(--ta-gray-900); text-decoration: none; }
81
+ .ta-nav-item.active { color: var(--ta-blue); background: rgba(0,122,255,0.08); }
82
+ .ta-nav-item svg { width: 18px; height: 18px; flex-shrink: 0; }
83
+
84
+ /* Cards */
85
+ .ta-card {
86
+ background: var(--ta-surface);
87
+ border: 1px solid var(--ta-border);
88
+ border-radius: var(--ta-radius-md);
89
+ box-shadow: var(--ta-shadow-sm);
90
+ }
91
+ .ta-card-header {
92
+ padding: 16px 20px;
93
+ border-bottom: 1px solid var(--ta-border);
94
+ display: flex; align-items: center; justify-content: space-between;
95
+ }
96
+ .ta-card-header h2 { font-size: 15px; font-weight: 600; letter-spacing: -0.2px; }
97
+ .ta-card-body { padding: 20px; }
98
+
99
+ /* Hero metrics grid */
100
+ .ta-hero-grid {
101
+ display: grid;
102
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
103
+ gap: 12px; margin-bottom: 24px;
104
+ }
105
+ .ta-hero-card {
106
+ background: var(--ta-surface);
107
+ border: 1px solid var(--ta-border);
108
+ border-radius: var(--ta-radius-md);
109
+ padding: 20px;
110
+ display: flex; align-items: flex-start; gap: 14px;
111
+ box-shadow: var(--ta-shadow-sm);
112
+ transition: box-shadow 0.2s;
113
+ }
114
+ .ta-hero-card:hover { box-shadow: var(--ta-shadow-md); }
115
+ .ta-hero-icon {
116
+ width: 40px; height: 40px; border-radius: var(--ta-radius-sm);
117
+ display: flex; align-items: center; justify-content: center;
118
+ flex-shrink: 0;
119
+ }
120
+ .ta-hero-icon svg { width: 20px; height: 20px; }
121
+ .ta-hero-card--blue .ta-hero-icon { background: rgba(0,122,255,0.12); color: var(--ta-blue); }
122
+ .ta-hero-card--green .ta-hero-icon { background: rgba(52,199,89,0.12); color: var(--ta-green); }
123
+ .ta-hero-card--orange .ta-hero-icon { background: rgba(255,149,0,0.12); color: var(--ta-orange); }
124
+ .ta-hero-card--teal .ta-hero-icon { background: rgba(90,200,250,0.12); color: var(--ta-teal); }
125
+ .ta-hero-label { font-size: 12px; font-weight: 500; color: var(--ta-gray-600); text-transform: uppercase; letter-spacing: 0.4px; }
126
+ .ta-hero-value { font-size: 28px; font-weight: 700; letter-spacing: -0.8px; line-height: 1.1; margin: 4px 0 2px; }
127
+ .ta-hero-meta { font-size: 12px; color: var(--ta-gray-600); }
128
+
129
+ /* Tables */
130
+ .ta-table { width: 100%; border-collapse: collapse; font-size: 13px; }
131
+ .ta-table th { padding: 10px 14px; text-align: left; font-weight: 600; font-size: 12px; color: var(--ta-gray-600); text-transform: uppercase; letter-spacing: 0.4px; border-bottom: 1px solid var(--ta-border); }
132
+ .ta-table td { padding: 11px 14px; border-bottom: 1px solid var(--ta-gray-100); }
133
+ .ta-table tr:last-child td { border-bottom: none; }
134
+ .ta-table tr:hover td { background: var(--ta-gray-50); }
135
+
136
+ /* Badges */
137
+ .ta-badge {
138
+ display: inline-flex; align-items: center;
139
+ padding: 3px 8px; border-radius: 99px;
140
+ font-size: 11px; font-weight: 600; letter-spacing: 0.2px;
141
+ }
142
+ .ta-badge--blue { background: rgba(0,122,255,0.1); color: var(--ta-blue); }
143
+ .ta-badge--green { background: rgba(52,199,89,0.1); color: var(--ta-green); }
144
+ .ta-badge--orange { background: rgba(255,149,0,0.1); color: var(--ta-orange); }
145
+ .ta-badge--red { background: rgba(255,59,48,0.1); color: var(--ta-red); }
146
+ .ta-badge--gray { background: var(--ta-gray-100); color: var(--ta-gray-700); }
147
+
148
+ /* Status dot */
149
+ .ta-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
150
+ .ta-dot--green { background: var(--ta-green); }
151
+ .ta-dot--orange { background: var(--ta-orange); }
152
+ .ta-dot--red { background: var(--ta-red); }
153
+
154
+ /* Buttons */
155
+ .ta-btn {
156
+ display: inline-flex; align-items: center; gap: 6px;
157
+ padding: 8px 16px; border-radius: var(--ta-radius-sm);
158
+ font-size: 13px; font-weight: 500; border: none; cursor: pointer;
159
+ transition: all 0.15s;
160
+ }
161
+ .ta-btn--primary { background: var(--ta-blue); color: #fff; }
162
+ .ta-btn--primary:hover { background: #0051d5; }
163
+ .ta-btn--ghost { background: var(--ta-gray-100); color: var(--ta-gray-800); }
164
+ .ta-btn--ghost:hover { background: var(--ta-gray-200); }
165
+ .ta-btn--danger { background: rgba(255,59,48,0.1); color: var(--ta-red); }
166
+ .ta-btn--danger:hover { background: rgba(255,59,48,0.2); }
167
+
168
+ /* Misc */
169
+ .ta-page-title { font-size: 22px; font-weight: 700; letter-spacing: -0.5px; margin-bottom: 4px; }
170
+ .ta-page-subtitle { color: var(--ta-gray-600); margin-bottom: 24px; }
171
+ .ta-section { margin-bottom: 24px; }
172
+ .ta-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
173
+ .ta-empty { text-align: center; padding: 48px; color: var(--ta-gray-500); }
174
+ .ta-empty p { margin-top: 8px; font-size: 13px; }
175
+ code { font-family: var(--ta-font-mono); background: var(--ta-gray-100); padding: 2px 6px; border-radius: 4px; font-size: 12px; }
@@ -0,0 +1,5 @@
1
+ import * as react from 'react';
2
+
3
+ declare function BotAnalyticsPage(): Promise<react.JSX.Element>;
4
+
5
+ export { BotAnalyticsPage };
@@ -0,0 +1,5 @@
1
+ import * as react from 'react';
2
+
3
+ declare function BotAnalyticsPage(): Promise<react.JSX.Element>;
4
+
5
+ export { BotAnalyticsPage };
@@ -0,0 +1,269 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/dashboard/ui/pages/BotAnalyticsPage.tsx
31
+ var BotAnalyticsPage_exports = {};
32
+ __export(BotAnalyticsPage_exports, {
33
+ BotAnalyticsPage: () => BotAnalyticsPage
34
+ });
35
+ module.exports = __toCommonJS(BotAnalyticsPage_exports);
36
+
37
+ // src/analytics/performance-stats.ts
38
+ var import_fs = __toESM(require("fs"));
39
+ var import_path = __toESM(require("path"));
40
+ var PerformanceStats = class {
41
+ constructor(dataDir = process.env.TA_DATA_DIR ?? "data") {
42
+ this.dataDir = dataDir;
43
+ }
44
+ compute(days = 30) {
45
+ const records = this.loadRecords(days);
46
+ const totalVisits = records.length;
47
+ const uniqueBots = [...new Set(records.map((r) => r.bot_name).filter(Boolean))];
48
+ const withResponseMs = records.filter((r) => r.response_ms !== null);
49
+ const avgResponseMs = withResponseMs.length > 0 ? withResponseMs.reduce((s, r) => s + r.response_ms, 0) / withResponseMs.length : null;
50
+ const cacheHitRate = records.length > 0 ? records.filter((r) => r.cache_hit).length / records.length : null;
51
+ const pageCounts = /* @__PURE__ */ new Map();
52
+ const botCounts = /* @__PURE__ */ new Map();
53
+ const dayCounts = /* @__PURE__ */ new Map();
54
+ for (const r of records) {
55
+ pageCounts.set(r.url, (pageCounts.get(r.url) ?? 0) + 1);
56
+ const name = r.bot_name ?? "unknown";
57
+ botCounts.set(name, (botCounts.get(name) ?? 0) + 1);
58
+ const day = r.timestamp.slice(0, 10);
59
+ dayCounts.set(day, (dayCounts.get(day) ?? 0) + 1);
60
+ }
61
+ const topPages = [...pageCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10).map(([url, visits]) => ({ url, visits }));
62
+ const topBots = [...botCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 10).map(([name, visits]) => ({ name, visits }));
63
+ const visitsByDay = [...dayCounts.entries()].sort((a, b) => a[0].localeCompare(b[0])).map(([date, visits]) => ({ date, visits }));
64
+ return { totalVisits, uniqueBots, avgResponseMs, cacheHitRate, topPages, topBots, visitsByDay };
65
+ }
66
+ loadRecords(days) {
67
+ const filePath = import_path.default.join(this.dataDir, "ta-visits.jsonl");
68
+ if (!import_fs.default.existsSync(filePath)) return [];
69
+ const cutoff = /* @__PURE__ */ new Date();
70
+ cutoff.setDate(cutoff.getDate() - days);
71
+ const cutoffStr = cutoff.toISOString();
72
+ return import_fs.default.readFileSync(filePath, "utf-8").split("\n").filter(Boolean).map((line) => {
73
+ try {
74
+ return JSON.parse(line);
75
+ } catch {
76
+ return null;
77
+ }
78
+ }).filter((r) => r !== null && r.timestamp >= cutoffStr);
79
+ }
80
+ };
81
+
82
+ // src/dashboard/ui/components/HeroCard.tsx
83
+ var import_jsx_runtime = require("react/jsx-runtime");
84
+ function HeroCard({ label, value, meta, color = "blue", icon }) {
85
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: `ta-hero-card ta-hero-card--${color}`, children: [
86
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-hero-icon", children: icon }),
87
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
88
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-hero-label", children: label }),
89
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-hero-value", children: value }),
90
+ meta && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ta-hero-meta", children: meta })
91
+ ] })
92
+ ] });
93
+ }
94
+
95
+ // src/dashboard/ui/components/Card.tsx
96
+ var import_jsx_runtime2 = require("react/jsx-runtime");
97
+ function Card({ title, action, children }) {
98
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ta-card ta-section", children: [
99
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ta-card-header", children: [
100
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { children: title }),
101
+ action
102
+ ] }),
103
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ta-card-body", children })
104
+ ] });
105
+ }
106
+
107
+ // src/dashboard/ui/components/VisitsChart.tsx
108
+ var import_jsx_runtime3 = require("react/jsx-runtime");
109
+ function VisitsChart({ data, height = 160 }) {
110
+ if (!data.length) {
111
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ta-empty", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: "No visit data yet." }) });
112
+ }
113
+ const max = Math.max(...data.map((d) => d.visits), 1);
114
+ const barWidth = Math.max(4, Math.floor(560 / data.length) - 2);
115
+ const showLabel = data.length <= 14;
116
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
117
+ "svg",
118
+ {
119
+ width: "100%",
120
+ viewBox: `0 0 ${Math.max(data.length * (barWidth + 2), 560)} ${height + 40}`,
121
+ style: { display: "block", minWidth: 320 },
122
+ children: data.map((d, i) => {
123
+ const barH = Math.max(2, Math.round(d.visits / max * height));
124
+ const x = i * (barWidth + 2);
125
+ const y = height - barH;
126
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("g", { children: [
127
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
128
+ "rect",
129
+ {
130
+ x,
131
+ y,
132
+ width: barWidth,
133
+ height: barH,
134
+ rx: 3,
135
+ fill: "var(--ta-blue)",
136
+ opacity: 0.85,
137
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("title", { children: `${d.date}: ${d.visits} visits` })
138
+ }
139
+ ),
140
+ showLabel && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
141
+ "text",
142
+ {
143
+ x: x + barWidth / 2,
144
+ y: height + 16,
145
+ textAnchor: "middle",
146
+ fontSize: 9,
147
+ fill: "var(--ta-gray-500)",
148
+ children: [
149
+ d.date.slice(5),
150
+ " "
151
+ ]
152
+ }
153
+ )
154
+ ] }, d.date);
155
+ })
156
+ }
157
+ ) });
158
+ }
159
+
160
+ // src/dashboard/ui/pages/BotAnalyticsPage.tsx
161
+ var import_jsx_runtime4 = require("react/jsx-runtime");
162
+ var BOT_COLORS = {
163
+ ClaudeBot: "orange",
164
+ GPTBot: "green",
165
+ PerplexityBot: "blue",
166
+ "Googlebot-AI": "teal",
167
+ default: "gray"
168
+ };
169
+ async function BotAnalyticsPage() {
170
+ const stats = new PerformanceStats();
171
+ const summary = stats.compute(30);
172
+ const cacheRate = summary.cacheHitRate !== null ? `${(summary.cacheHitRate * 100).toFixed(0)}%` : "\u2014";
173
+ const avgMs = summary.avgResponseMs !== null ? `${Math.round(summary.avgResponseMs)}ms` : "\u2014";
174
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
175
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h1", { className: "ta-page-title", children: "Bot Analytics" }),
176
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "ta-page-subtitle", children: "AI crawler visits over the last 30 days" }),
177
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ta-hero-grid", children: [
178
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
179
+ HeroCard,
180
+ {
181
+ label: "Total Bot Visits",
182
+ value: summary.totalVisits.toLocaleString(),
183
+ meta: `${summary.uniqueBots.length} unique bots`,
184
+ color: "blue",
185
+ icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "22 12 18 12 15 21 9 3 6 12 2 12" }) })
186
+ }
187
+ ),
188
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
189
+ HeroCard,
190
+ {
191
+ label: "Unique Pages Crawled",
192
+ value: summary.topPages.length.toLocaleString(),
193
+ meta: "distinct URLs visited",
194
+ color: "teal",
195
+ icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: [
196
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
197
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "14 2 14 8 20 8" })
198
+ ] })
199
+ }
200
+ ),
201
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
202
+ HeroCard,
203
+ {
204
+ label: "Cache Hit Rate",
205
+ value: cacheRate,
206
+ meta: "higher = faster bot response",
207
+ color: "green",
208
+ icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: [
209
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }),
210
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "22 4 12 14.01 9 11.01" })
211
+ ] })
212
+ }
213
+ ),
214
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
215
+ HeroCard,
216
+ {
217
+ label: "Avg Response",
218
+ value: avgMs,
219
+ meta: "for markdown requests",
220
+ color: "orange",
221
+ icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: [
222
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
223
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("polyline", { points: "12 6 12 12 16 14" })
224
+ ] })
225
+ }
226
+ )
227
+ ] }),
228
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Card, { title: "Daily Visits (30 days)", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(VisitsChart, { data: summary.visitsByDay }) }),
229
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ta-grid-2", children: [
230
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Card, { title: "Top Bots", children: summary.topBots.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ta-empty", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: "No bot visits recorded yet." }) }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("table", { className: "ta-table", children: [
231
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { children: [
232
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { children: "Bot" }),
233
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { children: "Visits" }),
234
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { children: "Share" })
235
+ ] }) }),
236
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tbody", { children: summary.topBots.map((b) => {
237
+ const pct = summary.totalVisits > 0 ? (b.visits / summary.totalVisits * 100).toFixed(1) : "0";
238
+ const color = BOT_COLORS[b.name] ?? BOT_COLORS.default;
239
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { children: [
240
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: `ta-badge ta-badge--${color}`, children: b.name }) }),
241
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: b.visits.toLocaleString() }) }),
242
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
243
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { flex: 1, height: 6, background: "var(--ta-gray-100)", borderRadius: 3 }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { width: `${pct}%`, height: "100%", background: "var(--ta-blue)", borderRadius: 3 } }) }),
244
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { fontSize: 12, color: "var(--ta-gray-600)", width: 36 }, children: [
245
+ pct,
246
+ "%"
247
+ ] })
248
+ ] }) })
249
+ ] }, b.name);
250
+ }) })
251
+ ] }) }),
252
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Card, { title: "Top Pages Crawled", children: summary.topPages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ta-empty", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: "No pages crawled yet." }) }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("table", { className: "ta-table", children: [
253
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { children: [
254
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { children: "Page" }),
255
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("th", { children: "Visits" })
256
+ ] }) }),
257
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("tbody", { children: summary.topPages.map((p) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("tr", { children: [
258
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("a", { href: p.url, target: "_blank", rel: "noreferrer", style: { fontFamily: "var(--ta-font-mono)", fontSize: 12 }, children: p.url }) }),
259
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("td", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: p.visits.toLocaleString() }) })
260
+ ] }, p.url)) })
261
+ ] }) })
262
+ ] })
263
+ ] });
264
+ }
265
+ // Annotate the CommonJS export names for ESM import in node:
266
+ 0 && (module.exports = {
267
+ BotAnalyticsPage
268
+ });
269
+ //# sourceMappingURL=BotAnalyticsPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/dashboard/ui/pages/BotAnalyticsPage.tsx","../../../../src/analytics/performance-stats.ts","../../../../src/dashboard/ui/components/HeroCard.tsx","../../../../src/dashboard/ui/components/Card.tsx","../../../../src/dashboard/ui/components/VisitsChart.tsx"],"sourcesContent":["import { PerformanceStats } from '../../../analytics/performance-stats.js'\nimport { HeroCard } from '../components/HeroCard.js'\nimport { Card } from '../components/Card.js'\nimport { VisitsChart } from '../components/VisitsChart.js'\n\nconst BOT_COLORS: Record<string, string> = {\n ClaudeBot: 'orange', GPTBot: 'green', PerplexityBot: 'blue',\n 'Googlebot-AI': 'teal', default: 'gray',\n}\n\nexport async function BotAnalyticsPage() {\n const stats = new PerformanceStats()\n const summary = stats.compute(30)\n\n const cacheRate = summary.cacheHitRate !== null\n ? `${(summary.cacheHitRate * 100).toFixed(0)}%` : '—'\n const avgMs = summary.avgResponseMs !== null\n ? `${Math.round(summary.avgResponseMs)}ms` : '—'\n\n return (\n <div>\n <h1 className=\"ta-page-title\">Bot Analytics</h1>\n <p className=\"ta-page-subtitle\">AI crawler visits over the last 30 days</p>\n\n {/* Hero metrics */}\n <div className=\"ta-hero-grid\">\n <HeroCard\n label=\"Total Bot Visits\"\n value={summary.totalVisits.toLocaleString()}\n meta={`${summary.uniqueBots.length} unique bots`}\n color=\"blue\"\n icon={<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}><polyline points=\"22 12 18 12 15 21 9 3 6 12 2 12\" /></svg>}\n />\n <HeroCard\n label=\"Unique Pages Crawled\"\n value={summary.topPages.length.toLocaleString()}\n meta=\"distinct URLs visited\"\n color=\"teal\"\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=\"Cache Hit Rate\"\n value={cacheRate}\n meta=\"higher = faster bot response\"\n color=\"green\"\n icon={<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}><path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/><polyline points=\"22 4 12 14.01 9 11.01\"/></svg>}\n />\n <HeroCard\n label=\"Avg Response\"\n value={avgMs}\n meta=\"for markdown requests\"\n color=\"orange\"\n icon={<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}><circle cx=\"12\" cy=\"12\" r=\"10\"/><polyline points=\"12 6 12 12 16 14\"/></svg>}\n />\n </div>\n\n {/* Visits chart */}\n <Card title=\"Daily Visits (30 days)\">\n <VisitsChart data={summary.visitsByDay} />\n </Card>\n\n <div className=\"ta-grid-2\">\n {/* Top bots */}\n <Card title=\"Top Bots\">\n {summary.topBots.length === 0 ? (\n <div className=\"ta-empty\"><p>No bot visits recorded yet.</p></div>\n ) : (\n <table className=\"ta-table\">\n <thead>\n <tr><th>Bot</th><th>Visits</th><th>Share</th></tr>\n </thead>\n <tbody>\n {summary.topBots.map(b => {\n const pct = summary.totalVisits > 0\n ? ((b.visits / summary.totalVisits) * 100).toFixed(1)\n : '0'\n const color = BOT_COLORS[b.name] ?? BOT_COLORS.default\n return (\n <tr key={b.name}>\n <td>\n <span className={`ta-badge ta-badge--${color}`}>{b.name}</span>\n </td>\n <td><strong>{b.visits.toLocaleString()}</strong></td>\n <td>\n <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>\n <div style={{ flex: 1, height: 6, background: 'var(--ta-gray-100)', borderRadius: 3 }}>\n <div style={{ width: `${pct}%`, height: '100%', background: 'var(--ta-blue)', borderRadius: 3 }} />\n </div>\n <span style={{ fontSize: 12, color: 'var(--ta-gray-600)', width: 36 }}>{pct}%</span>\n </div>\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n )}\n </Card>\n\n {/* Top pages */}\n <Card title=\"Top Pages Crawled\">\n {summary.topPages.length === 0 ? (\n <div className=\"ta-empty\"><p>No pages crawled yet.</p></div>\n ) : (\n <table className=\"ta-table\">\n <thead>\n <tr><th>Page</th><th>Visits</th></tr>\n </thead>\n <tbody>\n {summary.topPages.map(p => (\n <tr key={p.url}>\n <td>\n <a href={p.url} target=\"_blank\" rel=\"noreferrer\" style={{ fontFamily: 'var(--ta-font-mono)', fontSize: 12 }}>\n {p.url}\n </a>\n </td>\n <td><strong>{p.visits.toLocaleString()}</strong></td>\n </tr>\n ))}\n </tbody>\n </table>\n )}\n </Card>\n </div>\n </div>\n )\n}\n","import fs from 'fs'\nimport path from 'path'\nimport type { VisitRecord } from './visit-tracker.js'\n\nexport interface PerformanceSummary {\n totalVisits: number\n uniqueBots: string[]\n avgResponseMs: number | null\n cacheHitRate: number | null\n topPages: Array<{ url: string; visits: number }>\n topBots: Array<{ name: string; visits: number }>\n visitsByDay: Array<{ date: string; visits: number }>\n}\n\nexport class PerformanceStats {\n private dataDir: string\n\n constructor(dataDir = process.env.TA_DATA_DIR ?? 'data') {\n this.dataDir = dataDir\n }\n\n compute(days = 30): PerformanceSummary {\n const records = this.loadRecords(days)\n\n const totalVisits = records.length\n const uniqueBots = [...new Set(records.map(r => r.bot_name).filter(Boolean))] as string[]\n\n const withResponseMs = records.filter(r => r.response_ms !== null)\n const avgResponseMs = withResponseMs.length > 0\n ? withResponseMs.reduce((s, r) => s + r.response_ms!, 0) / withResponseMs.length\n : null\n\n const cacheHitRate = records.length > 0\n ? records.filter(r => r.cache_hit).length / records.length\n : null\n\n const pageCounts = new Map<string, number>()\n const botCounts = new Map<string, number>()\n const dayCounts = new Map<string, number>()\n\n for (const r of records) {\n pageCounts.set(r.url, (pageCounts.get(r.url) ?? 0) + 1)\n const name = r.bot_name ?? 'unknown'\n botCounts.set(name, (botCounts.get(name) ?? 0) + 1)\n const day = r.timestamp.slice(0, 10)\n dayCounts.set(day, (dayCounts.get(day) ?? 0) + 1)\n }\n\n const topPages = [...pageCounts.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n .map(([url, visits]) => ({ url, visits }))\n\n const topBots = [...botCounts.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n .map(([name, visits]) => ({ name, visits }))\n\n const visitsByDay = [...dayCounts.entries()]\n .sort((a, b) => a[0].localeCompare(b[0]))\n .map(([date, visits]) => ({ date, visits }))\n\n return { totalVisits, uniqueBots, avgResponseMs, cacheHitRate, topPages, topBots, visitsByDay }\n }\n\n private loadRecords(days: number): VisitRecord[] {\n const filePath = path.join(this.dataDir, 'ta-visits.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')\n .filter(Boolean)\n .map(line => { try { return JSON.parse(line) as VisitRecord } catch { return null } })\n .filter((r): r is VisitRecord => r !== null && r.timestamp >= cutoffStr)\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","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","'use client'\n\ninterface DayData { date: string; visits: number }\n\ninterface VisitsChartProps {\n data: DayData[]\n height?: number\n}\n\nexport function VisitsChart({ data, height = 160 }: VisitsChartProps) {\n if (!data.length) {\n return <div className=\"ta-empty\"><p>No visit data yet.</p></div>\n }\n\n const max = Math.max(...data.map(d => d.visits), 1)\n const barWidth = Math.max(4, Math.floor(560 / data.length) - 2)\n const showLabel = data.length <= 14\n\n return (\n <div style={{ overflowX: 'auto' }}>\n <svg\n width=\"100%\"\n viewBox={`0 0 ${Math.max(data.length * (barWidth + 2), 560)} ${height + 40}`}\n style={{ display: 'block', minWidth: 320 }}\n >\n {data.map((d, i) => {\n const barH = Math.max(2, Math.round((d.visits / max) * height))\n const x = i * (barWidth + 2)\n const y = height - barH\n return (\n <g key={d.date}>\n <rect\n x={x} y={y}\n width={barWidth} height={barH}\n rx={3}\n fill=\"var(--ta-blue)\"\n opacity={0.85}\n >\n <title>{`${d.date}: ${d.visits} visits`}</title>\n </rect>\n {showLabel && (\n <text\n x={x + barWidth / 2} y={height + 16}\n textAnchor=\"middle\"\n fontSize={9}\n fill=\"var(--ta-gray-500)\"\n >\n {d.date.slice(5)} {/* MM-DD */}\n </text>\n )}\n </g>\n )\n })}\n </svg>\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,gBAAe;AACf,kBAAiB;AAaV,IAAM,mBAAN,MAAuB;AAAA,EAG5B,YAAY,UAAU,QAAQ,IAAI,eAAe,QAAQ;AACvD,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,QAAQ,OAAO,IAAwB;AACrC,UAAM,UAAU,KAAK,YAAY,IAAI;AAErC,UAAM,cAAc,QAAQ;AAC5B,UAAM,aAAa,CAAC,GAAG,IAAI,IAAI,QAAQ,IAAI,OAAK,EAAE,QAAQ,EAAE,OAAO,OAAO,CAAC,CAAC;AAE5E,UAAM,iBAAiB,QAAQ,OAAO,OAAK,EAAE,gBAAgB,IAAI;AACjE,UAAM,gBAAgB,eAAe,SAAS,IAC1C,eAAe,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,aAAc,CAAC,IAAI,eAAe,SACxE;AAEJ,UAAM,eAAe,QAAQ,SAAS,IAClC,QAAQ,OAAO,OAAK,EAAE,SAAS,EAAE,SAAS,QAAQ,SAClD;AAEJ,UAAM,aAAa,oBAAI,IAAoB;AAC3C,UAAM,YAAY,oBAAI,IAAoB;AAC1C,UAAM,YAAY,oBAAI,IAAoB;AAE1C,eAAW,KAAK,SAAS;AACvB,iBAAW,IAAI,EAAE,MAAM,WAAW,IAAI,EAAE,GAAG,KAAK,KAAK,CAAC;AACtD,YAAM,OAAO,EAAE,YAAY;AAC3B,gBAAU,IAAI,OAAO,UAAU,IAAI,IAAI,KAAK,KAAK,CAAC;AAClD,YAAM,MAAM,EAAE,UAAU,MAAM,GAAG,EAAE;AACnC,gBAAU,IAAI,MAAM,UAAU,IAAI,GAAG,KAAK,KAAK,CAAC;AAAA,IAClD;AAEA,UAAM,WAAW,CAAC,GAAG,WAAW,QAAQ,CAAC,EACtC,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EAC1B,MAAM,GAAG,EAAE,EACX,IAAI,CAAC,CAAC,KAAK,MAAM,OAAO,EAAE,KAAK,OAAO,EAAE;AAE3C,UAAM,UAAU,CAAC,GAAG,UAAU,QAAQ,CAAC,EACpC,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EAC1B,MAAM,GAAG,EAAE,EACX,IAAI,CAAC,CAAC,MAAM,MAAM,OAAO,EAAE,MAAM,OAAO,EAAE;AAE7C,UAAM,cAAc,CAAC,GAAG,UAAU,QAAQ,CAAC,EACxC,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EACvC,IAAI,CAAC,CAAC,MAAM,MAAM,OAAO,EAAE,MAAM,OAAO,EAAE;AAE7C,WAAO,EAAE,aAAa,YAAY,eAAe,cAAc,UAAU,SAAS,YAAY;AAAA,EAChG;AAAA,EAEQ,YAAY,MAA6B;AAC/C,UAAM,WAAW,YAAAA,QAAK,KAAK,KAAK,SAAS,iBAAiB;AAC1D,QAAI,CAAC,UAAAC,QAAG,WAAW,QAAQ,EAAG,QAAO,CAAC;AAEtC,UAAM,SAAS,oBAAI,KAAK;AACxB,WAAO,QAAQ,OAAO,QAAQ,IAAI,IAAI;AACtC,UAAM,YAAY,OAAO,YAAY;AAErC,WAAO,UAAAA,QAAG,aAAa,UAAU,OAAO,EACrC,MAAM,IAAI,EACV,OAAO,OAAO,EACd,IAAI,UAAQ;AAAE,UAAI;AAAE,eAAO,KAAK,MAAM,IAAI;AAAA,MAAiB,QAAQ;AAAE,eAAO;AAAA,MAAK;AAAA,IAAE,CAAC,EACpF,OAAO,CAAC,MAAwB,MAAM,QAAQ,EAAE,aAAa,SAAS;AAAA,EAC3E;AACF;;;AClEM;AAHC,SAAS,SAAS,EAAE,OAAO,OAAO,MAAM,QAAQ,QAAQ,KAAK,GAAkB;AACpF,SACE,6CAAC,SAAI,WAAW,8BAA8B,KAAK,IACjD;AAAA,gDAAC,SAAI,WAAU,gBAAgB,gBAAK;AAAA,IACpC,6CAAC,SACC;AAAA,kDAAC,SAAI,WAAU,iBAAiB,iBAAM;AAAA,MACtC,4CAAC,SAAI,WAAU,iBAAiB,iBAAM;AAAA,MACrC,QAAQ,4CAAC,SAAI,WAAU,gBAAgB,gBAAK;AAAA,OAC/C;AAAA,KACF;AAEJ;;;ACVM,IAAAC,sBAAA;AAHC,SAAS,KAAK,EAAE,OAAO,QAAQ,SAAS,GAAc;AAC3D,SACE,8CAAC,SAAI,WAAU,sBACb;AAAA,kDAAC,SAAI,WAAU,kBACb;AAAA,mDAAC,QAAI,iBAAM;AAAA,MACV;AAAA,OACH;AAAA,IACA,6CAAC,SAAI,WAAU,gBAAgB,UAAS;AAAA,KAC1C;AAEJ;;;ACPqC,IAAAC,sBAAA;AAF9B,SAAS,YAAY,EAAE,MAAM,SAAS,IAAI,GAAqB;AACpE,MAAI,CAAC,KAAK,QAAQ;AAChB,WAAO,6CAAC,SAAI,WAAU,YAAW,uDAAC,OAAE,gCAAkB,GAAI;AAAA,EAC5D;AAEA,QAAM,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,OAAK,EAAE,MAAM,GAAG,CAAC;AAClD,QAAM,WAAW,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,KAAK,MAAM,IAAI,CAAC;AAC9D,QAAM,YAAY,KAAK,UAAU;AAEjC,SACE,6CAAC,SAAI,OAAO,EAAE,WAAW,OAAO,GAC9B;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,SAAS,OAAO,KAAK,IAAI,KAAK,UAAU,WAAW,IAAI,GAAG,CAAC,IAAI,SAAS,EAAE;AAAA,MAC1E,OAAO,EAAE,SAAS,SAAS,UAAU,IAAI;AAAA,MAExC,eAAK,IAAI,CAAC,GAAG,MAAM;AAClB,cAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAO,EAAE,SAAS,MAAO,MAAM,CAAC;AAC9D,cAAM,IAAI,KAAK,WAAW;AAC1B,cAAM,IAAI,SAAS;AACnB,eACE,8CAAC,OACC;AAAA;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cAAM;AAAA,cACN,OAAO;AAAA,cAAU,QAAQ;AAAA,cACzB,IAAI;AAAA,cACJ,MAAK;AAAA,cACL,SAAS;AAAA,cAET,uDAAC,WAAO,aAAG,EAAE,IAAI,KAAK,EAAE,MAAM,WAAU;AAAA;AAAA,UAC1C;AAAA,UACC,aACC;AAAA,YAAC;AAAA;AAAA,cACC,GAAG,IAAI,WAAW;AAAA,cAAG,GAAG,SAAS;AAAA,cACjC,YAAW;AAAA,cACX,UAAU;AAAA,cACV,MAAK;AAAA,cAEJ;AAAA,kBAAE,KAAK,MAAM,CAAC;AAAA,gBAAE;AAAA;AAAA;AAAA,UACnB;AAAA,aAlBI,EAAE,IAoBV;AAAA,MAEJ,CAAC;AAAA;AAAA,EACH,GACF;AAEJ;;;AJnCM,IAAAC,sBAAA;AAhBN,IAAM,aAAqC;AAAA,EACzC,WAAW;AAAA,EAAU,QAAQ;AAAA,EAAS,eAAe;AAAA,EACrD,gBAAgB;AAAA,EAAQ,SAAS;AACnC;AAEA,eAAsB,mBAAmB;AACvC,QAAM,QAAQ,IAAI,iBAAiB;AACnC,QAAM,UAAU,MAAM,QAAQ,EAAE;AAEhC,QAAM,YAAY,QAAQ,iBAAiB,OACvC,IAAI,QAAQ,eAAe,KAAK,QAAQ,CAAC,CAAC,MAAM;AACpD,QAAM,QAAQ,QAAQ,kBAAkB,OACpC,GAAG,KAAK,MAAM,QAAQ,aAAa,CAAC,OAAO;AAE/C,SACE,8CAAC,SACC;AAAA,iDAAC,QAAG,WAAU,iBAAgB,2BAAa;AAAA,IAC3C,6CAAC,OAAE,WAAU,oBAAmB,qDAAuC;AAAA,IAGvE,8CAAC,SAAI,WAAU,gBACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,OAAO,QAAQ,YAAY,eAAe;AAAA,UAC1C,MAAM,GAAG,QAAQ,WAAW,MAAM;AAAA,UAClC,OAAM;AAAA,UACN,MAAM,6CAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAa,GAAG,uDAAC,cAAS,QAAO,mCAAkC,GAAE;AAAA;AAAA,MACxI;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,OAAO,QAAQ,SAAS,OAAO,eAAe;AAAA,UAC9C,MAAK;AAAA,UACL,OAAM;AAAA,UACN,MAAM,8CAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAa,GAAG;AAAA,yDAAC,UAAK,GAAE,8DAA4D;AAAA,YAAE,6CAAC,cAAS,QAAO,kBAAgB;AAAA,aAAE;AAAA;AAAA,MAC5L;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,OAAO;AAAA,UACP,MAAK;AAAA,UACL,OAAM;AAAA,UACN,MAAM,8CAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAa,GAAG;AAAA,yDAAC,UAAK,GAAE,sCAAoC;AAAA,YAAE,6CAAC,cAAS,QAAO,yBAAuB;AAAA,aAAE;AAAA;AAAA,MAC3K;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,OAAO;AAAA,UACP,MAAK;AAAA,UACL,OAAM;AAAA,UACN,MAAM,8CAAC,SAAI,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAa,GAAG;AAAA,yDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAI;AAAA,YAAE,6CAAC,cAAS,QAAO,oBAAkB;AAAA,aAAE;AAAA;AAAA,MACxJ;AAAA,OACF;AAAA,IAGA,6CAAC,QAAK,OAAM,0BACV,uDAAC,eAAY,MAAM,QAAQ,aAAa,GAC1C;AAAA,IAEA,8CAAC,SAAI,WAAU,aAEb;AAAA,mDAAC,QAAK,OAAM,YACT,kBAAQ,QAAQ,WAAW,IAC1B,6CAAC,SAAI,WAAU,YAAW,uDAAC,OAAE,yCAA2B,GAAI,IAE5D,8CAAC,WAAM,WAAU,YACf;AAAA,qDAAC,WACC,wDAAC,QAAG;AAAA,uDAAC,QAAG,iBAAG;AAAA,UAAK,6CAAC,QAAG,oBAAM;AAAA,UAAK,6CAAC,QAAG,mBAAK;AAAA,WAAK,GAC/C;AAAA,QACA,6CAAC,WACE,kBAAQ,QAAQ,IAAI,OAAK;AACxB,gBAAM,MAAM,QAAQ,cAAc,KAC5B,EAAE,SAAS,QAAQ,cAAe,KAAK,QAAQ,CAAC,IAClD;AACJ,gBAAM,QAAQ,WAAW,EAAE,IAAI,KAAK,WAAW;AAC/C,iBACE,8CAAC,QACC;AAAA,yDAAC,QACC,uDAAC,UAAK,WAAW,sBAAsB,KAAK,IAAK,YAAE,MAAK,GAC1D;AAAA,YACA,6CAAC,QAAG,uDAAC,YAAQ,YAAE,OAAO,eAAe,GAAE,GAAS;AAAA,YAChD,6CAAC,QACC,wDAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,EAAE,GAC1D;AAAA,2DAAC,SAAI,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,sBAAsB,cAAc,EAAE,GAClF,uDAAC,SAAI,OAAO,EAAE,OAAO,GAAG,GAAG,KAAK,QAAQ,QAAQ,YAAY,kBAAkB,cAAc,EAAE,GAAG,GACnG;AAAA,cACA,8CAAC,UAAK,OAAO,EAAE,UAAU,IAAI,OAAO,sBAAsB,OAAO,GAAG,GAAI;AAAA;AAAA,gBAAI;AAAA,iBAAC;AAAA,eAC/E,GACF;AAAA,eAZO,EAAE,IAaX;AAAA,QAEJ,CAAC,GACH;AAAA,SACF,GAEJ;AAAA,MAGA,6CAAC,QAAK,OAAM,qBACT,kBAAQ,SAAS,WAAW,IAC3B,6CAAC,SAAI,WAAU,YAAW,uDAAC,OAAE,mCAAqB,GAAI,IAEtD,8CAAC,WAAM,WAAU,YACf;AAAA,qDAAC,WACC,wDAAC,QAAG;AAAA,uDAAC,QAAG,kBAAI;AAAA,UAAK,6CAAC,QAAG,oBAAM;AAAA,WAAK,GAClC;AAAA,QACA,6CAAC,WACE,kBAAQ,SAAS,IAAI,OACpB,8CAAC,QACC;AAAA,uDAAC,QACC,uDAAC,OAAE,MAAM,EAAE,KAAK,QAAO,UAAS,KAAI,cAAa,OAAO,EAAE,YAAY,uBAAuB,UAAU,GAAG,GACvG,YAAE,KACL,GACF;AAAA,UACA,6CAAC,QAAG,uDAAC,YAAQ,YAAE,OAAO,eAAe,GAAE,GAAS;AAAA,aANzC,EAAE,GAOX,CACD,GACH;AAAA,SACF,GAEJ;AAAA,OACF;AAAA,KACF;AAEJ;","names":["path","fs","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}