Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

README.md

Minimal SDK Example

This example demonstrates how to build a complete SDK using @prosdevlab/sdk-kit and its essential plugins.

Features Demonstrated

✅ Custom Plugin Development

Learn how to build your own plugins:

  • Logger Plugin - Console logging with levels
  • Analytics Plugin - Event tracking with batching
  • Monitor Plugin - Cross-plugin event monitoring

✅ Essential Plugins from @prosdevlab/sdk-kit-plugins

See how to use battle-tested plugins:

  • Storage Plugin - Multi-backend storage (localStorage, sessionStorage, cookies)
  • Consent Plugin - GDPR/CCPA compliance with state management
  • Context Plugin - Automatic page, device, and environment context collection
  • Poll Plugin - Wait for external scripts or conditions
  • Queue Plugin - Event batching with persistence
  • Transport Plugin - HTTP transport with retry logic

✅ Real-World Patterns

  • Consent-aware tracking - Only send events when consent is granted
  • Context attachment - Automatically attach context to all events
  • Queue + Transport - Batch and send events efficiently
  • Storage persistence - Survive page reloads
  • Plugin composition - Multiple plugins working together

Project Structure

examples/minimal-sdk/
├── src/
│   ├── index.ts              # Main SDK with 2 demos
│   └── plugins/
│       ├── logger.ts         # Custom logging plugin
│       ├── analytics.ts      # Custom analytics plugin
│       └── monitor.ts        # Custom monitoring plugin
├── package.json
├── tsconfig.json
└── README.md

Running the Example

Install Dependencies

From the repository root:

pnpm install

Build the Example

cd examples/minimal-sdk
pnpm build

Run the Demos

The example includes two demos:

1. Essential Plugins Demo

Shows all 6 essential plugins working together:

// In src/index.ts, uncomment:
demoEssentialPlugins().catch(console.error);

Then run:

pnpm start

2. Custom Plugins Demo

Shows only the custom plugins (original example):

// In src/index.ts, uncomment:
demoCustomPlugins().catch(console.error);

Then run:

pnpm start

Code Walkthrough

Essential Plugins Demo

Storage Plugin

// Set values in different backends
sdk.storage.set('user_id', 'user-123', { backend: 'localStorage' });
sdk.storage.set('session_id', 'session-456', { backend: 'sessionStorage' });
sdk.storage.set('preference', { theme: 'dark' }, {
  backend: 'cookie',
  ttl: 86400 // 1 day
});

// Get values
const userId = sdk.storage.get('user_id');
const preference = sdk.storage.get('preference', { backend: 'cookie' });

Features:

  • Multi-backend support (localStorage, sessionStorage, cookies, memory)
  • TTL expiration
  • Namespace isolation
  • JSON serialization
  • Graceful degradation

Consent Plugin

// Grant consent
sdk.consent.grant(['analytics', 'functional']);

// Check consent
if (sdk.consent.isGranted('analytics')) {
  // Track analytics
}

// Wait for consent
const granted = await sdk.consent.waitForConsent('marketing', {
  timeout: 5000
});

Features:

  • Category-based consent (necessary, functional, analytics, marketing, social)
  • Persistence to storage
  • Promise-based waitForConsent() API
  • State change events
  • Platform adapter support (OneTrust, Cookiebot, Usercentrics)

Context Plugin

// Collect all context
const context = sdk.context.get();
console.log(context.page.url);        // Page URL
console.log(context.device.type);     // 'mobile' or 'desktop'
console.log(context.screen.width);    // Screen dimensions
console.log(context.environment.language);  // Browser language

Features:

  • Page context (URL, path, query params, referrer, title, session)
  • Device context (type, user agent)
  • Screen context (dimensions)
  • Environment context (timezone, language, cookies, DNT, storage)
  • Privacy-first query parameter handling (UTM-only by default)
  • Caching with manual refresh

Poll Plugin

// Wait for a condition
const ready = await sdk.poll.waitFor(
  () => window.myLib !== undefined,
  { timeout: 5000, interval: 100 }
);

// Wait for DOM element
await sdk.poll.element('#my-element');

// Wait for global variable
await sdk.poll.global('myLib');

Features:

  • Promise-based API
  • Immediate check (no delay on first attempt)
  • Configurable interval and timeout
  • Event emission
  • Lifecycle integration

Queue Plugin

// Add events to queue
sdk.queue.add({ event: 'page_view', page: '/home' });
sdk.queue.add({ event: 'button_click', button: 'cta' });

// Queue auto-flushes when maxSize reached
sdk.on('queue:flush', async ({ items }) => {
  // Send to your backend
  await sdk.transport.send({
    url: 'https://api.example.com/events',
    method: 'POST',
    data: items
  });
});

Features:

  • Auto-flush based on size or interval
  • Persistence to storage (survives page reloads)
  • FIFO limiting
  • Lifecycle integration (flush on destroy)
  • Event emission

Transport Plugin

// Send HTTP request with automatic retry
const response = await sdk.transport.send({
  url: 'https://api.example.com/events',
  method: 'POST',
  data: { events: [...] }
});

if (response.ok) {
  console.log('Success!');
}

Features:

  • Multiple transports (fetch, beacon, XHR, pixel)
  • Automatic transport selection
  • Retry logic with exponential backoff
  • Request/response hooks
  • Timeout handling
  • Event emission

Real-World Pattern: Consent-Aware Tracking

// Only send events when consent is granted
sdk.on('queue:flush', async ({ items }) => {
  if (sdk.consent.isGranted('analytics')) {
    // Get context
    const context = sdk.context.get();
    
    // Send with context attached
    await sdk.transport.send({
      url: 'https://api.example.com/events',
      method: 'POST',
      data: {
        events: items,
        context: context
      }
    });
  }
});

// Events are queued automatically
sdk.queue.add({ event: 'page_view' });
sdk.queue.add({ event: 'click' });

// When consent is granted, queue flushes
sdk.consent.grant('analytics');

Custom Plugin Development

Logger Plugin Example

File: src/plugins/logger.ts

export const loggerPlugin: PluginFunction = (plugin, instance, config) => {
  plugin.ns('logger');
  
  plugin.defaults({
    logger: {
      enabled: true,
      level: 'info',
    },
  });
  
  plugin.expose({
    debug(message: string) { /* ... */ },
    info(message: string) { /* ... */ },
    warn(message: string) { /* ... */ },
    error(message: string) { /* ... */ },
  });
  
  instance.on('sdk:ready', () => {
    console.log('SDK ready!');
  });
};

Demonstrates:

  • Setting a namespace (plugin.ns())
  • Providing config defaults
  • Exposing public methods
  • Listening to lifecycle events
  • Emitting custom events

Analytics Plugin Example

File: src/plugins/analytics.ts

export const analyticsPlugin: PluginFunction = (plugin, instance, config) => {
  plugin.ns('analytics');
  
  plugin.expose({
    track(eventName: string, properties?: any) {
      eventQueue.push({ eventName, properties });
      plugin.emit('analytics:tracked', { eventName });
    },
    flush: async () => {
      // Send to server
    }
  });
  
  instance.on('sdk:ready', () => {
    startFlushTimer();
  });
  
  instance.on('sdk:destroy', () => {
    clearInterval(flushTimer);
  });
};

Demonstrates:

  • Event batching and auto-flush
  • Timer management in lifecycle
  • Emitting events for other plugins
  • Async operations

Monitor Plugin Example

File: src/plugins/monitor.ts

export const monitorPlugin: PluginFunction = (plugin, instance, config) => {
  plugin.ns('monitor');
  
  // Listen to all analytics events
  instance.on('analytics:*', (data) => {
    console.log('Analytics event:', data);
  });
  
  // Listen to specific events
  instance.on('analytics:tracked', () => {
    stats.trackedEvents++;
  });
  
  plugin.expose({
    getStats() {
      return stats;
    }
  });
};

Demonstrates:

  • Wildcard event subscriptions (analytics:*)
  • Plugin-to-plugin communication
  • Statistics collection
  • Reading config from other plugins

Expected Output

Essential Plugins Demo

============================================================
SDK Kit - Essential Plugins Demo
============================================================

✅ SDK is ready!

📦 Storage Plugin Demo
------------------------------------------------------------
localStorage user_id: user-123
sessionStorage session_id: session-456
cookie preference: { theme: 'dark', notifications: true }

🔒 Consent Plugin Demo
------------------------------------------------------------
Analytics consent: pending
Marketing consent: pending

✅ Granted: analytics, functional
Analytics consent: granted
Marketing consent: pending

🌍 Context Plugin Demo
------------------------------------------------------------
Page URL: http://localhost:3000/
Device type: desktop
Screen size: 1920x1080
Language: en-US
Timezone offset: -8

⏳ Poll Plugin Demo
------------------------------------------------------------
Waiting for storage to be ready...
Storage ready: ✅

🚀 Queue + Transport Demo
------------------------------------------------------------
Queue size: 3 events
📤 Flushing 3 events...
✅ Events sent successfully

🔗 Integration with Custom Plugins
------------------------------------------------------------
Custom analytics events tracked

⏱️  waitForConsent Demo
------------------------------------------------------------
Waiting for marketing consent...
User granted marketing consent
Marketing consent: granted ✅

📊 Monitoring Stats
------------------------------------------------------------
{ trackedEvents: 5, identifyCalls: 1, pageViews: 0, ... }

🧹 Cleanup
------------------------------------------------------------
Flushing remaining events...
Destroying SDK...

✅ Demo complete!
============================================================

Key Takeaways

Plugin Architecture

  • Plugins are pure functions that receive capabilities
  • Each plugin sets a unique namespace
  • Plugins can expose methods that become part of the SDK API
  • Plugins communicate via events (decoupled)

Essential Plugins

  • Storage - Universal storage abstraction
  • Consent - GDPR/CCPA compliance helpers
  • Context - Automatic context collection
  • Poll - Wait for external conditions
  • Queue - Event batching with persistence
  • Transport - HTTP transport with retry

Configuration

  • Hierarchical config with dot-notation access
  • User config wins over defaults
  • Config is accessible to all plugins
  • Can be updated at runtime

Events

  • Pub/sub pattern for loose coupling
  • Wildcard subscriptions (e.g., analytics:*)
  • Lifecycle events (sdk:init, sdk:ready, sdk:destroy)
  • Custom events for plugin communication

Lifecycle

  • init() - Start the SDK, emit events
  • destroy() - Clean up resources, flush data
  • Plugins can hook into lifecycle via events
  • Proper cleanup prevents memory leaks

Building Your Own Plugins

Tier 1 Plugins (Monorepo)

Generic, battle-tested plugins that live in @prosdevlab/sdk-kit-plugins:

  • Storage, Consent, Context, Poll, Queue, Transport
  • Available to all SDK Kit users
  • Maintained by the SDK Kit team

Tier 2 Plugins (Custom/Community)

Domain-specific plugins in separate npm packages:

  • Lytics-specific plugins (e.g., @prosdevlab/sdk-kit-plugin-lytics)
  • Your custom plugins
  • Community plugins

Creating a Custom Plugin

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

export const myPlugin: PluginFunction = (plugin, instance, config) => {
  // 1. Set namespace
  plugin.ns('my.plugin');
  
  // 2. Provide defaults
  plugin.defaults({
    my: { plugin: { setting: 'value' } }
  });
  
  // 3. Expose public API
  plugin.expose({
    myMethod() {
      const setting = config.get('my.plugin.setting');
      plugin.emit('my:event', { setting });
    }
  });
  
  // 4. Listen to lifecycle
  instance.on('sdk:ready', () => {
    console.log('Plugin initialized');
  });
  
  instance.on('sdk:destroy', () => {
    // Cleanup
  });
};

See the Plugin Development Guide for more details.

Next Steps

Questions?

See the main README or ROADMAP for more information.