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 🙏

© 2024 – Pkg Stats / Ryan Hefner

pg-events

v1.0.2

Published

Implements publish/subscribe or event emitting mechanism with PostgreSQL Notifications

Downloads

7

Readme

TypeSafe PubSub with PostgreSQL

version coverage minsize license node

Install

npm i --save pg-events

Usage

import { Client } from 'pg';
import { PubSub, ClientProvider, Contract, encoder, decoder } from 'pg-events';

// 1. Define channels
enum Channel {
  myChannel = 'myChannel',
}

// 2. Define protocol
interface Protocol {
  [Channel.myChannel]: { message: string };
}

// 3. Define conection options
const options = {
  user: 'postgres',
  password: 'postgres',
  database: 'postgres',
};

// 4. Initialize connection provider
const provider = new ClientProvider();

// 5. Initialize pubsub instance
const pubSub = new PubSub<Contract<Protocol>>({
  decoder, // default object->JSON decoder
  encoder, // default JSON->object encoder
  provider, // connection emitter
});

// 6. Usage

(async () => {
  // 7. Initialize PG connection
  const client = new Client(options);
  // 8. Connect to PostgreSQL server
  await client.connect();

  // 9. Emit connection to PubSub
  provider.next(client);

  // 10. Add event listener
  pubSub.on(Channel.myChannel, async ({ message }) => {
    console.warn('Received ' + message);
  });

  // 11. Subscribe to channel
  await pubSub.subscribe(Channel.myChannel);

  // 12. Emit message
  await pubSub.publish(Channel.myChannel, { message: 'Hello!' });

  // 13. Close PubSub
  await pubSub.end();
  await client.end();
})();

Strict mode

Implement AsyncEncoder to validate payload before broadcasting.

Implement AsyncDecoder to ensure valid payloads are received

import { Client } from 'pg';
import { PubSub, ClientProvider, Contract, encoder, decoder } from 'pg-events';

// 1. Define channels
enum Channel {
  myChannel = 'myChannel',
}

// 2. Define protocol
interface Protocol {
  [Channel.myChannel]: { value: number };
}

// 3. Define conection options
const options = {
  user: 'postgres',
  password: 'postgres',
  database: 'postgres',
};

// 4. Initialize connection provider
const provider = new ClientProvider();

// 4.1 Define validators
function isMyChannelMessage(obj: any): obj is Protocol['myChannel'] {
  return obj && typeof obj === 'object' && typeof obj.value === 'number' && obj.value >= 0;
}

function checkMyChannelPayload(payload: any) {
  if (!isMyChannelMessage(payload)) {
    throw new Error('myChannel.value must be a positive number');
  }
}

// 5. Initialize strict pubsub instance
const strictPubSub = new PubSub<Contract<Protocol>>({
  // Custom async encoder which validates payload before publishing
  encoder: {
    async encode(payload: object): Promise<string> {
      checkMyChannelPayload(payload);
      return encoder.encode(payload);
    },
  },
  // Custom async decoder which validates payload before emitting
  decoder: {
    async decode(data: string): Promise<object> {
      const payload = await decoder.decode(data);
      checkMyChannelPayload(payload);
      return payload;
    },
  },
  provider, // connection emitter
});

// 6. Usage

(async () => {
  // 7. Initialize PG connection
  const client = new Client(options);
  // 8. Connect to PostgreSQL server
  await client.connect();

  // 9. Emit connection to PubSub
  provider.next(client);

  // 10. Add event listener
  strictPubSub.on(Channel.myChannel, async ({ value }) => {
    console.warn('Received ' + value);
  });

  strictPubSub.on('unprocessed', async (error) => {
    console.warn(error);
  });

  // 11. Subscribe to channel
  await strictPubSub.subscribe(Channel.myChannel);

  // 12. Emit message
  console.warn('First call sends 5');
  await strictPubSub.publish(Channel.myChannel, { value: 5 });

  // 13. Emit message with invalid payload
  console.warn('Second call sends -1');
  try {
    await strictPubSub.publish(Channel.myChannel, { value: -1 });
  } catch (error) {
    console.warn('It fails because -1 is not a negative number');
  }
  // 14. Close PubSub
  await strictPubSub.end();
  await client.end();
})();