@geekmidas/telescope 9.0.2 → 10.0.0-alpha.1

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 (122) hide show
  1. package/README.md +14 -4
  2. package/dist/{http-D5kn3_Mt.d.mts → http-BiNtg85L.d.mts} +3 -3
  3. package/dist/{http-D5kn3_Mt.d.mts.map → http-BiNtg85L.d.mts.map} +1 -1
  4. package/dist/instrumentation/http.d.mts +1 -1
  5. package/dist/instrumentation/index.cjs +2 -2
  6. package/dist/instrumentation/index.d.cts +2 -2
  7. package/dist/instrumentation/index.d.mts +3 -3
  8. package/dist/instrumentation/index.mjs +2 -2
  9. package/dist/instrumentation/middleware.cjs +1 -1
  10. package/dist/instrumentation/middleware.d.cts +1 -1
  11. package/dist/instrumentation/middleware.d.mts +1 -1
  12. package/dist/instrumentation/middleware.mjs +1 -1
  13. package/dist/instrumentation/otel.cjs +1 -1
  14. package/dist/instrumentation/otel.d.cts +1 -1
  15. package/dist/instrumentation/otel.d.mts +1 -1
  16. package/dist/instrumentation/otel.mjs +1 -1
  17. package/dist/logger/console.d.cts.map +1 -1
  18. package/dist/logger/pino.d.mts +2 -2
  19. package/dist/{middleware-DqPQpcup.cjs → middleware-Bcq6XXGG.cjs} +2 -2
  20. package/dist/middleware-Bcq6XXGG.cjs.map +1 -0
  21. package/dist/{middleware-4-GrQlOT.mjs → middleware-D1XEHvyy.mjs} +2 -2
  22. package/dist/middleware-D1XEHvyy.mjs.map +1 -0
  23. package/dist/{middleware-CA84nsNN.d.cts → middleware-PeyS-9Ny.d.cts} +2 -2
  24. package/dist/{middleware-CA84nsNN.d.cts.map → middleware-PeyS-9Ny.d.cts.map} +1 -1
  25. package/dist/{middleware-DAceVpfw.d.mts → middleware-oHvo_ZgU.d.mts} +2 -2
  26. package/dist/{middleware-DAceVpfw.d.mts.map → middleware-oHvo_ZgU.d.mts.map} +1 -1
  27. package/dist/{otel-40udNP5g.mjs → otel-B9bNoeZ2.mjs} +3 -3
  28. package/dist/otel-B9bNoeZ2.mjs.map +1 -0
  29. package/dist/{otel-SBVoVEHr.d.cts → otel-Bk89b1lX.d.cts} +3 -3
  30. package/dist/{otel-1bJPb2Z7.d.mts.map → otel-Bk89b1lX.d.cts.map} +1 -1
  31. package/dist/{otel-COrpz_GZ.cjs → otel-BzjOtVxZ.cjs} +3 -3
  32. package/dist/otel-BzjOtVxZ.cjs.map +1 -0
  33. package/dist/{otel-1bJPb2Z7.d.mts → otel-lPMsM26e.d.mts} +3 -3
  34. package/dist/{otel-SBVoVEHr.d.cts.map → otel-lPMsM26e.d.mts.map} +1 -1
  35. package/dist/storage/kysely.cjs +48 -38
  36. package/dist/storage/kysely.cjs.map +1 -1
  37. package/dist/storage/kysely.d.cts +29 -9
  38. package/dist/storage/kysely.d.cts.map +1 -1
  39. package/dist/storage/kysely.d.mts +29 -9
  40. package/dist/storage/kysely.d.mts.map +1 -1
  41. package/dist/storage/kysely.mjs +48 -38
  42. package/dist/storage/kysely.mjs.map +1 -1
  43. package/dist/tracing-PnECEbEu.d.mts.map +1 -1
  44. package/package.json +6 -3
  45. package/CHANGELOG.md +0 -72
  46. package/dist/middleware-4-GrQlOT.mjs.map +0 -1
  47. package/dist/middleware-DqPQpcup.cjs.map +0 -1
  48. package/dist/otel-40udNP5g.mjs.map +0 -1
  49. package/dist/otel-COrpz_GZ.cjs.map +0 -1
  50. package/src/Telescope.ts +0 -561
  51. package/src/__tests__/Telescope.spec.ts +0 -438
  52. package/src/__tests__/pino-transport.spec.ts +0 -115
  53. package/src/__tests__/redact.spec.ts +0 -336
  54. package/src/adapters/__tests__/lambda.spec.ts +0 -318
  55. package/src/adapters/__tests__/middy.spec.ts +0 -741
  56. package/src/adapters/index.ts +0 -22
  57. package/src/adapters/lambda.ts +0 -432
  58. package/src/adapters/middy.ts +0 -402
  59. package/src/adapters/types.ts +0 -181
  60. package/src/core.ts +0 -51
  61. package/src/index.ts +0 -34
  62. package/src/instrumentation/__tests__/core.spec.ts +0 -248
  63. package/src/instrumentation/__tests__/hono.spec.ts +0 -348
  64. package/src/instrumentation/__tests__/middleware.spec.ts +0 -528
  65. package/src/instrumentation/__tests__/otel.spec.ts +0 -291
  66. package/src/instrumentation/__tests__/tracing.spec.ts +0 -208
  67. package/src/instrumentation/core.ts +0 -228
  68. package/src/instrumentation/hono.ts +0 -270
  69. package/src/instrumentation/http.ts +0 -306
  70. package/src/instrumentation/index.ts +0 -90
  71. package/src/instrumentation/middleware.ts +0 -297
  72. package/src/instrumentation/otel.ts +0 -271
  73. package/src/instrumentation/setup.ts +0 -246
  74. package/src/instrumentation/tracing.ts +0 -145
  75. package/src/logger/__tests__/console.spec.ts +0 -366
  76. package/src/logger/__tests__/pino.spec.ts +0 -217
  77. package/src/logger/console.ts +0 -230
  78. package/src/logger/pino.ts +0 -201
  79. package/src/metrics/MetricsAggregator.ts +0 -555
  80. package/src/metrics/__tests__/MetricsAggregator.spec.ts +0 -298
  81. package/src/metrics/index.ts +0 -2
  82. package/src/metrics/storage/InMemoryMetricsStorage.ts +0 -380
  83. package/src/metrics/storage/MetricsStorage.ts +0 -74
  84. package/src/metrics/storage/index.ts +0 -3
  85. package/src/metrics/storage/types.ts +0 -243
  86. package/src/otlp/__tests__/receiver.spec.ts +0 -367
  87. package/src/otlp/__tests__/transformer.spec.ts +0 -455
  88. package/src/otlp/hono.ts +0 -120
  89. package/src/otlp/index.ts +0 -22
  90. package/src/otlp/receiver.ts +0 -162
  91. package/src/otlp/transformer.ts +0 -367
  92. package/src/otlp/types.ts +0 -364
  93. package/src/redact.ts +0 -116
  94. package/src/server/__tests__/hono.spec.ts +0 -814
  95. package/src/server/hono.ts +0 -442
  96. package/src/storage/__tests__/kysely.spec.ts +0 -715
  97. package/src/storage/__tests__/memory.spec.ts +0 -694
  98. package/src/storage/kysely.ts +0 -599
  99. package/src/storage/memory.ts +0 -204
  100. package/src/types.ts +0 -447
  101. package/src/ui-assets.ts +0 -40
  102. package/tsconfig.json +0 -9
  103. package/ui/CHANGELOG.md +0 -7
  104. package/ui/index.html +0 -12
  105. package/ui/node_modules/.bin/tsc +0 -21
  106. package/ui/node_modules/.bin/tsserver +0 -21
  107. package/ui/node_modules/.bin/vite +0 -21
  108. package/ui/package.json +0 -24
  109. package/ui/src/App.tsx +0 -595
  110. package/ui/src/api.ts +0 -88
  111. package/ui/src/components/ExceptionDetail.tsx +0 -100
  112. package/ui/src/components/FilterBar.tsx +0 -162
  113. package/ui/src/components/LogDetail.tsx +0 -91
  114. package/ui/src/components/RequestDetail.tsx +0 -143
  115. package/ui/src/main.tsx +0 -10
  116. package/ui/src/styles.css +0 -11
  117. package/ui/src/types.ts +0 -63
  118. package/ui/src/vite-env.d.ts +0 -1
  119. package/ui/src/vite-plugin-gkm-config.ts +0 -54
  120. package/ui/tsconfig.json +0 -20
  121. package/ui/tsconfig.tsbuildinfo +0 -1
  122. package/ui/vite.config.ts +0 -13
@@ -1,22 +0,0 @@
1
- /**
2
- * Telescope Adapters
3
- *
4
- * Environment-specific adapters for integrating Telescope with various runtimes.
5
- */
6
-
7
- export type {
8
- AdapterConfig,
9
- AdapterErrorContext,
10
- AdapterLifecycle,
11
- AdapterRequestContext,
12
- AdapterResponseContext,
13
- HonoAdapterConfig,
14
- HonoContextWithTelescope,
15
- LambdaAdapterConfig,
16
- SpanProcessorOptions,
17
- SpanProcessorStrategy,
18
- TelescopeAdapter,
19
- TelescopeEnvironment,
20
- TelescopeHonoContext,
21
- TelescopeHonoVariables,
22
- } from './types';
@@ -1,432 +0,0 @@
1
- import type { Context as LambdaContext } from 'aws-lambda';
2
- import { nanoid } from 'nanoid';
3
- import { flushTelemetry } from '../instrumentation/core';
4
- import type { Telescope } from '../Telescope';
5
- import type {
6
- AdapterRequestContext,
7
- AdapterResponseContext,
8
- LambdaAdapterConfig,
9
- TelescopeAdapter,
10
- } from './types';
11
-
12
- // Re-export Middy middleware for convenience
13
- export {
14
- createTelescopeHandler,
15
- type TelescopeMiddlewareOptions,
16
- telescopeMiddleware,
17
- } from './middy';
18
-
19
- /**
20
- * Lambda resource attributes detected from environment
21
- */
22
- export interface LambdaResourceAttributes {
23
- 'cloud.provider': 'aws';
24
- 'cloud.region': string;
25
- 'faas.name': string;
26
- 'faas.version': string;
27
- 'faas.instance': string;
28
- 'faas.max_memory': number;
29
- [key: string]: string | number;
30
- }
31
-
32
- /**
33
- * Detect Lambda resource attributes from environment
34
- */
35
- export function detectLambdaResources(): LambdaResourceAttributes {
36
- return {
37
- 'cloud.provider': 'aws',
38
- 'cloud.region': process.env.AWS_REGION || 'unknown',
39
- 'faas.name': process.env.AWS_LAMBDA_FUNCTION_NAME || 'unknown',
40
- 'faas.version': process.env.AWS_LAMBDA_FUNCTION_VERSION || 'unknown',
41
- 'faas.instance': process.env.AWS_LAMBDA_LOG_STREAM_NAME || 'unknown',
42
- 'faas.max_memory': parseInt(
43
- process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE || '128',
44
- 10,
45
- ),
46
- };
47
- }
48
-
49
- /**
50
- * Extract invocation context from Lambda event
51
- */
52
- export function extractLambdaInvocationContext(
53
- _event: unknown,
54
- context: LambdaContext,
55
- ): {
56
- requestId: string;
57
- coldStart: boolean;
58
- remainingTimeMs: number;
59
- memoryLimitMB: number;
60
- functionName: string;
61
- functionVersion: string;
62
- } {
63
- return {
64
- requestId: context.awsRequestId,
65
- coldStart: !globalLambdaState.initialized,
66
- remainingTimeMs: context.getRemainingTimeInMillis(),
67
- memoryLimitMB: parseInt(String(context.memoryLimitInMB), 10),
68
- functionName: context.functionName,
69
- functionVersion: context.functionVersion,
70
- };
71
- }
72
-
73
- /**
74
- * Global state to track Lambda cold starts
75
- */
76
- const globalLambdaState = {
77
- initialized: false,
78
- };
79
-
80
- /**
81
- * Default Lambda adapter configuration
82
- */
83
- const DEFAULT_LAMBDA_CONFIG: LambdaAdapterConfig = {
84
- environment: 'lambda',
85
- spanProcessor: {
86
- strategy: 'simple', // Always use simple for Lambda
87
- },
88
- autoFlush: true,
89
- detectResource: true,
90
- };
91
-
92
- /**
93
- * Lambda adapter for Telescope.
94
- * Provides Lambda-specific request/response handling with auto-flush.
95
- */
96
- export class LambdaAdapter implements TelescopeAdapter<LambdaAdapterConfig> {
97
- readonly config: LambdaAdapterConfig;
98
- readonly telescope: Telescope;
99
- private resourceAttributes: LambdaResourceAttributes | null = null;
100
-
101
- constructor(telescope: Telescope, config: Partial<LambdaAdapterConfig> = {}) {
102
- this.telescope = telescope;
103
- this.config = { ...DEFAULT_LAMBDA_CONFIG, ...config };
104
- }
105
-
106
- async onSetup(): Promise<void> {
107
- if (this.config.detectResource) {
108
- this.resourceAttributes = detectLambdaResources();
109
- }
110
- globalLambdaState.initialized = true;
111
- }
112
-
113
- async onDestroy(): Promise<void> {
114
- await flushTelemetry();
115
- }
116
-
117
- /**
118
- * Extract request context from API Gateway event
119
- */
120
- extractRequestContext(event: unknown): AdapterRequestContext {
121
- // Handle API Gateway v1 (REST API)
122
- if (isApiGatewayV1Event(event)) {
123
- const headers = normalizeHeaders(event.headers || {});
124
- const requestSize = headers['content-length']
125
- ? parseInt(headers['content-length'], 10)
126
- : undefined;
127
- return {
128
- id: event.requestContext?.requestId || nanoid(),
129
- method: event.httpMethod || 'UNKNOWN',
130
- path: event.path || '/',
131
- url: event.path || '/',
132
- headers,
133
- query: event.queryStringParameters || {},
134
- body: parseBody(event.body, event.isBase64Encoded),
135
- ip:
136
- event.requestContext?.identity?.sourceIp ||
137
- event.headers?.['X-Forwarded-For']?.split(',')[0],
138
- startTime: Date.now(),
139
- requestSize,
140
- };
141
- }
142
-
143
- // Handle API Gateway v2 (HTTP API)
144
- if (isApiGatewayV2Event(event)) {
145
- const headers = normalizeHeaders(event.headers || {});
146
- const requestSize = headers['content-length']
147
- ? parseInt(headers['content-length'], 10)
148
- : undefined;
149
- return {
150
- id: event.requestContext?.requestId || nanoid(),
151
- method: event.requestContext?.http?.method || 'UNKNOWN',
152
- path: event.rawPath || '/',
153
- url: event.rawPath || '/',
154
- headers,
155
- query: event.queryStringParameters || {},
156
- body: parseBody(event.body, event.isBase64Encoded),
157
- ip:
158
- event.requestContext?.http?.sourceIp ||
159
- event.headers?.['x-forwarded-for']?.split(',')[0],
160
- startTime: Date.now(),
161
- requestSize,
162
- };
163
- }
164
-
165
- // Handle ALB event
166
- if (isAlbEvent(event)) {
167
- const headers = normalizeHeaders(event.headers || {});
168
- const requestSize = headers['content-length']
169
- ? parseInt(headers['content-length'], 10)
170
- : undefined;
171
- return {
172
- id: nanoid(),
173
- method: event.httpMethod || 'UNKNOWN',
174
- path: event.path || '/',
175
- url: event.path || '/',
176
- headers,
177
- query: event.queryStringParameters || {},
178
- body: parseBody(event.body, event.isBase64Encoded),
179
- ip: event.headers?.['x-forwarded-for']?.split(',')[0],
180
- startTime: Date.now(),
181
- requestSize,
182
- };
183
- }
184
-
185
- // Generic Lambda invocation (not HTTP)
186
- return {
187
- id: nanoid(),
188
- method: 'INVOKE',
189
- path: '/',
190
- url: '/',
191
- headers: {},
192
- query: {},
193
- body: event,
194
- startTime: Date.now(),
195
- };
196
- }
197
-
198
- /**
199
- * Extract response context from Lambda response
200
- */
201
- extractResponseContext(
202
- response: unknown,
203
- startTime: number,
204
- ): AdapterResponseContext {
205
- const duration = Date.now() - startTime;
206
-
207
- // API Gateway response format
208
- if (isApiGatewayResponse(response)) {
209
- const headers = normalizeHeaders(response.headers || {});
210
- // Prefer Content-Length header, fallback to body size
211
- const responseSize = headers['content-length']
212
- ? parseInt(headers['content-length'], 10)
213
- : typeof response.body === 'string'
214
- ? Buffer.byteLength(response.body, 'utf8')
215
- : undefined;
216
- return {
217
- status: response.statusCode || 200,
218
- headers,
219
- body: response.body,
220
- duration,
221
- responseSize,
222
- };
223
- }
224
-
225
- // Generic response
226
- return {
227
- status: 200,
228
- headers: {},
229
- body: response,
230
- duration,
231
- };
232
- }
233
-
234
- /**
235
- * Flush telemetry data before Lambda context freezes
236
- */
237
- async flush(): Promise<void> {
238
- await flushTelemetry();
239
- }
240
-
241
- /**
242
- * Get resource attributes for the Lambda function
243
- */
244
- getResourceAttributes(): LambdaResourceAttributes | null {
245
- return this.resourceAttributes;
246
- }
247
- }
248
-
249
- /**
250
- * Wrap a Lambda handler to automatically record requests and flush telemetry.
251
- *
252
- * @example
253
- * ```typescript
254
- * import { wrapLambdaHandler } from '@geekmidas/telescope/adapters/lambda';
255
- *
256
- * const telescope = new Telescope({ storage: new InMemoryStorage() });
257
- *
258
- * export const handler = wrapLambdaHandler(telescope, async (event, context) => {
259
- * // Your Lambda logic here
260
- * return { statusCode: 200, body: JSON.stringify({ success: true }) };
261
- * });
262
- * ```
263
- */
264
- export function wrapLambdaHandler<TEvent, TResult>(
265
- telescope: Telescope,
266
- handler: (event: TEvent, context: LambdaContext) => Promise<TResult>,
267
- options: Partial<LambdaAdapterConfig> = {},
268
- ): (event: TEvent, context: LambdaContext) => Promise<TResult> {
269
- const adapter = new LambdaAdapter(telescope, options);
270
-
271
- return async (event: TEvent, context: LambdaContext): Promise<TResult> => {
272
- const requestContext = adapter.extractRequestContext(event);
273
-
274
- try {
275
- const result = await handler(event, context);
276
-
277
- // Record the request
278
- const responseContext = adapter.extractResponseContext(
279
- result,
280
- requestContext.startTime,
281
- );
282
-
283
- await telescope.recordRequest({
284
- method: requestContext.method,
285
- path: requestContext.path,
286
- url: requestContext.url,
287
- headers: requestContext.headers,
288
- query: requestContext.query,
289
- body: requestContext.body,
290
- ip: requestContext.ip,
291
- status: responseContext.status,
292
- responseHeaders: responseContext.headers,
293
- responseBody: responseContext.body,
294
- duration: responseContext.duration,
295
- requestSize: requestContext.requestSize,
296
- responseSize: responseContext.responseSize,
297
- });
298
-
299
- return result;
300
- } catch (error) {
301
- // Record the exception
302
- if (error instanceof Error) {
303
- await telescope.exception(error, requestContext.id);
304
- }
305
- throw error;
306
- } finally {
307
- // Always flush before Lambda freezes
308
- if (options.autoFlush !== false) {
309
- await adapter.flush();
310
- }
311
- }
312
- };
313
- }
314
-
315
- // ============================================
316
- // Type Guards and Helpers
317
- // ============================================
318
-
319
- interface ApiGatewayV1Event {
320
- httpMethod?: string;
321
- path?: string;
322
- headers?: Record<string, string | undefined>;
323
- queryStringParameters?: Record<string, string>;
324
- body?: string | null;
325
- isBase64Encoded?: boolean;
326
- requestContext?: {
327
- requestId?: string;
328
- identity?: {
329
- sourceIp?: string;
330
- };
331
- };
332
- }
333
-
334
- interface ApiGatewayV2Event {
335
- rawPath?: string;
336
- headers?: Record<string, string | undefined>;
337
- queryStringParameters?: Record<string, string>;
338
- body?: string | null;
339
- isBase64Encoded?: boolean;
340
- requestContext?: {
341
- requestId?: string;
342
- http?: {
343
- method?: string;
344
- sourceIp?: string;
345
- };
346
- };
347
- }
348
-
349
- interface AlbEvent {
350
- httpMethod?: string;
351
- path?: string;
352
- headers?: Record<string, string | undefined>;
353
- queryStringParameters?: Record<string, string>;
354
- body?: string | null;
355
- isBase64Encoded?: boolean;
356
- }
357
-
358
- interface ApiGatewayResponse {
359
- statusCode?: number;
360
- headers?: Record<string, string | undefined>;
361
- body?: unknown;
362
- }
363
-
364
- function isApiGatewayV1Event(event: unknown): event is ApiGatewayV1Event {
365
- return (
366
- typeof event === 'object' &&
367
- event !== null &&
368
- 'httpMethod' in event &&
369
- 'path' in event
370
- );
371
- }
372
-
373
- function isApiGatewayV2Event(event: unknown): event is ApiGatewayV2Event {
374
- return (
375
- typeof event === 'object' &&
376
- event !== null &&
377
- 'rawPath' in event &&
378
- 'requestContext' in event &&
379
- typeof (event as ApiGatewayV2Event).requestContext === 'object' &&
380
- 'http' in ((event as ApiGatewayV2Event).requestContext || {})
381
- );
382
- }
383
-
384
- function isAlbEvent(event: unknown): event is AlbEvent {
385
- return (
386
- typeof event === 'object' &&
387
- event !== null &&
388
- 'httpMethod' in event &&
389
- !('requestContext' in event)
390
- );
391
- }
392
-
393
- function isApiGatewayResponse(
394
- response: unknown,
395
- ): response is ApiGatewayResponse {
396
- return (
397
- typeof response === 'object' &&
398
- response !== null &&
399
- 'statusCode' in response
400
- );
401
- }
402
-
403
- function normalizeHeaders(
404
- headers: Record<string, string | undefined>,
405
- ): Record<string, string> {
406
- const normalized: Record<string, string> = {};
407
- for (const [key, value] of Object.entries(headers)) {
408
- if (value !== undefined) {
409
- normalized[key.toLowerCase()] = value;
410
- }
411
- }
412
- return normalized;
413
- }
414
-
415
- function parseBody(
416
- body: string | null | undefined,
417
- isBase64Encoded?: boolean,
418
- ): unknown {
419
- if (!body) return undefined;
420
-
421
- try {
422
- const decoded = isBase64Encoded
423
- ? Buffer.from(body, 'base64').toString('utf-8')
424
- : body;
425
-
426
- // Try to parse as JSON
427
- return JSON.parse(decoded);
428
- } catch {
429
- // Return raw string if not JSON
430
- return body;
431
- }
432
- }