{"version":3,"sources":["../../src/util/http-status-error.ts","../../src/util/api-gateway-utils.ts"],"names":[],"mappings":"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","file":"api-gateway-utils.mjs","sourcesContent":["/**\n * Throw this error to return a specific HTTP status code from an API Gateway Lambda function.\n */\nexport class HttpStatusError extends Error {\n    constructor(\n        message: string,\n        public readonly statusCode: number\n    ) {\n        super(message);\n    }\n}\n","/**\n * Utility functions and types for AWS API Gateway Lambda integration.\n * This module provides type-safe wrappers and helpers for handling\n * API Gateway events and responses in AWS Lambda functions.\n */\nimport type {\n    APIGatewayEventRequestContextV2,\n    APIGatewayProxyEventV2WithRequestContext,\n    APIGatewayProxyHandlerV2,\n    APIGatewayProxyResultV2,\n    APIGatewayProxyStructuredResultV2,\n    Context\n} from 'aws-lambda';\nimport { HttpStatusError } from './http-status-error';\n\n/**\n * Extends the standard Error interface to include an optional HTTP status code.\n * This allows for standardized error handling with appropriate HTTP responses.\n */\nexport interface HttpError extends Error {\n    statusCode?: number;\n}\n\n/**\n * A type that enhances the standard API Gateway event by replacing the body property\n * with a strongly-typed version rather than the default string representation.\n *\n * @template TRequestBody - The type of the request body after parsing\n * @template TRequestContext - The type of the request context\n */\ninterface APIGatewayProxyEventPikaWithRequestContext<TRequestBody, TRequestContext> extends Omit<APIGatewayProxyEventV2WithRequestContext<TRequestContext>, 'body'> {\n    body: TRequestBody;\n}\n\n/**\n * A specialized API Gateway event type that includes:\n * 1. A strongly-typed request body\n * 2. The standard API Gateway request context\n * 3. Additional path and httpMethod properties for routing\n *\n * @template TRequestBody - The type of the parsed request body (defaults to never if not provided)\n */\nexport type APIGatewayProxyEventPika<TRequestBody = never> = APIGatewayProxyEventPikaWithRequestContext<TRequestBody, APIGatewayEventRequestContextV2> & {\n    path: string;\n    httpMethod: string;\n    resource: string;\n};\n\n/**\n * A generic handler type for AWS Lambda functions.\n *\n * @template TEvent - The event type (input) for the handler\n * @template TResult - The result type (output) returned by the handler\n * @returns Either void or a Promise containing the result\n */\nexport type HandlerPika<TEvent = unknown, TResult = unknown> = (event: TEvent, context: Context) => void | Promise<TResult>;\n\n/**\n * A specialized handler type for API Gateway Lambda integrations with typed request and response.\n *\n * @template B - The request body type (defaults to never if not provided)\n * @template T - The response type (defaults to never if not provided)\n */\nexport type APIGatewayProxyHandlerPika<B = never, T = never> = HandlerPika<APIGatewayProxyEventPika<B>, APIGatewayProxyResultV2<T>>;\n\n/**\n * Type guard function that determines if the provided data is a structured API Gateway response.\n * A structured response must be an object containing either 'statusCode' or 'body' properties.\n *\n * @template TResponse - The expected response type\n * @param data - The data to check\n * @returns A type predicate indicating if the data is a structured API Gateway response\n */\nfunction isObjectResponse<TResponse>(data: undefined | void | APIGatewayProxyResultV2<TResponse>): data is APIGatewayProxyStructuredResultV2 {\n    return data !== null && data !== undefined && typeof data === 'object' && ('statusCode' in data || 'body' in data);\n}\n\n/**\n * A higher-order function that wraps a typed Lambda handler to provide:\n * 1. Automatic JSON parsing of the request body\n * 2. Error handling with appropriate status codes\n * 3. Consistent response formatting\n *\n * @template TRequestBody - The expected type of the request body after parsing\n * @template TResponse - The expected type of the response\n * @param fn - The Lambda handler function to wrap\n * @returns A standard API Gateway Lambda handler with error handling and type safety\n */\nexport function apiGatewayFunctionDecorator<TRequestBody, TResponse>(fn: APIGatewayProxyHandlerPika<TRequestBody, TResponse>): APIGatewayProxyHandlerV2<TResponse> {\n    return async (event, context) => {\n        let error: any; // Use 'any' to preserve original error type for instanceof checks\n        let response: undefined | void | APIGatewayProxyResultV2<TResponse>;\n\n        // Just in case, add another version of the headers with all lowercase keys;\n        // helps when running locally.  Seems APIGateway automatically converts to lowercase\n        Object.keys(event.headers).forEach((k) => {\n            let lowerK = k.toLowerCase();\n            if (!event.headers[lowerK]) {\n                event.headers[lowerK] = event.headers[k];\n            }\n        });\n        try {\n            // Parse the request body if present and create a typed event object\n            const eventWithType: APIGatewayProxyEventPika<TRequestBody> = {\n                ...(event as any),\n                body: event.body ? JSON.parse(event.body) : undefined\n            };\n\n            // Call the handler with the typed event\n            response = await fn(eventWithType, context);\n        } catch (err) {\n            // Capture any errors that occur during processing\n            error = err;\n        }\n\n        // Handle errors by returning an appropriate error response\n        if (error) {\n            console.error(error);\n\n            // Handle HttpStatusError specifically (has required statusCode property)\n            if (error instanceof HttpStatusError) {\n                return toResponse(error.message, error.statusCode);\n            }\n\n            // Handle other HttpError types (has optional statusCode property)\n            const httpError = error as HttpError;\n            const statusCode = httpError.statusCode || 500;\n            return toResponse(typeof error === 'string' ? error : error.message, statusCode);\n        }\n\n        // Return resource not found if the response is undefined\n        if (response === undefined) {\n            return toResponse(\n                {\n                    message: 'Resource not found',\n                    code: 'RESOURCE_NOT_FOUND'\n                },\n                404\n            );\n        }\n\n        // Either return the structured response directly or wrap the result in a standard response\n        return isObjectResponse(response) ? response : toResponse(response, 200);\n    };\n}\n\n/**\n * Creates a standardized API Gateway response object.\n * Handles both string and non-string body types by automatically stringifying as needed.\n *\n * @template T - The type of the response body\n * @param body - The response body to send\n * @param statusCode - The HTTP status code (defaults to 200 OK)\n * @returns A properly formatted API Gateway response object\n */\nexport function toResponse<T>(body: T, statusCode = 200): APIGatewayProxyStructuredResultV2 {\n    return {\n        body: typeof body === 'string' ? body : JSON.stringify(body),\n        statusCode\n    };\n}\n\n/**\n * Type definition for Lambda Function URL events with additional IAM authorization details.\n * Extends the standard API Gateway event with specific requestContext properties for\n * Function URL integration patterns.\n *\n * @template T - The request body type\n */\nexport type LambdaFunctionUrlProxyEventPika<T = never> = APIGatewayProxyEventPika<T> & {\n    requestContext: {\n        authorizer?: {\n            iam: {\n                cognitoIdentity?: string;\n                cognitoIdentityId?: string;\n                userId?: string;\n                user?: string;\n                callerId?: string;\n                caller?: string;\n                accessKey?: string;\n                principalOrgId?: string;\n                accountId?: string;\n                userArn?: string;\n                [key: string]: any;\n            };\n        };\n        identity?: {\n            cognitoIdentity?: string;\n            cognitoIdentityId?: string;\n            user?: string;\n            userId?: string;\n            caller?: string;\n            callerId?: string;\n            accessKey?: string;\n            principalOrgId?: string;\n            accountId?: string;\n            userArn?: string;\n            [key: string]: any;\n        };\n    };\n};\n\n/**\n * Converts a Lambda Function URL event into a standardized API Gateway event.\n * This function ensures that IAM authorization details are properly mapped\n * from the authorizer to the identity property for consistent access patterns.\n *\n * Also, parses the body string into the generic type T if it exists and is a string\n *\n * This exists because the Lambda Function URL event has a different structure\n * than the API Gateway event and we almost never use Lambdas that are Function URL based\n * and so it's easier to just convert the event to a standard API Gateway event than\n * to handle the different event types.\n *\n * @template T - The request body type\n * @param event - The Lambda Function URL event to convert\n * @returns A standardized API Gateway event\n */\nexport function convertFunctionUrlEventToStandardApiGatewayEvent<T>(event: LambdaFunctionUrlProxyEventPika<T>): APIGatewayProxyEventPika<T> {\n    if (event.requestContext.identity == null && event.requestContext.authorizer?.iam != null) {\n        event.requestContext.identity = event.requestContext.authorizer.iam;\n        event.requestContext.authorizer.iam.cognitoIdentityId = event.headers['cognito-identity-id'];\n        event.requestContext.authorizer.iam.user = event.requestContext.authorizer.iam.userId;\n        event.requestContext.authorizer.iam.caller = event.requestContext.authorizer.iam.callerId;\n    }\n\n    // Parse the body string into the generic type T if it exists and is a string\n    if (event.body && typeof event.body === 'string') {\n        try {\n            // If content-type is not application/json, don't attempt to parse\n            const contentType = event.headers['content-type'] || event.headers['Content-Type'];\n            if (contentType && contentType.includes('application/json')) {\n                event.body = JSON.parse(event.body) as T;\n            }\n        } catch (error) {\n            console.error('Error parsing request body as JSON:', {\n                body: event.body,\n                errorMessage: error instanceof Error ? error.message : String(error),\n                errorStack: error instanceof Error ? error.stack : undefined\n            });\n            throw error;\n        }\n    }\n\n    return event;\n}\n"]}