# suub

> A simple pub/sub written in Typescript

Latest version **5.1.2** (published 2023-06-12) · MIT license · 0 weekly downloads

> **Deprecated.** This package is deprecated.

## Install

```sh
npm install suub
pnpm add suub
yarn add suub
bun add suub
```

## Health

**Score 10/100 (F)** — status: deprecated.

Negative: deprecated.

## Facts

| | |
|---|---|
| Version | 5.1.2 |
| Published | 2023-06-12 |
| First published | 2019-10-20 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 1 |
| Unpacked size | 34.1 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 14 |
| Author | Etienne Dldc |
| Maintainers | etienne-dldc |
| Keywords | subscribe, ts, pubsub, typescript |

## Links

- npm: https://www.npmjs.com/package/suub
- Repository: https://github.com/etienne-dldc/suub
- Homepage: https://github.com/etienne-dldc/suub#readme
- Issues: https://github.com/etienne-dldc/suub/issues
- npm.io page: https://npm.io/package/suub

## Dependencies (1)

- [erreur](https://npm.io/package/erreur.md) ^2.1.0

## Alternatives

- [csv-to-markdown-table](https://npm.io/package/csv-to-markdown-table.md) — 47.0K weekly downloads
- [@sapphire/ratelimits](https://npm.io/package/@sapphire/ratelimits.md) — 4.4K weekly downloads
- [js-csvparser](https://npm.io/package/js-csvparser.md) — 2.0K weekly downloads
- [@adadapted/js-sdk](https://npm.io/package/@adadapted/js-sdk.md) — 251 weekly downloads
- [@grapecity/spread-sheets-sparklines](https://npm.io/package/@grapecity/spread-sheets-sparklines.md) — 103 weekly downloads

## Recent versions

- 5.1.2 (latest) — 2023-06-12
- 5.1.1 — 2023-06-11
- 5.1.0 — 2023-05-18
- 5.0.2 — 2023-05-17
- 5.0.1 — 2023-05-17
- 5.0.0 — 2023-05-17
- 4.0.3 — 2023-05-17
- 4.0.2 — 2023-05-13
- 4.0.1 — 2023-03-25
- 4.0.0 — 2023-03-25
- 3.4.0 — 2023-03-09
- 3.3.0 — 2023-03-04
- 3.2.1 — 2022-05-10
- 3.2.0 — 2022-03-03
- 3.1.3 — 2020-11-17
- … 19 more at https://npm.io/package/suub/versions

## README

<p align="center">
  <img src="https://raw.githubusercontent.com/etienne-dldc/suub/main/design/logo.png" width="597" alt="suub logo">
</p>

# 📫 Suub

> A simple pub/sub written in Typescript

## Gist

```ts
import { Suub } from 'suub';

const mySub = Suub.createSubscription<number>();

const unsub = mySub.subscribe((num) => {
  console.log('num: ' + num);
});

mySub.emit(45); // num: 45

unsub();
```

## Guide

### Creating a Subscription

To create a `Subscription` you need to import the `Suub.createSubscription` function and call it.

```ts
import { Suub } from 'suub';

const subscription = Suub.createSubscription();
```

If you use TypeScript, you need to pass a type parameter to the `Suub.createSubscription` function to define the type of the value associated with the subscription.

```ts
import { Suub } from 'suub';

const numSubscription = Suub.createSubscription<number>();
```

If you don't want your subscription not to emit any value, you can use the `Suub.createVoidSubscription` function.

```ts
import { Suub } from 'suub';

const voidSubscription = Suub.createVoidSubscription();
```

### Subscribe and Unsubscribe

You have two ways to `subscribe` / `unsubscribe`.

- Using the reference of the callback function

```ts
const callback = () => {
  /*...*/
};

subscription.subscribe(callback);
// later
subscription.unsubscribe(callback);
```

- Using a SubId (a string)

```ts
subscription.subscribeById('mySubId', () => {
  /*...*/
});
// later
subscription.unsubscribeById('mySubId');
```

In both case the `subscribe[ById]` return a function that will unsubscribe:

```ts
const unsub = subscription.subscribe(/*...*/);
// later
unsub();
```

### Emitting value

To emit a value and trigger all subscribed `callback` you need to call the `emit` method.

```ts
subscription.emit(42);
// for void subscription you don't need to pass any value
subscription.emit();
```

### OnUnsubscribe

The `subscribe[ById]` methods accept a optional function after the callback, this function will be called when this callback you are subscribing is unsubscribed.

```ts
subscription.subscribe(
  () => {
    /* ... */
  },
  () => {
    console.log('Unsubscribed !');
  }
);

// or with a subId
subscription.subscribeById(
  'mySub',
  () => {
    /* ... */
  },
  () => {
    console.log('Unsubscribed !');
  }
);
```

### Unsubscribing all subscriptions

You can call `unsubscribeAll` method on a subscription to remove all callback. This will also trigger the `onUnsubscribe` if any.

```ts
subscription.unsubscribeAll();
```

### `Subscription` options

The `Subscription.create` (or `Subscription.createVoid`) functions accept an option object as parameter (all properties are optional):

```ts
const sub = Subscription.create({
  onFirstSubscription: () => {},
  onLastUnsubscribe: () => {},
  onDestroy: () => {},
  maxSubscriptionCount: 10000,
  maxRecursiveEmit: 1000,
  maxUnsubscribeAllLoop: 1000,
});
```

#### `onFirstSubscription`

> A function called when the number of subscribers goes from `0` to `1`

#### `onLastUnsubscribe`

> A function called when the number of subscribers goes from `1` to `0`

#### `onDestroy`

> A function called when the `destroy` method is called. Note that during this call the `Subscription` is already destroyed and you can't call `emit` or `subscribe` anymore.

#### `maxSubscriptionCount`

> A number to limit the maximum number of simultaneous subscriptions (default is `10000`). This limit exist to detect infinit subscription loop.

#### `maxRecursiveEmit`

> A number to limit the maximum recursive call of `emit` (default is `1000`). This limit exist to detect infinite loop where you `emit` in a `callback`.

#### `maxUnsubscribeAllLoop`

> A number to limit the maximum recursive call of `subscribe` inside a `onUnsubscribe` callback (default is `1000`).

### Testing if a callback / subId is subscribed

The `isSubscribed[ById]` methods let you test whether or not a callback / subId is currently subscribed

```ts
subscription.isSubscribed(myCallback); // <- boolean
subscription.isSubscribedById('my-sub-id'); // <- boolean
```

### Reading the number of active Subscriptions

You can call the `size` method to get the number of subscriptions.

```ts
subscription.size();
```

### Destroying a Subscription

You can call the `destroy` method to destroy a subscription. This will unsubscribe all callback and call the `onDestroy` option if any.

```ts
subscription.destroy();
```

Once destroyed, calling `emit` or `subscribe[ById]` will throw an error. You can still call the other methods but they will have no effect.

You can check if a subscription is destroyed by calling the `isDestroyed` method.

```ts
subscription.isDestroyed(); // <- boolean
```

## Channels

```
// TODO
```

## Some precisions

#### Callback are called in the order they are subscribed.

#### If you re-subscribe the same callback or id it will not re-do a subscription but instead move the subscription to the end.

In other words, calling `subscribe` on an already subscribed callback or subId will not make the callback called twice. But it will move the callback at the end of the subscription list.
In the case of a subId, the callback will be replaced by the new one.

#### If you call `unsubscribe` in a callback it will have effect immediatly.

If the callback you unsubscribe is supposed to run after the current callback, it will not be called.

#### If you `subscribe` in a callback it will not be called immediatly.

But it will be in the next `emit`.

#### If you `emit()` in a callback it will defer the call to after the current emit is done.

#### If you `subscribe` / `unsubscribe` / `emit` in an `onUnsubscribed` it will behave the same as if it was in the callback itself

#### Calling `destroy` will unsubscribe all callback and call the `onUnsubscribe` if any

In these `onUnsubscribe` callback the subscription is considered destroyed so you can't call `emit` or `subscribe` anymore.

#### Calling `destroy` on a destroyed subscription will have no effect

This is a no-op, it will not call `onDestroy` again.

#### The subscription is already considered destroyed when `onDestroy` is called

This means that you can't call `emit` or `subscribe` in the `onDestroy` callback and that `isDestroyed` will return `true` in the `onDestroy` callback.

## Examples

Take a look at the [Examples folder](https://github.com/etienne-dldc/suub/tree/master/examples).

## API

```ts
export type Unsubscribe = () => void;
export type OnUnsubscribed = () => void;
export type SubscriptionCallback<T> = (value: T) => void;
export type VoidSubscriptionCallback = () => void;
export type UnsubscribeAllMethod = () => void;

export interface SubscribeMethod<T> {
  (callback: SubscriptionCallback<T>, onUnsubscribe?: OnUnsubscribed): Unsubscribe;
  (subId: string, callback: SubscriptionCallback<T>, onUnsubscribe?: OnUnsubscribed): Unsubscribe;
}

export interface VoidSubscribeMethod {
  (callback: VoidSubscriptionCallback, onUnsubscribe?: OnUnsubscribed): Unsubscribe;
  (subId: string, callback: VoidSubscriptionCallback, onUnsubscribe?: OnUnsubscribed): Unsubscribe;
}

export interface IsSubscribedMethod<T> {
  (subId: string): boolean;
  (callback: SubscriptionCallback<T>): boolean;
}

export interface UnsubscribeMethod<T> {
  (subId: string): void;
  (callback: SubscriptionCallback<T>): void;
}

export interface VoidIsSubscribedMethod {
  (subId: string): boolean;
  (callback: VoidSubscriptionCallback): boolean;
}

export interface VoidUnsubscribeMethod {
  (subId: string): void;
  (callback: VoidSubscriptionCallback): void;
}

export interface ISubscription<T> {
  subscribe: SubscribeMethod<T>;
  unsubscribe: UnsubscribeMethod<T>;
  unsubscribeAll: UnsubscribeAllMethod;
  isSubscribed: IsSubscribedMethod<T>;
  size: () => number;
  emit: (newValue: T) => void;
  destroy: () => void;
  isDestroyed: () => boolean;
}

export interface IVoidSubscription {
  subscribe: VoidSubscribeMethod;
  unsubscribe: VoidUnsubscribeMethod;
  unsubscribeAll: UnsubscribeAllMethod;
  isSubscribed: VoidIsSubscribedMethod;
  size: () => number;
  emit: () => void;
  destroy: () => void;
  isDestroyed: () => boolean;
}

export interface ISubscriptionOptions {
  onFirstSubscription?: () => void;
  onLastUnsubscribe?: () => void;
  onDestroy?: () => void;
  maxSubscriptionCount?: number;
  maxRecursiveEmit?: number;
}
```

---
_Source: https://npm.io/package/suub · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
