Skip to content

CodyTseng/nostr-relay

Repository files navigation

nostr-relay

codecov FOSSA Status

Easily build your customized Nostr Relay.

Used By

Usage

I think examples are the best way to explain how to use this library.

import { NostrRelay, createOutgoingNoticeMessage } from '@nostr-relay/core';
import { EventRepositorySqlite } from '@nostr-relay/event-repository-sqlite';
import { Validator } from '@nostr-relay/validator';
import { WebSocketServer } from 'ws';

async function bootstrap() {
  const wss = new WebSocketServer({ port: 4869 });

  // You can implement your own event repository. It just needs to implement a few methods.
  const eventRepository = new EventRepositorySqlite();
  await eventRepository.init();
  const relay = new NostrRelay(eventRepository);
  const validator = new Validator();

  wss.on('connection', ws => {
    // Handle a new client connection. This method should be called when a new client connects to the Nostr Relay server.
    relay.handleConnection(ws);

    ws.on('message', async data => {
      try {
        // Validate the incoming message.
        const message = await validator.validateIncomingMessage(data);
        // Handle the incoming message.
        await relay.handleMessage(ws, message);
      } catch (error) {
        if (error instanceof Error) {
          ws.send(JSON.stringify(createOutgoingNoticeMessage(error.message)));
        }
      }
    });

    // Handle a client disconnection. This method should be called when a client disconnects from the Nostr Relay server.
    ws.on('close', () => relay.handleDisconnect(ws));

    ws.on('error', error => {
      ws.send(JSON.stringify(createOutgoingNoticeMessage(error.message)));
    });
  });
}
bootstrap();

Full API documentation can be found here

Plugin

Official plugins

You can create your own plugin to extend the functionality of the Nostr Relay. A plugin is just an object containing some of the following methods:

handleMessage

This method functions like Koa middleware and is called when a new message is received from a client.

Params:

  • ctx: The context object of the client.
  • message: The incoming message.
  • next: The next function to call the next plugin.

Example:

import { HandleMessagePlugin } from '@nostr-relay/common';

class MessageLoggerPlugin implements HandleMessagePlugin {
  async handleMessage(ctx, message, next) {
    const startTime = Date.now();
    console.log('Received message:', message);
    const result = await next();
    console.log('Message processed in', Date.now() - startTime, 'ms');
    return result;
  }
}

relay.register(new MessageLoggerPlugin());

beforeHandleEvent

This method will be called before handling an event. If the method returns false, the event will be ignored.

params:

  • event: The incoming event.

Example:

import { HandleMessagePlugin } from '@nostr-relay/common';

class BlacklistGuardPlugin implements BeforeHandleEventPlugin {
  private blacklist = [
    // ...
  ];

  beforeHandleEvent(event) {
    const canHandle = !this.blacklist.includes(event.pubkey);
    return {
      canHandle,
      message: canHandle ? undefined : 'block: you are blacklisted',
    };
  }
}

relay.register(new BlacklistGuardPlugin());

broadcast

This method functions like Koa middleware and is called when an event is broadcast.

Params:

  • event: The event to broadcast.
  • next: The next function to call the next plugin.

Example:

import { BroadcastPlugin } from '@nostr-relay/common';

class RedisBroadcastPlugin implements BroadcastPlugin {
  async broadcast(event, next) {
    await redis.publish('events', JSON.stringify(event));
    return next();
  }
}

relay.register(new RedisBroadcastPlugin());

More to come...

Donate

If you like this project, you can buy me a coffee :) ⚡️ codytseng@getalby.com ⚡️

License

FOSSA Status

About

A framework for developing a Nostr relay. (WIP)

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published