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

@bernierllc/slash-commands-core

v1.0.2

Published

Core foundation for slash command packages - provides interfaces, types, and utilities for building slash commands

Readme

@bernierllc/slash-commands-core

Core foundation package for building slash command packages. Provides types, utilities, and base classes following the validator pattern for MECE slash command architecture.

Installation

npm install @bernierllc/slash-commands-core

Features

  • Type Safety - Complete TypeScript definitions for slash commands
  • Base Classes - Abstract base class for consistent command packages
  • Validation - Built-in argument parsing and validation with Zod
  • Multi-platform - Support for in-app, Slack, Discord, Teams platforms
  • Rate Limiting - Built-in rate limiting utilities
  • Permission System - Role-based command permissions
  • NeverHub Integration - Service discovery and event system support

Quick Start

Creating a Slash Command Package

import { SlashCommandPackage, SlashCommandSpec, SlashCommandContext, SlashCommandResponse, z } from '@bernierllc/slash-commands-core';

export class MyCommandsPackage extends SlashCommandPackage {
  readonly packageName = '@my-org/my-commands';
  readonly version = '1.0.0';
  readonly description = 'My custom slash commands';

  readonly commands: Record<string, SlashCommandSpec> = {
    'hello': {
      name: 'hello',
      description: 'Say hello to someone',
      usage: '<name>',
      examples: ['/hello John', '/hello @user'],
      arguments: [{
        name: 'name',
        description: 'Name to greet',
        required: true,
        type: 'string',
        schema: z.string().min(1).max(50)
      }],
      requiresAuth: false,
      platforms: ['in-app', 'slack', 'discord']
    }
  };

  async initialize(): Promise<void> {
    // Register command handlers
    this.handlers.set('hello', this.handleHello.bind(this));
  }

  private async handleHello(
    context: SlashCommandContext, 
    args: Record<string, any>
  ): Promise<SlashCommandResponse> {
    const name = args.name as string;
    
    return {
      success: true,
      message: `Hello, ${name}! 👋`,
      formatting: {
        markdown: `**Hello, ${name}!** 👋`,
        plainText: `Hello, ${name}!`
      }
    };
  }
}

Using with NeverHub Service Discovery

import { NeverHubAdapter } from '@bernierllc/neverhub-adapter';

export class NeverHubCommandPackage extends SlashCommandPackage {
  private neverhub?: NeverHubAdapter;

  async initialize(): Promise<void> {
    // Initialize command handlers first
    await super.initialize();
    
    // Setup NeverHub integration
    if (await NeverHubAdapter.detect()) {
      this.neverhub = new NeverHubAdapter();
      
      await this.neverhub.register({
        type: 'slash-commands-tasks',
        name: this.packageName,
        version: this.version,
        capabilities: [{
          type: 'slash-commands',
          name: 'task-management',
          commands: Object.keys(this.commands),
          version: this.version
        }]
      });
      
      // Listen for command execution events
      await this.neverhub.subscribe('slash-command.execute', async (event) => {
        if (this.commands[event.data.command]) {
          const response = await this.execute(event.data);
          
          await this.neverhub!.publishEvent({
            type: 'slash-command.response',
            data: {
              commandId: event.data.commandId,
              response,
              userId: event.data.userId
            }
          });
        }
      });
    }
  }
}

Core Types

SlashCommandContext

interface SlashCommandContext {
  commandId: string;           // Unique execution ID
  command: string;             // Command name (without /)
  args: string[];              // Raw arguments
  userId: string;              // User who executed
  platform: string;           // Platform (in-app, slack, etc.)
  conversationId?: string;     // Channel/conversation ID
  metadata?: Record<string, any>; // Platform-specific data
  timestamp: Date;             // Execution timestamp
}

SlashCommandResponse

interface SlashCommandResponse {
  success: boolean;            // Execution success
  message?: string;            // User-facing message
  data?: any;                  // Structured response data
  error?: string;              // Error message if failed
  formatting?: {               // Platform-specific formatting
    markdown?: string;
    plainText?: string;
    platform?: Record<string, any>;
  };
  ephemeral?: boolean;         // Private response flag
}

SlashCommandSpec

interface SlashCommandSpec {
  name: string;                // Command name
  description: string;         // Human-readable description
  usage?: string;              // Usage syntax
  examples?: string[];         // Usage examples
  aliases?: string[];          // Alternative names
  arguments?: SlashCommandArgument[]; // Expected arguments
  requiresAuth?: boolean;      // Authentication required
  minRole?: string;            // Minimum role required
  adminOnly?: boolean;         // Admin-only command
  platforms?: string[];        // Supported platforms
  category?: string;           // Help category
  enabled?: boolean;           // Default enabled state
}

Utilities

Command Parsing

import { parseCommandString, createCommandContext } from '@bernierllc/slash-commands-core';

const { command, args } = parseCommandString('/hello world');
// command: "hello", args: ["world"]

const context = createCommandContext('/hello world', 'user123', 'in-app');

Response Helpers

import { createSuccessResponse, createErrorResponse } from '@bernierllc/slash-commands-core';

// Success response
const success = createSuccessResponse('Task created successfully', { id: '123' });

// Error response  
const error = createErrorResponse('Task not found', true);

Validation

import { validateCommandArgs, isValidCommandName, z } from '@bernierllc/slash-commands-core';

// Validate command name
const valid = isValidCommandName('my-command'); // true
const invalid = isValidCommandName('My Command'); // false

// Validate arguments with Zod
const schema = z.object({
  title: z.string().min(1),
  priority: z.enum(['low', 'medium', 'high'])
});

Rate Limiting

import { CommandRateLimiter } from '@bernierllc/slash-commands-core';

const limiter = new CommandRateLimiter(10, 60000); // 10 requests per minute

if (!limiter.isAllowed(userId)) {
  const remaining = limiter.getRemainingRequests(userId);
  const resetTime = limiter.getTimeUntilReset(userId);
  // Handle rate limit exceeded
}

Platform Formatting

import { formatResponseForPlatform, escapeForPlatform } from '@bernierllc/slash-commands-core';

const response = {
  success: true,
  message: 'Default message',
  formatting: {
    markdown: '**Bold** message',
    plainText: 'Bold message'
  }
};

const slackFormatted = formatResponseForPlatform(response, 'slack');
const escaped = escapeForPlatform('Special *chars*', 'discord');

Architecture Pattern

The slash-commands-core follows the validator pattern used throughout BernierLLC packages:

  1. Core Package (@bernierllc/slash-commands-core) - Provides foundation types and utilities
  2. Specific Packages (@bernierllc/slash-commands-tasks, etc.) - Implement specific commands
  3. Suite Integration - In-app-chat suite orchestrates command routing via NeverHub

MECE Principles

  • Mutually Exclusive - Each command package handles distinct functionality
  • Collectively Exhaustive - All command needs covered by the ecosystem
  • Service Discovery - Commands auto-register when packages come online
  • Graceful Degradation - Works without optional command packages

Integration with In-App Chat

Commands automatically integrate with @bernierllc/in-app-chat when both packages are available:

  1. Command packages register with NeverHub
  2. In-app-chat discovers available commands
  3. Users can execute commands across platforms (in-app, Slack, Discord, Teams)
  4. Responses are formatted appropriately for each platform

Development Workflow

1. Create Command Package

mkdir my-commands-package
cd my-commands-package
npm init
npm install @bernierllc/slash-commands-core

2. Implement Commands

Extend SlashCommandPackage and implement your commands following the examples above.

3. Test Locally

const package = new MyCommandsPackage();
await package.initialize();

const context = createCommandContext('/hello world', 'user123', 'in-app');
const response = await package.execute(context);

4. Publish and Register

Once published, the package will automatically be discovered by in-app-chat suite when both are running.

See Also

License

Copyright (c) 2025 Bernier LLC. All rights reserved.