@mantleframework/core
The core package provides handler factory functions, the withObservability() utility, decorators, response helpers, and shared types for Lambda development.
Handler Functions
defineEventBridgeHandler()
Create a fully-observable EventBridge Lambda handler with typed detail-type extraction.
import { defineEventBridgeHandler } from '@mantleframework/core'
function defineEventBridgeHandler<TDetailType extends string, TDetail = unknown>(
options: {
detailTypes: TDetailType[] // Detail types this handler responds to
source?: string // Event source for filtering (informational)
operationName?: string // Metrics/tracing name (default: handler function name or 'EventBridgeHandler')
timeout?: number // Lambda timeout in seconds
memorySize?: number // Lambda memory in MB
reservedConcurrency?: number // Reserved concurrent executions
ephemeralStorage?: number // Ephemeral storage in MB
deadLetterQueue?: boolean | { targetArn?: string }
retryAttempts?: number // 0-2
}
): (handler: (params: EventBridgeHandlerParams<TDetailType, TDetail>) => Promise<EventBridgeResult>) => (event: EventBridgeEvent<TDetailType, TDetail>, context: Context) => Promise<EventBridgeResult>Usage:
import { defineEventBridgeHandler } from '@mantleframework/core'
const eb = defineEventBridgeHandler({ detailTypes: ['ExportHealthData'], timeout: 60, operationName: 'ExportHealthData' })
export const handler = eb(async ({ detail, detailType, source, context }) => {
const data = await HealthQueries.getTodayData()
await exportToS3('health-export.json', data)
return { processed: 1, detailType }
})Built-in behaviour:
- X-Ray annotations for
detailTypeandeventSource - Structured log entry with detail type and source
- Full observability via
withObservability()
defineScheduledHandler()
Create a fully-observable scheduled Lambda handler for CloudWatch cron/rate events.
import { defineScheduledHandler } from '@mantleframework/core'
function defineScheduledHandler(
options: {
operationName?: string // Metrics/tracing name (default: handler function name or 'ScheduledHandler')
schedule?: {
expression: string // 'rate(6 hours)' | 'cron(0 12 * * ? *)'
enabled?: boolean // Default: true
}
timeout?: number // Lambda timeout in seconds
memorySize?: number // Lambda memory in MB
reservedConcurrency?: number // Reserved concurrent executions
ephemeralStorage?: number // Ephemeral storage in MB
deadLetterQueue?: boolean | { targetArn?: string }
retryAttempts?: number // 0-2
}
): (handler: (params: ScheduledHandlerParams) => Promise<ScheduledResult>) => (event: ScheduledEvent, context: Context) => Promise<ScheduledResult>Usage:
import { defineScheduledHandler } from '@mantleframework/core'
const scheduled = defineScheduledHandler({ schedule: { expression: 'rate(6 hours)' }, timeout: 300, operationName: 'DailyCleanup' })
export const handler = scheduled(async ({ event, context }) => {
const deleted = await cleanupExpiredRecords()
return { deleted, processed: deleted }
})withObservability()
Internal utility that wraps any handler with full observability. This is used internally by all define*Handler functions -- you do not need to call it directly.
function withObservability<TEvent, TResult>(
options: { operationName: string },
handler: (event: TEvent, context: Context, metadata: WrapperMetadata) => Promise<TResult>
): (event: TEvent, context: Context) => Promise<TResult>Provides:
- Cold start detection (
ColdStartmetric) - Logger context injection (operation name, Lambda context)
- Correlation ID extraction and propagation
- X-Ray tracing span per invocation
<OperationName>Attemptand<OperationName>SuccessCloudWatch metrics- Automatic
metrics.publishStoredMetrics()infinallyblock
Decorators
Stage 3 decorators (no experimentalDecorators).
@RequiresDatabase(tables)
Class decorator that declares database table permissions for IAM policy extraction. Used on entity query classes or handler-adjacent code.
@RequiresDatabase([{ table: 'users', actions: ['read', 'write'] }])
class UserQueries { ... }@RequiresServices(services)
Class decorator that declares AWS service permissions for IAM policy extraction.
@RequiresServices([{ service: 'sqs', actions: ['sendMessage'], resource: '*' }])
class NotificationService { ... }@Traced(spanName?)
Method decorator that wraps a method with an OpenTelemetry span. Used on entity query methods and service functions -- not on handler functions (handlers get tracing automatically via withObservability()).
class UserQueries {
@Traced('getUserById')
static async getUserById(id: string) { ... }
}@LogMetrics(options?)
Method decorator that publishes CloudWatch metrics. Used internally -- handler functions get metrics automatically.
@InjectContext()
Method decorator that injects Lambda context into the Powertools logger. Used internally -- handler functions get context injection automatically.
getDatabasePermissions(target)
Extract database permission declarations from a decorated class (used by CLI for IAM policy generation).
getServicePermissions(target)
Extract service permission declarations from a decorated class.
Response Helpers
buildValidatedResponse(context, statusCode, body, schema)
Build a response and validate the body against a Zod schema before sending. This is the recommended response builder for all API handlers.
import { buildValidatedResponse } from '@mantleframework/core'
import { z } from '@mantleframework/validation'
const ResponseSchema = z.object({ items: z.array(z.object({ id: z.string() })) })
return buildValidatedResponse(context, 200, { items }, ResponseSchema)buildResponse(context, statusCode, body?, headers?)
Build a standard API Gateway response with correlation headers. Use when response validation is not needed.
return buildResponse(context, 204)
return buildResponse(context, 200, { message: 'ok' })buildErrorResponse(context, error, metadata?, requestInfo?)
Build an error response from a thrown error. Maps error types to HTTP status codes automatically. Used internally by defineApiHandler.
sanitizeErrorMessage(message)
Strip sensitive information from error messages before sending to clients.
getErrorMessage(error)
Safely extract an error message string from an unknown error value.
Types
WrapperMetadata
Metadata passed to all wrapped handlers for distributed tracing.
interface WrapperMetadata {
traceId: string // AWS request ID for this Lambda invocation
correlationId: string // Correlation ID for end-to-end request tracing
}ApiHandlerParams
Parameters passed to API Gateway handlers without body validation.
interface ApiHandlerParams<TEvent = APIGatewayProxyEvent> {
event: TEvent
context: Context
metadata: WrapperMetadata
}ValidatedApiParams<TBody>
Parameters passed to API Gateway handlers with body validation.
interface ValidatedApiParams<TBody, TEvent = APIGatewayProxyEvent> {
event: TEvent
context: Context
metadata: WrapperMetadata
body: TBody
}EventBridgeHandlerParams<TDetailType, TDetail>
Parameters passed to EventBridge handler functions.
interface EventBridgeHandlerParams<TDetailType extends string, TDetail> {
event: EventBridgeEvent<TDetailType, TDetail>
context: Context
metadata: WrapperMetadata
detailType: TDetailType
detail: TDetail
source: string
}ScheduledHandlerParams
Parameters passed to scheduled handler functions.
interface ScheduledHandlerParams {
event: ScheduledEvent
context: Context
metadata: WrapperMetadata
}EventBridgeResult
interface EventBridgeResult {
processed?: number
detailType?: string
[key: string]: unknown
}ScheduledResult
interface ScheduledResult {
processed?: number
deleted?: number
[key: string]: unknown
}Configuration
defineConfig(config)
Type-safe project configuration for mantle.config.ts.
import { defineConfig } from '@mantleframework/core'
export default defineConfig({
name: 'my-app',
database: { provider: 'aurora-dsql' },
eventbridge: { bus: 'my-app-events' },
storage: [{
name: 'uploads',
cloudfront: true,
corsOrigins: ['https://example.com'],
}],
})MantleConfig
interface MantleConfig {
name: string
database?: { provider: 'aurora-dsql' | 'aurora-serverless-v2' | 'neon' }
auth?: { provider: string }
features?: { observability?: boolean; resilience?: boolean }
storage?: StorageBucketConfig[]
eventbridge?: EventBridgeConfig
}EventBridgeConfig
interface EventBridgeConfig {
bus: string
}StorageBucketConfig
interface StorageBucketConfig {
name: string
cloudfront?: boolean
cloudfrontPriceClass?: string
corsOrigins?: string[]
corsMethods?: string[]
responseHeaders?: {
corsOrigins?: string[]
corsMethods?: string[]
maxAgeSec?: number
}
intelligentTiering?: boolean
versioning?: boolean
}defineLambda(config)
Build-time macro for per-Lambda configuration. No-op at runtime -- the CLI extracts config via ts-morph AST analysis.
For EventBridge and scheduled handlers, LambdaConfig properties are passed directly as options to defineEventBridgeHandler and defineScheduledHandler. defineLambda() is only needed for standalone handlers that have no corresponding define*Handler call.
import { defineLambda } from '@mantleframework/core'
// Only needed for standalone handlers
defineLambda({
timeout: 60,
memorySize: 256,
deadLetterQueue: true,
retryAttempts: 2,
})LambdaConfig
interface LambdaConfig {
timeout?: number
memorySize?: number // Default: 128
reservedConcurrency?: number
ephemeralStorage?: number // Default: 512
schedule?: {
expression: string // 'rate(6 hours)' | 'cron(0 12 * * ? *)'
enabled?: boolean // Default: true
}
eventbridge?: {
detailTypes: string[]
}
deadLetterQueue?: boolean | {
targetArn?: string
}
retryAttempts?: number // 0-2
}Utility Functions
extractCorrelationId(event, context)
Extract or generate a correlation ID from any event type (API Gateway, SQS, EventBridge, S3, Scheduled).
appendCorrelationToLogger(correlationId, traceId)
Append correlation and trace IDs to the Powertools logger context.
validateStaticBearerToken(event, expectedToken)
Validate a static bearer token from an API Gateway event's Authorization header. Throws UnauthorizedError if the token is missing or does not match.