add-resource-events

Add real-time event emission to a resource service. Use when adding SSE/real-time capabilities to a resource. Triggers on "add events", "real-time events", "SSE events".

16 stars

Best use case

add-resource-events is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Add real-time event emission to a resource service. Use when adding SSE/real-time capabilities to a resource. Triggers on "add events", "real-time events", "SSE events".

Teams using add-resource-events should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/add-resource-events/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/backend/add-resource-events/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/add-resource-events/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How add-resource-events Compares

Feature / Agentadd-resource-eventsStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Add real-time event emission to a resource service. Use when adding SSE/real-time capabilities to a resource. Triggers on "add events", "real-time events", "SSE events".

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Add Resource Events

Enables real-time event emission for a resource service via Server-Sent Events (SSE).

## Quick Reference

**Event Infrastructure**:

- `src/events/event-emitter.ts` - Singleton `AppEventEmitter`
- `src/events/base.service.ts` - `BaseService` with `emitEvent()`
- `src/schemas/event.schema.ts` - Event type definitions
- `src/routes/events.router.ts` - SSE endpoint

**Event Pattern**: `{serviceName}:{action}` (e.g., `notes:created`, `notes:updated`)

## Prerequisites

To add events to a resource:

1. Service must extend `BaseService` (see `create-resource-service`)
2. Authorization methods for events in `AuthorizationService`

## How It Works

### 1. BaseService Provides emitEvent()

```typescript
// src/events/base.service.ts
export abstract class BaseService {
  constructor(protected serviceName: string) {}

  protected emitEvent<T>(
    action: ServiceEventType["action"],
    data: T,
    options?: {
      id?: string;
      user?: { userId: string; [key: string]: unknown };
    },
  ) {
    appEvents.emitServiceEvent(this.serviceName, {
      id: options?.id || uuidv4(),
      action,
      data,
      user: eventUser,
      timestamp: new Date(),
      resourceType: this.serviceName,
    });
  }
}
```

### 2. Resource Service Emits Events

```typescript
export class NoteService extends BaseService {
  constructor(...) {
    super("notes"); // Service name for event routing
  }

  async create(data, user) {
    // ... create logic ...

    this.emitEvent("created", note, { id: note.id, user });

    return note;
  }

  async update(id, data, user) {
    // ... update logic ...

    this.emitEvent("updated", updatedNote, { id: updatedNote.id, user });

    return updatedNote;
  }

  async delete(id, user) {
    // ... delete logic ...

    this.emitEvent("deleted", note, { id: note.id, user });

    return true;
  }
}
```

### 3. Events Router Streams to Clients

```typescript
// src/routes/events.router.ts
appEvents.on("notes:created", eventHandler);
appEvents.on("notes:updated", eventHandler);
appEvents.on("notes:deleted", eventHandler);
```

## Adding Events to a New Resource

### Step 1: Extend BaseService

Your service must extend `BaseService`:

```typescript
import { BaseService } from "@/events/base.service";

export class {Entity}Service extends BaseService {
  constructor(...) {
    super("{entities}"); // Plural for event namespace
  }
}
```

### Step 2: Emit Events in CRUD Methods

Add `emitEvent()` calls after successful operations:

```typescript
async create(data, user) {
  const {entity} = await this.repository.create(data, user.userId);

  this.emitEvent("created", {entity}, { id: {entity}.id, user });

  return {entity};
}

async update(id, data, user) {
  const updated = await this.repository.update(id, data);
  if (!updated) return null;

  this.emitEvent("updated", updated, { id: updated.id, user });

  return updated;
}

async delete(id, user) {
  const {entity} = await this.repository.findById(id);
  const deleted = await this.repository.remove(id);

  if (deleted) {
    this.emitEvent("deleted", {entity}, { id: {entity}.id, user });
  }

  return deleted;
}
```

### Step 3: Add Event Authorization

In `src/services/authorization.service.ts`:

```typescript
async canReceive{Entity}Event(
  user: AuthenticatedUserContextType,
  {entity}Data: { createdBy: string; [key: string]: unknown },
): Promise<boolean> {
  if (this.isAdmin(user)) return true;
  if ({entity}Data.createdBy === user.userId) return true;
  return false;
}
```

### Step 4: Update Events Router

In `src/routes/events.router.ts`, add listeners:

```typescript
// Listen to {entity} events
appEvents.on("{entities}:created", eventHandler);
appEvents.on("{entities}:updated", eventHandler);
appEvents.on("{entities}:deleted", eventHandler);
```

Update the `shouldUserReceiveEvent` function:

```typescript
async function shouldUserReceiveEvent(
  event: ServiceEventType,
  user: AuthenticatedUserContextType,
  authorizationService: AuthorizationService,
): Promise<boolean> {
  switch (event.resourceType) {
    case "notes":
      // ... existing ...
    case "{entities}":
      if (
        typeof event.data === "object" &&
        event.data !== null &&
        "createdBy" in event.data
      ) {
        return await authorizationService.canReceive{Entity}Event(
          user,
          event.data as { createdBy: string; [key: string]: unknown },
        );
      }
      return false;
    default:
      return false;
  }
}
```

### Step 5: Add Event Schema (Optional)

In `src/schemas/event.schema.ts`:

```typescript
export const {entity}EventSchema = serviceEventSchema.extend({
  data: z.object({
    id: z.string(),
    // ... entity-specific fields
    createdAt: z.date().optional(),
    updatedAt: z.date().optional(),
  }),
});

export type {Entity}EventType = z.infer<typeof {entity}EventSchema>;
```

## Event Flow

```
1. Client: POST /notes (create a note)
2. Controller: calls NoteService.create()
3. Service: creates note, calls this.emitEvent("created", note, ...)
4. BaseService: appEvents.emitServiceEvent("notes", { action: "created", ... })
5. EventEmitter: emits "notes:created" event
6. Events Router: catches event, checks authorization
7. SSE Stream: sends to authorized clients
8. Client: receives { event: "notes:created", data: {...} }
```

## Client-Side Usage

```javascript
const eventSource = new EventSource("/events", {
  headers: { Authorization: `Bearer ${token}` },
});

eventSource.addEventListener("notes:created", (event) => {
  const data = JSON.parse(event.data);
  console.log("New note:", data);
});

eventSource.addEventListener("notes:updated", (event) => {
  const data = JSON.parse(event.data);
  console.log("Updated note:", data);
});

eventSource.addEventListener("notes:deleted", (event) => {
  const data = JSON.parse(event.data);
  console.log("Deleted note:", data);
});
```

## What NOT to Do

- Do NOT emit events before confirming operation succeeded
- Do NOT emit events for failed/unauthorized operations
- Do NOT skip authorization checks in events router
- Do NOT forget to clean up event listeners on disconnect

## See Also

- `create-resource-service` - Creating services with event emission
- `create-routes` - Events router example
- `test-resource-service` - Testing event emission

Related Skills

analytics-events

16
from diegosouzapw/awesome-omni-skill

Add product analytics events to track user interactions in the Metabase frontend

events-webinars

16
from diegosouzapw/awesome-omni-skill

Use this skill when a VP of Events or field marketing leader needs to plan and execute the full events program — including webinars, technology workshops, solution workshops, global speaking engagements, conferences, and community events — capturing leads, filling the sales calendar post-event, and building market presence with investors, enterprise buyers, and practitioners.

symfony:api-platform-resources

16
from diegosouzapw/awesome-omni-skill

Use when symfony api platform resources

symfony:api-platform-dto-resources

16
from diegosouzapw/awesome-omni-skill

Use when symfony api platform dto resources

newsletter-events-write

16
from diegosouzapw/awesome-omni-skill

Generate markdown newsletters from stored events. Use when the user wants to create, write, or generate a newsletter from scraped events.

microsoft-azure-webjobs-extensions-authentication-events-dotnet

16
from diegosouzapw/awesome-omni-skill

Microsoft Entra Authentication Events SDK for .NET. Azure Functions triggers for custom authentication extensions.

azure-resource-manager-sql-dotnet

16
from diegosouzapw/awesome-omni-skill

Azure Resource Manager SDK for Azure SQL in .NET.

azure-resource-manager-redis-dotnet

16
from diegosouzapw/awesome-omni-skill

Azure Resource Manager SDK for Redis in .NET.

azure-resource-manager-postgresql-dotnet

16
from diegosouzapw/awesome-omni-skill

Azure PostgreSQL Flexible Server SDK for .NET. Database management for PostgreSQL Flexible Server deployments.

azure-resource-manager-mysql-dotnet

16
from diegosouzapw/awesome-omni-skill

Azure MySQL Flexible Server SDK for .NET. Database management for MySQL Flexible Server deployments.

api-resource-patterns

16
from diegosouzapw/awesome-omni-skill

Best practices for Laravel API Resources including resource transformation, collection handling, conditional attributes, and relationship loading.

ado-resource-validator

16
from diegosouzapw/awesome-omni-skill

Validates Azure DevOps projects, area paths, and teams exist with auto-creation of missing resources. Use when setting up ADO integration, configuring .env variables, or troubleshooting missing project errors. Supports project-per-team, area-path-based, and team-based strategies.