@type_sync/lambda
Advanced tools
+146
| /** | ||
| * TypeSync Lambda - AWS Lambda adapter for serverless deployment | ||
| */ | ||
| /** | ||
| * Router type (simplified for Lambda adapter) | ||
| */ | ||
| export type Router = any; | ||
| /** | ||
| * Lambda event type | ||
| */ | ||
| export interface LambdaEvent { | ||
| httpMethod: string; | ||
| path: string; | ||
| pathParameters?: Record<string, string>; | ||
| queryStringParameters?: Record<string, string>; | ||
| headers?: Record<string, string>; | ||
| body?: string; | ||
| isBase64Encoded?: boolean; | ||
| requestContext?: any; | ||
| } | ||
| /** | ||
| * Lambda response | ||
| */ | ||
| export interface LambdaResponse { | ||
| statusCode: number; | ||
| headers?: Record<string, string>; | ||
| body: string; | ||
| isBase64Encoded?: boolean; | ||
| } | ||
| /** | ||
| * Lambda context | ||
| */ | ||
| export interface LambdaContext { | ||
| functionName: string; | ||
| functionVersion: string; | ||
| invokedFunctionArn: string; | ||
| memoryLimitInMB: string; | ||
| awsRequestId: string; | ||
| logGroupName: string; | ||
| logStreamName: string; | ||
| getRemainingTimeInMillis(): number; | ||
| } | ||
| /** | ||
| * Lambda adapter configuration | ||
| */ | ||
| export interface LambdaAdapterConfig { | ||
| basePath?: string; | ||
| cors?: { | ||
| origin: string | string[]; | ||
| methods?: string[]; | ||
| allowedHeaders?: string[]; | ||
| exposedHeaders?: string[]; | ||
| credentials?: boolean; | ||
| maxAge?: number; | ||
| }; | ||
| compression?: boolean; | ||
| defaultHeaders?: Record<string, string>; | ||
| } | ||
| /** | ||
| * TypeSync Lambda Adapter | ||
| */ | ||
| export declare class TypeSyncLambdaAdapter { | ||
| private router; | ||
| private config; | ||
| constructor(router: Router, config?: LambdaAdapterConfig); | ||
| /** | ||
| * Create Lambda handler | ||
| */ | ||
| handler(): (event: LambdaEvent, context: LambdaContext) => Promise<LambdaResponse>; | ||
| /** | ||
| * Parse Lambda event to request format | ||
| */ | ||
| private parseEvent; | ||
| /** | ||
| * Normalize headers to lowercase | ||
| */ | ||
| private normalizeHeaders; | ||
| /** | ||
| * Parse request body | ||
| */ | ||
| private parseBody; | ||
| /** | ||
| * Find matching route | ||
| */ | ||
| private findRoute; | ||
| /** | ||
| * Execute route handler | ||
| */ | ||
| private executeRoute; | ||
| /** | ||
| * Create Lambda response | ||
| */ | ||
| private createResponse; | ||
| /** | ||
| * Get CORS headers | ||
| */ | ||
| private getCorsHeaders; | ||
| /** | ||
| * Get allowed origin | ||
| */ | ||
| private getAllowedOrigin; | ||
| } | ||
| /** | ||
| * Create Lambda adapter | ||
| */ | ||
| export declare function createLambdaAdapter(router: Router, config?: LambdaAdapterConfig): TypeSyncLambdaAdapter; | ||
| /** | ||
| * Wrap router for Lambda | ||
| */ | ||
| export declare function createLambdaHandler(router: Router, config?: LambdaAdapterConfig): (event: LambdaEvent, context: LambdaContext) => Promise<LambdaResponse>; | ||
| /** | ||
| * Lambda error response helper | ||
| */ | ||
| export declare function lambdaError(statusCode: number, message: string, details?: any): LambdaResponse; | ||
| /** | ||
| * Lambda success response helper | ||
| */ | ||
| export declare function lambdaSuccess<T>(data: T, statusCode?: number): LambdaResponse; | ||
| /** | ||
| * Warm-up helper (prevents cold starts) | ||
| */ | ||
| export declare function handleWarmUp(event: LambdaEvent): LambdaResponse | null; | ||
| /** | ||
| * CORS preflight handler | ||
| */ | ||
| export declare function handlePreflight(event: LambdaEvent, config: LambdaAdapterConfig['cors']): LambdaResponse | null; | ||
| /** | ||
| * API Gateway Proxy integration types | ||
| */ | ||
| export type APIGatewayProxyHandler = (event: LambdaEvent, context: LambdaContext) => Promise<LambdaResponse>; | ||
| /** | ||
| * Middleware for Lambda | ||
| */ | ||
| export type LambdaMiddleware = (event: LambdaEvent, context: LambdaContext, next: () => Promise<LambdaResponse>) => Promise<LambdaResponse>; | ||
| /** | ||
| * Compose Lambda middlewares | ||
| */ | ||
| export declare function composeLambdaMiddlewares(...middlewares: LambdaMiddleware[]): (handler: APIGatewayProxyHandler) => APIGatewayProxyHandler; | ||
| /** | ||
| * Logging middleware | ||
| */ | ||
| export declare function loggingMiddleware(): LambdaMiddleware; | ||
| /** | ||
| * Error handling middleware | ||
| */ | ||
| export declare function errorHandlingMiddleware(): LambdaMiddleware; |
+303
| "use strict"; | ||
| /** | ||
| * TypeSync Lambda - AWS Lambda adapter for serverless deployment | ||
| */ | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.TypeSyncLambdaAdapter = void 0; | ||
| exports.createLambdaAdapter = createLambdaAdapter; | ||
| exports.createLambdaHandler = createLambdaHandler; | ||
| exports.lambdaError = lambdaError; | ||
| exports.lambdaSuccess = lambdaSuccess; | ||
| exports.handleWarmUp = handleWarmUp; | ||
| exports.handlePreflight = handlePreflight; | ||
| exports.composeLambdaMiddlewares = composeLambdaMiddlewares; | ||
| exports.loggingMiddleware = loggingMiddleware; | ||
| exports.errorHandlingMiddleware = errorHandlingMiddleware; | ||
| /** | ||
| * TypeSync Lambda Adapter | ||
| */ | ||
| class TypeSyncLambdaAdapter { | ||
| constructor(router, config = {}) { | ||
| this.router = router; | ||
| this.config = { | ||
| basePath: config.basePath || '', | ||
| cors: config.cors, | ||
| compression: config.compression !== false, | ||
| defaultHeaders: config.defaultHeaders || {} | ||
| }; | ||
| } | ||
| /** | ||
| * Create Lambda handler | ||
| */ | ||
| handler() { | ||
| return async (event, context) => { | ||
| try { | ||
| // Parse request | ||
| const request = this.parseEvent(event); | ||
| // Find matching route | ||
| const route = this.findRoute(request.method, request.path); | ||
| if (!route) { | ||
| return this.createResponse(404, { error: 'Route not found' }); | ||
| } | ||
| // Validate and execute route | ||
| const result = await this.executeRoute(route, request); | ||
| // Create response | ||
| return this.createResponse(200, result, { | ||
| 'Content-Type': 'application/json', | ||
| ...this.getCorsHeaders(event) | ||
| }); | ||
| } | ||
| catch (error) { | ||
| console.error('[Lambda] Error:', error); | ||
| return this.createResponse(error.statusCode || 500, { error: error.message || 'Internal server error' }, this.getCorsHeaders(event)); | ||
| } | ||
| }; | ||
| } | ||
| /** | ||
| * Parse Lambda event to request format | ||
| */ | ||
| parseEvent(event) { | ||
| const path = event.path.replace(this.config.basePath, ''); | ||
| return { | ||
| method: event.httpMethod, | ||
| path, | ||
| params: event.pathParameters || {}, | ||
| query: event.queryStringParameters || {}, | ||
| headers: this.normalizeHeaders(event.headers || {}), | ||
| body: event.body ? this.parseBody(event.body, event.isBase64Encoded) : undefined, | ||
| rawEvent: event | ||
| }; | ||
| } | ||
| /** | ||
| * Normalize headers to lowercase | ||
| */ | ||
| normalizeHeaders(headers) { | ||
| const normalized = {}; | ||
| for (const [key, value] of Object.entries(headers)) { | ||
| normalized[key.toLowerCase()] = value; | ||
| } | ||
| return normalized; | ||
| } | ||
| /** | ||
| * Parse request body | ||
| */ | ||
| parseBody(body, isBase64Encoded) { | ||
| try { | ||
| if (isBase64Encoded) { | ||
| body = Buffer.from(body, 'base64').toString('utf-8'); | ||
| } | ||
| return JSON.parse(body); | ||
| } | ||
| catch { | ||
| return body; | ||
| } | ||
| } | ||
| /** | ||
| * Find matching route | ||
| */ | ||
| findRoute(method, path) { | ||
| // This would integrate with TypeSync router | ||
| // Simplified for now | ||
| return null; | ||
| } | ||
| /** | ||
| * Execute route handler | ||
| */ | ||
| async executeRoute(route, request) { | ||
| // This would execute the actual route handler | ||
| // with validation and all TypeSync features | ||
| return {}; | ||
| } | ||
| /** | ||
| * Create Lambda response | ||
| */ | ||
| createResponse(statusCode, body, headers = {}) { | ||
| return { | ||
| statusCode, | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| ...this.config.defaultHeaders, | ||
| ...headers | ||
| }, | ||
| body: JSON.stringify(body) | ||
| }; | ||
| } | ||
| /** | ||
| * Get CORS headers | ||
| */ | ||
| getCorsHeaders(event) { | ||
| if (!this.config.cors) { | ||
| return {}; | ||
| } | ||
| const origin = event.headers?.origin || event.headers?.Origin; | ||
| const allowedOrigin = this.getAllowedOrigin(origin); | ||
| const headers = {}; | ||
| if (allowedOrigin) { | ||
| headers['Access-Control-Allow-Origin'] = allowedOrigin; | ||
| } | ||
| if (this.config.cors.credentials) { | ||
| headers['Access-Control-Allow-Credentials'] = 'true'; | ||
| } | ||
| if (this.config.cors.methods) { | ||
| headers['Access-Control-Allow-Methods'] = this.config.cors.methods.join(', '); | ||
| } | ||
| if (this.config.cors.allowedHeaders) { | ||
| headers['Access-Control-Allow-Headers'] = this.config.cors.allowedHeaders.join(', '); | ||
| } | ||
| if (this.config.cors.exposedHeaders) { | ||
| headers['Access-Control-Expose-Headers'] = this.config.cors.exposedHeaders.join(', '); | ||
| } | ||
| if (this.config.cors.maxAge) { | ||
| headers['Access-Control-Max-Age'] = this.config.cors.maxAge.toString(); | ||
| } | ||
| return headers; | ||
| } | ||
| /** | ||
| * Get allowed origin | ||
| */ | ||
| getAllowedOrigin(origin) { | ||
| if (!this.config.cors || !origin) { | ||
| return null; | ||
| } | ||
| const { origin: allowedOrigins } = this.config.cors; | ||
| if (allowedOrigins === '*') { | ||
| return '*'; | ||
| } | ||
| if (typeof allowedOrigins === 'string') { | ||
| return allowedOrigins === origin ? origin : null; | ||
| } | ||
| return allowedOrigins.includes(origin) ? origin : null; | ||
| } | ||
| } | ||
| exports.TypeSyncLambdaAdapter = TypeSyncLambdaAdapter; | ||
| /** | ||
| * Create Lambda adapter | ||
| */ | ||
| function createLambdaAdapter(router, config) { | ||
| return new TypeSyncLambdaAdapter(router, config); | ||
| } | ||
| /** | ||
| * Wrap router for Lambda | ||
| */ | ||
| function createLambdaHandler(router, config) { | ||
| const adapter = new TypeSyncLambdaAdapter(router, config); | ||
| return adapter.handler(); | ||
| } | ||
| /** | ||
| * Lambda error response helper | ||
| */ | ||
| function lambdaError(statusCode, message, details) { | ||
| return { | ||
| statusCode, | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| body: JSON.stringify({ | ||
| error: message, | ||
| details, | ||
| timestamp: new Date().toISOString() | ||
| }) | ||
| }; | ||
| } | ||
| /** | ||
| * Lambda success response helper | ||
| */ | ||
| function lambdaSuccess(data, statusCode = 200) { | ||
| return { | ||
| statusCode, | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| body: JSON.stringify(data) | ||
| }; | ||
| } | ||
| /** | ||
| * Warm-up helper (prevents cold starts) | ||
| */ | ||
| function handleWarmUp(event) { | ||
| if (event.requestContext?.['warmup'] === 'true' || event.path === '/warmup') { | ||
| console.log('[Lambda] Warm-up request'); | ||
| return lambdaSuccess({ message: 'Lambda warmed up' }); | ||
| } | ||
| return null; | ||
| } | ||
| /** | ||
| * CORS preflight handler | ||
| */ | ||
| function handlePreflight(event, config) { | ||
| if (event.httpMethod === 'OPTIONS') { | ||
| const headers = { | ||
| 'Access-Control-Allow-Methods': config?.methods?.join(', ') || 'GET, POST, PUT, DELETE, OPTIONS', | ||
| 'Access-Control-Allow-Headers': config?.allowedHeaders?.join(', ') || 'Content-Type, Authorization', | ||
| 'Access-Control-Max-Age': (config?.maxAge || 86400).toString() | ||
| }; | ||
| if (config?.origin) { | ||
| if (typeof config.origin === 'string') { | ||
| headers['Access-Control-Allow-Origin'] = config.origin; | ||
| } | ||
| else { | ||
| const origin = event.headers?.origin || event.headers?.Origin; | ||
| if (origin && config.origin.includes(origin)) { | ||
| headers['Access-Control-Allow-Origin'] = origin; | ||
| } | ||
| } | ||
| } | ||
| if (config?.credentials) { | ||
| headers['Access-Control-Allow-Credentials'] = 'true'; | ||
| } | ||
| return { | ||
| statusCode: 200, | ||
| headers, | ||
| body: '' | ||
| }; | ||
| } | ||
| return null; | ||
| } | ||
| /** | ||
| * Compose Lambda middlewares | ||
| */ | ||
| function composeLambdaMiddlewares(...middlewares) { | ||
| return (handler) => { | ||
| return async (event, context) => { | ||
| let index = 0; | ||
| const next = async () => { | ||
| if (index < middlewares.length) { | ||
| const middleware = middlewares[index++]; | ||
| return middleware(event, context, next); | ||
| } | ||
| return handler(event, context); | ||
| }; | ||
| return next(); | ||
| }; | ||
| }; | ||
| } | ||
| /** | ||
| * Logging middleware | ||
| */ | ||
| function loggingMiddleware() { | ||
| return async (event, context, next) => { | ||
| const start = Date.now(); | ||
| console.log('[Lambda] Request:', { | ||
| method: event.httpMethod, | ||
| path: event.path, | ||
| requestId: context.awsRequestId | ||
| }); | ||
| const response = await next(); | ||
| console.log('[Lambda] Response:', { | ||
| statusCode: response.statusCode, | ||
| duration: Date.now() - start, | ||
| requestId: context.awsRequestId | ||
| }); | ||
| return response; | ||
| }; | ||
| } | ||
| /** | ||
| * Error handling middleware | ||
| */ | ||
| function errorHandlingMiddleware() { | ||
| return async (event, context, next) => { | ||
| try { | ||
| return await next(); | ||
| } | ||
| catch (error) { | ||
| console.error('[Lambda] Error:', error); | ||
| return lambdaError(error.statusCode || 500, error.message || 'Internal server error', process.env.NODE_ENV === 'development' ? error.stack : undefined); | ||
| } | ||
| }; | ||
| } |
+8
-2
| { | ||
| "name": "@type_sync/lambda", | ||
| "version": "0.1.1", | ||
| "version": "0.1.2", | ||
| "description": "AWS Lambda adapter for TypeSync - deploy type-safe APIs to serverless", | ||
@@ -58,3 +58,9 @@ "main": "./dist/index.js", | ||
| "access": "public" | ||
| } | ||
| }, | ||
| "files": [ | ||
| "dist", | ||
| "src", | ||
| "README.md", | ||
| "LICENSE" | ||
| ] | ||
| } |
| { | ||
| "compilerOptions": { | ||
| "target": "ES2020", | ||
| "module": "commonjs", | ||
| "lib": ["ES2020"], | ||
| "declaration": true, | ||
| "outDir": "./dist", | ||
| "rootDir": "./src", | ||
| "strict": true, | ||
| "esModuleInterop": true, | ||
| "skipLibCheck": true, | ||
| "forceConsistentCasingInFileNames": true, | ||
| "moduleResolution": "node", | ||
| "resolveJsonModule": true | ||
| }, | ||
| "include": ["src/**/*"], | ||
| "exclude": ["node_modules", "dist"] | ||
| } |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
25160
105.61%4
33.33%837
106.16%2
100%