@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,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
- }