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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@slingts/core

v0.1.8

Published

Core runtime and function system for Sling framework

Readme

@slingts/core

Core runtime and function system for the Sling framework.

Installation

pnpm add @slingts/core

Quick Start

Define a Function

import { defineFunction } from '@slingts/core';

export const getUser = defineFunction({
  handler: async (params: { userId: string }) => {
    return {
      id: params.userId,
      name: 'John Doe',
      email: '[email protected]',
    };
  },
});

Register and Start Server

import { registerFunction, createSlingServer } from '@slingts/core';
import { getUser } from './functions/getUser';

// Register functions
registerFunction('getUser', getUser);

// Start server
const server = await createSlingServer({ port: 3000 });

Call from Frontend

curl -X POST http://localhost:3000/getUser \
  -H "Content-Type: application/json" \
  -d '{"userId": "123"}'

Features

Type-Safe Functions

Functions are fully typed, with automatic type inference:

const myFunction = defineFunction({
  handler: async (params: { name: string }) => {
    return { message: `Hello, ${params.name}!` };
  },
});

Validation with Zod

Sling integrates with Zod for runtime validation and automatic type inference:

import { defineFunction, z } from '@slingts/core';

export const createUser = defineFunction({
  validate: z.object({
    name: z.string().min(1).max(100),
    email: z.string().email(),
    age: z.number().min(18).optional(),
    tags: z.array(z.string()).max(10).optional(),
  }),
  handler: async (params) => {
    // params is fully typed: { name: string; email: string; age?: number; tags?: string[] }
    return {
      id: '123',
      ...params,
      createdAt: new Date().toISOString(),
    };
  },
});

Validation Features

  • Automatic type inference - Parameter types are inferred from Zod schemas
  • Runtime validation - Invalid inputs are rejected before the handler executes
  • Detailed error messages - Validation errors include field-level details
  • All Zod features - Supports nested objects, arrays, unions, refinements, transforms, etc.

Error Handling

When validation fails, a ValidationError is returned with field details:

{
  "success": false,
  "error": {
    "message": "Validation failed: Invalid email",
    "code": "VALIDATION_ERROR",
    "statusCode": 400,
    "details": {
      "email": ["Invalid email"],
      "age": ["Number must be greater than or equal to 18"]
    }
  }
}

Type Generation

Generate TypeScript types for your frontend automatically:

# Generate types once
npx sling generate

# Watch mode - regenerate on changes
npx sling generate --watch

# Custom paths
npx sling generate --dir ./src/api --output ./src/types/api.d.ts

This creates a sling-client.d.ts file with full type definitions:

export interface SlingClient {
  createUser(params: {
    name: string;
    email: string;
    age?: number;
    tags?: string[];
  }): Promise<{ id: string; name: string; email: string; ... }>;

  // ... all other functions
}

Service Adapters

Sling provides a pluggable adapter system for services like databases, storage, email, etc.

Using Service Adapters

import { globalAdapterRegistry, createMemoryDBAdapter } from '@slingts/core';

// Register an adapter
const dbAdapter = createMemoryDBAdapter();
globalAdapterRegistry.register('db', dbAdapter, {
  adapter: 'memory-db',
  config: { debug: true },
});

// Initialize and get services
const services = {
  db: await globalAdapterRegistry.getClient('db'),
};

// Pass to server
await createSlingServer({
  port: 3000,
  services,
});

Accessing Services in Functions

export const createUser = defineFunction({
  validate: z.object({
    name: z.string(),
    email: z.string().email(),
  }),
  handler: async (params, ctx) => {
    // Access service via context
    const user = await ctx.services.db.create('users', params);
    return user;
  },
});

Built-in Adapters

  • MemoryDBAdapter - In-memory database for development and testing

Creating Custom Adapters

import type { ServiceAdapter } from '@slingts/core';

class MyServiceAdapter implements ServiceAdapter<MyClient, MyConfig> {
  name = 'my-service';

  async initialize(config?: MyConfig): Promise<void> {
    // Initialize your service
  }

  async shutdown(): Promise<void> {
    // Cleanup resources
  }

  async healthCheck(): Promise<boolean> {
    // Check if service is healthy
    return true;
  }

  getClient(): MyClient {
    // Return service client
    return this.client;
  }
}

AuthorizationControl access with authorization functions:

export const deleteUser = defineFunction({
  auth: 'required',
  authorize: async (params, ctx) => {
    return ctx.user?.role === 'admin';
  },
  handler: async (params: { userId: string }) => {
    // Only admins can reach here
    return { success: true };
  },
});

Error Handling

Use built-in error classes for consistent error responses:

import { NotFoundError, AuthorizationError } from '@slingts/core';

export const getPost = defineFunction({
  handler: async (params: { postId: string }, ctx) => {
    const post = await db.posts.findOne({ id: params.postId });

    if (!post) {
      throw new NotFoundError('Post not found');
    }

    if (post.isPrivate && post.authorId !== ctx.user?.id) {
      throw new AuthorizationError('Cannot access private post');
    }

    return post;
  },
});

Function Context

Every handler receives a context object:

export const myFunction = defineFunction({
  handler: async (params, ctx) => {
    // Access request information
    ctx.requestId; // Unique request ID
    ctx.timestamp; // Request timestamp
    ctx.user; // Authenticated user (if any)

    // Use logger
    ctx.log.info('Processing request');
    ctx.log.error('Something went wrong');

    // Access environment
    ctx.env.NODE_ENV;

    // Services (Phase 3)
    // ctx.services.db
    // ctx.services.storage

    return { result: 'success' };
  },
});

API Reference

defineFunction(definition)

Create a function definition.

interface FunctionDefinition {
  auth?: 'required' | 'optional' | 'none';
  authorize?: (params, ctx) => boolean | Promise<boolean>;
  rateLimit?: RateLimitConfig | false;
  timeout?: number;
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
  description?: string;
  handler: (params, ctx) => Promise<result> | result;
}

registerFunction(name, definition)

Register a function with the global registry.

createSlingServer(options)

Create and start an HTTP server.

interface ServerOptions {
  port?: number; // Default: 3000
  host?: string; // Default: '0.0.0.0'
  isDev?: boolean; // Default: NODE_ENV === 'development'
  timeout?: number; // Default: 30000 (30 seconds)
}

Built-in Endpoints

  • /_health - Health check endpoint
  • /_functions - List all registered functions with metadata

Error Classes

  • SlingError - Base error class
  • ValidationError - Input validation failed
  • AuthenticationError - User not authenticated
  • AuthorizationError - User lacks permission
  • NotFoundError - Resource not found
  • RateLimitError - Too many requests
  • TimeoutError - Operation timed out
  • ServiceError - External service failed

License

MIT