Skip to content

@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.

typescript
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:

typescript
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 detailType and eventSource
  • 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.

typescript
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:

typescript
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.

typescript
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 (ColdStart metric)
  • Logger context injection (operation name, Lambda context)
  • Correlation ID extraction and propagation
  • X-Ray tracing span per invocation
  • <OperationName>Attempt and <OperationName>Success CloudWatch metrics
  • Automatic metrics.publishStoredMetrics() in finally block

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.

typescript
@RequiresDatabase([{ table: 'users', actions: ['read', 'write'] }])
class UserQueries { ... }

@RequiresServices(services)

Class decorator that declares AWS service permissions for IAM policy extraction.

typescript
@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()).

typescript
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.

typescript
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.

typescript
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.

typescript
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.

typescript
interface ApiHandlerParams<TEvent = APIGatewayProxyEvent> {
  event: TEvent
  context: Context
  metadata: WrapperMetadata
}

ValidatedApiParams<TBody>

Parameters passed to API Gateway handlers with body validation.

typescript
interface ValidatedApiParams<TBody, TEvent = APIGatewayProxyEvent> {
  event: TEvent
  context: Context
  metadata: WrapperMetadata
  body: TBody
}

EventBridgeHandlerParams<TDetailType, TDetail>

Parameters passed to EventBridge handler functions.

typescript
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.

typescript
interface ScheduledHandlerParams {
  event: ScheduledEvent
  context: Context
  metadata: WrapperMetadata
}

EventBridgeResult

typescript
interface EventBridgeResult {
  processed?: number
  detailType?: string
  [key: string]: unknown
}

ScheduledResult

typescript
interface ScheduledResult {
  processed?: number
  deleted?: number
  [key: string]: unknown
}

Configuration

defineConfig(config)

Type-safe project configuration for mantle.config.ts.

typescript
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

typescript
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

typescript
interface EventBridgeConfig {
  bus: string
}

StorageBucketConfig

typescript
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.

typescript
import { defineLambda } from '@mantleframework/core'

// Only needed for standalone handlers
defineLambda({
  timeout: 60,
  memorySize: 256,
  deadLetterQueue: true,
  retryAttempts: 2,
})

LambdaConfig

typescript
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.