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

faas-spec

v1.0.0

Published

A library that auto-generates CDK code from TypeSpec API definitions. Used together with [faas-stack](https://github.com/heycalmdown/faas-stack) for **type-safe Lambda deployment**.

Downloads

110

Readme

faas-spec

A library that auto-generates CDK code from TypeSpec API definitions. Used together with faas-stack for type-safe Lambda deployment.


Installation

npm install faas-spec

Quick Start

1. Write TypeSpec File

// typespec/faas/main.tsp
import "@typespec/http";
import "faas-spec";

using TypeSpec.Http;
using FaasSuite.FaasSpec;

@service(#{ title: "faas-my-service" })
@route("/my-service")
namespace MyService;

@post
@route("/vendors/{vendorId}/signup")
op BuyerSignUp(@path vendorId: string, @body body: SignUpRequest): SignUpResponse;

2. Generate faas-spec.ts

npm run tsp  # Compile TypeSpec

3. Use in lambda-stack.ts

import * as APIs from './faas-spec'

export class LambdaStack extends FaasStack {
  constructor(scope: App, id: string, props?: StackProps) {
    super(scope, id, props, SERVICE, STAGE)

    APIs.BuyerSignUp(this, envs())  // Type-safe!
  }
}

Problems faas-spec Solves

1. Prevents Path and Filename Mismatch

Before: Error-prone

// Typo 1: Missing hyphen in filename
this.post('/vendors/{vendorId}/signup', 'buyer-signup.ts', envs())
// Actual file: buyer-sign-up.ts → Runtime error

// Typo 2: Path typo
this.post('/vendors/{vendorId}/signpu', 'buyer-sign-up.ts', envs())
// signpu vs signup → API call fails

After: TypeSpec ensures consistency

@post
@route("/vendors/{vendorId}/signup")
op BuyerSignUp(@path vendorId: string, ...): ...;
// Auto-generated - typos impossible
export const BuyerSignUp = defineSpec(
  'BuyerSignUp',
  'buyer-sign-up.ts',  // Auto-generated from operation name
  'post',
  '/vendors/{vendorId}/signup',
  'node'
)

2. Prevents HTTP Method Mistakes

Before: Method mistakes

// Registered as POST when it should be GET
this.post('/products/{id}', 'get-product.ts', envs())

After: TypeSpec decorators determine method

@get
@route("/products/{id}")
op GetProduct(@path id: string): Product;
// Correct method used automatically
export const GetProduct = defineSpec('GetProduct', 'get-product.ts', 'get', ...)

3. Build-time File Existence Validation

Before: Errors discovered after deployment

this.post('/path', 'non-existent-file.ts', envs())
// CDK synth succeeds, deployment fails

After: Error at CDK synth time

APIs.NonExistentOperation(this)
// Error: File "./src/non-existent-operation.ts" not found by "NonExistentOperation"
// Discovered immediately before deployment!

4. IDE Autocomplete Support

Before: No autocomplete for strings

this.post('/vendors/{vendorId}/signup', 'buyer-sign-up.ts', envs())

After: Autocomplete works for functions

APIs.  // ← Ctrl+Space shows all available APIs

5. Function Metadata Access

APIs.BuyerSignUp(this, envs())

// Access created function
APIs.BuyerSignUp.func      // IFunction
APIs.BuyerSignUp.filename  // 'buyer-sign-up.ts'

// Usage example
const topic = this.findTopic('notifications')
topic.grantPublish(APIs.BuyerSignUp.func!)

faas-spec Decorators

Event Handlers

// SQS queue subscription
@event("sqs")
op OnSqsOrderCreated(@body body: OrderEvent): void;
// → Queue name: faas-{service}-order-created

// Kafka topic subscription (future support)
@event("kafka")
op OnKafkaOrderChange(@body body: OrderEvent): void;

Scheduled Tasks

// Cron expression
@schedule
@cron(#{ hour: "20", minute: "15" })  // Daily at 20:15 UTC
op OnScheduleCleanup(): {};

// Rate-based
@schedule
@rate("1h")   // Every hour
op OnScheduleHourly(): {};

@schedule
@rate("1d")   // Every day
op OnScheduleDaily(): {};

@schedule
@rate("5m")   // Every 5 minutes
op OnScheduleFrequent(): {};

Rate units: | Unit | Description | Example | |------|-------------|---------| | m | Minutes | "5m" = 5 minutes | | h | Hours | "1h" = 1 hour | | d | Days | "1d" = 1 day |

Language Selection

// Default: Node.js (TypeScript)
@get
@route("/products")
op GetProducts(): Product[];
// → File: src/get-products.ts

// Go language
@lang("go")
@get
@route("/hello")
op Hello(): HelloResponse;
// → File: go/hello/main.go

Generation Rules

Operation Name → Filename Conversion

| Operation | Filename (Node.js) | Filename (Go) | |-----------|-------------------|---------------| | GetProducts | get-products.ts | get-products/main.go | | BuyerSignUp | buyer-sign-up.ts | buyer-sign-up/main.go | | OnSqsOrderCreated | on-sqs-order-created.ts | - | | OnScheduleDaily | on-schedule-daily.ts | - |

Conversion rule: PascalCase → kebab-case

SQS Queue Name Extraction

@event("sqs")
op OnSqsOrderCreated(...): void;
//      ~~~~~~~~~~~~
//      Queue name extracted from this part: order-created

Actual queue ARN: arn:aws:sqs:{region}:{accountId}:faas-{service}-order-created


Complete Example

TypeSpec Definition

// typespec/faas/main.tsp
import "@typespec/http";
import "faas-spec";

using TypeSpec.Http;
using FaasSuite.FaasSpec;

@service(#{ title: "faas-order" })
@route("/order")
namespace Order;

// HTTP APIs
@get @route("/vendors/{vendorId}/orders")
op ListOrders(@path vendorId: string): Order[];

@post @route("/vendors/{vendorId}/orders")
@tag("faas.plugo.world")
op CreateOrder(@path vendorId: string, @body body: CreateOrderRequest): Order;

// Event Handler
@event("sqs")
op OnSqsOrderCreated(@body body: OrderCreatedEvent): void;

// Scheduled Tasks
@schedule @cron(#{ hour: "2", minute: "0" })
op OnScheduleOrderCleanup(): {};

@schedule @rate("1h")
op OnScheduleOrderStats(): {};

Generated faas-spec.ts

// GET faas.plugo.town/order/vendors/{vendorId}/orders
export const ListOrders = defineSpec('ListOrders', 'list-orders.ts', 'get', '/vendors/{vendorId}/orders', 'node')

// POST faas.plugo.world/order/vendors/{vendorId}/orders
export const CreateOrder = defineSpec('CreateOrder', 'create-order.ts', 'post', '/vendors/{vendorId}/orders', 'node')

// EVENT(sqs) - faas-order-order-created
export const OnSqsOrderCreated = defineSqsSpec('OnSqsOrderCreated', 'on-sqs-order-created.ts', 'order-created')

// SCHEDULE - order-cleanup
export const OnScheduleOrderCleanup = defineScheduleSpec('OnScheduleOrderCleanup', 'on-schedule-order-cleanup.ts', Schedule.cron({"minute":"0","hour":"2"}))

// SCHEDULE - order-stats
export const OnScheduleOrderStats = defineScheduleSpec('OnScheduleOrderStats', 'on-schedule-order-stats.ts', Schedule.rate(Duration.hours(1)))

lambda-stack.ts

import * as APIs from './faas-spec'

export class LambdaStack extends FaasStack {
  constructor(scope: App, id: string, props?: StackProps) {
    super(scope, id, props, SERVICE, STAGE, { shareFaasSecurityGroup: true, awsv3: true })

    // External API
    APIs.CreateOrder(this, envs())

    // Internal API
    this.switchToPrivateGateway()
    APIs.ListOrders(this, envs())

    // Event & Schedule
    APIs.OnSqsOrderCreated(this, envs())
    APIs.OnScheduleOrderCleanup(this, envs())
    APIs.OnScheduleOrderStats(this, envs())

    // Grant permissions
    const table = this.findTable('Orders')
    for (const name in this.functionCache) {
      table.grantReadWriteData(this.functionCache[name])
    }
  }
}

Validation and Error Messages

faas-spec validates the following at TypeSpec compile time:

| Error Code | Description | |------------|-------------| | event-before-route | @event must be used after @route | | invalid-route-path | @event route must start with /events/{type} | | invalid-operation-name | @event operation name must start with On{Type} | | schedule-requires-cron-or-rate | @schedule requires @cron or @rate | | invalid-rate-unit | Rate unit must be m/h/d |