stacks-listeners

$npx mdskill add stacksjs/stacks/stacks-listeners

Create event listeners to handle application events

  • Define and register event listeners in `app/Listeners/` for specific events.
  • Use TypeScript's dynamic import feature to load corresponding actions based on listener names.
  • Decide which action to execute by matching the event name with registered listeners in `app/Events.ts`.
  • Execute the selected action, caching it once per module to improve performance.

SKILL.md

.github/skills/stacks-listenersView on GitHub ↗
---
name: stacks-listeners
description: Use when creating event listeners in app/Listeners/ — the listener file structure, registering listeners in app/Events.ts, the listener-to-action mapping pattern, CLI event listeners in Console.ts, or debugging listener execution. For the event system API (dispatch, listen, emitter, model events), see stacks-events.
license: MIT
compatibility: Bun >= 1.3.0, TypeScript
allowed-tools: Read Edit Write Bash Grep Glob
---

# Stacks Event Listeners

Application-level event listeners in `app/Listeners/`.

## Key Paths
- Listeners: `app/Listeners/`
- Event mapping: `app/Events.ts`
- Listener setup: `app/Listener.ts`

## Event → Listener Mapping (app/Events.ts)

```typescript
export default {
  'user:registered': ['SendWelcomeEmail'],    // triggers app/Actions/SendWelcomeEmail.ts
  'user:created': ['NotifyUser'],             // triggers app/Actions/NotifyUser.ts
  'order:created': ['ProcessPayment', 'SendOrderConfirmation'],  // multiple listeners
} satisfies Events
```

Keys are event names. Values are arrays of Action names from `app/Actions/`.

## How Listeners Work

1. Events are dispatched: `dispatch('user:registered', { id: 1 })`
2. The wildcard handler in `app/Listener.ts` catches ALL events
3. Checks if the event has registered listeners in `app/Events.ts`
4. For each listener, dynamically imports `app/Actions/{listener}.ts`
5. Calls `action.handle(eventData)`
6. Action modules are cached after first import

## Creating a Listener Action

```typescript
// app/Actions/SendWelcomeEmail.ts
export default {
  name: 'SendWelcomeEmail',

  async handle(event: { id: number; email: string; name: string }) {
    // event contains the data passed to dispatch()
    await sendWelcomeEmail({ to: event.email, name: event.name })
    return { success: true }
  }
}
```

## CLI Event Listeners (app/Listeners/Console.ts)

For CLI-specific events (not HTTP):

```typescript
export default function(cli: CLI) {
  // Specific command
  cli.on('inspire:three', () => {
    console.log(getThreeQuotes())
  })

  // Default handler (unknown commands)
  cli.on('inspire:!', () => {
    console.log('Unknown inspire command')
  })

  // Wildcard (matches inspire:anything)
  cli.on('inspire:*', () => {
    console.log('Some inspire variant')
  })
}
```

## Multiple Listeners Per Event

```typescript
// app/Events.ts
{
  'order:created': [
    'ProcessPayment',          // runs first
    'SendOrderConfirmation',   // runs second
    'UpdateInventory',         // runs third
    'NotifyWarehouse'          // runs fourth
  ]
}
```

Listeners execute sequentially (not in parallel) — each awaits completion.

## Gotchas
- Listeners are Action names, not file paths — `'SendWelcomeEmail'` resolves to `app/Actions/SendWelcomeEmail.ts`
- The action must have a `handle(event)` method
- Listeners run sequentially per event — order in the array matters
- Action modules are cached after first load — no hot-reload for listeners
- CLI listeners are separate from HTTP event listeners
- For the event API (dispatch, listen, emitter), see the `stacks-events` skill

More from stacksjs/stacks

SkillDescription
stacks-actionsUse when working with Stacks server actions — creating actions in app/Actions/, auto-generated API actions from the useApi model trait, the 80+ default framework actions (auth, dashboard, commerce, content, deployment, jobs), action request/response handling, or action registration. Covers @stacksjs/actions and storage/framework/defaults/actions/.
stacks-aiUse when integrating AI capabilities into a Stacks application — using Anthropic/OpenAI/Ollama/AWS Bedrock drivers, image generation (DALL-E), vision analysis, RAG/vector search, embeddings, MCP (Model Context Protocol) clients, text summarization, sentiment analysis, content classification, personalization, or the buddy AI assistant. Covers @stacksjs/ai and config/ai.ts.
stacks-aliasUse when working with path aliases in a Stacks project — import resolution, module aliasing, or debugging import paths. Covers @stacksjs/alias which defines 260+ path mappings for the entire framework.
stacks-analyticsUse when adding analytics to a Stacks application — configuring Fathom or self-hosted analytics, generating tracking scripts, privacy-friendly analytics setup, or the analytics configuration. Covers @stacksjs/analytics and config/analytics.ts.
stacks-apiUse when building, modifying, or debugging API endpoints in a Stacks application — defining routes, handling requests, API middleware, working with the API server, HTTP client (fetcher), API resources, or OpenAPI generation. Covers both @stacksjs/api utilities and the stacks-api server implementation.
stacks-arraysUse when working with array utilities in Stacks — statistical operations (average, median, mode, standard deviation, z-score, percentile, covariance), array manipulation (unique, flatten, partition, shuffle, sample, move), containment checks, or the Arr facade. Covers @stacksjs/arrays.
stacks-authUse when implementing authentication, authorization, passkeys, TOTP/2FA, RBAC, gates, policies, session auth, token management, email verification, password resets, or rate limiting in a Stacks application. Covers the @stacksjs/auth package, config/auth.ts, app/Gates.ts, and app/Middleware/.
stacks-auto-importsUse when working with the Stacks auto-import system — understanding how browser and server auto-imports work, configuring auto-imported functions/models/composables, the auto-import manifests, type generation, or how globals are injected. Covers the auto-import pipeline at storage/framework/auto-imports/.
stacks-brandkitUse when defining or exploring a brand identity for a Stacks project and you want premium brand-kit REFERENCE IMAGES first - logo directions, palettes, typography specimens, identity boards, and application/mockup decks. Generates IMAGES ONLY, never code. Trained for minimalist, cinematic, editorial, dark-tech, luxury, cultural, security, gaming, developer-tool, and consumer-app brand systems with intentional logo concepting, sparse type, strong symbolic meaning, and disciplined palettes a coding step can build against.
stacks-browseUse for headless browser QA on Stacks applications — navigation, screenshots, responsive testing, console/network monitoring, and accessibility snapshots. Dependency-free: drives a system browser over the Chrome DevTools Protocol using only Bun (no Playwright/Puppeteer). Invoke with /stacks-browse.