npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

cdk-serverless-agentic-api

v0.5.3

Published

CDK construct for serverless web applications with CloudFront, S3, Cognito, API Gateway, and Lambda

Readme

CDK Serverless Agentic API

A CDK construct that simplifies the creation of serverless web applications on AWS by providing a comprehensive solution that integrates CloudFront, S3, Cognito, API Gateway, and Lambda functions.

npm version License: MIT Build and Publish constructs.dev

Overview

The CDK Serverless Agentic API is a high-level CDK construct that helps you deploy a complete serverless web application infrastructure on AWS with minimal configuration. It combines several AWS services into a cohesive architecture:

Important Note for TypeScript Users: If you encounter TypeScript errors related to incompatible Construct types, you may need to ensure your project uses the same version of the constructs package as this library. Add "skipLibCheck": true to your tsconfig.json file's compilerOptions to resolve these issues.

  • CloudFront for global content delivery with SSL/TLS
  • S3 for static website hosting
  • Cognito for user authentication and management
  • API Gateway for RESTful API endpoints
  • Lambda for serverless backend logic

This construct follows AWS best practices for security, performance, and cost optimization.

Architecture

┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│               │     │               │     │               │
│   CloudFront  │────▶│  S3 Bucket    │     │   Cognito     │
│  Distribution │     │ (Static Site) │     │  User Pool    │
│               │     │               │     │               │
└───────┬───────┘     └───────────────┘     └───────┬───────┘
        │                                           │
        │                                           │
        ▼                                           │
┌───────────────┐                                   │
│               │                                   │
│  API Gateway  │◀──────────────────────────────────┘
│    REST API   │          Authorizes
│               │
└───────┬───────┘
        │
        │
        ▼
┌───────────────┐
│               │
│    Lambda     │
│   Functions   │
│               │
└───────────────┘

Requirements

  • Node.js: 22.0.0 or higher (LTS recommended)
  • npm: 8.0.0 or higher
  • AWS CDK: 2.170.0 or higher

Quick Start

import { CDKServerlessAgenticAPI } from 'cdk-serverless-agentic-api';
import { Stack } from 'aws-cdk-lib';

export class MyStack extends Stack {
  constructor(scope, id, props) {
    super(scope, id, props);
    
    // Create the serverless API with default settings
    const api = new CDKServerlessAgenticAPI(this, 'MyApi');
    
    // Add an endpoint
    api.addResource({
      path: '/hello',
      lambdaSourcePath: './lambda/hello',
      requiresAuth: false
    });
  }
}

Installation

TypeScript / JavaScript

cdk init app --language typescript

# npm
npm install cdk-serverless-agentic-api

Project Structure

├── src/
│   ├── index.ts                          # Main export file
│   ├── cdk-serverless-agentic-api.ts     # Core construct implementation
│   ├── types.ts                          # TypeScript interfaces and types
│   ├── error-handling.ts                 # Error handling utilities
│   └── security-validation.ts            # Security validation utilities
├── test/
│   ├── cdk-serverless-agentic-api.test.ts  # Unit tests
│   ├── integration/                      # Integration tests
│   └── lambda/                           # Lambda function tests
├── lambda/
│   ├── health/                           # Default health check endpoint
│   └── whoami/                           # Default authentication endpoint
├── lib/                                  # Compiled JavaScript output (generated)
├── package.json                          # Project dependencies and scripts
├── tsconfig.json                         # TypeScript configuration
├── vitest.config.ts                      # Test configuration
├── .eslintrc.js                          # ESLint configuration
└── README.md                             # This file

Development

Prerequisites

  • Node.js 22+
  • npm or yarn
  • AWS CDK v2

Installation

npm install

Building

npm run build

Testing

# Run tests once
npm test

# Run tests in watch mode
npm run test:watch

# Run integration tests
npm run test:integration

Linting

# Check for linting issues
npm run lint

# Fix linting issues automatically
npm run lint:fix

Usage

Basic Usage

import { CDKServerlessAgenticAPI } from 'cdk-serverless-agentic-api';
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class MyStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const webApp = new CDKServerlessAgenticAPI(this, 'MyWebApp');

    // Add API resources
    webApp.addResource({
      path: '/users',
      lambdaSourcePath: './lambda/users',
      requiresAuth: true
    });
  }
}

Custom Domain Configuration

const webApp = new CDKServerlessAgenticAPI(this, 'MyWebApp', {
  domainName: 'example.com',
  certificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012'
});

Adding API Resources

// Public endpoint (no authentication required)
webApp.addResource({
  path: '/products',
  lambdaSourcePath: './lambda/products',
  requiresAuth: false
});

// Authenticated endpoint
webApp.addResource({
  path: '/users',
  lambdaSourcePath: './lambda/users',
  requiresAuth: true
});

// Specific HTTP method
webApp.addResource({
  path: '/orders',
  method: 'POST',
  lambdaSourcePath: './lambda/create-order',
  requiresAuth: true
});

// With environment variables
webApp.addResource({
  path: '/payments',
  lambdaSourcePath: './lambda/payments',
  requiresAuth: true,
  environment: {
    STRIPE_API_KEY: process.env.STRIPE_API_KEY || '',
    PAYMENT_MODE: 'test'
  }
});

// With Dead Letter Queue enabled
webApp.addResource({
  path: '/critical',
  lambdaSourcePath: './lambda/critical',
  requiresAuth: true,
  enableDLQ: true  // Enable DLQ for failed invocations
});

// With health alarms enabled
webApp.addResource({
  path: '/monitored',
  lambdaSourcePath: './lambda/monitored',
  requiresAuth: false,
  enableHealthAlarms: true  // Enable CloudWatch alarms
});

Accessing Lambda Functions

// Access Lambda functions using the new getLambdaFunction method
const usersFunction = webApp.getLambdaFunction('/users', 'GET');
if (usersFunction) {
  // Grant additional permissions
  myDynamoTable.grantReadWriteData(usersFunction);
  
  // Add event source mappings
  usersFunction.addEventSource(new SqsEventSource(myQueue));
}

// Use the helper method for DynamoDB permissions
const createUserFunction = webApp.addResource({
  path: '/users',
  method: 'POST',
  lambdaSourcePath: './lambda/create-user',
  requiresAuth: true
});

// Grant DynamoDB access using the helper method
webApp.grantDynamoDBAccess(createUserFunction, myTable, 'readwrite');

Security Validation

// Validate security configuration
const securityResults = webApp.validateSecurity();

// Check results
securityResults.forEach(result => {
  if (!result.passed) {
    console.warn(`Security issue: ${result.message}`);
    console.warn(`Details: ${JSON.stringify(result.details)}`);
  }
});

// Validate with custom options
webApp.validateSecurity({
  throwOnFailure: true,  // Throw error if validation fails
  logResults: true       // Log results to console
});

API Reference

Key Methods

// Add an API endpoint with Lambda integration
const userFunction = api.addResource({
  path: '/users',
  method: 'GET',
  lambdaSourcePath: './lambda/users',
  requiresAuth: true
});

// Get a Lambda function by path and method
const getUsersFunction = api.getLambdaFunction('/users', 'GET');

// Create a standalone Lambda function
const processor = api.createLambdaFunction(
  'DataProcessor',
  './lambda/processor',
  { BUCKET_NAME: api.bucket?.bucketName }
);

// Grant DynamoDB access to a Lambda function
api.grantDynamoDBAccess(userFunction, myTable, 'readwrite');

// Get exportable resource IDs for extension stacks
const resourceIds = api.getExportableResourceIds();

// Validate security configuration
api.validateSecurity({ throwOnFailure: true });

// Apply security best practices
api.enforceSecurityBestPractices();

Key Properties

// Access underlying AWS resources
api.bucket                // S3 bucket for static files
api.distribution          // CloudFront distribution
api.api                   // API Gateway REST API
api.userPool              // Cognito User Pool
api.lambdaFunctions       // Map of all Lambda functions

For complete API documentation, see API_REFERENCE.md

CDKServerlessAgenticAPIProps

Configuration properties for the CDKServerlessAgenticAPI.

| Property | Type | Required | Default | Description | | ------------------ | --------- | ------------------------------ | ----------------------------- | ----------------------------------------------------------------------------------------- | | domainName | string | No | CloudFront generated domain | Custom domain name for the CloudFront distribution | | certificateArn | string | Only if domainName is provided | - | ARN of the SSL certificate for the custom domain | | bucketName | string | No | CDK generated name | Custom name for the S3 bucket | | userPoolName | string | No | CDK generated name | Custom name for the Cognito User Pool | | apiName | string | No | CDK generated name | Custom name for the API Gateway | | enableLogging | boolean | No | true | Enable detailed logging for all components | | lambdaSourcePath | string | No | Bundled lambda directory | Custom path to the directory containing Lambda function source code for default endpoints | | errorPagesPath | string | No | Bundled error-pages directory | Custom path to the directory containing error page HTML files |

AddResourceOptions

Options for adding a new API resource to the construct.

| Property | Type | Required | Default | Description | | ------------------ | --------------------------- | -------- | ------- | ---------------------------------------------------------------- | | path | string | Yes | - | The API path for the resource (e.g., '/users', '/products') | | method | string | No | 'GET' | HTTP method for the resource | | lambdaSourcePath | string | Yes | - | Path to the directory containing the Lambda function source code | | requiresAuth | boolean | No | false | Whether the resource requires authentication | | cognitoGroup | string | No | - | Cognito group required to access this resource | | environment | { [key: string]: string } | No | - | Environment variables to pass to the Lambda function | | enableDLQ | boolean | No | false | Whether to enable Dead Letter Queue for the Lambda function | | enableHealthAlarms | boolean | No | false | Whether to enable health alarms for the Lambda function |

Lambda Function Structure

When adding resources with addResource, you need to provide a Lambda function source directory. The directory should have the following structure:

lambda/
└── my-function/
    ├── index.js        # Main handler file
    ├── package.json    # Dependencies
    └── node_modules/   # Installed dependencies (optional)

The index.js file should export a handler function:

exports.handler = async (event, context) => {
  // Your Lambda function code
  return {
    statusCode: 200,
    headers: {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*'
    },
    body: JSON.stringify({
      message: 'Hello from Lambda!'
    })
  };
};

Default Endpoints

The construct automatically creates three default endpoints:

  1. Health Check (/api/health): A public endpoint that returns a 200 OK response
  2. WhoAmI (/api/whoami): An authenticated endpoint that returns the current user's Cognito claims
  3. Config (/api/config): A public endpoint that provides frontend configuration information

Using the Config Endpoint

The config endpoint returns essential information needed by frontend applications to connect to the backend services:

// Example of fetching configuration from the config endpoint
async function fetchConfig() {
  const response = await fetch('https://your-api-url.com/api/config');
  const config = await response.json();
  
  // Use the configuration to set up your frontend app
  // This avoids hardcoding values from CDK outputs
  return config;
}

// Example response structure
{
  "auth": {
    "region": "us-east-1",
    "userPoolId": "us-east-1_abcdefghi",
    "userPoolWebClientId": "1234567890abcdefghijklmnop",
    "oauth": {
      "domain": "your-domain.auth.us-east-1.amazoncognito.com",
      "scope": ["email", "profile", "openid"],
      "redirectSignIn": "",
      "redirectSignOut": "",
      "responseType": "code"
    }
  },
  "api": {
    "endpoints": [
      {
        "name": "api",
        "endpoint": "https://api-id.execute-api.us-east-1.amazonaws.com/api",
        "region": "us-east-1"
      }
    ]
  },
  "version": "1.0.0"
}

Important: Always use the config endpoint instead of hardcoding values from CDK outputs. This ensures your frontend application can adapt to changes in the backend infrastructure.

Customizing Default Resources

The construct comes with bundled Lambda functions and error pages that are used by default. However, you can customize these resources by providing your own paths.

Custom Lambda Functions

You can provide your own Lambda functions for the default endpoints (health, whoami, config) by specifying the lambdaSourcePath property:

const webApp = new CDKServerlessAgenticAPI(this, 'MyWebApp', {
  lambdaSourcePath: './my-custom-lambda'
});

Your custom Lambda directory should have the following structure:

my-custom-lambda/
├── health/
│   └── index.js
├── whoami/
│   └── index.js
└── config/
    └── index.js

Custom Error Pages

You can provide your own error pages by specifying the errorPagesPath property:

const webApp = new CDKServerlessAgenticAPI(this, 'MyWebApp', {
  errorPagesPath: './my-custom-error-pages'
});

Your custom error pages directory should have the following structure:

my-custom-error-pages/
├── 400.html
├── 403.html
├── 404.html
└── 500.html

Note: If you don't provide custom paths, the construct will use the bundled Lambda functions and error pages that come with the package.

Extension Mode (Multi-Stack Support)

For large applications that exceed the 500 resource limit per stack, you can use extension mode to split resources across multiple stacks while sharing core infrastructure.

Main Stack

// Create the main stack with core infrastructure
const mainStack = new CDKServerlessAgenticAPI(this, 'MainAPI', {
  domainName: 'example.com',
  certificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012'
});

// Add some API resources
mainStack.addResource({
  path: '/users',
  lambdaSourcePath: './lambda/users',
  requiresAuth: true
});

// Export resource IDs for use in extension stacks
const resourceIds = mainStack.getExportableResourceIds();

Extension Stack

// Create an extension stack that reuses the main stack's infrastructure
const extensionStack = new CDKServerlessAgenticAPI(this, 'ExtensionAPI', {
  extensionMode: {
    apiId: resourceIds.apiId,
    userPoolId: resourceIds.userPoolId,
    userPoolClientId: resourceIds.userPoolClientId,
    cognitoAuthorizerId: resourceIds.cognitoAuthorizerId
  },
  skipResources: {
    skipBucket: true,           // Don't create S3 bucket
    skipDistribution: true,     // Don't create CloudFront distribution
    skipDefaultEndpoints: true, // Don't create default endpoints
    skipLoggingBucket: true     // Don't create logging bucket
  }
});

// Add additional API resources to the extension stack
extensionStack.addResource({
  path: '/products',
  lambdaSourcePath: './lambda/products',
  requiresAuth: true
});

Security Best Practices

The construct implements several security best practices:

  • HTTPS Enforcement: All traffic is encrypted in transit
  • S3 Bucket Security: Public access blocking, encryption at rest
  • IAM Least Privilege: Minimal permissions for Lambda functions
  • Cognito Authentication: JWT-based authentication for API endpoints
  • CORS Configuration: Secure cross-origin resource sharing
  • Security Headers: HTTP security headers for CloudFront

Examples

Complete Example with Custom Domain

import { CDKServerlessAgenticAPI } from 'cdk-serverless-agentic-api';
import { Stack, StackProps, App } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';

class MyWebAppStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // Create DynamoDB table for the application
    const table = new dynamodb.Table(this, 'UsersTable', {
      partitionKey: { name: 'userId', type: dynamodb.AttributeType.STRING },
      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST
    });

    // Create the serverless web app construct
    const webApp = new CDKServerlessAgenticAPI(this, 'MyWebApp', {
      domainName: 'example.com',
      certificateArn: 'arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012',
      enableLogging: true
    });

    // Add API resources
    const getUsersFunction = webApp.addResource({
      path: '/users',
      method: 'GET',
      lambdaSourcePath: './lambda/get-users',
      requiresAuth: true,
      environment: {
        TABLE_NAME: table.tableName
      }
    });

    const createUserFunction = webApp.addResource({
      path: '/users',
      method: 'POST',
      lambdaSourcePath: './lambda/create-user',
      requiresAuth: true,
      environment: {
        TABLE_NAME: table.tableName
      }
    });

    // Grant permissions to Lambda functions
    table.grantReadData(getUsersFunction);
    table.grantWriteData(createUserFunction);
  }
}

const app = new App();
new MyWebAppStack(app, 'MyWebAppStack');
app.synth();

Example with Security Validation

import { CDKServerlessAgenticAPI } from 'cdk-serverless-agentic-api';
import { Stack, StackProps, App } from 'aws-cdk-lib';
import { Construct } from 'constructs';

class SecureWebAppStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // Create the serverless web app construct
    const webApp = new CDKServerlessAgenticAPI(this, 'SecureWebApp');

    // Add API resources
    webApp.addResource({
      path: '/secure-data',
      lambdaSourcePath: './lambda/secure-data',
      requiresAuth: true
    });

    // Validate security configuration
    const securityResults = webApp.validateSecurity({
      throwOnFailure: true,  // Throw error if validation fails
      logResults: true       // Log results to console
    });

    // Output security validation results
    new cdk.CfnOutput(this, 'SecurityValidationResults', {
      value: JSON.stringify(securityResults.map(r => ({
        component: r.message,
        passed: r.passed
      })))
    });
  }
}

const app = new App();
new SecureWebAppStack(app, 'SecureWebAppStack');
app.synth();

Deployment Guide

Prerequisites

  1. Install the AWS CLI and configure your credentials:

    aws configure
  2. Install the AWS CDK:

    npm install -g aws-cdk
  3. Bootstrap your AWS environment (if not already done):

    cdk bootstrap aws://ACCOUNT-NUMBER/REGION

Deployment Steps

  1. Create a new CDK project:

    mkdir my-serverless-app
    cd my-serverless-app
    cdk init app --language typescript
  2. Install the cdk-serverless-agentic-api:

    npm install cdk-serverless-agentic-api
  3. Update your stack code to use the construct (see examples above)

  4. Deploy the stack:

    cdk deploy
  5. After deployment, the CDK will output the CloudFront domain name and other important information.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Troubleshooting

TypeScript Errors with Constructs

If you encounter TypeScript errors like this:

TS2345: Argument of type 'this' is not assignable to parameter of type 'Construct'.
Type 'YourStack' is not assignable to type 'Construct'.
Types of property 'node' are incompatible.

This is due to a version mismatch between the constructs package in your project and the one used by this library. To fix this, you can:

  1. Use version 0.3.15 or later of this library, which has a more flexible type definition that avoids this issue.

  2. Add "skipLibCheck": true to your tsconfig.json file's compilerOptions:

{
  "compilerOptions": {
    // other options...
    "skipLibCheck": true
  }
}
  1. Ensure you're using a compatible version of the constructs package:
npm install constructs@^10.0.0
  1. If you're using AWS CDK v2, make sure you're using the correct imports:
import { Construct } from 'constructs';
import * as cdk from 'aws-cdk-lib';
import { CDKServerlessAgenticAPI } from 'cdk-serverless-agentic-api';

export class MyStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    
    const api = new CDKServerlessAgenticAPI(this, 'AgenticAPI');
  }
}

License

This project is licensed under the MIT License - see the LICENSE file for details.