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

@enclosurejs/commands

v1.1.0

Published

Semantic command registry with execute pipeline for Enclosure apps

Downloads

245

Readme

@enclosurejs/commands — Semantic command registry with keyboard shortcut binding

[!IMPORTANT] This is a universal module that provides a semantic command registry for Enclosure apps. Commands are registered with a stable string id, human-readable title, and handler. Any surface — command palette, menu, toolbar, keyboard shortcut, test harness — invokes the same handler through execute(id). Optional integration with ShortcutToken binds platform keyboard shortcuts to command execution without coupling the registry to any platform.

The Problem

Desktop and web shells need a single execution path for user actions: palette search, menu clicks, toolbar buttons, and keyboard shortcuts should all funnel through the same handler. Without a registry, each app reinvents command lookup, duplicate-id detection, shortcut binding, and disposable cleanup. The raw ShortcutService in core maps accelerator → callback but has no notion of command identity, metadata for UI discovery, or structured registration/unregistration.

@enclosurejs/commands solves this with:

  • Registryregister(definition, handler) with duplicate detection (strictIds) and Disposable cleanup
  • Executeexecute(id) as the single invocation path, sync and async handlers, CoreError on unknown ids
  • Discoverylist() returns sorted descriptors for palette/menu rendering
  • Shortcut bindingbindShortcut(id, accelerator) delegates to ShortcutToken when present in DI

Architecture

┌─────────────────── Application ──────────────────┐
│                                                    │
│  Module installs CommandsService via DI            │
│                                                    │
│  register({ id: 'app.save', title: 'Save' }, fn)  │
│           │                                        │
│           │  ┌──────────────┐                      │
│           └─▶│   Registry   │◀── execute('app.save')
│              │  Map<id, fn> │                      │
│              └──────┬───────┘                      │
│                     │                              │
│        bindShortcut('app.save', 'Ctrl+S')          │
│                     │                              │
│              ┌──────▼───────┐                      │
│              │ ShortcutToken │  (optional, via DI)  │
│              │  platform KB  │                      │
│              └──────────────┘                      │
└────────────────────────────────────────────────────┘

Relationship to ShortcutService

| Layer | Responsibility | | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | ShortcutService (core capability) | Platform: register(accelerator, handler) — global key chord fires callback | | @enclosurejs/commands | App: register({ id, title }, handler) + execute(id) + optional bindShortcut(id, accelerator) that delegates to ShortcutToken |

No overlap — shortcuts stay the low-level platform capability; commands add identity, discovery, and a single funnel for invocation.

Quick Start

Via Module (recommended)

import { createCommandsModule, CommandsToken } from '@enclosurejs/commands';

const app = createApp({
    modules: [createCommandsModule()],
    // ...
});

// After app start, resolve from DI:
const commands = context.use(CommandsToken);

const disposable = commands.register(
    { id: 'app.save', title: 'Save', category: 'File' },
    async () => {
        await saveDocument();
    },
);

await commands.execute('app.save');

// Optional: bind a keyboard shortcut (requires ShortcutToken in DI)
commands.bindShortcut('app.save', 'Ctrl+S');

// Cleanup
disposable.dispose();

Direct use (without Module)

import { CommandsServiceImpl } from '@enclosurejs/commands';

const service = new CommandsServiceImpl(context, { strictIds: false });
service.register({ id: 'edit.copy', title: 'Copy' }, () => copySelection());

API

| Export | Kind | Purpose | | ---------------------- | ------- | ----------------------------------------------------- | | createCommandsModule | factory | Returns a Module that provides CommandsToken | | CommandsToken | token | Resolve CommandsService from DI | | CommandsServiceImpl | class | Direct instantiation without module system | | createShortcutBinder | factory | Low-level bridge to ShortcutToken (used internally) |

CommandDefinition

| Field | Type | Required | Description | | ---------- | -------- | -------- | -------------------------------------- | | id | string | Yes | Stable identifier (e.g. 'app.save') | | title | string | Yes | Human-readable label for palette/menu | | category | string | No | Grouping key (e.g. 'File', 'Edit') |

CommandsOptions

| Field | Type | Default | Description | | ----------- | --------- | ------- | ------------------------------------------------------- | | strictIds | boolean | true | true: duplicate id throws; false: replaces silently |

CommandsService

| Member | Type | Description | | ------------------------------- | ------ | ------------------------------------------------------------------------------------- | | register(definition, handler) | method | Register a command. Returns Disposable that unregisters on dispose | | unregister(id) | method | Remove by id. No-op if missing | | execute(id) | method | Invoke the handler. Throws CoreError (COMMAND_NOT_FOUND) if unknown | | has(id) | method | Check if a command is registered | | list() | method | All descriptors, sorted by id | | bindShortcut(id, accelerator) | method | Bind keyboard shortcut via ShortcutToken. Throws if token absent or command unknown |

ShortcutBinder

| Member | Type | Description | | ------------------------------ | ------ | ----------------------------------------------------------------------- | | bind(commandId, accelerator) | method | Register an accelerator that executes the command. Returns Disposable |

Configuration

Zero configuration files. Pass CommandsOptions to createCommandsModule() or CommandsServiceImpl constructor:

createCommandsModule({ strictIds: false });

The only option is strictIds (default true) — controls duplicate command id policy.

Types Exported

| Type | Used by | | ------------------- | ----------------------------------------------- | | CommandsService | Consumers resolving from DI via CommandsToken | | CommandDefinition | Command registration call sites | | CommandDescriptor | Palette/menu renderers consuming list() | | CommandHandler | Handler functions passed to register() | | CommandsOptions | Module/service configuration | | ShortcutBinder | Advanced: custom shortcut binding logic |

Safety

Error Model

All errors thrown by this package are CoreError instances (domain 'commands'):

| Code | When | | --------------------- | ----------------------------------------------------------- | | DUPLICATE_COMMAND | register() with an already-used id when strictIds: true | | COMMAND_NOT_FOUND | execute() or bindShortcut() with an unknown command id | | NO_SHORTCUT_SERVICE | bindShortcut() when ShortcutToken is not in DI |

Lifecycle Safety

  • register() returns Disposable — add to DisposableGroup for automatic cleanup
  • unregister() is idempotent (no-op for missing ids)
  • bindShortcut() returns Disposable that unbinds the keyboard shortcut

Handler Safety

  • Sync and async handlers are both supported via Promise.resolve(handler())
  • Handler errors propagate through the execute() promise — callers can catch per-command
  • Concurrent executions of the same command are allowed (no single-flight restriction)

Benchmarks

Not applicable. The command registry is a thin in-memory Map lookup — register, execute, has are O(1), list is O(n log n) sort. No I/O, no workers, no async overhead beyond handler execution. Performance is dominated by the handlers themselves, not the registry.

Bundle Size

| Output | File | Size | | ------------ | ------------ | ------- | | Runtime (JS) | index.js | 2.65 KB | | Types (DTS) | index.d.ts | 2.51 KB | | Total | | 5.16 KB |

Single entrypoint. Single external dependency (@enclosurejs/core) marked as external in the build.

Quality

| Metric | Value | | --------------------- | ------------------------------------------------------------------ | | Unit tests | 38 (all pass) | | Test files | 3 (service, module, shortcuts-bind) | | Source files | 5 (types, service, shortcuts-bind, module, index) | | Dependencies | 1 (@enclosurejs/core — workspace) | | External dependencies | 0 (devDependencies only: tsup) | | Coverage thresholds | statements >= 90%, branches >= 85%, functions >= 95%, lines >= 90% |

Quality Layers

Layer 1: STATIC ANALYSIS (every commit)
  tsc --noEmit        strict mode, zero errors
  eslint              ESLint 9 flat config, zero warnings
  prettier --check    formatting

Layer 2: UNIT TESTS (every commit)
  38 tests            service (23), module (8), shortcuts-bind (7)
                      covers register, unregister, execute, has, list,
                      duplicate detection, strictIds, dispose, bindShortcut,
                      ShortcutToken absent/present, async handlers,
                      concurrent execute, error propagation
  v8 coverage         statements >= 90%, branches >= 85%, functions >= 95%, lines >= 90%

Layer 3: BENCHMARKS
  N/A                 in-memory Map — no meaningful benchmark target

Layer 4: PACKAGE HEALTH
  1 workspace dep     @enclosurejs/core (types + CoreError + DI, externalized in build)
  tsup build          ESM + DTS output, single entrypoint

File Structure

packages/commands/
├── src/
│   ├── index.ts              Barrel: types, service, module, binder
│   ├── types.ts              CommandDefinition, CommandDescriptor, CommandsService, CommandsOptions
│   ├── service.ts            CommandsServiceImpl — registry, execute, list, shortcut binding
│   ├── shortcuts-bind.ts     ShortcutBinder — optional bridge to ShortcutToken
│   ├── module.ts             createCommandsModule(), CommandsToken
│   └── __tests__/
│       ├── service.test.ts       23 tests — register, unregister, execute, has, list, bindShortcut
│       ├── module.test.ts         8 tests — module id, install, token provision, options forwarding
│       └── shortcuts-bind.test.ts 7 tests — binder creation, bind/unbind, handler delegation
├── .prettierignore
├── package.json
├── tsconfig.json
├── tsup.config.ts
├── spec.md
└── README.md

License

MIT