@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.
- package/README.md +14 -4
- package/dist/{http-D5kn3_Mt.d.mts → http-BiNtg85L.d.mts} +3 -3
- package/dist/{http-D5kn3_Mt.d.mts.map → http-BiNtg85L.d.mts.map} +1 -1
- package/dist/instrumentation/http.d.mts +1 -1
- package/dist/instrumentation/index.cjs +2 -2
- package/dist/instrumentation/index.d.cts +2 -2
- package/dist/instrumentation/index.d.mts +3 -3
- package/dist/instrumentation/index.mjs +2 -2
- package/dist/instrumentation/middleware.cjs +1 -1
- package/dist/instrumentation/middleware.d.cts +1 -1
- package/dist/instrumentation/middleware.d.mts +1 -1
- package/dist/instrumentation/middleware.mjs +1 -1
- package/dist/instrumentation/otel.cjs +1 -1
- package/dist/instrumentation/otel.d.cts +1 -1
- package/dist/instrumentation/otel.d.mts +1 -1
- package/dist/instrumentation/otel.mjs +1 -1
- package/dist/logger/console.d.cts.map +1 -1
- package/dist/logger/pino.d.mts +2 -2
- package/dist/{middleware-DqPQpcup.cjs → middleware-Bcq6XXGG.cjs} +2 -2
- package/dist/middleware-Bcq6XXGG.cjs.map +1 -0
- package/dist/{middleware-4-GrQlOT.mjs → middleware-D1XEHvyy.mjs} +2 -2
- package/dist/middleware-D1XEHvyy.mjs.map +1 -0
- package/dist/{middleware-CA84nsNN.d.cts → middleware-PeyS-9Ny.d.cts} +2 -2
- package/dist/{middleware-CA84nsNN.d.cts.map → middleware-PeyS-9Ny.d.cts.map} +1 -1
- package/dist/{middleware-DAceVpfw.d.mts → middleware-oHvo_ZgU.d.mts} +2 -2
- package/dist/{middleware-DAceVpfw.d.mts.map → middleware-oHvo_ZgU.d.mts.map} +1 -1
- package/dist/{otel-40udNP5g.mjs → otel-B9bNoeZ2.mjs} +3 -3
- package/dist/otel-B9bNoeZ2.mjs.map +1 -0
- package/dist/{otel-SBVoVEHr.d.cts → otel-Bk89b1lX.d.cts} +3 -3
- package/dist/{otel-1bJPb2Z7.d.mts.map → otel-Bk89b1lX.d.cts.map} +1 -1
- package/dist/{otel-COrpz_GZ.cjs → otel-BzjOtVxZ.cjs} +3 -3
- package/dist/otel-BzjOtVxZ.cjs.map +1 -0
- package/dist/{otel-1bJPb2Z7.d.mts → otel-lPMsM26e.d.mts} +3 -3
- package/dist/{otel-SBVoVEHr.d.cts.map → otel-lPMsM26e.d.mts.map} +1 -1
- package/dist/storage/kysely.cjs +48 -38
- package/dist/storage/kysely.cjs.map +1 -1
- package/dist/storage/kysely.d.cts +29 -9
- package/dist/storage/kysely.d.cts.map +1 -1
- package/dist/storage/kysely.d.mts +29 -9
- package/dist/storage/kysely.d.mts.map +1 -1
- package/dist/storage/kysely.mjs +48 -38
- package/dist/storage/kysely.mjs.map +1 -1
- package/dist/tracing-PnECEbEu.d.mts.map +1 -1
- package/package.json +6 -3
- package/CHANGELOG.md +0 -72
- package/dist/middleware-4-GrQlOT.mjs.map +0 -1
- package/dist/middleware-DqPQpcup.cjs.map +0 -1
- package/dist/otel-40udNP5g.mjs.map +0 -1
- package/dist/otel-COrpz_GZ.cjs.map +0 -1
- package/src/Telescope.ts +0 -561
- package/src/__tests__/Telescope.spec.ts +0 -438
- package/src/__tests__/pino-transport.spec.ts +0 -115
- package/src/__tests__/redact.spec.ts +0 -336
- package/src/adapters/__tests__/lambda.spec.ts +0 -318
- package/src/adapters/__tests__/middy.spec.ts +0 -741
- package/src/adapters/index.ts +0 -22
- package/src/adapters/lambda.ts +0 -432
- package/src/adapters/middy.ts +0 -402
- package/src/adapters/types.ts +0 -181
- package/src/core.ts +0 -51
- package/src/index.ts +0 -34
- package/src/instrumentation/__tests__/core.spec.ts +0 -248
- package/src/instrumentation/__tests__/hono.spec.ts +0 -348
- package/src/instrumentation/__tests__/middleware.spec.ts +0 -528
- package/src/instrumentation/__tests__/otel.spec.ts +0 -291
- package/src/instrumentation/__tests__/tracing.spec.ts +0 -208
- package/src/instrumentation/core.ts +0 -228
- package/src/instrumentation/hono.ts +0 -270
- package/src/instrumentation/http.ts +0 -306
- package/src/instrumentation/index.ts +0 -90
- package/src/instrumentation/middleware.ts +0 -297
- package/src/instrumentation/otel.ts +0 -271
- package/src/instrumentation/setup.ts +0 -246
- package/src/instrumentation/tracing.ts +0 -145
- package/src/logger/__tests__/console.spec.ts +0 -366
- package/src/logger/__tests__/pino.spec.ts +0 -217
- package/src/logger/console.ts +0 -230
- package/src/logger/pino.ts +0 -201
- package/src/metrics/MetricsAggregator.ts +0 -555
- package/src/metrics/__tests__/MetricsAggregator.spec.ts +0 -298
- package/src/metrics/index.ts +0 -2
- package/src/metrics/storage/InMemoryMetricsStorage.ts +0 -380
- package/src/metrics/storage/MetricsStorage.ts +0 -74
- package/src/metrics/storage/index.ts +0 -3
- package/src/metrics/storage/types.ts +0 -243
- package/src/otlp/__tests__/receiver.spec.ts +0 -367
- package/src/otlp/__tests__/transformer.spec.ts +0 -455
- package/src/otlp/hono.ts +0 -120
- package/src/otlp/index.ts +0 -22
- package/src/otlp/receiver.ts +0 -162
- package/src/otlp/transformer.ts +0 -367
- package/src/otlp/types.ts +0 -364
- package/src/redact.ts +0 -116
- package/src/server/__tests__/hono.spec.ts +0 -814
- package/src/server/hono.ts +0 -442
- package/src/storage/__tests__/kysely.spec.ts +0 -715
- package/src/storage/__tests__/memory.spec.ts +0 -694
- package/src/storage/kysely.ts +0 -599
- package/src/storage/memory.ts +0 -204
- package/src/types.ts +0 -447
- package/src/ui-assets.ts +0 -40
- package/tsconfig.json +0 -9
- package/ui/CHANGELOG.md +0 -7
- package/ui/index.html +0 -12
- package/ui/node_modules/.bin/tsc +0 -21
- package/ui/node_modules/.bin/tsserver +0 -21
- package/ui/node_modules/.bin/vite +0 -21
- package/ui/package.json +0 -24
- package/ui/src/App.tsx +0 -595
- package/ui/src/api.ts +0 -88
- package/ui/src/components/ExceptionDetail.tsx +0 -100
- package/ui/src/components/FilterBar.tsx +0 -162
- package/ui/src/components/LogDetail.tsx +0 -91
- package/ui/src/components/RequestDetail.tsx +0 -143
- package/ui/src/main.tsx +0 -10
- package/ui/src/styles.css +0 -11
- package/ui/src/types.ts +0 -63
- package/ui/src/vite-env.d.ts +0 -1
- package/ui/src/vite-plugin-gkm-config.ts +0 -54
- package/ui/tsconfig.json +0 -20
- package/ui/tsconfig.tsbuildinfo +0 -1
- package/ui/vite.config.ts +0 -13
package/src/adapters/index.ts
DELETED
|
@@ -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';
|
package/src/adapters/lambda.ts
DELETED
|
@@ -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
|
-
}
|