Observers

In Harpia, Observers provide a powerful mechanism to listen for and react to database events using Prisma’s extension capabilities. They allow you to trigger side effects automatically whenever a specific database operation occurs, such as sending a welcome email after a user is created or invalidating a cache when a record is updated.

This approach ensures that your core business logic (Services) remains strictly decoupled from secondary side effects.

Generating an Observer

Observers are defined within the app/observers/ directory. You can quickly generate a new observer using the Harpia CLI:

bun harpia generate observer user

Alternatively, using the shorthand:

bun g observer user

This command scaffolds a new observer file (user.observer.ts) tailored for your specified model.

Defining Triggers

Harpia’s Observer system uses a fluent registration API. An observer file imports the global Observer object and registers a callback for a specific model and operation via the Observer.model() method.

// app/observers/user.observer.ts
import { Observer } from "app/observers";

/**
 * Observer for the User model.
 */
Observer.model("User", "create", async ({ data, model, operation }) => {
  /**
   * This callback runs every time a `create` operation is successfully called
   * on the User model.
   *
   * Add your custom logic here, like logging, triggering side effects, etc.
   */
  console.log(`A new ${model} was created!`);
  
  // Example: Triggering an email service
  // await mailService.sendWelcomeEmail(data.email);
});

The Callback Arguments

The asynchronous callback function receives a single context object containing three properties:

  • data: The exact arguments passed to the underlying Prisma operation (e.g., data, where, select).
  • model: A string representing the name of the model being operated on (e.g., "User").
  • operation: A string representing the executed Prisma operation (e.g., "create").

Auto-Discovery Mechanism

You do not need to manually import your observer files anywhere in your application.

Under the hood, Harpia uses an ObserverManager (located in app/observers/index.ts) which recursively scans for any file ending in .observer.ts during the server boot phase (start/server.ts). This guarantees that your side-effect logic is automatically discovered, registered, and bound to the Prisma Client Extension invisibly.

Supported Operations

You can hook into any of the standard Prisma operations. The operation argument in Observer.model() strongly types these events, including but not limited to:

  • create, createMany, createManyAndReturn
  • update, updateMany
  • delete, deleteMany
  • upsert
  • findUnique, findFirst, findMany

Simply register a new Observer.model() block for every distinct operation you wish to observe.