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

skeleton-crew-runtime

v0.3.4

Published

A minimal plugin runtime for building modular JavaScript applications.

Downloads

230

Readme

Skeleton Crew Runtime v0.3.3

A minimal plugin runtime for building modular JavaScript applications.

Stop wiring up infrastructure. Start building features.

npm install skeleton-crew-runtime@^0.3.3

What's New in v0.3.3

Browser Compatibility - Fixed critical runtime crash in browsers by lazy-loading Node.js dependencies
📝 Documentation - Updated all examples to use proper TypeScript import type syntax
🔧 Stability - Improved test reliability for performance monitoring

→ Complete v0.3.3 Features

What's New in v0.3.2

Service Locator API - New ctx.services API for type-safe inter-plugin communication
📝 Service Locator Guide - New dedicated guide for using the Service Locator pattern

→ Complete v0.3.2 Features

What's New in v0.3.0

Config Validation - Validate plugin configuration before setup runs with detailed error reporting
📝 Logger Documentation - Comprehensive guide to the built-in logging system and external integrations
📊 Optimized Telemetry - Cleaner startup logs with consolidated plugin loading information
🔍 Introspection - Enhanced plugin metadata for better runtime transparency

→ Complete v0.3.0 Features

What's New in v0.2.1

🔍 Plugin Discovery - Automatic plugin loading from file paths and npm packages
🔄 Dependency Resolution - Automatic topological sorting for correct plugin initialization order
🛠️ Enhanced DX - Better error messages with dependency hints for missing actions
🚀 Production Ready - All critical bugs fixed based on real-world usage feedback
Verified Stable - Tested and validated in production migrations

Plugin Discovery Example

// Automatic plugin discovery - no manual registration needed!
const runtime = new Runtime<MyConfig>({
  config: myConfig,
  
  // Load plugins from directories
  pluginPaths: [
    './plugins',           // Load all plugins from directory
    './custom-plugin.js'   // Load specific plugin file
  ],
  
  // Load plugins from npm packages
  pluginPackages: [
    '@my-org/auth-plugin',
    'my-custom-plugin'
  ]
});

await runtime.initialize(); // Plugins auto-loaded and sorted by dependencies!

→ Complete v0.2.1 Features

What's New in v0.2.0

🎯 Generic Runtime/Context - Full TypeScript generic support for type-safe configuration
Sync Config Access - Direct synchronous access to configuration via ctx.config
🔗 Plugin Dependencies - Explicit dependency resolution with validation
📝 Enhanced Logger - Logger available on context for all plugins
🔄 100% Backward Compatible - All v0.1.x code continues to work

Quick Migration Example

// v0.1.x
const runtime = new Runtime({
  hostContext: { config: myConfig }
});

// v0.2.0 - Fully typed!
interface MyConfig { apiUrl: string; }
const runtime = new Runtime<MyConfig>({
  config: { apiUrl: 'https://api.example.com' }
});

→ Complete Migration Guide


Documentation

Getting Started

v0.2.0 Migration & Guides

Use Cases

Advanced


What is this?

Skeleton Crew Runtime is a lightweight foundation for building applications where features can be added, removed, or replaced without touching existing code. Think VS Code's extension system, but for any JavaScript application.

Core idea: Your app is a collection of plugins. Each plugin registers actions (business logic), screens (UI definitions), and events (communication). The runtime coordinates everything.

Result: Add features by dropping in plugins. Remove features by taking them out. No refactoring. No breaking changes.

Why would I use this?

You're building something modular and you might know these challenges:

  • Wiring up infrastructure - Event buses, plugin loaders, action registries
  • Tight coupling - Changing one feature breaks three others
  • Testing nightmares - Can't test features in isolation
  • Framework lock-in - Married to React/Vue/whatever forever
  • Refactoring hell - Adding features means touching existing code

Skeleton Crew Runtime gives you:

  • Plugin isolation - Features don't know about each other
  • Event-driven communication - Plugins coordinate without coupling
  • Framework freedom - Business logic separate from UI
  • Testability - Mock what you need, test what matters
  • Minimal core - < 5KB, zero dependencies

Show me code

Here's a complete plugin that adds a feature to your app:

import { Runtime } from 'skeleton-crew-runtime';
import type { PluginDefinition, RuntimeContext } from 'skeleton-crew-runtime';

// v0.2.0: Define your config interface
interface AppConfig {
  notifications: {
    apiKey: string;
    defaultTimeout: number;
  };
  features: {
    pushNotifications: boolean;
  };
}

// 1. Create typed runtime
const runtime = new Runtime<AppConfig>({
  config: {
    notifications: {
      apiKey: process.env.NOTIFICATION_API_KEY!,
      defaultTimeout: 5000
    },
    features: {
      pushNotifications: true
    }
  }
});

await runtime.initialize();
const ctx = runtime.getContext();

// 2. Write a plugin (this is a complete feature)
const notificationsPlugin: PluginDefinition<AppConfig> = {
  name: 'notifications',
  version: '1.0.0',
  dependencies: [], // v0.2.0: Explicit dependencies
  
  setup(ctx: RuntimeContext<AppConfig>) {
    // ✅ Fully typed config access
    const { notifications, features } = ctx.config;
    
    if (!features.pushNotifications) {
      ctx.logger.info('Push notifications disabled');
      return;
    }
    
    // Register business logic with type safety
    ctx.actions.registerAction<
      { userId: string; message: string },
      { success: boolean; messageId: string }
    >({
      id: 'notifications:send',
      handler: async ({ userId, message }, ctx) => {
        // ✅ Typed config access in handlers
        const { apiKey, defaultTimeout } = ctx.config.notifications;
        
        // Your logic here
        const messageId = await sendPushNotification(userId, message, {
          apiKey,
          timeout: defaultTimeout
        });
        
        // Let other plugins know
        ctx.events.emit('notification:sent', { userId, messageId });
        
        return { success: true, messageId };
      },
      timeout: notifications.defaultTimeout
    });
    
    // React to other plugins
    ctx.events.on('user:registered', async (user: any) => {
      await ctx.actions.runAction('notifications:send', {
        userId: user.id,
        message: 'Welcome!'
      });
    });
    
    ctx.logger.info('Notifications plugin initialized');
  }
};

// 3. Register and use
ctx.plugins.registerPlugin(notificationsPlugin);

// anywhere in your app - fully typed!
const result = await ctx.actions.runAction('notifications:send', {
  userId: '123',
  message: 'Your order shipped!'
});

console.log(`Message sent: ${result.messageId}`);

That's it. The plugin is isolated, testable, fully typed, and can be removed without breaking anything.

Core concepts (5 minutes)

1. Plugin Discovery (v0.2.1): Automatic Loading

No more manual plugin registration! The runtime can automatically discover and load plugins:

import { Runtime } from 'skeleton-crew-runtime';

const runtime = new Runtime<MyConfig>({
  config: myConfig,
  
  // Discover plugins from file system
  pluginPaths: [
    './src/plugins',        // Directory: loads all .js/.mjs files
    './auth-plugin.js',     // Single file: loads specific plugin
    './dist/plugins'        // Works with compiled TypeScript too!
  ],
  
  // Discover plugins from npm packages
  pluginPackages: [
    '@my-org/auth-plugin',  // npm package with plugin export
    'my-logging-plugin'     // Any package that exports a plugin
  ]
});

await runtime.initialize();
// ✅ All plugins auto-loaded and sorted by dependencies!

Dependency Resolution: Plugins are automatically sorted by their dependencies array, so they initialize in the correct order.

2. Plugins: Isolated Features

2. Plugins: Isolated Features

A plugin is just an object with a name and a setup function:

import type { PluginDefinition, RuntimeContext } from 'skeleton-crew-runtime';

// v0.2.0: Define your config type
interface MyAppConfig {
  apiUrl: string;
  features: { analytics: boolean };
}

export const myPlugin: PluginDefinition<MyAppConfig> = {
  name: 'my-plugin',
  version: '1.0.0',
  dependencies: ['config'], // v0.2.0: Explicit dependencies
  
  setup(ctx: RuntimeContext<MyAppConfig>) {
    // ✅ Fully typed config access
    const { apiUrl, features } = ctx.config;
    
    if (features.analytics) {
      ctx.logger.info(`Plugin initialized for ${apiUrl}`);
    }
    
    // Register your feature here
  },
  
  dispose(ctx: RuntimeContext<MyAppConfig>) {
    // Optional: cleanup resources when plugin is removed
    // Use this for: closing connections, clearing timers, releasing memory
    // Event listeners auto-cleanup, so you usually don't need this
  }
};

3. Actions: Business Logic

Actions are named functions that do work:

// v0.2.0: Type-safe action registration
interface CreateOrderParams {
  customerId: string;
  items: Array<{ id: string; quantity: number }>;
}

interface Order {
  id: string;
  customerId: string;
  total: number;
  status: 'pending' | 'confirmed';
}

// Register an action
ctx.actions.registerAction<CreateOrderParams, Order>({
  id: 'orders:create',
  handler: async (orderData, ctx) => {
    // ✅ Typed config access
    const { apiUrl } = ctx.config;
    
    // ✅ Typed parameters
    const { customerId, items } = orderData;
    
    const order = await createOrder(customerId, items);
    ctx.events.emit('order:created', order);
    
    ctx.logger.info(`Order created: ${order.id}`);
    return order; // ✅ Typed return value
  },
  timeout: 10000 // Optional timeout
});

// Call from anywhere - fully typed!
const order = await ctx.actions.runAction<CreateOrderParams, Order>(
  'orders:create',
  { customerId: '123', items: [{ id: 'item1', quantity: 2 }] }
);

4. Events: Decouple Features

Plugins communicate without knowing about each other:

// Plugin A: Emit event
ctx.events.emit('order:created', order);

// Plugin B: React (doesn't know about Plugin A)
ctx.events.on('order:created', (order) => {
  sendConfirmationEmail(order);
});

// v0.2.0: Async event handling
await ctx.events.emitAsync('order:created', order); // Wait for all handlers

5. Configuration: Type-Safe Access (v0.2.0)

Direct synchronous access to typed configuration:

import { Runtime } from 'skeleton-crew-runtime';

interface AppConfig {
  database: { url: string; maxConnections: number };
  api: { baseUrl: string; timeout: number };
  features: { caching: boolean; analytics: boolean };
}

const runtime = new Runtime<AppConfig>({
  config: {
    database: {
      url: process.env.DATABASE_URL!,
      maxConnections: 10
    },
    api: {
      baseUrl: 'https://api.example.com',
      timeout: 5000
    },
    features: {
      caching: true,
      analytics: process.env.NODE_ENV === 'production'
    }
  }
});

// In plugins: direct typed access
setup(ctx: RuntimeContext<AppConfig>) {
  // ✅ Fully typed, synchronous access
  const { database, api, features } = ctx.config;
  
  if (features.caching) {
    initializeCache();
  }
  
  // ✅ Available in action handlers
  ctx.actions.registerAction({
    id: 'api:request',
    handler: async (endpoint: string) => {
      const { baseUrl, timeout } = ctx.config.api;
      return await fetch(`${baseUrl}${endpoint}`, { timeout });
    }
  });
}

6. Host Context: Bridge to Existing Code

Inject your existing services so plugins can use them:

import { Runtime } from 'skeleton-crew-runtime';

const runtime = new Runtime<AppConfig>({
  config: myTypedConfig,
  hostContext: {
    // Legacy services
    db: yourDatabase,
    cache: redisClient,
    logger: yourLogger
  }
});

await runtime.initialize();
const ctx = runtime.getContext();

// Plugins access via ctx.host (for legacy integration)
const { db, logger } = ctx.host;

7. Service Locator (v0.3.1): Type-safe inter-plugin communication

Plugins can register and consume shared services without hard dependency coupling:

// Plugin A: Register a service
setup(ctx) {
  const myService = {
    doSomething: () => console.log('Service in action!')
  };
  ctx.services.register('my-api', myService);
}

// Plugin B: Consume the service
setup(ctx) {
  // Wait for the providing plugin to initialize first!
  const api = ctx.services.get<MyApiType>('my-api');
  api.doSomething();
}

8. Screens (Optional): UI Definitions

Define screens that any UI framework can render:

ctx.screens.registerScreen({
  id: 'orders:list',
  title: 'Orders',
  component: 'OrderListComponent'  // string, class, function, or any type
});

What can I build?

Skeleton Crew works for any modular JavaScript application:

Developer Tools

  • CLI tools - Task runners, deployment scripts, dev environments
  • Browser extensions - Tab managers, productivity tools, dev tools
  • Build tools - Custom bundlers, code generators, linters

Internal Applications

  • Admin panels - User management, content moderation, analytics
  • Dashboards - Monitoring, reporting, data visualization
  • Workflow tools - Approval systems, task management, automation

Real-Time Applications

  • Collaboration tools - Shared editing, presence, chat
  • Live dashboards - Stock tickers, sports scores, IoT monitoring
  • Multiplayer features - Game state sync, player coordination

Modular Systems

  • Plugin marketplaces - Let users extend your app
  • White-label products - Different features for different customers
  • Microservices - Coordinate distributed services

Not ideal for: Public-facing websites (use Next.js), complex routing (use React Router), heavy state management (use Redux).


Real examples

CLI Tool (150 lines vs 500+)

What you'll see: Interactive CLI that runs commands, shows output, handles errors. All plugin-based.

# Build a command palette for Git, npm, and Docker:
cd demo/dev-launcher
npm install && npm start

Real-Time Collaboration (130 lines vs 500+)

What you'll see: Multiple clients syncing state in real-time. No Firebase, no Socket.io boilerplate.

# Build a multi-user sync system:
cd demo/collab-hub
npm install && npm run build
npm run server  # Terminal 1
npm run client  # Terminal 2-3

See all demos →


FAQ

Do I need to rewrite my app?

No. Skeleton Crew runs alongside your existing code. Write new features as plugins, keep old code unchanged.

What if I want to migrate existing features later?

You can gradually replace legacy code with plugins using feature flags. Or don't — both approaches work fine.

Does this work with my UI framework?

Yes. Skeleton Crew is UI-agnostic. Use React, Vue, Svelte, or no UI at all. The runtime doesn't care.

Is this overkill for small apps?

Possibly. If you have a simple app with no legacy code and no plans to grow, you might not need this. But if you're dealing with technical debt or planning for modularity, it's a good fit.

How big is the runtime?

Less than 5KB gzipped. Minimal overhead.

Can I use this in production?

Yes. The runtime is stable and tested. Start with non-critical features, then expand.


Built for developers who need to modernize legacy apps without the risk of a full rewrite.