@lytics/sdk-kit
v0.1.1
Published
Core SDK framework with functional plugin architecture
Downloads
251
Readme
@lytics/sdk-kit
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-kitQuick 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 workSDK 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
