@polishd/next 0.1.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 (127) hide show
  1. package/AGENTS.md +262 -0
  2. package/DATABASE.md +147 -0
  3. package/LICENSE +21 -0
  4. package/README.md +310 -0
  5. package/bin/init.mjs +224 -0
  6. package/dist/ai/actions.d.ts +23 -0
  7. package/dist/ai/actions.d.ts.map +1 -0
  8. package/dist/ai/actions.js +58 -0
  9. package/dist/ai/actions.js.map +1 -0
  10. package/dist/ai/digest.d.ts +9 -0
  11. package/dist/ai/digest.d.ts.map +1 -0
  12. package/dist/ai/digest.js +108 -0
  13. package/dist/ai/digest.js.map +1 -0
  14. package/dist/ai/github.d.ts +51 -0
  15. package/dist/ai/github.d.ts.map +1 -0
  16. package/dist/ai/github.js +175 -0
  17. package/dist/ai/github.js.map +1 -0
  18. package/dist/ai/guard.d.ts +43 -0
  19. package/dist/ai/guard.d.ts.map +1 -0
  20. package/dist/ai/guard.js +57 -0
  21. package/dist/ai/guard.js.map +1 -0
  22. package/dist/ai/issues.d.ts +21 -0
  23. package/dist/ai/issues.d.ts.map +1 -0
  24. package/dist/ai/issues.js +291 -0
  25. package/dist/ai/issues.js.map +1 -0
  26. package/dist/ai/profile.d.ts +26 -0
  27. package/dist/ai/profile.d.ts.map +1 -0
  28. package/dist/ai/profile.js +160 -0
  29. package/dist/ai/profile.js.map +1 -0
  30. package/dist/ai/providers.d.ts +40 -0
  31. package/dist/ai/providers.d.ts.map +1 -0
  32. package/dist/ai/providers.js +142 -0
  33. package/dist/ai/providers.js.map +1 -0
  34. package/dist/ai/scan.d.ts +38 -0
  35. package/dist/ai/scan.d.ts.map +1 -0
  36. package/dist/ai/scan.js +274 -0
  37. package/dist/ai/scan.js.map +1 -0
  38. package/dist/ai/settings.d.ts +31 -0
  39. package/dist/ai/settings.d.ts.map +1 -0
  40. package/dist/ai/settings.js +182 -0
  41. package/dist/ai/settings.js.map +1 -0
  42. package/dist/ai/summary.d.ts +26 -0
  43. package/dist/ai/summary.d.ts.map +1 -0
  44. package/dist/ai/summary.js +260 -0
  45. package/dist/ai/summary.js.map +1 -0
  46. package/dist/ai/types.d.ts +188 -0
  47. package/dist/ai/types.d.ts.map +1 -0
  48. package/dist/ai/types.js +13 -0
  49. package/dist/ai/types.js.map +1 -0
  50. package/dist/client/init.d.ts +14 -0
  51. package/dist/client/init.d.ts.map +1 -0
  52. package/dist/client/init.js +274 -0
  53. package/dist/client/init.js.map +1 -0
  54. package/dist/client/monitor.d.ts +23 -0
  55. package/dist/client/monitor.d.ts.map +1 -0
  56. package/dist/client/monitor.js +176 -0
  57. package/dist/client/monitor.js.map +1 -0
  58. package/dist/client.d.ts +11 -0
  59. package/dist/client.d.ts.map +1 -0
  60. package/dist/client.js +10 -0
  61. package/dist/client.js.map +1 -0
  62. package/dist/config.d.ts +36 -0
  63. package/dist/config.d.ts.map +1 -0
  64. package/dist/config.js +26 -0
  65. package/dist/config.js.map +1 -0
  66. package/dist/dashboard/elements.d.ts +6 -0
  67. package/dist/dashboard/elements.d.ts.map +1 -0
  68. package/dist/dashboard/elements.js +35 -0
  69. package/dist/dashboard/elements.js.map +1 -0
  70. package/dist/dashboard/features.d.ts +6 -0
  71. package/dist/dashboard/features.d.ts.map +1 -0
  72. package/dist/dashboard/features.js +28 -0
  73. package/dist/dashboard/features.js.map +1 -0
  74. package/dist/dashboard/index.d.ts +54 -0
  75. package/dist/dashboard/index.d.ts.map +1 -0
  76. package/dist/dashboard/index.js +140 -0
  77. package/dist/dashboard/index.js.map +1 -0
  78. package/dist/dashboard/journeys.d.ts +5 -0
  79. package/dist/dashboard/journeys.d.ts.map +1 -0
  80. package/dist/dashboard/journeys.js +158 -0
  81. package/dist/dashboard/journeys.js.map +1 -0
  82. package/dist/dashboard/pages.d.ts +5 -0
  83. package/dist/dashboard/pages.d.ts.map +1 -0
  84. package/dist/dashboard/pages.js +104 -0
  85. package/dist/dashboard/pages.js.map +1 -0
  86. package/dist/dashboard/summary.d.ts +13 -0
  87. package/dist/dashboard/summary.d.ts.map +1 -0
  88. package/dist/dashboard/summary.js +333 -0
  89. package/dist/dashboard/summary.js.map +1 -0
  90. package/dist/index.d.ts +10 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +10 -0
  93. package/dist/index.js.map +1 -0
  94. package/dist/proxy.d.ts +40 -0
  95. package/dist/proxy.d.ts.map +1 -0
  96. package/dist/proxy.js +29 -0
  97. package/dist/proxy.js.map +1 -0
  98. package/dist/route.d.ts +24 -0
  99. package/dist/route.d.ts.map +1 -0
  100. package/dist/route.js +37 -0
  101. package/dist/route.js.map +1 -0
  102. package/dist/server/ingest.d.ts +14 -0
  103. package/dist/server/ingest.d.ts.map +1 -0
  104. package/dist/server/ingest.js +73 -0
  105. package/dist/server/ingest.js.map +1 -0
  106. package/dist/server/queries.d.ts +245 -0
  107. package/dist/server/queries.d.ts.map +1 -0
  108. package/dist/server/queries.js +547 -0
  109. package/dist/server/queries.js.map +1 -0
  110. package/dist/server/store.d.ts +29 -0
  111. package/dist/server/store.d.ts.map +1 -0
  112. package/dist/server/store.js +359 -0
  113. package/dist/server/store.js.map +1 -0
  114. package/dist/server.d.ts +15 -0
  115. package/dist/server.d.ts.map +1 -0
  116. package/dist/server.js +15 -0
  117. package/dist/server.js.map +1 -0
  118. package/dist/session.d.ts +16 -0
  119. package/dist/session.d.ts.map +1 -0
  120. package/dist/session.js +29 -0
  121. package/dist/session.js.map +1 -0
  122. package/dist/shared/types.d.ts +56 -0
  123. package/dist/shared/types.d.ts.map +1 -0
  124. package/dist/shared/types.js +27 -0
  125. package/dist/shared/types.js.map +1 -0
  126. package/docs/SETUP.md +315 -0
  127. package/package.json +92 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,YAAY,EAAoB,MAAM,aAAa,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAsB,MAAM,UAAU,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,mEAAmE;AACnE,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC;AAChC,sEAAsE;AACtE,MAAM,CAAC,MAAM,OAAO,GAAG,eAAe,CAAC;AAEvC,MAAM,UAAU,kBAAkB,CAAC,SAAiC,EAAE;IACpE,MAAM,GAAG,GAAG,EAAE,GAAG,oBAAoB,EAAE,GAAG,MAAM,EAAE,CAAC;IAEnD,OAAO,KAAK,UAAU,IAAI,CAAC,GAAgB;QACzC,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAC/E,CAAC;QAED,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC;QAC9D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAE/C,uEAAuE;QACvE,yDAAyD;QACzD,OAAO,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACtE,CAAC,CAAC;AACJ,CAAC;AAED,wDAAwD;AACxD,MAAM,CAAC,MAAM,IAAI,GAAG,kBAAkB,EAAE,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface IngestResult {
2
+ ok: boolean;
3
+ stored: number;
4
+ reason?: string;
5
+ }
6
+ /**
7
+ * Pull the anonymous session id from the cookie. Returns null when absent —
8
+ * the middleware normally guarantees one, but a client with cookies disabled
9
+ * legitimately has none, in which case we skip rather than error.
10
+ */
11
+ export declare function sessionIdFromCookie(cookieValue: string | undefined): string | null;
12
+ /** Ingest a raw request body. `cookieValue` is the session cookie's value. */
13
+ export declare function ingest(body: unknown, cookieValue: string | undefined): Promise<IngestResult>;
14
+ //# sourceMappingURL=ingest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest.d.ts","sourceRoot":"","sources":["../../src/server/ingest.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAElF;AAiCD,8EAA8E;AAC9E,wBAAsB,MAAM,CAC1B,IAAI,EAAE,OAAO,EACb,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,OAAO,CAAC,YAAY,CAAC,CAevB"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Polishd — ingest (server only).
3
+ *
4
+ * Validates and sanitizes an inbound batch, then hands clean events to the
5
+ * store. The session id is taken from the request's cookie, never from the
6
+ * body, so events are always attributed to the bearer of the cookie.
7
+ */
8
+ import { defaultPolishdConfig } from "../config";
9
+ import { CLIENT_EVENT_TYPES } from "../shared/types";
10
+ import { insertEvents } from "./store";
11
+ const MAX_EVENTS_PER_BATCH = 200;
12
+ const MAX_TEXT_LEN = 120;
13
+ const MAX_SELECTOR_LEN = 300;
14
+ /**
15
+ * Pull the anonymous session id from the cookie. Returns null when absent —
16
+ * the middleware normally guarantees one, but a client with cookies disabled
17
+ * legitimately has none, in which case we skip rather than error.
18
+ */
19
+ export function sessionIdFromCookie(cookieValue) {
20
+ return cookieValue && cookieValue.length <= 64 ? cookieValue : null;
21
+ }
22
+ /** Validate + clamp a single raw event. Returns null to drop it. */
23
+ function sanitize(raw) {
24
+ if (!raw || typeof raw !== "object")
25
+ return null;
26
+ const e = raw;
27
+ const type = e.type;
28
+ if (typeof type !== "string" || !CLIENT_EVENT_TYPES.has(type)) {
29
+ return null;
30
+ }
31
+ const ts = typeof e.ts === "number" && Number.isFinite(e.ts) ? e.ts : Date.now();
32
+ const path = typeof e.path === "string" ? e.path.slice(0, 512) : "/";
33
+ const out = { type: type, ts, path };
34
+ if (typeof e.selector === "string")
35
+ out.selector = e.selector.slice(0, MAX_SELECTOR_LEN);
36
+ if (typeof e.component === "string")
37
+ out.component = e.component.slice(0, 80);
38
+ if (typeof e.text === "string")
39
+ out.text = e.text.trim().slice(0, MAX_TEXT_LEN);
40
+ if (typeof e.value === "number" && Number.isFinite(e.value))
41
+ out.value = e.value;
42
+ if (e.meta && typeof e.meta === "object") {
43
+ const meta = {};
44
+ for (const [k, v] of Object.entries(e.meta)) {
45
+ if (k.length > 40)
46
+ continue;
47
+ if (typeof v === "string")
48
+ meta[k] = v.slice(0, 500);
49
+ else if (typeof v === "number" || typeof v === "boolean" || v === null)
50
+ meta[k] = v;
51
+ }
52
+ out.meta = meta;
53
+ }
54
+ return out;
55
+ }
56
+ /** Ingest a raw request body. `cookieValue` is the session cookie's value. */
57
+ export async function ingest(body, cookieValue) {
58
+ const sessionId = sessionIdFromCookie(cookieValue);
59
+ if (!sessionId)
60
+ return { ok: true, stored: 0, reason: "no_session" };
61
+ if (!defaultPolishdConfig.enabled)
62
+ return { ok: true, stored: 0, reason: "disabled" };
63
+ const rawEvents = body?.events;
64
+ if (!Array.isArray(rawEvents))
65
+ return { ok: false, stored: 0, reason: "no_events" };
66
+ const events = rawEvents
67
+ .slice(0, MAX_EVENTS_PER_BATCH)
68
+ .map(sanitize)
69
+ .filter((e) => e !== null);
70
+ const stored = await insertEvents(sessionId, events);
71
+ return { ok: true, stored };
72
+ }
73
+ //# sourceMappingURL=ingest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest.js","sourceRoot":"","sources":["../../src/server/ingest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,245 @@
1
+ import type { PolishdEventType } from "../shared/types";
2
+ export interface OverviewStats {
3
+ ready: boolean;
4
+ totalEvents: number;
5
+ sessions: number;
6
+ pageViews: number;
7
+ rageClicks: number;
8
+ deadClicks: number;
9
+ jsErrors: number;
10
+ }
11
+ export interface PageStat {
12
+ path: string;
13
+ sessions: number;
14
+ pageViews: number;
15
+ rageClicks: number;
16
+ deadClicks: number;
17
+ jsErrors: number;
18
+ avgScrollDepth: number | null;
19
+ /** Composite score; higher = worse. */
20
+ score: number;
21
+ }
22
+ export interface RecentError {
23
+ path: string;
24
+ message: string;
25
+ component?: string;
26
+ ts: number;
27
+ }
28
+ export interface ElementStat {
29
+ /** The DOM selector this element was interacted with as. */
30
+ label: string;
31
+ /** A representative DOM selector for this element. */
32
+ selector: string | null;
33
+ /** A sample of the element's visible text (label), if any. */
34
+ sampleText: string | null;
35
+ /** How many distinct pages this element was interacted with on. */
36
+ pages: number;
37
+ clicks: number;
38
+ rageClicks: number;
39
+ deadClicks: number;
40
+ /** Composite score; higher = worse. */
41
+ score: number;
42
+ /** Client timestamp of the most recent interaction with this element, ms. */
43
+ lastInteraction: number;
44
+ }
45
+ export interface DeviceBucket {
46
+ /** Device category: "mobile" | "tablet" | "desktop". */
47
+ category: string;
48
+ /** Distinct sessions that fell into this bucket. */
49
+ sessions: number;
50
+ /** Share of all measured sessions, 0–100. */
51
+ pct: number;
52
+ /** Average viewport width (CSS px) for the bucket. */
53
+ avgWidth: number | null;
54
+ }
55
+ export interface TopInteraction {
56
+ /** Component name (from data-component) or, failing that, the selector. */
57
+ label: string;
58
+ /** True when `label` is a real component name, false when it's a raw selector. */
59
+ isComponent: boolean;
60
+ /** A representative DOM selector for this element. */
61
+ selector: string | null;
62
+ /** A sample of the element's visible text (label), if any. */
63
+ sampleText: string | null;
64
+ /** Total successful (interactive) clicks on this element. */
65
+ clicks: number;
66
+ /** Distinct sessions that clicked it. */
67
+ sessions: number;
68
+ /** Distinct pages it was clicked on. */
69
+ pages: number;
70
+ }
71
+ export declare function getOverview(): Promise<OverviewStats>;
72
+ /**
73
+ * Score ranking. Weights match the build plan's guidance — rage clicks are
74
+ * the strongest frustration signal, then dead clicks and errors; shallow
75
+ * scroll (content not reached) contributes mildly.
76
+ */
77
+ export declare function getPageStats(limit?: number): Promise<PageStat[]>;
78
+ /** One point in a page's sessions-over-time series (one calendar day, UTC). */
79
+ export interface PageTrendPoint {
80
+ /** Bucket start — UTC midnight, ms since epoch. */
81
+ ts: number;
82
+ /** Short human label for the bucket, e.g. "Jun 14". */
83
+ label: string;
84
+ /** Distinct sessions that viewed the page on that day. */
85
+ sessions: number;
86
+ }
87
+ /** A top page plus its session trend, for the "Top pages" table + drawer chart. */
88
+ export interface TopPage {
89
+ path: string;
90
+ sessions: number;
91
+ pageViews: number;
92
+ rageClicks: number;
93
+ deadClicks: number;
94
+ jsErrors: number;
95
+ avgScrollDepth: number | null;
96
+ /** Daily sessions series, oldest → newest, gap-filled. */
97
+ trend: PageTrendPoint[];
98
+ }
99
+ /**
100
+ * The most-visited pages, ranked by distinct sessions, each with a daily
101
+ * sessions-over-time series for the detail chart. The aggregate is one grouped
102
+ * query; the trend comes from a second pull of page_view events for just the
103
+ * top paths, bucketed by UTC day in JS so it stays backend-portable.
104
+ */
105
+ export declare function getTopPages(limit?: number): Promise<TopPage[]>;
106
+ /**
107
+ * Per-element interaction breakdown, grouped by DOM selector path. This is the
108
+ * data that makes Stage 2 synthesis possible: it tells you *which UI element*
109
+ * the issues are, not just which page.
110
+ *
111
+ * Explicitly monitored components (those wrapped in <PolishdMonitor>, the only
112
+ * source of `data-component`) are excluded here — they get their own dedicated
113
+ * "Monitored components" section, so this table covers the rest of the UI.
114
+ */
115
+ export declare function getElementStats(limit?: number): Promise<ElementStat[]>;
116
+ /**
117
+ * Device-size distribution. One `viewport` event is sampled per session at
118
+ * start; its category lives in the `text` column (mobile/tablet/desktop) and
119
+ * its width in `value`, so this groups without touching the JSON `meta` column.
120
+ * Sorted most-used device first — answers "what size screen do visitors use?".
121
+ */
122
+ export declare function getDeviceBreakdown(): Promise<DeviceBucket[]>;
123
+ /**
124
+ * Most-used features. Ranks interactive elements by raw click volume (the
125
+ * `click` type — successful clicks on links/buttons/etc., excluding rage and
126
+ * dead clicks). Where `getElementStats` surfaces what's *broken*, this
127
+ * surfaces what's *popular* — which buttons and features people actually use.
128
+ */
129
+ export declare function getTopInteractions(limit?: number): Promise<TopInteraction[]>;
130
+ /** One action in a reconstructed session, in the order it happened. */
131
+ export interface JourneyStep {
132
+ type: PolishdEventType;
133
+ /** Client clock for this action, ms since epoch. */
134
+ ts: number;
135
+ /** Pathname the action occurred on. */
136
+ path: string;
137
+ /** Component name, element text, or selector — whatever identifies the target. */
138
+ label: string | null;
139
+ /** Extra context for the step (error message, scroll %, etc.). */
140
+ detail: string | null;
141
+ }
142
+ /** Device/viewport details sampled once at the start of a session. */
143
+ export interface JourneyDevice {
144
+ category: string | null;
145
+ width: number | null;
146
+ height: number | null;
147
+ dpr: number | null;
148
+ }
149
+ /** A single sampled session, reconstructed start-to-finish for the flow chart. */
150
+ export interface SessionJourney {
151
+ /** Short, display-safe slice of the opaque session id. */
152
+ id: string;
153
+ /** First and last client timestamps seen for the session. */
154
+ startedAt: number;
155
+ endedAt: number;
156
+ /** Wall-clock length of the recording, ms. */
157
+ durationMs: number;
158
+ /** True when a `session_end` event was captured (a complete recording). */
159
+ complete: boolean;
160
+ /** Distinct pages visited. */
161
+ pages: number;
162
+ device: JourneyDevice;
163
+ rageClicks: number;
164
+ deadClicks: number;
165
+ jsErrors: number;
166
+ /** Composite score; higher = worse. Drives the sampling order. */
167
+ score: number;
168
+ /** Ordered list of user actions. */
169
+ steps: JourneyStep[];
170
+ /** True when `steps` was capped and the journey is longer than shown. */
171
+ truncated: boolean;
172
+ }
173
+ /**
174
+ * Sampled full-session recordings, reconstructed as ordered action flows.
175
+ *
176
+ * Sampling strategy: every session is scored by a composite score (rage×3 + dead×2 +
177
+ * errors×2.5). We surface the highest-scoring sessions first — those are the
178
+ * ones worth replaying — preferring *complete* recordings (a `session_end` was
179
+ * captured) and breaking ties by recency. When there's no signal at all this
180
+ * degrades to "most recent complete sessions", so the section is still useful.
181
+ */
182
+ export declare function getSessionJourneys(limit?: number): Promise<SessionJourney[]>;
183
+ /** One explicitly-monitored component (wrapped in <PolishdMonitor>). */
184
+ export interface MonitoredComponent {
185
+ /** The name passed to <PolishdMonitor name="...">. */
186
+ name: string;
187
+ /** Normal clicks attributed to this component. */
188
+ clicks: number;
189
+ rageClicks: number;
190
+ deadClicks: number;
191
+ /** Deliberate hovers recorded (≥200ms dwell). */
192
+ hovers: number;
193
+ /** Average hover dwell time in ms. Null when no hover data. */
194
+ avgHoverMs: number | null;
195
+ /** Times the region was rendered (mount events). Only for `content` monitors. */
196
+ mounts: number;
197
+ /** Total component_view events (one per continuous viewport visit ≥500ms). */
198
+ componentViews: number;
199
+ /** Average time visible per viewport visit, in ms. Null when no view data. */
200
+ avgViewMs: number | null;
201
+ /**
202
+ * Largest rendered height in px observed across all view events. We take the
203
+ * max (not the average) because a component name can be attached to more than
204
+ * one element — note slugs wrap both the short sidebar row and the tall
205
+ * article body — and the max is the meaningful "how long is this content".
206
+ */
207
+ heightPx: number | null;
208
+ /** Average max scroll-depth % reached across all view events. */
209
+ avgScrollDepth: number | null;
210
+ /** Distinct sessions that interacted with this component. */
211
+ sessions: number;
212
+ /** Distinct pages the component appeared on. */
213
+ pages: number;
214
+ }
215
+ /**
216
+ * Fetch all components explicitly wrapped in <PolishdMonitor>. The definitive
217
+ * marker is the presence of at least one "hover", "component_view", or "mount"
218
+ * event for that component name (all three are only emitted by PolishdMonitor).
219
+ * We then pull all event types for those components so the table shows the
220
+ * complete picture.
221
+ *
222
+ * The per-view `meta` (height, scrollDepth) is aggregated in JS rather than SQL:
223
+ * the two backends spell JSON extraction differently (SQLite `JSON_EXTRACT`,
224
+ * Postgres `->>`), and there's no portable function, so we parse meta here —
225
+ * matching how `getSessionJourneys` and `getTopPages` keep their SQL portable.
226
+ */
227
+ export declare function getMonitoredComponents(): Promise<MonitoredComponent[]>;
228
+ /** Everything the dashboard (and the AI summary) reads, in one shape. */
229
+ export interface PolishdDashboardData {
230
+ overview: Awaited<ReturnType<typeof getOverview>>;
231
+ pages: Awaited<ReturnType<typeof getTopPages>>;
232
+ elements: Awaited<ReturnType<typeof getElementStats>>;
233
+ devices: Awaited<ReturnType<typeof getDeviceBreakdown>>;
234
+ topUsed: Awaited<ReturnType<typeof getTopInteractions>>;
235
+ journeys: Awaited<ReturnType<typeof getSessionJourneys>>;
236
+ errors: Awaited<ReturnType<typeof getRecentErrors>>;
237
+ monitored: Awaited<ReturnType<typeof getMonitoredComponents>>;
238
+ }
239
+ /**
240
+ * Fetch every dashboard query in parallel. Server-only. Lives here (not in the
241
+ * dashboard) so the AI summary layer can reuse it without importing React.
242
+ */
243
+ export declare function loadPolishdDashboardData(): Promise<PolishdDashboardData>;
244
+ export declare function getRecentErrors(limit?: number): Promise<RecentError[]>;
245
+ //# sourceMappingURL=queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/server/queries.ts"],"names":[],"mappings":"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"}