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

commoneventframework

v1.0.7

Published

Common Event Framework for Lambda AWS

Readme

Common Event Framework (CEF)

Framework Node.js pour AWS Lambda qui normalise les différents types d'événements AWS (API Gateway v1/v2, S3, SQS, SNS, invocation directe) en un CommonEvent unique, et route automatiquement les requêtes vers les handlers déclarés dans un fichier OpenAPI YAML.

Installation

npm install commoneventframework

Initialiser un projet

La commande cef-init génère automatiquement toute la structure d'un projet prêt à l'emploi :

npx cef-init

Cela crée les fichiers suivants dans le répertoire courant :

my-lambda/
├── src/
│   ├── index.ts              # Point d'entrée Lambda
│   ├── root.yaml             # Définition des routes OpenAPI
│   └── handlers/
│       ├── types.ts          # Types HandlerFn / InputParserFn
│       └── hello.ts          # Handler exemple (GET /hello, GET /hello/:name)
├── .env
├── package.json
└── tsconfig.json

Les fichiers existants ne sont pas écrasés. Utilisez --force pour forcer la réécriture :

npx cef-init --force

Ensuite :

npm install
npm run dev          # Serveur local sur localhost:8888
npm run build:full   # Bundle + ZIP pour AWS Lambda

Démarrage rapide (manuel)

1. Créer le fichier root.yaml

Créez un fichier root.yaml à côté de votre point d'entrée (src/index.ts). C'est un document OpenAPI 3.0 standard, enrichi de deux extensions custom :

  • x-handler : référence vers la fonction handler au format fichier#fonction
  • x-inputParser (optionnel) : référence vers la fonction de parsing/validation des entrées
openapi: 3.0.3
info:
  title: Mon API
  version: 1.0.0
paths:
  /hello:
    get:
      x-handler: handlers/hello#getHello
      summary: Retourne un message de bienvenue
      responses:
        '200':
          description: Succès

  /users/:id:
    get:
      x-handler: handlers/users#getUser
      x-inputParser: handlers/users#parseGetUserInput
      summary: Récupère un utilisateur par ID
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Utilisateur trouvé
        '400':
          description: Paramètre manquant
        '404':
          description: Utilisateur non trouvé

Note : les path parameters utilisent la syntaxe :param (ex. /users/:id), compatible avec le moteur de matching path-parser.

2. Créer le point d'entrée src/index.ts

import { loadEnv } from "commoneventframework";
loadEnv();

import {
  APIGatewayProxyStructuredResultV2,
  Context,
  buildCommonEvent,
  getRouteConfig,
  resolveHandlerRef,
  Response,
  setLambdaContext
} from "commoneventframework";
import { CommonEvent, LambdaEvent } from "commoneventframework/dist/types/commonEvent";

export const handler = async (
  event: LambdaEvent,
  context: Context
): Promise<APIGatewayProxyStructuredResultV2> => {
  setLambdaContext(context);
  const commonEvent: CommonEvent = await buildCommonEvent(event);

  try {
    const routeConfig = getRouteConfig(commonEvent);

    if (!routeConfig || !routeConfig.handler) {
      return new Response(404, { error: "Route not found" });
    }

    const handlerFn = resolveHandlerRef(routeConfig.handler);
    const parserFn = routeConfig.inputParser
      ? resolveHandlerRef(routeConfig.inputParser)
      : undefined;

    if (!handlerFn) {
      return new Response(500, { error: `Handler "${routeConfig.handler}" not found` });
    }

    const input = parserFn ? parserFn(commonEvent) : {};
    if (input instanceof Response) return input;

    const result = await handlerFn(input, commonEvent);

    if (result && 'statusCode' in result) {
      return result as APIGatewayProxyStructuredResultV2;
    }
    return new Response(200, result as object);
  } catch (err) {
    return new Response(500, err as object);
  }
};

// Serveur de développement local
if (process.argv.includes("--local")) {
  const { startDevServer } = require("commoneventframework");
  startDevServer(handler);
}

3. Définir les handlers

Chaque handler est un fichier TypeScript dans src/handlers/ qui exporte une fonction handler et optionnellement une fonction inputParser.

Types

import { CommonEvent } from "commoneventframework/dist/types/commonEvent";
import { APIGatewayProxyStructuredResultV2 } from "commoneventframework";

type InputParserFn = (event: CommonEvent) => any;
type HandlerFn = (input: any, event: CommonEvent) => Promise<APIGatewayProxyStructuredResultV2 | object>;

Exemple : src/handlers/hello.ts

import { HandlerFn } from "./types";

export const getHello: HandlerFn = async () => {
  return { message: "Bonjour !" };
};

Le résultat est automatiquement enveloppé dans une Response(200, ...) par le point d'entrée.

Exemple avec inputParser : src/handlers/users.ts

import { CommonEvent } from "commoneventframework/dist/types/commonEvent";
import { Response } from "commoneventframework";
import { InputParserFn, HandlerFn } from "./types";

interface GetUserInput {
  id: string;
}

export const parseGetUserInput: InputParserFn = (event: CommonEvent) => {
  const id = event.pathParameters?.id;
  if (!id) {
    return new Response(400, { error: "Missing path parameter: id" });
  }
  return { id } as GetUserInput;
};

export const getUser: HandlerFn = async (input: GetUserInput) => {
  // ... logique métier
  return { user: { id: input.id, name: "Jean" } };
};

Validation : si l'inputParser retourne une instance de Response (ex. new Response(400, ...)), celle-ci est renvoyée directement au client sans appeler le handler.

Concepts clés

CommonEvent

Tous les événements AWS sont normalisés en un objet CommonEvent :

type CommonEvent = {
  path: string;
  method: string;
  body: string | null;
  pathParameters: { [name: string]: string | undefined } | undefined;
  queryStringParameters: { [name: string]: string | undefined } | undefined;
  headers: { [name: string]: string | undefined } | undefined;
  version: string;
};

Le champ version indique la source de l'événement ("1.0" pour API Gateway v1, "2.0" pour v2, "commonEvent" pour le serveur de dev, etc.).

Événements supportés

| Source AWS | method | path | |--------------------|-------------------|-------------------------| | API Gateway v1 | Méthode HTTP | Resource path | | API Gateway v2 | Méthode HTTP | Route key | | SQS | PUT | /sqs/{queueName} | | S3 | PUT | /s3/{bucketName} | | SNS → S3 | PUT | /s3/{bucketName} | | Invocation directe | PUT | path de l'événement |

Résolution fichier#fonction

La référence x-handler: handlers/search#searchProducts est résolue dynamiquement :

  1. Le chemin handlers/search est résolu relativement au répertoire du module principal
  2. Le module est chargé via require()
  3. L'export nommé searchProducts est extrait et mis en cache

Classe Response

Wrapper autour de APIGatewayProxyStructuredResultV2 qui ajoute automatiquement les headers CORS :

import { Response } from "commoneventframework";

new Response(200, { data: "ok" });
new Response(400, { error: "Bad request" });
new Response(500, { error: "Internal error" }, { "X-Custom": "value" });

Headers CORS par défaut :

  • Access-Control-Allow-Origin : valeur de process.env.FRONT_END_URL ou *
  • Access-Control-Allow-Methods : OPTIONS,GET,POST,PUT,DELETE
  • Access-Control-Allow-Credentials : true
  • Content-Type : application/json

Routes intégrées

Le framework enregistre automatiquement ces routes :

| Route | Description | |---------------|------------------------------------------------------| | GET /doc | Interface Swagger UI (via Scalar) | | GET /doc/spec | Spécification OpenAPI au format JSON | | GET /context | Informations sur le contexte Lambda | | GET /dependencies | Liste des dépendances du projet (package.json) |

Développement local

Le framework inclut un serveur HTTP qui simule API Gateway.

Démarrer le serveur

node dist/index.js --local
# ou avec ts-node / nodemon
npx ts-node src/index.ts --local --port 8088

Le serveur démarre sur localhost:8888 par défaut (configurable via le 3e argument de process.argv).

Simuler différents types d'événements

Le serveur de dev intercepte les URLs spéciales pour simuler les sources AWS :

| URL du serveur | Type d'événement simulé | |------------------|-------------------------| | POST /invoke | Invocation Lambda directe | | POST /sqs | Message SQS | | POST /s3event | Événement S3 | | Toute autre URL | API Gateway (CommonEvent)|

Build et déploiement

Le package fournit un script de build via la commande cef-build :

# Bundle uniquement (esbuild)
npx cef-build

# Bundle + ZIP pour déploiement Lambda
npx cef-build --full

Ou dans votre package.json :

{
  "scripts": {
    "build": "cef-build",
    "build:full": "cef-build --full"
  }
}

Le build utilise esbuild pour bundler src/index.ts vers dist/index.js, puis optionnellement crée dist/dist.zip prêt à être déployé sur AWS Lambda.

Utilitaires

Le package expose également quelques utilitaires :

loadEnv()

Charge les fichiers .env et .env.local depuis le répertoire courant. Doit être appelé avant tout import dépendant de variables d'environnement.

import { loadEnv } from "commoneventframework";
loadEnv();

setLambdaContext(context)

Stocke le contexte Lambda pour qu'il soit accessible depuis les routes intégrées (/context).

getEnvValue(key, fallback?)

Récupère une variable d'environnement. Lance une erreur si la variable est absente et qu'aucun fallback n'est fourni.

import { getEnvValue } from "commoneventframework/dist/utils/getEnvValue";

const dbHost = getEnvValue("DB_HOST", "localhost");

Structure recommandée d'un projet

my-lambda/
├── src/
│   ├── index.ts          # Point d'entrée Lambda + handler principal
│   ├── root.yaml         # Définition des routes (OpenAPI + x-handler)
│   └── handlers/
│       ├── types.ts      # Types HandlerFn et InputParserFn
│       ├── hello.ts      # Handler exemple
│       └── users.ts      # Handler avec inputParser
├── dist/                 # Sortie du build (esbuild)
├── .env                  # Variables d'environnement
├── package.json
└── tsconfig.json