# rx-postmessenger

> Minimal RxJS adapter for the window.postMessage API for request-response streams and notification streams across frame windows.

Latest version **3.0.0** (published 2021-08-17) · MIT license · 0 weekly downloads

## Install

```sh
npm install rx-postmessenger
pnpm add rx-postmessenger
yarn add rx-postmessenger
bun add rx-postmessenger
```

## Health

**Score 30/100 (F)** — status: abandoned.

Positive: has types; esm support; no vulnerabilities; high quality score.

Warnings: low downloads.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 3.0.0 |
| Published | 2021-08-17 |
| First published | 2017-11-26 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 0 |
| Unpacked size | 380.1 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | Jeffrey Westerkamp |
| Maintainers | jjwesterkamp |
| Keywords | RxJS, Browser, iframe, postMessage, event, request, response, mapped, typescript |

## Links

- npm: https://www.npmjs.com/package/rx-postmessenger
- Repository: https://github.com/JJWesterkamp/rx-postmessenger
- Homepage: https://github.com/JJWesterkamp/rx-postmessenger#readme
- Issues: https://github.com/JJWesterkamp/rx-postmessenger/issues
- npm.io page: https://npm.io/package/rx-postmessenger

## Alternatives

- [async-exit-hook](https://npm.io/package/async-exit-hook.md) — 3.7M weekly downloads
- [evnty](https://npm.io/package/evnty.md) — 7.2K weekly downloads
- [eleventy-plugin-asciidoc](https://npm.io/package/eleventy-plugin-asciidoc.md) — 3.5K weekly downloads
- [@jswork/next-get2get](https://npm.io/package/@jswork/next-get2get.md) — 945 weekly downloads
- [@dashersw/axon](https://npm.io/package/@dashersw/axon.md) — 934 weekly downloads

## Recent versions

- 3.0.0 (latest) — 2021-08-17
- 2.0.1 — 2019-06-22
- 2.0.0 — 2019-05-27
- 2.0.0-alpha.1 — 2019-01-06
- 1.0.4 — 2019-01-06
- 1.0.3 — 2018-05-15
- 1.0.2 — 2018-03-17
- 1.0.1 — 2018-03-17
- 1.0.0 — 2018-03-12
- 1.0.0-beta.1 — 2018-01-14
- 0.2.1 — 2018-01-01
- 0.2.0 — 2018-01-01
- 0.1.12 — 2017-12-07
- 0.1.11 — 2017-12-07
- 0.1.10 — 2017-12-07
- … 9 more at https://npm.io/package/rx-postmessenger/versions

## README

# rx-postmessenger
[![npm version](https://badge.fury.io/js/rx-postmessenger.svg)](https://badge.fury.io/js/rx-postmessenger)
[![Build Status](https://travis-ci.com/JJWesterkamp/rx-postmessenger.svg?branch=master)](https://travis-ci.com/JJWesterkamp/rx-postmessenger)
[![Coverage Status](https://coveralls.io/repos/github/JJWesterkamp/rx-postmessenger/badge.svg?branch=master)](https://coveralls.io/github/JJWesterkamp/rx-postmessenger?branch=master)

Minimal [RxJS][rxgh] adapter for the [`Window # postMessage`][postmessage] API for request-response streams and notification streams across frame windows.

## In short

An RxPostmessenger class instance establishes one end of a connection between 2 window objects, using the `Window # postMessage` API. Each instance provides methods to initiate outgoing messages and handle incoming messages, both categorized by channel name.

Each instance targets _one single_ `Window` object. It propagates incoming `MessageEvent`s only from that specific window object while it's serving documents from _one single_ origin.

## RxJS Interoperability

|               | RxPostmessenger v1.x | RxPostmessenger v2.x | RxPostmessenger v3.x |
|---------------|:--------------------:|:--------------------:|:--------------------:|
| RxJS v5.x     |           ✅         |           ❌         |          ❌          |
| RxJS v6.x     |           ❌         |           ✅         |          ✅          |
| RxJS v7.x     |           ❌         |           ❌         |          ✅          |

[View changelog.][changelog]

## Installation

```bash
$ npm install rx-postmessenger --save
```

## Contents / API

**Static methods**

|Method|Description|
|:-|:-|
|[`connect()`](#connecting-2-window-objects)|Connect `Window` objects by creating messenger instances.|

**`Messenger` Instance methods**

|Method|Description|
|:-|:-|
|[`notify()`](#sending-notifications)|Send notifications to the connected window.|
|[`notifications()`](#listening-for-inbound-notifications)|Listen for inbound notifications.|
|[`request()`](#sending-requests)|Send requests to the connected window.|
|[`requests()`](#listening-for-inbound-requests)|Listen for inbound requests.|

**`Request` Instance methods**

|Method|Description|
|:-|:-|
|[`respond()`](#sending-request-responses)|Respond to the request with a certain payload.

---

## Usage

```javascript
import RxPostmessenger from 'rx-postmessenger';
```

### Static methods

#### Connecting 2 Window objects

> ```typescript
> RxPostmessenger.connect(otherWindow: Window, origin: string): RxPostmessenger.Messenger
> ```

Both ends of the connection should implement this package. One in a _parent_ project (that implements the iframe), and one in a _child_ project (that's being served by the iframe). Creating a new messenger is straightforward:

_At parent window - `https://parent-project.com`_

```javascript
const childMessenger = RxPostmessenger.connect(
    someIFrame.contentWindow,
    'https://child-project.com'
);
```

_At child window - `https://child-project.com`_

```javascript
const parentMessenger = RxPostmessenger.connect(
    window.parent,
    'https://parent-project.com'
);
```

### `Messenger` Instance methods

#### Sending notifications
> ```typescript
> Messenger.notify<T>(channel: string, payload?: T): void
> ```

The messenger instances give you a way to send notifications to the other `Window` through the `notify()` method. 
The notify method is void -- notifications are fire-and-forget. 
Use [`request()`](#sending-requests) instead if you require data back.
Consider an example where we want to notify a child window of price changes:

```javascript
childMessenger.notify('price-changed', {
    oldPrice: 12.50,
    newPrice: 14.50,
});
```

#### Listening for inbound notifications
> ```typescript
> Messenger.notifications<T = any>(channel: string): Observable<T>
> ```

The child project can request an Observable stream for a certain notification channel. 
In this case we're interested in `'price-changed'` events, but only the ones where the price increased. 
The ability to use RxJS operators can help us out:

```javascript
parentMessenger.notifications('price-changed').pipe(
    filter(({ oldPrice, newPrice }) => newPrice > oldPrice),
    map(({ oldPrice, newPrice }) => newPrice - oldPrice),
).subscribe((increase) => console.log(`Price increased with €${increase}!`));

// > 'Price increased with €2!'
```

#### Sending requests

> ```typescript
> Messenger.request<T = any, U = any>(channel: string, payload?: T): Observable<U>
> ```

RxPostmessenger also supports request - response communication. 
At the requester side a request is initiated by calling the `request()` method with 1 or 2 arguments. 
The first is a request alias (actually just another channel) of our choice.

_A notification-channel and a request-channel can both have the same channel name without any problem._

An observable is returned that emits the response when arrived, and then completes. 
Let's request a greeting from the child window, and tell it to localize the response to `'en'`:

```javascript
const greetingResponse$ = childMessenger.request('greeting', {
    language: 'en',
});
```

We can then subscribe to the greeting response stream.
Provided that the greeting says something nice, we'll log it for everyone to see:

```javascript
greetingResponse$.pipe(
    filter((greeting) => isNiceGreeting(greeting)),
).subscribe(console.log);

// > 'Hi parent!'
```

#### Listening for inbound requests
> ```typescript
> Messenger.requests<T = any, U = any>(channel: string): Observable<RxPostmessenger.Request<T, U>>
> ```

No greeting would ever be received by `parentMessenger` when the child project does not listen 
for requests to handle and respond to. Let's not be rude and create a request stream for 
`'greeting'` requests, and subscribe to it. We'll pass the `RxPostmessenger.Request` objects 
that the subscription receives into a function `handleGreetingRequest()`:

```javascript
parentMessenger
    .requests('greeting')
    .subscribe(handleGreetingRequest);
```

---

### `Request` instance methods

#### Sending request responses

> ```typescript
> RxPostmessenger.Request<T, U> ~ respond(payload: U): void
> ```

The `requests` method returns an observable of `RxPostmessenger.Request` objects. 
They provide a single method `respond` that accepts one argument: the response payload. 
Let's use the method on the requests we give to `handleGreetingRequest`:

```javascript
const handleGreetingRequest = (request) => {

    // The data that was sent along with the request
    const requestPayload = request.payload;

    // A hypothetical greeting translator
    const localizedGreeting = translateGreeting(
        'Hi parent!',
        requestPayload.language
    );

    // Eventually respond to the request with some data (payload)
    request.respond(localizedGreeting);
};
```

## License

The MIT License (MIT). See [license file] for more information.

[license file]: https://github.com/JJWesterkamp/rx-postmessenger/blob/master/LICENSE
[rxjs-imports]: https://github.com/JJWesterkamp/rx-postmessenger/tree/master/src/vendor/rxjs/index.ts
[changelog]: https://github.com/JJWesterkamp/rx-postmessenger/tree/master/CHANGELOG.md
[postmessage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
[rxgh]: https://github.com/ReactiveX/RxJS

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