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

@lytics/sdk-kit

v0.1.1

Published

Core SDK framework with functional plugin architecture

Downloads

251

Readme

@lytics/sdk-kit

npm version npm downloads License: MIT

A lightweight, extensible TypeScript framework for building JavaScript SDKs with a powerful functional plugin architecture.

Features

  • 🔌 Functional Plugin System - Pure functions with capability injection
  • 🎯 TypeScript First - Full type safety with strict mode
  • 📦 Tree-Shakeable - Ship only what you use
  • 🪶 Zero Dependencies - No runtime dependencies in core
  • 🎨 Flexible - Build any kind of SDK (analytics, tracking, APIs, etc.)
  • Event-Driven - Built-in event system with wildcard support

Installation

npm install @lytics/sdk-kit
# or
pnpm add @lytics/sdk-kit
# or
yarn add @lytics/sdk-kit

Quick Start

Basic Usage

import { SDK } from '@lytics/sdk-kit';

// Create SDK instance
const sdk = new SDK({
  name: 'my-sdk',
  apiKey: 'abc123',
});

// Register plugins
sdk.use((plugin, instance, config) => {
  plugin.ns('analytics');
  
  plugin.defaults({
    analytics: {
      endpoint: 'https://api.example.com',
    },
  });
  
  plugin.expose({
    track(event: string, properties?: any) {
      const endpoint = config.get('analytics.endpoint');
      console.log(`Tracking ${event} to ${endpoint}`, properties);
    },
  });
});

// Initialize and use
await sdk.init();
sdk.track('page_view', { path: '/home' });

Creating a Plugin

import type { PluginFunction } from '@lytics/sdk-kit';

export const myPlugin: PluginFunction = (plugin, instance, config) => {
  // 1. Set namespace (required)
  plugin.ns('my.plugin');
  
  // 2. Set default config
  plugin.defaults({
    my: {
      plugin: {
        enabled: true,
        setting: 'default value',
      },
    },
  });
  
  // 3. Expose public methods
  plugin.expose({
    myMethod() {
      const setting = config.get('my.plugin.setting');
      console.log('My method called with:', setting);
    },
  });
  
  // 4. Listen to events
  instance.on('sdk:ready', () => {
    console.log('Plugin initialized!');
  });
  
  // 5. Emit custom events
  plugin.emit('my:custom:event', { data: 'value' });
};

// Usage
sdk.use(myPlugin);

Core Concepts

Plugin Capabilities

Each plugin receives a plugin object with these capabilities:

Namespace

plugin.ns('my.plugin'); // Set plugin namespace (required, can only be set once)

Config Defaults

plugin.defaults({
  my: { 
    plugin: { 
      setting: 'value' 
    } 
  }
});
// Note: User config always wins (underwrite pattern)

Event Emitter

// Subscribe to events
plugin.on('event:name', (data) => console.log(data));

// Emit events
plugin.emit('my:event', { key: 'value' });

// Unsubscribe
plugin.off('event:name', handler);

// Wildcard support
plugin.on('track:*', (data) => {
  // Matches track:page, track:event, etc.
});

Expose API

plugin.expose({
  publicMethod() {
    return 'Called from SDK';
  },
  anotherMethod(arg: string) {
    return `Arg: ${arg}`;
  },
});

// Now available as:
// sdk.publicMethod()
// sdk.anotherMethod('test')

Required Plugins

plugin.mustEnable(); // Mark this plugin as required for SDK to work

SDK Instance

The second parameter is the SDK instance with these methods:

// Event handling
instance.on('sdk:ready', () => {});
instance.emit('custom:event', data);

// Config access
const value = config.get('path.to.value');
config.set('path.to.value', 'new value');

// Check initialization
if (instance.isReady()) {
  // SDK is initialized
}

Configuration

The third parameter is the config object:

// Get values with dot-notation
const timeout = config.get('api.timeout');
const nested = config.get('deeply.nested.value');

// Set values
config.set('api.timeout', 5000);

// Get all config
const allConfig = config.getAll();

// Set defaults (user config wins)
config.defaults({ api: { timeout: 3000 } });

Lifecycle Events

The SDK emits these lifecycle events:

// Before initialization
sdk.on('sdk:init', () => {
  console.log('SDK initializing...');
});

// After initialization (SDK is ready)
sdk.on('sdk:ready', () => {
  console.log('SDK ready!');
});

// During cleanup
sdk.on('sdk:destroy', () => {
  console.log('SDK cleaning up...');
});

API Reference

SDK Class

Constructor

new SDK(config?: SDKConfig)

Methods

use(pluginFn: PluginFunction): this
Register a plugin. Returns this for chaining.

async init(): Promise<void>
Initialize the SDK. Idempotent (safe to call multiple times).

async destroy(): Promise<void>
Destroy the SDK and clean up resources.

get<T>(path: string): T
Get a config value by dot-notation path.

set(path: string, value: any): void
Set a config value by dot-notation path.

on(event: string, handler: Function): () => void
Subscribe to an event. Returns unsubscribe function.

off(event: string, handler: Function): void
Unsubscribe from an event.

emit(event: string, ...args: any[]): void
Emit an event.

getAll(): Record<string, any>
Get all config as an immutable copy.

isReady(): boolean
Check if SDK is initialized.

Advanced Patterns

Plugin Communication

Plugins can communicate via events:

// Publisher plugin
sdk.use((plugin) => {
  plugin.ns('publisher');
  plugin.expose({
    publish(message: string) {
      plugin.emit('message:published', message);
    },
  });
});

// Subscriber plugin
sdk.use((plugin, instance) => {
  plugin.ns('subscriber');
  instance.on('message:published', (message) => {
    console.log('Received:', message);
  });
});

Shared Configuration

Plugins can share config:

// Config provider
sdk.use((plugin) => {
  plugin.ns('config.provider');
  plugin.defaults({
    shared: { apiKey: 'key123' },
  });
});

// Config consumer
sdk.use((plugin, instance, config) => {
  plugin.ns('config.consumer');
  const apiKey = config.get('shared.apiKey'); // 'key123'
});

Async Initialization

Wait for SDK to be ready:

sdk.use((plugin, instance) => {
  plugin.ns('async.plugin');
  
  instance.on('sdk:ready', async () => {
    // Do async setup
    await fetchRemoteConfig();
    console.log('Plugin ready!');
  });
});

await sdk.init();

Method Chaining

const sdk = new SDK({ name: 'my-sdk' })
  .use(plugin1)
  .use(plugin2)
  .use(plugin3);

await sdk.init();

TypeScript Support

Full TypeScript support with strict types:

import type { SDK, PluginFunction, Plugin } from '@lytics/sdk-kit';

// Type-safe plugin
const myPlugin: PluginFunction = (plugin, instance, config) => {
  plugin.ns('typed.plugin');
  
  plugin.expose({
    typedMethod(arg: string): number {
      return arg.length;
    },
  });
};

// Extend SDK type for exposed methods
declare module '@lytics/sdk-kit' {
  interface SDK {
    typedMethod(arg: string): number;
  }
}

Examples

See the examples directory for complete examples:

  • Basic SDK - Simple SDK with tracking
  • Analytics SDK - Full-featured analytics SDK
  • API Client - REST API client wrapper
  • Real-time SDK - WebSocket-based SDK

Contributing

See CONTRIBUTING.md for development setup and guidelines.

License

MIT © Lytics