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

@celerity-sdk/core

v0.8.3

Published

Core SDK for building Celerity applications — decorators, DI, middleware, guards, and handler adapters

Readme

@celerity-sdk/core

Core SDK for building Celerity applications — decorators, dependency injection, layers, guards, handler pipelines, and the application factory.

Installation

pnpm add @celerity-sdk/core

Requires reflect-metadata and @celerity-sdk/types as peer dependencies.

Handler Types

The core package supports five handler types, each with class-based (decorator-first) and function-based (blueprint-first) styles.

HTTP

// Class-based
@Controller("/orders")
class OrdersHandler {
  @Get("/{orderId}")
  getOrder(@Param("orderId") id: string) {
    return { id };
  }

  @Post("/")
  createOrder(@Body() body: unknown) {
    return { created: true };
  }
}

// Function-based
const getHealth = httpGet("/health", (req, ctx) => ({ status: "ok" }));
const handler = createHttpHandler({}, (req, ctx) => ({ ok: true }));

WebSocket

// Class-based
@WebSocketController()
class ChatHandler {
  @OnConnect()
  connect(@ConnectionId() connId: string) {}

  @OnMessage()
  message(@ConnectionId() connId: string, @MessageBody() body: unknown) {}

  @OnDisconnect()
  disconnect(@ConnectionId() connId: string) {}
}

// Function-based
const wsHandler = createWebSocketHandler({ route: "$default" }, (msg, ctx) => {});

Consumer

// Class-based
@Consumer("ordersConsumer")
class OrderConsumer {
  @MessageHandler()
  async process(
    @Messages(OrderSchema) messages: ValidatedConsumerMessage<Order>[],
  ): Promise<EventResult> {
    return { success: true };
  }
}

// Function-based
const consumer = createConsumerHandler(
  { messageSchema: OrderSchema },
  async (messages, ctx) => ({ success: true }),
);

Schedule

// Class-based — cross-cutting, works on any controller type
@Controller()
class MaintenanceTasks {
  @ScheduleHandler("dailyCleanup")
  async cleanup(@ScheduleInput() input: unknown): Promise<EventResult> {
    return { success: true };
  }

  @ScheduleHandler("rate(1 hour)")
  async sync(): Promise<EventResult> {
    return { success: true };
  }
}

// Function-based
const scheduled = createScheduleHandler(
  { source: "dailyCleanup", schedule: "rate(1 day)" },
  async (event, ctx) => ({ success: true }),
);

Custom / Invocable

// Class-based
@Controller()
class Reports {
  @Invoke("generateReport")
  async generate(@Payload() data: unknown) {
    return { reportId: "r-1" };
  }
}

// Function-based
const custom = createCustomHandler(
  { name: "generateReport" },
  async (payload, ctx) => ({ reportId: "r-1" }),
);

Decorators

Class Decorators

| Decorator | Purpose | |---|---| | @Controller(prefix?) | HTTP handler controller with optional path prefix | | @WebSocketController() | WebSocket handler controller | | @Consumer(source?) | Consumer controller with optional blueprint resource name | | @Injectable() | Marks a class for DI registration | | @Guard(name) | Declares a class as a named custom guard | | @Module(metadata) | Defines a module with controllers, providers, imports, and exports |

HTTP Method Decorators

| Decorator | Purpose | |---|---| | @Get(path?), @Post(path?), @Put(path?), @Patch(path?), @Delete(path?), @Head(path?), @Options(path?) | HTTP method routing on controller methods |

WebSocket Event Decorators

| Decorator | Purpose | |---|---| | @OnConnect() | Handles $connect events | | @OnMessage(route?) | Handles messages (custom route or $default) | | @OnDisconnect() | Handles $disconnect events |

Other Handler Decorators

| Decorator | Purpose | |---|---| | @MessageHandler(route?) | Consumer message handler with optional routing key | | @ScheduleHandler(arg?) | Schedule handler — string or { source?, schedule? } | | @Invoke(name) | Custom invocable handler |

Cross-Cutting Decorators

| Decorator | Purpose | |---|---| | @ProtectedBy(...guards) | Declares guard requirements (class or method level) | | @Public() | Opts a method out of guard protection | | @UseLayer(...layers) / @UseLayers(layers) | Attaches layers to handler or controller | | @UseResource(...names) / @UseResources(names) | Declares blueprint resource dependencies | | @SetMetadata(key, value) / @Action(name) | Attaches custom metadata | | @Inject(token) | Overrides DI token for a constructor parameter |

Parameter Decorators

| Handler Type | Decorators | |---|---| | HTTP | @Body(schema?), @Query(key?, schema?), @Param(key?, schema?), @Headers(key?, schema?), @Auth(), @Token(), @Req(), @Cookies(key?), @RequestId() | | WebSocket | @ConnectionId(), @MessageBody(schema?), @MessageId(), @RequestContext(), @EventType() | | Consumer | @Messages(schema?), @EventInput(), @Vendor(), @ConsumerTraceContext() | | Schedule | @ScheduleInput(schema?), @ScheduleId(), @ScheduleExpression(), @ScheduleEventInputParam() | | Custom | @Payload(schema?), @InvokeContext() |

Parameter decorators that accept a schema use any Zod-compatible Schema<T> ({ parse(data): T }) for automatic validation.

Dependency Injection

The DI container supports class, factory, and value providers with automatic constructor injection, lazy resolution, and circular dependency detection.

@Injectable()
class OrderService {
  constructor(private db: DatabaseClient) {}
}

@Module({
  providers: [
    OrderService,
    { provide: DB_TOKEN, useFactory: () => new DatabaseClient(), onClose: (db) => db.close() },
  ],
  controllers: [OrdersHandler],
})
class AppModule {}

Provider types:

| Type | Registration | |---|---| | Class | @Injectable() class or { provide: token, useClass: MyClass } | | Factory | { provide: token, useFactory: (...deps) => value, inject?: [tokens] } | | Value | { provide: token, useValue: value } |

All providers support an optional onClose hook for shutdown cleanup. The container also auto-detects close, end, quit, disconnect, and destroy methods.

Layers

Layers are the cross-cutting mechanism (similar to middleware). They wrap handler execution in a composable pipeline.

class LoggingLayer implements CelerityLayer {
  async handle(ctx: BaseHandlerContext, next: NextFunction) {
    console.log("before");
    const result = await next();
    console.log("after");
    return result;
  }
}

@Controller("/orders")
@UseLayer(LoggingLayer)
class OrdersHandler {
  @Post("/")
  @UseLayer(validate({ body: orderSchema }))
  createOrder(@Body() body: Order) {
    return { created: true };
  }
}

Layer execution order: [system layers] → [app layers] → [class layers] → [method layers] → handler.

The built-in validate() layer factory supports schema validation for all handler types:

validate({ body: schema })            // HTTP body
validate({ query: schema })           // HTTP query
validate({ consumerMessage: schema })  // Consumer messages
validate({ scheduleInput: schema })    // Schedule input
validate({ customPayload: schema })    // Custom payload
validate({ wsMessageBody: schema })    // WebSocket message body

Guards

Guards are declarative — they annotate handlers with protection requirements but do not execute in the Node.js process. Guard enforcement happens at the Rust runtime layer (containers) or API Gateway (serverless).

@Guard("jwt")
class JwtGuard {
  async check(req: GuardHandlerRequest, ctx: GuardHandlerContext) {
    return { sub: "user-1", role: "admin" };
  }
}

@Controller("/api")
@ProtectedBy("jwt")
class ApiController {
  @Public()
  @Get("/health")
  health() { return { ok: true }; }

  @Get("/secret")
  secret(@Auth() claims: unknown) { return claims; }
}

Function-based guards: createGuard({ name: "jwt" }, async (req, ctx) => claims).

Application Factory

import { CelerityFactory } from "@celerity-sdk/core";

// Auto-detects platform from CELERITY_RUNTIME_PLATFORM env var
const app = await CelerityFactory.create(AppModule);

Three application types:

| Class | Purpose | |---|---| | CelerityApplication | Runtime container application (default) | | ServerlessApplication | Serverless adapter (created when adapter option provided) | | TestingApplication | Lightweight app for unit testing handlers |

Module System

Modules organize controllers, providers, and sub-modules into a dependency graph.

@Module({
  imports: [DatabaseModule, AuthModule],
  controllers: [UserController, OrderController],
  providers: [UserService],
  functionHandlers: [healthCheck],
  guards: [JwtGuard],
})
class AppModule {}

Testing

import { CelerityFactory, mockRequest, mockConsumerEvent, mockScheduleEvent } from "@celerity-sdk/core";

const app = await CelerityFactory.createTestingApp(AppModule);

// HTTP
const response = await app.injectHttp(mockRequest({ method: "GET", path: "/orders/1" }));

// Consumer
const result = await app.injectConsumer("tag", mockConsumerEvent("tag"));

// Schedule
const result = await app.injectSchedule("tag", mockScheduleEvent("tag"));

// Custom
const result = await app.injectCustom("generateReport", { type: "monthly" });

// WebSocket
await app.injectWebSocket("$default", mockWebSocketMessage());

Handler Resolution

When a handler is invoked by ID (e.g. from a blueprint's spec.handler field), the SDK resolves it using a multi-step strategy:

  1. Direct registry ID match — looks up the handler by its explicit id.
  2. Module resolution fallback — treats the ID as a module reference and dynamically imports it (e.g. "handlers.hello" → named export hello from module handlers).
  3. Path/method routing — falls back to matching the incoming request's HTTP method and path against the registry.

HTTP Exceptions

All extend HttpException(statusCode, message, details?) and are caught by the HTTP pipeline to return structured error responses:

| Exception | Status | |---|---| | BadRequestException | 400 | | UnauthorizedException | 401 | | ForbiddenException | 403 | | NotFoundException | 404 | | MethodNotAllowedException | 405 | | NotAcceptableException | 406 | | ConflictException | 409 | | GoneException | 410 | | UnprocessableEntityException | 422 | | TooManyRequestsException | 429 | | InternalServerErrorException | 500 | | NotImplementedException | 501 | | BadGatewayException | 502 | | ServiceUnavailableException | 503 | | GatewayTimeoutException | 504 |

Advanced Exports

For adapter authors building custom serverless or runtime integrations:

| Export | Purpose | |---|---| | HandlerRegistry | Handler registry with route and ID-based lookups | | resolveHandlerByModuleRef | Resolve a handler ID as a module reference via dynamic import | | executeHttpPipeline | Execute the HTTP layer + handler pipeline | | executeWebSocketPipeline | Execute the WebSocket pipeline | | executeConsumerPipeline | Execute the consumer pipeline | | executeSchedulePipeline | Execute the schedule pipeline | | executeCustomPipeline | Execute the custom handler pipeline | | executeGuardPipeline | Execute the guard pipeline | | bootstrapForRuntime | Bootstrap for the Celerity runtime host | | mapRuntimeRequest / mapToRuntimeResponse | Runtime request/response mappers | | mapWebSocketMessage | Runtime WebSocket message mapper | | mapConsumerEventInput | Runtime consumer event mapper | | mapScheduleEventInput | Runtime schedule event mapper | | mapToNapiEventResult | Runtime EventResult mapper |

Part of the Celerity Framework

See celerityframework.io for full documentation.