@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.
- package/README.md +13 -1
- package/dist/collectors/exception.d.ts +13 -0
- package/dist/collectors/exception.d.ts.map +1 -1
- package/dist/collectors/exception.js +13 -0
- package/dist/collectors/exception.js.map +1 -1
- package/dist/collectors/request.d.ts.map +1 -1
- package/dist/collectors/request.js +15 -4
- package/dist/collectors/request.js.map +1 -1
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -1
- package/dist/routes.d.ts +8 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +20 -6
- package/dist/routes.js.map +1 -1
- package/dist/storage.d.ts +26 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +34 -6
- package/dist/storage.js.map +1 -1
- package/dist/stream.d.ts +23 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +96 -0
- package/dist/stream.js.map +1 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +22 -0
- package/dist/types.js.map +1 -1
- package/dist/views/vanilla/EntryList.d.ts +8 -0
- package/dist/views/vanilla/EntryList.d.ts.map +1 -1
- package/dist/views/vanilla/EntryList.js +62 -11
- package/dist/views/vanilla/EntryList.js.map +1 -1
- package/dist/views/vanilla/Layout.d.ts.map +1 -1
- package/dist/views/vanilla/Layout.js +6 -1
- package/dist/views/vanilla/Layout.js.map +1 -1
- package/dist/views/vanilla/details/ai-views.d.ts +16 -0
- package/dist/views/vanilla/details/ai-views.d.ts.map +1 -0
- package/dist/views/vanilla/details/ai-views.js +136 -0
- package/dist/views/vanilla/details/ai-views.js.map +1 -0
- package/dist/views/vanilla/details/format.d.ts +16 -0
- package/dist/views/vanilla/details/format.d.ts.map +1 -0
- package/dist/views/vanilla/details/format.js +45 -0
- package/dist/views/vanilla/details/format.js.map +1 -0
- package/dist/views/vanilla/details/request-views.d.ts +15 -0
- package/dist/views/vanilla/details/request-views.d.ts.map +1 -0
- package/dist/views/vanilla/details/request-views.js +135 -0
- package/dist/views/vanilla/details/request-views.js.map +1 -0
- package/dist/views/vanilla/details/views.d.ts.map +1 -1
- package/dist/views/vanilla/details/views.js +3 -295
- package/dist/views/vanilla/details/views.js.map +1 -1
- 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, '<')
|
|
13
|
+
.replace(/>/g, '>')
|
|
14
|
+
.replace(/"/g, '"')
|
|
15
|
+
.replace(/'/g, ''');
|
|
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;
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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, '&')
|
|
643
|
-
.replace(/</g, '<')
|
|
644
|
-
.replace(/>/g, '>')
|
|
645
|
-
.replace(/"/g, '"')
|
|
646
|
-
.replace(/'/g, ''');
|
|
647
|
-
}
|
|
648
356
|
//# sourceMappingURL=views.js.map
|