@geekmidas/telescope 1.1.1 → 10.0.0-alpha.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 (167) hide show
  1. package/README.md +14 -4
  2. package/dist/{hono-Bz9PQQzj.mjs → hono-Bw-ey6CT.mjs} +2 -2
  3. package/dist/{hono-Bz9PQQzj.mjs.map → hono-Bw-ey6CT.mjs.map} +1 -1
  4. package/dist/{hono-Z_JIICmt.cjs → hono-CPHX7FAm.cjs} +2 -2
  5. package/dist/{hono-Z_JIICmt.cjs.map → hono-CPHX7FAm.cjs.map} +1 -1
  6. package/dist/{http-Crsriv32.mjs → http-BIvr0YdI.mjs} +1 -1
  7. package/dist/{http-Crsriv32.mjs.map → http-BIvr0YdI.mjs.map} +1 -1
  8. package/dist/{http-JycFRfSe.cjs → http-BsqmhurZ.cjs} +1 -1
  9. package/dist/{http-JycFRfSe.cjs.map → http-BsqmhurZ.cjs.map} +1 -1
  10. package/dist/{http-D5kn3_Mt.d.mts → http-DULM1u2L.d.cts} +3 -3
  11. package/dist/{http-D5kn3_Mt.d.mts.map → http-DULM1u2L.d.cts.map} +1 -1
  12. package/dist/{http-Dvca6fC3.d.cts → http-GB-Nlvwc.d.mts} +3 -3
  13. package/dist/{http-Dvca6fC3.d.cts.map → http-GB-Nlvwc.d.mts.map} +1 -1
  14. package/dist/instrumentation/hono.cjs +2 -2
  15. package/dist/instrumentation/hono.mjs +2 -2
  16. package/dist/instrumentation/http.cjs +1 -1
  17. package/dist/instrumentation/http.d.cts +1 -1
  18. package/dist/instrumentation/http.d.mts +1 -1
  19. package/dist/instrumentation/http.mjs +1 -1
  20. package/dist/instrumentation/index.cjs +5 -5
  21. package/dist/instrumentation/index.d.cts +3 -3
  22. package/dist/instrumentation/index.d.mts +3 -3
  23. package/dist/instrumentation/index.mjs +5 -5
  24. package/dist/instrumentation/middleware.cjs +2 -2
  25. package/dist/instrumentation/middleware.d.cts +1 -1
  26. package/dist/instrumentation/middleware.d.mts +1 -1
  27. package/dist/instrumentation/middleware.mjs +2 -2
  28. package/dist/instrumentation/otel.cjs +2 -2
  29. package/dist/instrumentation/otel.d.cts +1 -1
  30. package/dist/instrumentation/otel.d.mts +1 -1
  31. package/dist/instrumentation/otel.mjs +2 -2
  32. package/dist/instrumentation/setup.cjs +1 -1
  33. package/dist/instrumentation/setup.mjs +1 -1
  34. package/dist/logger/console.d.cts.map +1 -1
  35. package/dist/{middleware-D3v5SnSs.cjs → middleware-Bcq6XXGG.cjs} +3 -3
  36. package/dist/middleware-Bcq6XXGG.cjs.map +1 -0
  37. package/dist/{middleware-Dy1ctr2N.mjs → middleware-D1XEHvyy.mjs} +3 -3
  38. package/dist/middleware-D1XEHvyy.mjs.map +1 -0
  39. package/dist/{middleware-CA84nsNN.d.cts → middleware-PeyS-9Ny.d.cts} +2 -2
  40. package/dist/{middleware-CA84nsNN.d.cts.map → middleware-PeyS-9Ny.d.cts.map} +1 -1
  41. package/dist/{middleware-DAceVpfw.d.mts → middleware-oHvo_ZgU.d.mts} +2 -2
  42. package/dist/{middleware-DAceVpfw.d.mts.map → middleware-oHvo_ZgU.d.mts.map} +1 -1
  43. package/dist/{otel-DPKNyJ0t.mjs → otel-B9bNoeZ2.mjs} +4 -4
  44. package/dist/otel-B9bNoeZ2.mjs.map +1 -0
  45. package/dist/{otel-1bJPb2Z7.d.mts → otel-Bk89b1lX.d.cts} +3 -3
  46. package/dist/{otel-1bJPb2Z7.d.mts.map → otel-Bk89b1lX.d.cts.map} +1 -1
  47. package/dist/{otel-DuiBeBPU.cjs → otel-BzjOtVxZ.cjs} +4 -4
  48. package/dist/otel-BzjOtVxZ.cjs.map +1 -0
  49. package/dist/{otel-SBVoVEHr.d.cts → otel-lPMsM26e.d.mts} +3 -3
  50. package/dist/{otel-SBVoVEHr.d.cts.map → otel-lPMsM26e.d.mts.map} +1 -1
  51. package/dist/otlp/hono.cjs +3 -3
  52. package/dist/otlp/hono.mjs +3 -3
  53. package/dist/otlp/index.cjs +3 -3
  54. package/dist/otlp/index.mjs +3 -3
  55. package/dist/otlp/receiver.cjs +3 -3
  56. package/dist/otlp/receiver.mjs +3 -3
  57. package/dist/otlp/transformer.cjs +2 -2
  58. package/dist/otlp/transformer.mjs +2 -2
  59. package/dist/otlp/types.cjs +1 -1
  60. package/dist/otlp/types.mjs +1 -1
  61. package/dist/{receiver-q4f7eirs.mjs → receiver-D46dfkYI.mjs} +2 -2
  62. package/dist/{receiver-q4f7eirs.mjs.map → receiver-D46dfkYI.mjs.map} +1 -1
  63. package/dist/{receiver-BW_4go_X.cjs → receiver-slCoAFat.cjs} +2 -2
  64. package/dist/{receiver-BW_4go_X.cjs.map → receiver-slCoAFat.cjs.map} +1 -1
  65. package/dist/{setup-BhCp2LUp.mjs → setup-DC9JMEYZ.mjs} +1 -1
  66. package/dist/{setup-BhCp2LUp.mjs.map → setup-DC9JMEYZ.mjs.map} +1 -1
  67. package/dist/{setup-_uT4L_x5.cjs → setup-DufxQpi9.cjs} +1 -1
  68. package/dist/{setup-_uT4L_x5.cjs.map → setup-DufxQpi9.cjs.map} +1 -1
  69. package/dist/storage/kysely.cjs +48 -38
  70. package/dist/storage/kysely.cjs.map +1 -1
  71. package/dist/storage/kysely.d.cts +29 -9
  72. package/dist/storage/kysely.d.cts.map +1 -1
  73. package/dist/storage/kysely.d.mts +29 -9
  74. package/dist/storage/kysely.d.mts.map +1 -1
  75. package/dist/storage/kysely.mjs +48 -38
  76. package/dist/storage/kysely.mjs.map +1 -1
  77. package/dist/tracing-BX8uY2nR.d.cts.map +1 -1
  78. package/dist/tracing-PnECEbEu.d.mts.map +1 -1
  79. package/dist/{transformer-CFrJQkUg.mjs → transformer-CFQ4WFk6.mjs} +2 -2
  80. package/dist/{transformer-CFrJQkUg.mjs.map → transformer-CFQ4WFk6.mjs.map} +1 -1
  81. package/dist/{transformer-DvDYyFRQ.cjs → transformer-Csl6fbgv.cjs} +2 -2
  82. package/dist/{transformer-DvDYyFRQ.cjs.map → transformer-Csl6fbgv.cjs.map} +1 -1
  83. package/dist/types-B1EIa_cQ.d.mts.map +1 -1
  84. package/dist/{types-BBeTDpHr.cjs → types-BMiHgsi4.cjs} +1 -1
  85. package/dist/{types-BBeTDpHr.cjs.map → types-BMiHgsi4.cjs.map} +1 -1
  86. package/dist/{types-CXYLhG_G.mjs → types-Cj59nqy7.mjs} +1 -1
  87. package/dist/{types-CXYLhG_G.mjs.map → types-Cj59nqy7.mjs.map} +1 -1
  88. package/dist/types-l7Rlb5Mg.d.cts.map +1 -1
  89. package/package.json +6 -3
  90. package/CHANGELOG.md +0 -51
  91. package/dist/middleware-D3v5SnSs.cjs.map +0 -1
  92. package/dist/middleware-Dy1ctr2N.mjs.map +0 -1
  93. package/dist/otel-DPKNyJ0t.mjs.map +0 -1
  94. package/dist/otel-DuiBeBPU.cjs.map +0 -1
  95. package/src/Telescope.ts +0 -561
  96. package/src/__tests__/Telescope.spec.ts +0 -438
  97. package/src/__tests__/pino-transport.spec.ts +0 -115
  98. package/src/__tests__/redact.spec.ts +0 -336
  99. package/src/adapters/__tests__/lambda.spec.ts +0 -318
  100. package/src/adapters/__tests__/middy.spec.ts +0 -741
  101. package/src/adapters/index.ts +0 -22
  102. package/src/adapters/lambda.ts +0 -432
  103. package/src/adapters/middy.ts +0 -402
  104. package/src/adapters/types.ts +0 -181
  105. package/src/core.ts +0 -51
  106. package/src/index.ts +0 -34
  107. package/src/instrumentation/__tests__/core.spec.ts +0 -248
  108. package/src/instrumentation/__tests__/hono.spec.ts +0 -348
  109. package/src/instrumentation/__tests__/middleware.spec.ts +0 -528
  110. package/src/instrumentation/__tests__/otel.spec.ts +0 -291
  111. package/src/instrumentation/__tests__/tracing.spec.ts +0 -208
  112. package/src/instrumentation/core.ts +0 -228
  113. package/src/instrumentation/hono.ts +0 -270
  114. package/src/instrumentation/http.ts +0 -306
  115. package/src/instrumentation/index.ts +0 -90
  116. package/src/instrumentation/middleware.ts +0 -297
  117. package/src/instrumentation/otel.ts +0 -271
  118. package/src/instrumentation/setup.ts +0 -246
  119. package/src/instrumentation/tracing.ts +0 -145
  120. package/src/logger/__tests__/console.spec.ts +0 -366
  121. package/src/logger/__tests__/pino.spec.ts +0 -217
  122. package/src/logger/console.ts +0 -230
  123. package/src/logger/pino.ts +0 -201
  124. package/src/metrics/MetricsAggregator.ts +0 -555
  125. package/src/metrics/__tests__/MetricsAggregator.spec.ts +0 -298
  126. package/src/metrics/index.ts +0 -2
  127. package/src/metrics/storage/InMemoryMetricsStorage.ts +0 -380
  128. package/src/metrics/storage/MetricsStorage.ts +0 -74
  129. package/src/metrics/storage/index.ts +0 -3
  130. package/src/metrics/storage/types.ts +0 -243
  131. package/src/otlp/__tests__/receiver.spec.ts +0 -367
  132. package/src/otlp/__tests__/transformer.spec.ts +0 -455
  133. package/src/otlp/hono.ts +0 -120
  134. package/src/otlp/index.ts +0 -22
  135. package/src/otlp/receiver.ts +0 -162
  136. package/src/otlp/transformer.ts +0 -367
  137. package/src/otlp/types.ts +0 -364
  138. package/src/redact.ts +0 -116
  139. package/src/server/__tests__/hono.spec.ts +0 -814
  140. package/src/server/hono.ts +0 -442
  141. package/src/storage/__tests__/kysely.spec.ts +0 -715
  142. package/src/storage/__tests__/memory.spec.ts +0 -694
  143. package/src/storage/kysely.ts +0 -599
  144. package/src/storage/memory.ts +0 -204
  145. package/src/types.ts +0 -447
  146. package/src/ui-assets.ts +0 -40
  147. package/tsconfig.json +0 -9
  148. package/ui/CHANGELOG.md +0 -7
  149. package/ui/index.html +0 -12
  150. package/ui/node_modules/.bin/tsc +0 -21
  151. package/ui/node_modules/.bin/tsserver +0 -21
  152. package/ui/node_modules/.bin/vite +0 -21
  153. package/ui/package.json +0 -24
  154. package/ui/src/App.tsx +0 -595
  155. package/ui/src/api.ts +0 -88
  156. package/ui/src/components/ExceptionDetail.tsx +0 -100
  157. package/ui/src/components/FilterBar.tsx +0 -162
  158. package/ui/src/components/LogDetail.tsx +0 -91
  159. package/ui/src/components/RequestDetail.tsx +0 -143
  160. package/ui/src/main.tsx +0 -10
  161. package/ui/src/styles.css +0 -11
  162. package/ui/src/types.ts +0 -63
  163. package/ui/src/vite-env.d.ts +0 -1
  164. package/ui/src/vite-plugin-gkm-config.ts +0 -54
  165. package/ui/tsconfig.json +0 -20
  166. package/ui/tsconfig.tsbuildinfo +0 -1
  167. package/ui/vite.config.ts +0 -13
@@ -1,100 +0,0 @@
1
- import type { ExceptionEntry } from '../types';
2
-
3
- interface ExceptionDetailProps {
4
- exception: ExceptionEntry;
5
- onClose: () => void;
6
- }
7
-
8
- export function ExceptionDetail({ exception, onClose }: ExceptionDetailProps) {
9
- return (
10
- <div className="fixed top-0 right-0 bottom-0 w-1/2 max-w-3xl bg-bg-secondary border-l border-border flex flex-col z-50 shadow-2xl">
11
- <div className="flex items-center justify-between p-4 border-b border-border">
12
- <h2 className="text-base font-semibold text-red-400">
13
- {exception.name}
14
- </h2>
15
- <button
16
- className="text-slate-400 hover:text-slate-100 p-2 text-xl leading-none"
17
- onClick={onClose}
18
- >
19
- &times;
20
- </button>
21
- </div>
22
-
23
- <div className="flex-1 overflow-y-auto p-4">
24
- <section className="mb-6">
25
- <h3 className="text-xs font-semibold uppercase text-slate-500 mb-2">
26
- Overview
27
- </h3>
28
- <div className="space-y-2 text-sm">
29
- <div className="flex py-2 border-b border-border">
30
- <span className="text-slate-500 min-w-32">Message</span>
31
- <span className="wrap-break-word">{exception.message}</span>
32
- </div>
33
- <div className="flex py-2 border-b border-border">
34
- <span className="text-slate-500 min-w-32">Handled</span>
35
- <span>{exception.handled ? 'Yes' : 'No'}</span>
36
- </div>
37
- <div className="flex py-2 border-b border-border">
38
- <span className="text-slate-500 min-w-32">Timestamp</span>
39
- <span>{new Date(exception.timestamp).toLocaleString()}</span>
40
- </div>
41
- {exception.requestId && (
42
- <div className="flex py-2 border-b border-border">
43
- <span className="text-slate-500 min-w-32">Request ID</span>
44
- <span className="font-mono text-xs">{exception.requestId}</span>
45
- </div>
46
- )}
47
- {exception.tags && exception.tags.length > 0 && (
48
- <div className="flex py-2">
49
- <span className="text-slate-500 min-w-32">Tags</span>
50
- <span>{exception.tags.join(', ')}</span>
51
- </div>
52
- )}
53
- </div>
54
- </section>
55
-
56
- {exception.source && (
57
- <section className="mb-6">
58
- <h3 className="text-xs font-semibold uppercase text-slate-500 mb-2">
59
- Source
60
- </h3>
61
- <div className="text-sm mb-2">
62
- <span className="text-slate-500">File: </span>
63
- <span>
64
- {exception.source.file}
65
- {exception.source.line && `:${exception.source.line}`}
66
- </span>
67
- </div>
68
- {exception.source.code && (
69
- <pre className="bg-bg-primary border border-border rounded-lg p-4 overflow-x-auto text-xs leading-relaxed">
70
- {exception.source.code}
71
- </pre>
72
- )}
73
- </section>
74
- )}
75
-
76
- <section className="mb-6">
77
- <h3 className="text-xs font-semibold uppercase text-slate-500 mb-2">
78
- Stack Trace
79
- </h3>
80
- <div className="text-xs leading-relaxed space-y-1">
81
- {exception.stack.map((frame, index) => (
82
- <div key={index} className="text-slate-400">
83
- <span className="text-blue-400">
84
- {frame.function || '<anonymous>'}
85
- </span>
86
- {frame.file && (
87
- <span className="text-slate-500 ml-2">
88
- at {frame.file}
89
- {frame.line !== undefined && `:${frame.line}`}
90
- {frame.column !== undefined && `:${frame.column}`}
91
- </span>
92
- )}
93
- </div>
94
- ))}
95
- </div>
96
- </section>
97
- </div>
98
- </div>
99
- );
100
- }
@@ -1,162 +0,0 @@
1
- import type { Tab } from '../types';
2
-
3
- export interface RequestFilters {
4
- search: string;
5
- method: string;
6
- status: string;
7
- }
8
-
9
- export interface LogFilters {
10
- search: string;
11
- level: string;
12
- }
13
-
14
- export interface ExceptionFilters {
15
- search: string;
16
- }
17
-
18
- interface FilterBarProps {
19
- tab: Tab;
20
- requestFilters: RequestFilters;
21
- logFilters: LogFilters;
22
- exceptionFilters: ExceptionFilters;
23
- onRequestFiltersChange: (filters: RequestFilters) => void;
24
- onLogFiltersChange: (filters: LogFilters) => void;
25
- onExceptionFiltersChange: (filters: ExceptionFilters) => void;
26
- onClear: () => void;
27
- }
28
-
29
- const HTTP_METHODS = ['', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
30
- const STATUS_RANGES = [
31
- { value: '', label: 'All Status' },
32
- { value: '2xx', label: '2xx Success' },
33
- { value: '3xx', label: '3xx Redirect' },
34
- { value: '4xx', label: '4xx Client Error' },
35
- { value: '5xx', label: '5xx Server Error' },
36
- ];
37
- const LOG_LEVELS = ['', 'debug', 'info', 'warn', 'error'];
38
-
39
- export function FilterBar({
40
- tab,
41
- requestFilters,
42
- logFilters,
43
- exceptionFilters,
44
- onRequestFiltersChange,
45
- onLogFiltersChange,
46
- onExceptionFiltersChange,
47
- onClear,
48
- }: FilterBarProps) {
49
- const hasActiveFilters =
50
- (tab === 'requests' &&
51
- (requestFilters.search ||
52
- requestFilters.method ||
53
- requestFilters.status)) ||
54
- (tab === 'logs' && (logFilters.search || logFilters.level)) ||
55
- (tab === 'exceptions' && exceptionFilters.search);
56
-
57
- return (
58
- <div className="bg-bg-secondary border-b border-border px-4 py-3 flex items-center gap-3">
59
- {tab === 'requests' && (
60
- <>
61
- <input
62
- type="text"
63
- placeholder="Search path..."
64
- value={requestFilters.search}
65
- onChange={(e) =>
66
- onRequestFiltersChange({
67
- ...requestFilters,
68
- search: e.target.value,
69
- })
70
- }
71
- className="bg-bg-tertiary border border-border rounded px-3 py-1.5 text-sm text-slate-100 placeholder-slate-500 focus:outline-none focus:border-blue-500 w-64"
72
- />
73
- <select
74
- value={requestFilters.method}
75
- onChange={(e) =>
76
- onRequestFiltersChange({
77
- ...requestFilters,
78
- method: e.target.value,
79
- })
80
- }
81
- className="bg-bg-tertiary border border-border rounded px-3 py-1.5 text-sm text-slate-100 focus:outline-none focus:border-blue-500"
82
- >
83
- <option value="">All Methods</option>
84
- {HTTP_METHODS.filter(Boolean).map((method) => (
85
- <option key={method} value={method}>
86
- {method}
87
- </option>
88
- ))}
89
- </select>
90
- <select
91
- value={requestFilters.status}
92
- onChange={(e) =>
93
- onRequestFiltersChange({
94
- ...requestFilters,
95
- status: e.target.value,
96
- })
97
- }
98
- className="bg-bg-tertiary border border-border rounded px-3 py-1.5 text-sm text-slate-100 focus:outline-none focus:border-blue-500"
99
- >
100
- {STATUS_RANGES.map((range) => (
101
- <option key={range.value} value={range.value}>
102
- {range.label}
103
- </option>
104
- ))}
105
- </select>
106
- </>
107
- )}
108
-
109
- {tab === 'logs' && (
110
- <>
111
- <input
112
- type="text"
113
- placeholder="Search message..."
114
- value={logFilters.search}
115
- onChange={(e) =>
116
- onLogFiltersChange({ ...logFilters, search: e.target.value })
117
- }
118
- className="bg-bg-tertiary border border-border rounded px-3 py-1.5 text-sm text-slate-100 placeholder-slate-500 focus:outline-none focus:border-blue-500 w-64"
119
- />
120
- <select
121
- value={logFilters.level}
122
- onChange={(e) =>
123
- onLogFiltersChange({ ...logFilters, level: e.target.value })
124
- }
125
- className="bg-bg-tertiary border border-border rounded px-3 py-1.5 text-sm text-slate-100 focus:outline-none focus:border-blue-500"
126
- >
127
- <option value="">All Levels</option>
128
- {LOG_LEVELS.filter(Boolean).map((level) => (
129
- <option key={level} value={level}>
130
- {level}
131
- </option>
132
- ))}
133
- </select>
134
- </>
135
- )}
136
-
137
- {tab === 'exceptions' && (
138
- <input
139
- type="text"
140
- placeholder="Search exception..."
141
- value={exceptionFilters.search}
142
- onChange={(e) =>
143
- onExceptionFiltersChange({
144
- ...exceptionFilters,
145
- search: e.target.value,
146
- })
147
- }
148
- className="bg-bg-tertiary border border-border rounded px-3 py-1.5 text-sm text-slate-100 placeholder-slate-500 focus:outline-none focus:border-blue-500 w-64"
149
- />
150
- )}
151
-
152
- {hasActiveFilters && (
153
- <button
154
- onClick={onClear}
155
- className="text-xs text-slate-400 hover:text-slate-200 px-2 py-1 rounded hover:bg-bg-tertiary transition-colors"
156
- >
157
- Clear filters
158
- </button>
159
- )}
160
- </div>
161
- );
162
- }
@@ -1,91 +0,0 @@
1
- import type { LogEntry } from '../types';
2
-
3
- interface LogDetailProps {
4
- log: LogEntry;
5
- onClose: () => void;
6
- }
7
-
8
- export function LogDetail({ log, onClose }: LogDetailProps) {
9
- const formatJson = (data: unknown) => {
10
- try {
11
- return JSON.stringify(data, null, 2);
12
- } catch {
13
- return String(data);
14
- }
15
- };
16
-
17
- const getLogLevelColor = (level: string) => {
18
- const colors: Record<string, string> = {
19
- debug: 'bg-slate-500/20 text-slate-400',
20
- info: 'bg-blue-500/20 text-blue-400',
21
- warn: 'bg-amber-500/20 text-amber-400',
22
- error: 'bg-red-500/20 text-red-400',
23
- };
24
- return colors[level] || 'bg-slate-500/20 text-slate-400';
25
- };
26
-
27
- return (
28
- <div className="fixed top-0 right-0 bottom-0 w-1/2 max-w-3xl bg-bg-secondary border-l border-border flex flex-col z-50 shadow-2xl">
29
- <div className="flex items-center justify-between p-4 border-b border-border">
30
- <h2 className="text-base font-semibold flex items-center gap-2">
31
- <span
32
- className={`px-2 py-1 rounded text-xs ${getLogLevelColor(log.level)}`}
33
- >
34
- {log.level}
35
- </span>
36
- Log Entry
37
- </h2>
38
- <button
39
- className="text-slate-400 hover:text-slate-100 p-2 text-xl leading-none"
40
- onClick={onClose}
41
- >
42
- &times;
43
- </button>
44
- </div>
45
-
46
- <div className="flex-1 overflow-y-auto p-4">
47
- <section className="mb-6">
48
- <h3 className="text-xs font-semibold uppercase text-slate-500 mb-2">
49
- Overview
50
- </h3>
51
- <div className="space-y-2 text-sm">
52
- <div className="flex py-2 border-b border-border">
53
- <span className="text-slate-500 min-w-32">Level</span>
54
- <span>{log.level}</span>
55
- </div>
56
- <div className="flex py-2 border-b border-border">
57
- <span className="text-slate-500 min-w-32">Timestamp</span>
58
- <span>{new Date(log.timestamp).toLocaleString()}</span>
59
- </div>
60
- {log.requestId && (
61
- <div className="flex py-2">
62
- <span className="text-slate-500 min-w-32">Request ID</span>
63
- <span className="font-mono text-xs">{log.requestId}</span>
64
- </div>
65
- )}
66
- </div>
67
- </section>
68
-
69
- <section className="mb-6">
70
- <h3 className="text-xs font-semibold uppercase text-slate-500 mb-2">
71
- Message
72
- </h3>
73
- <pre className="bg-bg-primary border border-border rounded-lg p-4 overflow-x-auto text-xs leading-relaxed whitespace-pre-wrap">
74
- {log.message}
75
- </pre>
76
- </section>
77
-
78
- {log.context && Object.keys(log.context).length > 0 && (
79
- <section className="mb-6">
80
- <h3 className="text-xs font-semibold uppercase text-slate-500 mb-2">
81
- Context
82
- </h3>
83
- <pre className="bg-bg-primary border border-border rounded-lg p-4 overflow-x-auto text-xs leading-relaxed">
84
- {formatJson(log.context)}
85
- </pre>
86
- </section>
87
- )}
88
- </div>
89
- </div>
90
- );
91
- }
@@ -1,143 +0,0 @@
1
- import type { RequestEntry } from '../types';
2
-
3
- interface RequestDetailProps {
4
- request: RequestEntry;
5
- onClose: () => void;
6
- }
7
-
8
- export function RequestDetail({ request, onClose }: RequestDetailProps) {
9
- const formatJson = (data: unknown) => {
10
- try {
11
- return JSON.stringify(data, null, 2);
12
- } catch {
13
- return String(data);
14
- }
15
- };
16
-
17
- const getMethodColor = (method: string) => {
18
- const colors: Record<string, string> = {
19
- GET: 'bg-green-500/20 text-green-400',
20
- POST: 'bg-blue-500/20 text-blue-400',
21
- PUT: 'bg-amber-500/20 text-amber-400',
22
- PATCH: 'bg-purple-500/20 text-purple-400',
23
- DELETE: 'bg-red-500/20 text-red-400',
24
- };
25
- return colors[method] || 'bg-slate-500/20 text-slate-400';
26
- };
27
-
28
- return (
29
- <div className="fixed top-0 right-0 bottom-0 w-1/2 max-w-3xl bg-bg-secondary border-l border-border flex flex-col z-50 shadow-2xl">
30
- <div className="flex items-center justify-between p-4 border-b border-border">
31
- <h2 className="text-base font-semibold flex items-center gap-2">
32
- <span
33
- className={`px-2 py-1 rounded text-xs ${getMethodColor(request.method)}`}
34
- >
35
- {request.method}
36
- </span>
37
- <span className="truncate">{request.path}</span>
38
- </h2>
39
- <button
40
- className="text-slate-400 hover:text-slate-100 p-2 text-xl leading-none"
41
- onClick={onClose}
42
- >
43
- &times;
44
- </button>
45
- </div>
46
-
47
- <div className="flex-1 overflow-y-auto p-4">
48
- <section className="mb-6">
49
- <h3 className="text-xs font-semibold uppercase text-slate-500 mb-2">
50
- Overview
51
- </h3>
52
- <div className="space-y-2 text-sm">
53
- <div className="flex py-2 border-b border-border">
54
- <span className="text-slate-500 min-w-32">Status</span>
55
- <span>{request.status}</span>
56
- </div>
57
- <div className="flex py-2 border-b border-border">
58
- <span className="text-slate-500 min-w-32">Duration</span>
59
- <span>{request.duration.toFixed(2)}ms</span>
60
- </div>
61
- <div className="flex py-2 border-b border-border">
62
- <span className="text-slate-500 min-w-32">URL</span>
63
- <span className="break-all">{request.url}</span>
64
- </div>
65
- <div className="flex py-2 border-b border-border">
66
- <span className="text-slate-500 min-w-32">Timestamp</span>
67
- <span>{new Date(request.timestamp).toLocaleString()}</span>
68
- </div>
69
- {request.ip && (
70
- <div className="flex py-2 border-b border-border">
71
- <span className="text-slate-500 min-w-32">IP</span>
72
- <span>{request.ip}</span>
73
- </div>
74
- )}
75
- {request.userId && (
76
- <div className="flex py-2 border-b border-border">
77
- <span className="text-slate-500 min-w-32">User ID</span>
78
- <span>{request.userId}</span>
79
- </div>
80
- )}
81
- {request.tags && request.tags.length > 0 && (
82
- <div className="flex py-2">
83
- <span className="text-slate-500 min-w-32">Tags</span>
84
- <span>{request.tags.join(', ')}</span>
85
- </div>
86
- )}
87
- </div>
88
- </section>
89
-
90
- <section className="mb-6">
91
- <h3 className="text-xs font-semibold uppercase text-slate-500 mb-2">
92
- Request Headers
93
- </h3>
94
- <pre className="bg-bg-primary border border-border rounded-lg p-4 overflow-x-auto text-xs leading-relaxed">
95
- {formatJson(request.headers)}
96
- </pre>
97
- </section>
98
-
99
- {request.query && Object.keys(request.query).length > 0 && (
100
- <section className="mb-6">
101
- <h3 className="text-xs font-semibold uppercase text-slate-500 mb-2">
102
- Query Parameters
103
- </h3>
104
- <pre className="bg-bg-primary border border-border rounded-lg p-4 overflow-x-auto text-xs leading-relaxed">
105
- {formatJson(request.query)}
106
- </pre>
107
- </section>
108
- )}
109
-
110
- {request.body !== undefined && (
111
- <section className="mb-6">
112
- <h3 className="text-xs font-semibold uppercase text-slate-500 mb-2">
113
- Request Body
114
- </h3>
115
- <pre className="bg-bg-primary border border-border rounded-lg p-4 overflow-x-auto text-xs leading-relaxed">
116
- {formatJson(request.body)}
117
- </pre>
118
- </section>
119
- )}
120
-
121
- <section className="mb-6">
122
- <h3 className="text-xs font-semibold uppercase text-slate-500 mb-2">
123
- Response Headers
124
- </h3>
125
- <pre className="bg-bg-primary border border-border rounded-lg p-4 overflow-x-auto text-xs leading-relaxed">
126
- {formatJson(request.responseHeaders)}
127
- </pre>
128
- </section>
129
-
130
- {request.responseBody !== undefined && (
131
- <section className="mb-6">
132
- <h3 className="text-xs font-semibold uppercase text-slate-500 mb-2">
133
- Response Body
134
- </h3>
135
- <pre className="bg-bg-primary border border-border rounded-lg p-4 overflow-x-auto text-xs leading-relaxed">
136
- {formatJson(request.responseBody)}
137
- </pre>
138
- </section>
139
- )}
140
- </div>
141
- </div>
142
- );
143
- }
package/ui/src/main.tsx DELETED
@@ -1,10 +0,0 @@
1
- import { StrictMode } from 'react';
2
- import { createRoot } from 'react-dom/client';
3
- import { App } from './App';
4
- import './styles.css';
5
-
6
- createRoot(document.getElementById('root')!).render(
7
- <StrictMode>
8
- <App />
9
- </StrictMode>,
10
- );
package/ui/src/styles.css DELETED
@@ -1,11 +0,0 @@
1
- @import "tailwindcss";
2
-
3
- @theme {
4
- --color-bg-primary: #0f172a;
5
- --color-bg-secondary: #1e293b;
6
- --color-bg-tertiary: #334155;
7
- --color-border: #334155;
8
- --font-family-mono:
9
- ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono",
10
- monospace;
11
- }
package/ui/src/types.ts DELETED
@@ -1,63 +0,0 @@
1
- export interface RequestEntry {
2
- id: string;
3
- method: string;
4
- path: string;
5
- url: string;
6
- headers: Record<string, string>;
7
- body?: unknown;
8
- query?: Record<string, string>;
9
- status: number;
10
- responseHeaders: Record<string, string>;
11
- responseBody?: unknown;
12
- duration: number;
13
- timestamp: string;
14
- ip?: string;
15
- userId?: string;
16
- tags?: string[];
17
- }
18
-
19
- export interface ExceptionEntry {
20
- id: string;
21
- name: string;
22
- message: string;
23
- stack: Array<{
24
- file?: string;
25
- line?: number;
26
- column?: number;
27
- function?: string;
28
- }>;
29
- source?: {
30
- file?: string;
31
- line?: number;
32
- code?: string;
33
- };
34
- requestId?: string;
35
- timestamp: string;
36
- handled: boolean;
37
- tags?: string[];
38
- }
39
-
40
- export interface LogEntry {
41
- id: string;
42
- level: 'debug' | 'info' | 'warn' | 'error';
43
- message: string;
44
- context?: Record<string, unknown>;
45
- requestId?: string;
46
- timestamp: string;
47
- }
48
-
49
- export interface TelescopeStats {
50
- requests: number;
51
- exceptions: number;
52
- logs: number;
53
- oldestEntry?: string;
54
- newestEntry?: string;
55
- }
56
-
57
- export type Tab = 'requests' | 'exceptions' | 'logs';
58
-
59
- export interface WebSocketMessage {
60
- type: 'request' | 'exception' | 'log' | 'connected';
61
- payload: unknown;
62
- timestamp: number;
63
- }
@@ -1 +0,0 @@
1
- /// <reference types="vite/client" />
@@ -1,54 +0,0 @@
1
- import { existsSync } from 'node:fs';
2
- import { resolve } from 'node:path';
3
- import type { Plugin } from 'vite';
4
-
5
- interface GkmConfig {
6
- server?: boolean | { port?: number };
7
- telescope?: { port?: number };
8
- }
9
-
10
- /**
11
- * Vite plugin that reads configuration from gkm.config.ts
12
- * to configure the dev server proxy.
13
- */
14
- export function gkmConfigPlugin(): Plugin {
15
- let serverPort = 3000;
16
-
17
- return {
18
- name: 'gkm-config',
19
- async config() {
20
- const cwd = process.cwd();
21
- const configPath = resolve(cwd, 'gkm.config.ts');
22
-
23
- if (existsSync(configPath)) {
24
- try {
25
- const config = (await import(configPath)).default as GkmConfig;
26
-
27
- // Check for telescope.port first, then server.port
28
- if (config.telescope?.port) {
29
- serverPort = config.telescope.port;
30
- } else if (typeof config.server === 'object' && config.server.port) {
31
- serverPort = config.server.port;
32
- }
33
- } catch {
34
- // Silently fall back to default port
35
- }
36
- }
37
-
38
- return {
39
- server: {
40
- proxy: {
41
- '/__telescope/api': {
42
- target: `http://localhost:${serverPort}`,
43
- changeOrigin: true,
44
- },
45
- '/__telescope/ws': {
46
- target: `ws://localhost:${serverPort}`,
47
- ws: true,
48
- },
49
- },
50
- },
51
- };
52
- },
53
- };
54
- }
package/ui/tsconfig.json DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "lib": ["ES2022", "DOM", "DOM.Iterable"],
5
- "module": "ESNext",
6
- "skipLibCheck": true,
7
- "moduleResolution": "bundler",
8
- "allowImportingTsExtensions": true,
9
- "isolatedModules": true,
10
- "moduleDetection": "force",
11
- "noEmit": true,
12
- "jsx": "react-jsx",
13
- "strict": true,
14
- "noUnusedLocals": true,
15
- "noUnusedParameters": true,
16
- "noFallthroughCasesInSwitch": true,
17
- "noUncheckedSideEffectImports": true
18
- },
19
- "include": ["src"]
20
- }
@@ -1 +0,0 @@
1
- {"root":["./src/app.tsx","./src/api.ts","./src/main.tsx","./src/types.ts","./src/vite-env.d.ts","./src/vite-plugin-gkm-config.ts","./src/components/exceptiondetail.tsx","./src/components/filterbar.tsx","./src/components/logdetail.tsx","./src/components/requestdetail.tsx"],"version":"5.8.2"}
package/ui/vite.config.ts DELETED
@@ -1,13 +0,0 @@
1
- import tailwindcss from '@tailwindcss/vite';
2
- import react from '@vitejs/plugin-react';
3
- import { defineConfig } from 'vite';
4
- import { gkmConfigPlugin } from './src/vite-plugin-gkm-config';
5
-
6
- export default defineConfig({
7
- plugins: [react(), tailwindcss(), gkmConfigPlugin()],
8
- base: '/__telescope/',
9
- build: {
10
- outDir: '../dist/ui',
11
- emptyOutDir: true,
12
- },
13
- });