@rudderjs/telescope 13.0.2 → 13.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 (51) hide show
  1. package/README.md +13 -1
  2. package/dist/collectors/exception.d.ts +13 -0
  3. package/dist/collectors/exception.d.ts.map +1 -1
  4. package/dist/collectors/exception.js +13 -0
  5. package/dist/collectors/exception.js.map +1 -1
  6. package/dist/collectors/request.d.ts.map +1 -1
  7. package/dist/collectors/request.js +15 -4
  8. package/dist/collectors/request.js.map +1 -1
  9. package/dist/index.d.ts +18 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +24 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/routes.d.ts +8 -0
  14. package/dist/routes.d.ts.map +1 -1
  15. package/dist/routes.js +20 -6
  16. package/dist/routes.js.map +1 -1
  17. package/dist/storage.d.ts +26 -0
  18. package/dist/storage.d.ts.map +1 -1
  19. package/dist/storage.js +34 -6
  20. package/dist/storage.js.map +1 -1
  21. package/dist/stream.d.ts +23 -0
  22. package/dist/stream.d.ts.map +1 -0
  23. package/dist/stream.js +96 -0
  24. package/dist/stream.js.map +1 -0
  25. package/dist/types.d.ts +29 -0
  26. package/dist/types.d.ts.map +1 -1
  27. package/dist/types.js +22 -0
  28. package/dist/types.js.map +1 -1
  29. package/dist/views/vanilla/EntryList.d.ts +8 -0
  30. package/dist/views/vanilla/EntryList.d.ts.map +1 -1
  31. package/dist/views/vanilla/EntryList.js +62 -11
  32. package/dist/views/vanilla/EntryList.js.map +1 -1
  33. package/dist/views/vanilla/Layout.d.ts.map +1 -1
  34. package/dist/views/vanilla/Layout.js +6 -1
  35. package/dist/views/vanilla/Layout.js.map +1 -1
  36. package/dist/views/vanilla/details/ai-views.d.ts +16 -0
  37. package/dist/views/vanilla/details/ai-views.d.ts.map +1 -0
  38. package/dist/views/vanilla/details/ai-views.js +136 -0
  39. package/dist/views/vanilla/details/ai-views.js.map +1 -0
  40. package/dist/views/vanilla/details/format.d.ts +16 -0
  41. package/dist/views/vanilla/details/format.d.ts.map +1 -0
  42. package/dist/views/vanilla/details/format.js +45 -0
  43. package/dist/views/vanilla/details/format.js.map +1 -0
  44. package/dist/views/vanilla/details/request-views.d.ts +15 -0
  45. package/dist/views/vanilla/details/request-views.d.ts.map +1 -0
  46. package/dist/views/vanilla/details/request-views.js +135 -0
  47. package/dist/views/vanilla/details/request-views.js.map +1 -0
  48. package/dist/views/vanilla/details/views.d.ts.map +1 -1
  49. package/dist/views/vanilla/details/views.js +3 -295
  50. package/dist/views/vanilla/details/views.js.map +1 -1
  51. package/package.json +14 -14
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../../src/views/vanilla/details/format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,+DAA+D;AAC/D,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAOxC;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAMxD;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIjD;AAED,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMlD"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Shared formatting helpers used across per-watcher detail views.
3
+ *
4
+ * Kept package-internal — none of these are re-exported from the package
5
+ * entry. They're tiny, side-effect free, and only meaningful within the
6
+ * dashboard rendering pipeline.
7
+ */
8
+ /** HTML-escape a value for use inside raw template strings. */
9
+ export function escape(s) {
10
+ return String(s ?? '')
11
+ .replace(/&/g, '&')
12
+ .replace(/</g, '&lt;')
13
+ .replace(/>/g, '&gt;')
14
+ .replace(/"/g, '&quot;')
15
+ .replace(/'/g, '&#39;');
16
+ }
17
+ /** Format a Date (or ISO string) using the browser's locale. */
18
+ export function formatTimestamp(d) {
19
+ const date = d instanceof Date ? d : new Date(d);
20
+ return date.toLocaleString(undefined, {
21
+ year: 'numeric', month: 'short', day: 'numeric',
22
+ hour: '2-digit', minute: '2-digit', second: '2-digit',
23
+ });
24
+ }
25
+ /** Format a byte count with the smallest unit that keeps the magnitude ≥ 1. */
26
+ export function formatBytes(bytes) {
27
+ if (bytes < 1024)
28
+ return `${bytes} B`;
29
+ if (bytes < 1024 * 1024)
30
+ return `${(bytes / 1024).toFixed(1)} KB`;
31
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
32
+ }
33
+ /** Tailwind class string for an HTTP status badge — colored by status range. */
34
+ export function statusColor(status) {
35
+ if (status >= 500)
36
+ return 'bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-300';
37
+ if (status >= 400)
38
+ return 'bg-amber-100 text-amber-700 dark:bg-amber-900 dark:text-amber-300';
39
+ if (status >= 300)
40
+ return 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300';
41
+ if (status >= 200)
42
+ return 'bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300';
43
+ return 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400';
44
+ }
45
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../../src/views/vanilla/details/format.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,+DAA+D;AAC/D,MAAM,UAAU,MAAM,CAAC,CAAS;IAC9B,OAAO,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;SACnB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;AAC3B,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,eAAe,CAAC,CAAgB;IAC9C,MAAM,IAAI,GAAG,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAA;IAChD,OAAO,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE;QACpC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS;QAC/C,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS;KACtD,CAAC,CAAA;AACJ,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,IAAI,CAAA;IACrC,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAA;IACjE,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAA;AACnD,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,IAAI,MAAM,IAAI,GAAG;QAAE,OAAO,2DAA2D,CAAA;IACrF,IAAI,MAAM,IAAI,GAAG;QAAE,OAAO,mEAAmE,CAAA;IAC7F,IAAI,MAAM,IAAI,GAAG;QAAE,OAAO,+DAA+D,CAAA;IACzF,IAAI,MAAM,IAAI,GAAG;QAAE,OAAO,mEAAmE,CAAA;IAC7F,OAAO,+DAA+D,CAAA;AACxE,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { type SafeString } from '../_html.js';
2
+ import type { TelescopeEntry } from '../../../types.js';
3
+ /**
4
+ * Per-watcher detail views for "request-shaped" entries — those that
5
+ * render a payload-and-response surface around an HTTP status badge.
6
+ *
7
+ * Today: the `request` watcher (inbound) and the `http` watcher (outbound
8
+ * HTTP client). Both share the status-badge / payload-tabs idiom; keeping
9
+ * them in one file makes that family resemblance obvious.
10
+ */
11
+ type ViewFn = (entry: TelescopeEntry) => SafeString;
12
+ export declare const RequestView: ViewFn;
13
+ export declare const HttpView: ViewFn;
14
+ export {};
15
+ //# sourceMappingURL=request-views.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-views.d.ts","sourceRoot":"","sources":["../../../../src/views/vanilla/details/request-views.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAGxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD;;;;;;;GAOG;AAEH,KAAK,MAAM,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,UAAU,CAAA;AAEnD,eAAO,MAAM,WAAW,EAAE,MAyFzB,CAAA;AAED,eAAO,MAAM,QAAQ,EAAE,MAiDtB,CAAA"}
@@ -0,0 +1,135 @@
1
+ import { html, raw } from '../_html.js';
2
+ import { Card, KeyValueTable, JsonBlock, CodeBlock, Badge, Tabs } from './sections.js';
3
+ import { escape, formatTimestamp, formatBytes, statusColor } from './format.js';
4
+ export const RequestView = (entry) => {
5
+ const c = entry.content;
6
+ const headers = c['headers'];
7
+ const responseHeaders = c['responseHeaders'];
8
+ const body = c['body'];
9
+ const query = c['query'];
10
+ const params = c['params'];
11
+ const session = c['session'];
12
+ const user = c['user'];
13
+ const controller = c['controller'];
14
+ const middlewareList = c['middleware'];
15
+ const memoryUsage = c['memoryUsage'];
16
+ // Status badge with color based on status code
17
+ const status = c['status'];
18
+ const statusBadge = status
19
+ ? raw(`<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${statusColor(status)}">${status}</span>`)
20
+ : raw('<span class="text-gray-300 dark:text-gray-600">—</span>');
21
+ // Build the details table — only include fields that have values
22
+ const details = {
23
+ Time: formatTimestamp(entry.createdAt),
24
+ Method: Badge(c['method']),
25
+ Path: raw(`<span class="font-mono text-xs">${escape(c['path'])}</span>`),
26
+ };
27
+ if (controller)
28
+ details['Controller Action'] = controller;
29
+ if (middlewareList && middlewareList.length > 0)
30
+ details['Middleware'] = middlewareList.join(', ');
31
+ Object.assign(details, {
32
+ Status: statusBadge,
33
+ Duration: c['duration'] != null ? `${c['duration']}ms` : '—',
34
+ Hostname: c['hostname'],
35
+ 'IP Address': c['ip'],
36
+ });
37
+ if (memoryUsage != null)
38
+ details['Memory Usage'] = formatBytes(memoryUsage);
39
+ if (entry.tags.length > 0) {
40
+ details['Tags'] = raw(entry.tags.map(t => `<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300 font-mono">${escape(t)}</span>`).join(' '));
41
+ }
42
+ const responseBody = c['responseBody'];
43
+ const hasQuery = !!query && Object.keys(query).length > 0;
44
+ const hasParams = !!params && Object.keys(params).length > 0;
45
+ const hasBody = body !== undefined && body !== null && body !== '' && !(typeof body === 'object' && Object.keys(body).length === 0);
46
+ const hasPayload = hasQuery || hasParams || hasBody;
47
+ const hasSession = !!session && Object.keys(session).length > 0;
48
+ const hasResHeaders = !!responseHeaders && Object.keys(responseHeaders).length > 0;
49
+ const hasResBody = responseBody !== undefined && responseBody !== null && responseBody !== '';
50
+ const subheading = (label) => raw(`<h4 class="text-xs uppercase tracking-wide font-medium text-gray-500 dark:text-gray-400 mb-2">${escape(label)}</h4>`);
51
+ // Always show a Payload tab — matches Laravel Telescope, which renders `[]`
52
+ // for GET requests with no query/body/params.
53
+ const payloadContent = hasPayload
54
+ ? html `
55
+ ${hasQuery ? html `<div class="mb-4">${subheading('Query String')}${JsonBlock(query)}</div>` : ''}
56
+ ${hasBody ? html `<div class="mb-4">${subheading('Body')}${JsonBlock(body)}</div>` : ''}
57
+ ${hasParams ? html `<div class="mb-4">${subheading('Route Parameters')}${JsonBlock(params)}</div>` : ''}
58
+ `
59
+ : JsonBlock([]);
60
+ // Two separate tab groups (Laravel-style):
61
+ // Request — Payload + Headers
62
+ // Response — Headers + Session (session is scoped to the resolved response)
63
+ const requestTabs = Tabs([
64
+ { label: 'Payload', content: payloadContent },
65
+ ...(headers ? [{ label: 'Headers', content: JsonBlock(headers) }] : []),
66
+ ]);
67
+ const responseBodyContent = hasResBody
68
+ ? (typeof responseBody === 'string'
69
+ ? CodeBlock(responseBody)
70
+ : JsonBlock(responseBody))
71
+ : '';
72
+ const responseTabs = Tabs([
73
+ ...(hasResBody ? [{ label: 'Response', content: responseBodyContent }] : []),
74
+ ...(hasResHeaders ? [{ label: 'Headers', content: JsonBlock(responseHeaders) }] : []),
75
+ ...(hasSession ? [{ label: 'Session', content: JsonBlock(session) }] : []),
76
+ ]);
77
+ return html `
78
+ ${Card('Request Details', KeyValueTable(details))}
79
+
80
+ ${user ? Card('Authenticated User', KeyValueTable({
81
+ ID: user['id'],
82
+ Name: user['name'],
83
+ 'Email Address': user['email'],
84
+ })) : ''}
85
+
86
+ ${requestTabs}
87
+ ${responseTabs}
88
+ `;
89
+ };
90
+ export const HttpView = (entry) => {
91
+ const c = entry.content;
92
+ const reqHeaders = c['reqHeaders'];
93
+ const resHeaders = c['resHeaders'];
94
+ const reqBody = c['reqBody'];
95
+ const resBody = c['resBody'];
96
+ const isFailure = c['kind'] === 'request.failed';
97
+ const status = c['status'];
98
+ const statusBadge = isFailure
99
+ ? Badge('FAILED')
100
+ : (status != null
101
+ ? raw(`<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${statusColor(status)}">${status}</span>`)
102
+ : Badge('—'));
103
+ // Always show a Payload tab — matches the Request entry's behavior
104
+ const hasReqBody = reqBody !== undefined && reqBody !== null && reqBody !== ''
105
+ && !(typeof reqBody === 'object' && Object.keys(reqBody).length === 0);
106
+ const payloadContent = hasReqBody ? JsonBlock(reqBody) : JsonBlock([]);
107
+ const requestTabs = Tabs([
108
+ { label: 'Payload', content: payloadContent },
109
+ { label: 'Headers', content: reqHeaders && Object.keys(reqHeaders).length > 0
110
+ ? JsonBlock(reqHeaders)
111
+ : raw('<p class="text-sm text-gray-400 dark:text-gray-500">No request headers.</p>') },
112
+ ]);
113
+ const hasResBody = resBody !== undefined && resBody !== null && resBody !== '';
114
+ const hasResHeaders = !!resHeaders && Object.keys(resHeaders).length > 0;
115
+ const responseBodyContent = hasResBody
116
+ ? (typeof resBody === 'string' ? CodeBlock(resBody, { maxHeight: '[400px]' }) : JsonBlock(resBody))
117
+ : '';
118
+ const responseTabs = Tabs([
119
+ ...(hasResBody ? [{ label: 'Body', content: responseBodyContent }] : []),
120
+ ...(hasResHeaders ? [{ label: 'Headers', content: JsonBlock(resHeaders) }] : []),
121
+ ]);
122
+ return html `
123
+ ${Card(null, KeyValueTable({
124
+ Method: Badge(c['method']),
125
+ URL: raw(`<span class="font-mono text-xs break-all">${escape(c['url'] ?? '')}</span>`),
126
+ Status: statusBadge,
127
+ Duration: c['duration'] != null ? `${c['duration']}ms` : '—',
128
+ 'Resp Size': c['resSize'] != null ? `${c['resSize']} bytes` : '—',
129
+ }))}
130
+ ${requestTabs}
131
+ ${responseTabs}
132
+ ${isFailure && c['error'] ? Card('Error', raw(`<div class="text-sm text-red-600 dark:text-red-400">${escape(c['error'])}</div>`)) : ''}
133
+ `;
134
+ };
135
+ //# sourceMappingURL=request-views.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-views.js","sourceRoot":"","sources":["../../../../src/views/vanilla/details/request-views.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"views.d.ts","sourceRoot":"","sources":["../../../../src/views/vanilla/details/views.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAExD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD;;;;;;;GAOG;AAEH,KAAK,MAAM,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,UAAU,CAAA;AAipBnD,uEAAuE;AACvE,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAqB9C,CAAA"}
1
+ {"version":3,"file":"views.d.ts","sourceRoot":"","sources":["../../../../src/views/vanilla/details/views.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAKxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAEvD;;;;;;;GAOG;AAEH,KAAK,MAAM,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,UAAU,CAAA;AAiWnD,uEAAuE;AACvE,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAqB9C,CAAA"}
@@ -1,116 +1,8 @@
1
1
  import { html, raw } from '../_html.js';
2
2
  import { Card, KeyValueTable, JsonBlock, CodeBlock, Badge, Tabs } from './sections.js';
3
- const RequestView = (entry) => {
4
- const c = entry.content;
5
- const headers = c['headers'];
6
- const responseHeaders = c['responseHeaders'];
7
- const body = c['body'];
8
- const query = c['query'];
9
- const params = c['params'];
10
- const session = c['session'];
11
- const user = c['user'];
12
- const controller = c['controller'];
13
- const middlewareList = c['middleware'];
14
- const memoryUsage = c['memoryUsage'];
15
- // Status badge with color based on status code
16
- const status = c['status'];
17
- const statusBadge = status
18
- ? raw(`<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${statusColor(status)}">${status}</span>`)
19
- : raw('<span class="text-gray-300 dark:text-gray-600">—</span>');
20
- // Build the details table — only include fields that have values
21
- const details = {
22
- Time: formatTimestamp(entry.createdAt),
23
- Method: Badge(c['method']),
24
- Path: raw(`<span class="font-mono text-xs">${escape(c['path'])}</span>`),
25
- };
26
- if (controller)
27
- details['Controller Action'] = controller;
28
- if (middlewareList && middlewareList.length > 0)
29
- details['Middleware'] = middlewareList.join(', ');
30
- Object.assign(details, {
31
- Status: statusBadge,
32
- Duration: c['duration'] != null ? `${c['duration']}ms` : '—',
33
- Hostname: c['hostname'],
34
- 'IP Address': c['ip'],
35
- });
36
- if (memoryUsage != null)
37
- details['Memory Usage'] = formatBytes(memoryUsage);
38
- if (entry.tags.length > 0) {
39
- details['Tags'] = raw(entry.tags.map(t => `<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-300 font-mono">${escape(t)}</span>`).join(' '));
40
- }
41
- const responseBody = c['responseBody'];
42
- const hasQuery = !!query && Object.keys(query).length > 0;
43
- const hasParams = !!params && Object.keys(params).length > 0;
44
- const hasBody = body !== undefined && body !== null && body !== '' && !(typeof body === 'object' && Object.keys(body).length === 0);
45
- const hasPayload = hasQuery || hasParams || hasBody;
46
- const hasSession = !!session && Object.keys(session).length > 0;
47
- const hasResHeaders = !!responseHeaders && Object.keys(responseHeaders).length > 0;
48
- const hasResBody = responseBody !== undefined && responseBody !== null && responseBody !== '';
49
- const subheading = (label) => raw(`<h4 class="text-xs uppercase tracking-wide font-medium text-gray-500 dark:text-gray-400 mb-2">${escape(label)}</h4>`);
50
- // Always show a Payload tab — matches Laravel Telescope, which renders `[]`
51
- // for GET requests with no query/body/params.
52
- const payloadContent = hasPayload
53
- ? html `
54
- ${hasQuery ? html `<div class="mb-4">${subheading('Query String')}${JsonBlock(query)}</div>` : ''}
55
- ${hasBody ? html `<div class="mb-4">${subheading('Body')}${JsonBlock(body)}</div>` : ''}
56
- ${hasParams ? html `<div class="mb-4">${subheading('Route Parameters')}${JsonBlock(params)}</div>` : ''}
57
- `
58
- : JsonBlock([]);
59
- // Two separate tab groups (Laravel-style):
60
- // Request — Payload + Headers
61
- // Response — Headers + Session (session is scoped to the resolved response)
62
- const requestTabs = Tabs([
63
- { label: 'Payload', content: payloadContent },
64
- ...(headers ? [{ label: 'Headers', content: JsonBlock(headers) }] : []),
65
- ]);
66
- const responseBodyContent = hasResBody
67
- ? (typeof responseBody === 'string'
68
- ? CodeBlock(responseBody)
69
- : JsonBlock(responseBody))
70
- : '';
71
- const responseTabs = Tabs([
72
- ...(hasResBody ? [{ label: 'Response', content: responseBodyContent }] : []),
73
- ...(hasResHeaders ? [{ label: 'Headers', content: JsonBlock(responseHeaders) }] : []),
74
- ...(hasSession ? [{ label: 'Session', content: JsonBlock(session) }] : []),
75
- ]);
76
- return html `
77
- ${Card('Request Details', KeyValueTable(details))}
78
-
79
- ${user ? Card('Authenticated User', KeyValueTable({
80
- ID: user['id'],
81
- Name: user['name'],
82
- 'Email Address': user['email'],
83
- })) : ''}
84
-
85
- ${requestTabs}
86
- ${responseTabs}
87
- `;
88
- };
89
- function formatTimestamp(d) {
90
- const date = d instanceof Date ? d : new Date(d);
91
- return date.toLocaleString(undefined, {
92
- year: 'numeric', month: 'short', day: 'numeric',
93
- hour: '2-digit', minute: '2-digit', second: '2-digit',
94
- });
95
- }
96
- function formatBytes(bytes) {
97
- if (bytes < 1024)
98
- return `${bytes} B`;
99
- if (bytes < 1024 * 1024)
100
- return `${(bytes / 1024).toFixed(1)} KB`;
101
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
102
- }
103
- function statusColor(status) {
104
- if (status >= 500)
105
- return 'bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-300';
106
- if (status >= 400)
107
- return 'bg-amber-100 text-amber-700 dark:bg-amber-900 dark:text-amber-300';
108
- if (status >= 300)
109
- return 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300';
110
- if (status >= 200)
111
- return 'bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300';
112
- return 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400';
113
- }
3
+ import { escape } from './format.js';
4
+ import { RequestView, HttpView } from './request-views.js';
5
+ import { AiView } from './ai-views.js';
114
6
  const QueryView = (entry) => {
115
7
  const c = entry.content;
116
8
  return html `
@@ -272,51 +164,6 @@ const CommandView = (entry) => {
272
164
  `) : ''}
273
165
  `;
274
166
  };
275
- const HttpView = (entry) => {
276
- const c = entry.content;
277
- const reqHeaders = c['reqHeaders'];
278
- const resHeaders = c['resHeaders'];
279
- const reqBody = c['reqBody'];
280
- const resBody = c['resBody'];
281
- const isFailure = c['kind'] === 'request.failed';
282
- const status = c['status'];
283
- const statusBadge = isFailure
284
- ? Badge('FAILED')
285
- : (status != null
286
- ? raw(`<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${statusColor(status)}">${status}</span>`)
287
- : Badge('—'));
288
- // Always show a Payload tab — matches the Request entry's behavior
289
- const hasReqBody = reqBody !== undefined && reqBody !== null && reqBody !== ''
290
- && !(typeof reqBody === 'object' && Object.keys(reqBody).length === 0);
291
- const payloadContent = hasReqBody ? JsonBlock(reqBody) : JsonBlock([]);
292
- const requestTabs = Tabs([
293
- { label: 'Payload', content: payloadContent },
294
- { label: 'Headers', content: reqHeaders && Object.keys(reqHeaders).length > 0
295
- ? JsonBlock(reqHeaders)
296
- : raw('<p class="text-sm text-gray-400 dark:text-gray-500">No request headers.</p>') },
297
- ]);
298
- const hasResBody = resBody !== undefined && resBody !== null && resBody !== '';
299
- const hasResHeaders = !!resHeaders && Object.keys(resHeaders).length > 0;
300
- const responseBodyContent = hasResBody
301
- ? (typeof resBody === 'string' ? CodeBlock(resBody, { maxHeight: '[400px]' }) : JsonBlock(resBody))
302
- : '';
303
- const responseTabs = Tabs([
304
- ...(hasResBody ? [{ label: 'Body', content: responseBodyContent }] : []),
305
- ...(hasResHeaders ? [{ label: 'Headers', content: JsonBlock(resHeaders) }] : []),
306
- ]);
307
- return html `
308
- ${Card(null, KeyValueTable({
309
- Method: Badge(c['method']),
310
- URL: raw(`<span class="font-mono text-xs break-all">${escape(c['url'] ?? '')}</span>`),
311
- Status: statusBadge,
312
- Duration: c['duration'] != null ? `${c['duration']}ms` : '—',
313
- 'Resp Size': c['resSize'] != null ? `${c['resSize']} bytes` : '—',
314
- }))}
315
- ${requestTabs}
316
- ${responseTabs}
317
- ${isFailure && c['error'] ? Card('Error', raw(`<div class="text-sm text-red-600 dark:text-red-400">${escape(c['error'])}</div>`)) : ''}
318
- `;
319
- };
320
167
  const GateView = (entry) => {
321
168
  const c = entry.content;
322
169
  const args = c['args'];
@@ -402,136 +249,6 @@ const BroadcastView = (entry) => {
402
249
  : ''}
403
250
  `;
404
251
  };
405
- function renderToolCalls(toolCalls) {
406
- if (toolCalls.length === 0)
407
- return html ``;
408
- const items = toolCalls.map((tc) => {
409
- const t = tc;
410
- const name = String(t['name'] ?? t['toolName'] ?? '—');
411
- const duration = t['duration'] != null ? `${t['duration']}ms` : null;
412
- const approved = t['approved'] === true;
413
- const needsApproval = t['requiresApproval'] === true;
414
- const args = t['args'] ?? t['input'] ?? t['arguments'];
415
- const result = t['result'] ?? t['output'];
416
- const approvalBadge = needsApproval
417
- ? raw(`<span class="ml-1 inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-amber-100 text-amber-700 dark:bg-amber-900 dark:text-amber-300">${approved ? 'Approved' : 'Pending'}</span>`)
418
- : '';
419
- return html `
420
- <div class="border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden mb-2">
421
- <div class="flex items-center gap-2 px-3 py-2 bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700">
422
- ${Badge(name)}
423
- ${approvalBadge}
424
- ${duration ? raw(`<span class="text-xs text-gray-400 dark:text-gray-500 ml-auto">${escape(duration)}</span>`) : ''}
425
- </div>
426
- ${args !== undefined ? html `
427
- <details class="group">
428
- <summary class="px-3 py-1.5 text-xs font-medium text-gray-500 dark:text-gray-400 cursor-pointer select-none hover:bg-gray-50 dark:hover:bg-gray-800">Args</summary>
429
- <div class="px-3 pb-2">${JsonBlock(args)}</div>
430
- </details>
431
- ` : ''}
432
- ${result !== undefined ? html `
433
- <details class="group">
434
- <summary class="px-3 py-1.5 text-xs font-medium text-gray-500 dark:text-gray-400 cursor-pointer select-none hover:bg-gray-50 dark:hover:bg-gray-800">Result</summary>
435
- <div class="px-3 pb-2">${JsonBlock(result)}</div>
436
- </details>
437
- ` : ''}
438
- </div>
439
- `;
440
- }).join('');
441
- return raw(items);
442
- }
443
- function renderSteps(steps) {
444
- if (steps.length <= 1)
445
- return html ``;
446
- const items = steps.map((s, i) => {
447
- const step = s;
448
- const usage = step['usage'];
449
- const tokens = usage ? (usage['totalTokens'] ?? usage['total_tokens']) : undefined;
450
- const tcCount = Array.isArray(step['toolCalls']) ? step['toolCalls'].length : (step['toolCallCount'] ?? 0);
451
- const finishReason = step['finishReason'] ?? step['finish_reason'];
452
- return html `
453
- <div class="border border-gray-200 dark:border-gray-700 rounded-lg px-3 py-2 mb-2">
454
- ${Card(null, KeyValueTable({
455
- Iteration: i + 1,
456
- Tokens: tokens != null ? String(tokens) : '—',
457
- 'Tool Calls': String(tcCount),
458
- 'Finish Reason': finishReason ? Badge(String(finishReason)) : raw('<span class="text-gray-300 dark:text-gray-600">—</span>'),
459
- }))}
460
- </div>
461
- `;
462
- }).join('');
463
- return raw(items);
464
- }
465
- const AiView = (entry) => {
466
- const c = entry.content;
467
- const status = String(c['status'] ?? '');
468
- const statusBadge = status === 'failed'
469
- ? raw(`<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-300">Failed</span>`)
470
- : raw(`<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300">Completed</span>`);
471
- const finishReason = c['finishReason'] ?? c['finish_reason'];
472
- const streaming = c['streaming'] === true ? 'Yes' : 'No';
473
- const toolCalls = Array.isArray(c['toolCalls']) ? c['toolCalls'] : [];
474
- const steps = Array.isArray(c['steps']) ? c['steps'] : [];
475
- const usage = c['usage'];
476
- const requestRows = {
477
- Status: statusBadge,
478
- Agent: c['agentName'] ?? c['agent'] ?? '—',
479
- Model: c['model'] ? Badge(String(c['model'])) : raw('<span class="text-gray-300 dark:text-gray-600">—</span>'),
480
- Provider: c['provider'] ?? '—',
481
- Duration: c['duration'] != null ? `${c['duration']}ms` : '—',
482
- 'Finish Reason': finishReason ? Badge(String(finishReason)) : raw('<span class="text-gray-300 dark:text-gray-600">—</span>'),
483
- Steps: steps.length > 0 ? steps.length : (c['stepCount'] ?? '—'),
484
- 'Tool Calls': toolCalls.length > 0 ? toolCalls.length : (c['toolCallCount'] ?? '—'),
485
- Streaming: streaming,
486
- };
487
- if (c['conversationId']) {
488
- requestRows['Conversation ID'] = raw(`<span class="font-mono text-xs">${escape(String(c['conversationId']))}</span>`);
489
- }
490
- const failoverAttempts = c['failoverAttempts'];
491
- if (failoverAttempts != null && failoverAttempts > 0) {
492
- requestRows['Failover Attempts'] = failoverAttempts;
493
- }
494
- const inputValue = c['input'];
495
- const outputValue = c['output'];
496
- const errorValue = c['error'];
497
- const inputStr = typeof inputValue === 'string' ? inputValue : JSON.stringify(inputValue, null, 2);
498
- const outputStr = typeof outputValue === 'string' ? outputValue : JSON.stringify(outputValue, null, 2);
499
- return html `
500
- ${Card('AI Request', KeyValueTable(requestRows))}
501
-
502
- ${usage ? Card('Token Usage', KeyValueTable({
503
- Prompt: usage['promptTokens'] ?? usage['prompt_tokens'] ?? '—',
504
- Completion: usage['completionTokens'] ?? usage['completion_tokens'] ?? '—',
505
- Total: usage['totalTokens'] ?? usage['total_tokens'] ?? '—',
506
- })) : ''}
507
-
508
- ${(() => {
509
- const conversationTabs = [];
510
- if (outputValue !== undefined && outputValue !== null) {
511
- conversationTabs.push({ label: 'Output', content: CodeBlock(outputStr, { maxHeight: '[400px]' }) });
512
- }
513
- if (inputValue !== undefined && inputValue !== null) {
514
- conversationTabs.push({ label: 'Input', content: CodeBlock(inputStr, { maxHeight: '[200px]' }) });
515
- }
516
- return conversationTabs.length > 0 ? Tabs(conversationTabs) : '';
517
- })()}
518
-
519
- ${errorValue
520
- ? Card('Error', raw(`<pre class="text-sm text-red-600 dark:text-red-400 whitespace-pre-wrap break-words">${escape(typeof errorValue === 'string' ? errorValue : JSON.stringify(errorValue, null, 2))}</pre>`))
521
- : ''}
522
-
523
- ${(() => {
524
- const executionTabs = [];
525
- if (toolCalls.length > 0) {
526
- executionTabs.push({ label: `Tool Calls (${toolCalls.length})`, content: renderToolCalls(toolCalls) });
527
- }
528
- if (steps.length > 1) {
529
- executionTabs.push({ label: `Steps (${steps.length})`, content: renderSteps(steps) });
530
- }
531
- return executionTabs.length > 0 ? Tabs(executionTabs) : '';
532
- })()}
533
- `;
534
- };
535
252
  const LiveView = (entry) => {
536
253
  const c = entry.content;
537
254
  const kind = String(c['kind'] ?? '');
@@ -636,13 +353,4 @@ export const detailViews = {
636
353
  mcp: McpView,
637
354
  view: ViewRenderView,
638
355
  };
639
- /** Internal escape helper — used inside `raw()` blocks for safety. */
640
- function escape(s) {
641
- return String(s ?? '')
642
- .replace(/&/g, '&amp;')
643
- .replace(/</g, '&lt;')
644
- .replace(/>/g, '&gt;')
645
- .replace(/"/g, '&quot;')
646
- .replace(/'/g, '&#39;');
647
- }
648
356
  //# sourceMappingURL=views.js.map