@geekmidas/telescope 9.0.2 → 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 (128) hide show
  1. package/README.md +14 -4
  2. package/dist/{http-D5kn3_Mt.d.mts → http-DULM1u2L.d.cts} +3 -3
  3. package/dist/{http-Dvca6fC3.d.cts.map → http-DULM1u2L.d.cts.map} +1 -1
  4. package/dist/{http-Dvca6fC3.d.cts → http-GB-Nlvwc.d.mts} +3 -3
  5. package/dist/{http-D5kn3_Mt.d.mts.map → http-GB-Nlvwc.d.mts.map} +1 -1
  6. package/dist/instrumentation/http.d.cts +1 -1
  7. package/dist/instrumentation/http.d.mts +1 -1
  8. package/dist/instrumentation/index.cjs +2 -2
  9. package/dist/instrumentation/index.d.cts +3 -3
  10. package/dist/instrumentation/index.d.mts +3 -3
  11. package/dist/instrumentation/index.mjs +2 -2
  12. package/dist/instrumentation/middleware.cjs +1 -1
  13. package/dist/instrumentation/middleware.d.cts +1 -1
  14. package/dist/instrumentation/middleware.d.mts +1 -1
  15. package/dist/instrumentation/middleware.mjs +1 -1
  16. package/dist/instrumentation/otel.cjs +1 -1
  17. package/dist/instrumentation/otel.d.cts +1 -1
  18. package/dist/instrumentation/otel.d.mts +1 -1
  19. package/dist/instrumentation/otel.mjs +1 -1
  20. package/dist/logger/console.d.cts.map +1 -1
  21. package/dist/logger/console.d.mts.map +1 -1
  22. package/dist/logger/pino.d.cts +2 -2
  23. package/dist/{middleware-DqPQpcup.cjs → middleware-Bcq6XXGG.cjs} +2 -2
  24. package/dist/middleware-Bcq6XXGG.cjs.map +1 -0
  25. package/dist/{middleware-4-GrQlOT.mjs → middleware-D1XEHvyy.mjs} +2 -2
  26. package/dist/middleware-D1XEHvyy.mjs.map +1 -0
  27. package/dist/{middleware-CA84nsNN.d.cts → middleware-PeyS-9Ny.d.cts} +2 -2
  28. package/dist/{middleware-CA84nsNN.d.cts.map → middleware-PeyS-9Ny.d.cts.map} +1 -1
  29. package/dist/{middleware-DAceVpfw.d.mts → middleware-oHvo_ZgU.d.mts} +2 -2
  30. package/dist/{middleware-DAceVpfw.d.mts.map → middleware-oHvo_ZgU.d.mts.map} +1 -1
  31. package/dist/{otel-40udNP5g.mjs → otel-B9bNoeZ2.mjs} +3 -3
  32. package/dist/otel-B9bNoeZ2.mjs.map +1 -0
  33. package/dist/{otel-1bJPb2Z7.d.mts → otel-Bk89b1lX.d.cts} +3 -3
  34. package/dist/{otel-1bJPb2Z7.d.mts.map → otel-Bk89b1lX.d.cts.map} +1 -1
  35. package/dist/{otel-COrpz_GZ.cjs → otel-BzjOtVxZ.cjs} +3 -3
  36. package/dist/otel-BzjOtVxZ.cjs.map +1 -0
  37. package/dist/{otel-SBVoVEHr.d.cts → otel-lPMsM26e.d.mts} +3 -3
  38. package/dist/{otel-SBVoVEHr.d.cts.map → otel-lPMsM26e.d.mts.map} +1 -1
  39. package/dist/storage/kysely.cjs +48 -38
  40. package/dist/storage/kysely.cjs.map +1 -1
  41. package/dist/storage/kysely.d.cts +29 -9
  42. package/dist/storage/kysely.d.cts.map +1 -1
  43. package/dist/storage/kysely.d.mts +29 -9
  44. package/dist/storage/kysely.d.mts.map +1 -1
  45. package/dist/storage/kysely.mjs +48 -38
  46. package/dist/storage/kysely.mjs.map +1 -1
  47. package/dist/tracing-BX8uY2nR.d.cts.map +1 -1
  48. package/dist/types-B1EIa_cQ.d.mts.map +1 -1
  49. package/dist/types-l7Rlb5Mg.d.cts.map +1 -1
  50. package/package.json +6 -3
  51. package/CHANGELOG.md +0 -72
  52. package/dist/middleware-4-GrQlOT.mjs.map +0 -1
  53. package/dist/middleware-DqPQpcup.cjs.map +0 -1
  54. package/dist/otel-40udNP5g.mjs.map +0 -1
  55. package/dist/otel-COrpz_GZ.cjs.map +0 -1
  56. package/src/Telescope.ts +0 -561
  57. package/src/__tests__/Telescope.spec.ts +0 -438
  58. package/src/__tests__/pino-transport.spec.ts +0 -115
  59. package/src/__tests__/redact.spec.ts +0 -336
  60. package/src/adapters/__tests__/lambda.spec.ts +0 -318
  61. package/src/adapters/__tests__/middy.spec.ts +0 -741
  62. package/src/adapters/index.ts +0 -22
  63. package/src/adapters/lambda.ts +0 -432
  64. package/src/adapters/middy.ts +0 -402
  65. package/src/adapters/types.ts +0 -181
  66. package/src/core.ts +0 -51
  67. package/src/index.ts +0 -34
  68. package/src/instrumentation/__tests__/core.spec.ts +0 -248
  69. package/src/instrumentation/__tests__/hono.spec.ts +0 -348
  70. package/src/instrumentation/__tests__/middleware.spec.ts +0 -528
  71. package/src/instrumentation/__tests__/otel.spec.ts +0 -291
  72. package/src/instrumentation/__tests__/tracing.spec.ts +0 -208
  73. package/src/instrumentation/core.ts +0 -228
  74. package/src/instrumentation/hono.ts +0 -270
  75. package/src/instrumentation/http.ts +0 -306
  76. package/src/instrumentation/index.ts +0 -90
  77. package/src/instrumentation/middleware.ts +0 -297
  78. package/src/instrumentation/otel.ts +0 -271
  79. package/src/instrumentation/setup.ts +0 -246
  80. package/src/instrumentation/tracing.ts +0 -145
  81. package/src/logger/__tests__/console.spec.ts +0 -366
  82. package/src/logger/__tests__/pino.spec.ts +0 -217
  83. package/src/logger/console.ts +0 -230
  84. package/src/logger/pino.ts +0 -201
  85. package/src/metrics/MetricsAggregator.ts +0 -555
  86. package/src/metrics/__tests__/MetricsAggregator.spec.ts +0 -298
  87. package/src/metrics/index.ts +0 -2
  88. package/src/metrics/storage/InMemoryMetricsStorage.ts +0 -380
  89. package/src/metrics/storage/MetricsStorage.ts +0 -74
  90. package/src/metrics/storage/index.ts +0 -3
  91. package/src/metrics/storage/types.ts +0 -243
  92. package/src/otlp/__tests__/receiver.spec.ts +0 -367
  93. package/src/otlp/__tests__/transformer.spec.ts +0 -455
  94. package/src/otlp/hono.ts +0 -120
  95. package/src/otlp/index.ts +0 -22
  96. package/src/otlp/receiver.ts +0 -162
  97. package/src/otlp/transformer.ts +0 -367
  98. package/src/otlp/types.ts +0 -364
  99. package/src/redact.ts +0 -116
  100. package/src/server/__tests__/hono.spec.ts +0 -814
  101. package/src/server/hono.ts +0 -442
  102. package/src/storage/__tests__/kysely.spec.ts +0 -715
  103. package/src/storage/__tests__/memory.spec.ts +0 -694
  104. package/src/storage/kysely.ts +0 -599
  105. package/src/storage/memory.ts +0 -204
  106. package/src/types.ts +0 -447
  107. package/src/ui-assets.ts +0 -40
  108. package/tsconfig.json +0 -9
  109. package/ui/CHANGELOG.md +0 -7
  110. package/ui/index.html +0 -12
  111. package/ui/node_modules/.bin/tsc +0 -21
  112. package/ui/node_modules/.bin/tsserver +0 -21
  113. package/ui/node_modules/.bin/vite +0 -21
  114. package/ui/package.json +0 -24
  115. package/ui/src/App.tsx +0 -595
  116. package/ui/src/api.ts +0 -88
  117. package/ui/src/components/ExceptionDetail.tsx +0 -100
  118. package/ui/src/components/FilterBar.tsx +0 -162
  119. package/ui/src/components/LogDetail.tsx +0 -91
  120. package/ui/src/components/RequestDetail.tsx +0 -143
  121. package/ui/src/main.tsx +0 -10
  122. package/ui/src/styles.css +0 -11
  123. package/ui/src/types.ts +0 -63
  124. package/ui/src/vite-env.d.ts +0 -1
  125. package/ui/src/vite-plugin-gkm-config.ts +0 -54
  126. package/ui/tsconfig.json +0 -20
  127. package/ui/tsconfig.tsbuildinfo +0 -1
  128. 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
- }