{"id":21455016,"url":"https://github.com/jjwesterkamp/rx-postmessenger","last_synced_at":"2025-07-14T23:32:30.363Z","repository":{"id":26934862,"uuid":"111960694","full_name":"JJWesterkamp/rx-postmessenger","owner":"JJWesterkamp","description":"Minimal RxJS adapter for the window.postMessage API for request-response streams and notification streams across frame windows.","archived":false,"fork":false,"pushed_at":"2023-03-06T08:25:00.000Z","size":1380,"stargazers_count":27,"open_issues_count":6,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-08-10T08:14:44.918Z","etag":null,"topics":["angular","events","iframe","notification","postmessage","request","rxjs","typescript"],"latest_commit_sha":null,"homepage":"https://jjwesterkamp.github.io/rx-postmessenger/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JJWesterkamp.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-11-24T22:45:58.000Z","updated_at":"2022-08-30T04:37:30.000Z","dependencies_parsed_at":"2023-01-14T05:38:54.173Z","dependency_job_id":null,"html_url":"https://github.com/JJWesterkamp/rx-postmessenger","commit_stats":null,"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JJWesterkamp%2Frx-postmessenger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JJWesterkamp%2Frx-postmessenger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JJWesterkamp%2Frx-postmessenger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JJWesterkamp%2Frx-postmessenger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JJWesterkamp","download_url":"https://codeload.github.com/JJWesterkamp/rx-postmessenger/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226003013,"owners_count":17558157,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","events","iframe","notification","postmessage","request","rxjs","typescript"],"created_at":"2024-11-23T05:10:03.605Z","updated_at":"2024-11-23T05:10:04.210Z","avatar_url":"https://github.com/JJWesterkamp.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rx-postmessenger\n[![npm version](https://badge.fury.io/js/rx-postmessenger.svg)](https://badge.fury.io/js/rx-postmessenger)\n[![Build Status](https://travis-ci.com/JJWesterkamp/rx-postmessenger.svg?branch=master)](https://travis-ci.com/JJWesterkamp/rx-postmessenger)\n[![Coverage Status](https://coveralls.io/repos/github/JJWesterkamp/rx-postmessenger/badge.svg?branch=master)](https://coveralls.io/github/JJWesterkamp/rx-postmessenger?branch=master)\n\nMinimal [RxJS][rxgh] adapter for the [`Window # postMessage`][postmessage] API for request-response streams and notification streams across frame windows.\n\n## In short\n\nAn 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.\n\nEach 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.\n\n## RxJS Interoperability\n\n|               | RxPostmessenger v1.x | RxPostmessenger v2.x | RxPostmessenger v3.x |\n|---------------|:--------------------:|:--------------------:|:--------------------:|\n| RxJS v5.x     |           ✅         |           ❌         |          ❌          |\n| RxJS v6.x     |           ❌         |           ✅         |          ✅          |\n| RxJS v7.x     |           ❌         |           ❌         |          ✅          |\n\n[View changelog.][changelog]\n\n## Installation\n\n```bash\n$ npm install rx-postmessenger --save\n```\n\n## Contents / API\n\n**Static methods**\n\n|Method|Description|\n|:-|:-|\n|[`connect()`](#connecting-2-window-objects)|Connect `Window` objects by creating messenger instances.|\n\n**`Messenger` Instance methods**\n\n|Method|Description|\n|:-|:-|\n|[`notify()`](#sending-notifications)|Send notifications to the connected window.|\n|[`notifications()`](#listening-for-inbound-notifications)|Listen for inbound notifications.|\n|[`request()`](#sending-requests)|Send requests to the connected window.|\n|[`requests()`](#listening-for-inbound-requests)|Listen for inbound requests.|\n\n**`Request` Instance methods**\n\n|Method|Description|\n|:-|:-|\n|[`respond()`](#sending-request-responses)|Respond to the request with a certain payload.\n\n---\n\n## Usage\n\n```javascript\nimport RxPostmessenger from 'rx-postmessenger';\n```\n\n### Static methods\n\n#### Connecting 2 Window objects\n\n\u003e ```typescript\n\u003e RxPostmessenger.connect(otherWindow: Window, origin: string): RxPostmessenger.Messenger\n\u003e ```\n\nBoth 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:\n\n_At parent window - `https://parent-project.com`_\n\n```javascript\nconst childMessenger = RxPostmessenger.connect(\n    someIFrame.contentWindow,\n    'https://child-project.com'\n);\n```\n\n_At child window - `https://child-project.com`_\n\n```javascript\nconst parentMessenger = RxPostmessenger.connect(\n    window.parent,\n    'https://parent-project.com'\n);\n```\n\n### `Messenger` Instance methods\n\n#### Sending notifications\n\u003e ```typescript\n\u003e Messenger.notify\u003cT\u003e(channel: string, payload?: T): void\n\u003e ```\n\nThe messenger instances give you a way to send notifications to the other `Window` through the `notify()` method. \nThe notify method is void -- notifications are fire-and-forget. \nUse [`request()`](#sending-requests) instead if you require data back.\nConsider an example where we want to notify a child window of price changes:\n\n```javascript\nchildMessenger.notify('price-changed', {\n    oldPrice: 12.50,\n    newPrice: 14.50,\n});\n```\n\n#### Listening for inbound notifications\n\u003e ```typescript\n\u003e Messenger.notifications\u003cT = any\u003e(channel: string): Observable\u003cT\u003e\n\u003e ```\n\nThe child project can request an Observable stream for a certain notification channel. \nIn this case we're interested in `'price-changed'` events, but only the ones where the price increased. \nThe ability to use RxJS operators can help us out:\n\n```javascript\nparentMessenger.notifications('price-changed').pipe(\n    filter(({ oldPrice, newPrice }) =\u003e newPrice \u003e oldPrice),\n    map(({ oldPrice, newPrice }) =\u003e newPrice - oldPrice),\n).subscribe((increase) =\u003e console.log(`Price increased with €${increase}!`));\n\n// \u003e 'Price increased with €2!'\n```\n\n#### Sending requests\n\n\u003e ```typescript\n\u003e Messenger.request\u003cT = any, U = any\u003e(channel: string, payload?: T): Observable\u003cU\u003e\n\u003e ```\n\nRxPostmessenger also supports request - response communication. \nAt the requester side a request is initiated by calling the `request()` method with 1 or 2 arguments. \nThe first is a request alias (actually just another channel) of our choice.\n\n_A notification-channel and a request-channel can both have the same channel name without any problem._\n\nAn observable is returned that emits the response when arrived, and then completes. \nLet's request a greeting from the child window, and tell it to localize the response to `'en'`:\n\n```javascript\nconst greetingResponse$ = childMessenger.request('greeting', {\n    language: 'en',\n});\n```\n\nWe can then subscribe to the greeting response stream.\nProvided that the greeting says something nice, we'll log it for everyone to see:\n\n```javascript\ngreetingResponse$.pipe(\n    filter((greeting) =\u003e isNiceGreeting(greeting)),\n).subscribe(console.log);\n\n// \u003e 'Hi parent!'\n```\n\n#### Listening for inbound requests\n\u003e ```typescript\n\u003e Messenger.requests\u003cT = any, U = any\u003e(channel: string): Observable\u003cRxPostmessenger.Request\u003cT, U\u003e\u003e\n\u003e ```\n\nNo greeting would ever be received by `parentMessenger` when the child project does not listen \nfor requests to handle and respond to. Let's not be rude and create a request stream for \n`'greeting'` requests, and subscribe to it. We'll pass the `RxPostmessenger.Request` objects \nthat the subscription receives into a function `handleGreetingRequest()`:\n\n```javascript\nparentMessenger\n    .requests('greeting')\n    .subscribe(handleGreetingRequest);\n```\n\n---\n\n### `Request` instance methods\n\n#### Sending request responses\n\n\u003e ```typescript\n\u003e RxPostmessenger.Request\u003cT, U\u003e ~ respond(payload: U): void\n\u003e ```\n\nThe `requests` method returns an observable of `RxPostmessenger.Request` objects. \nThey provide a single method `respond` that accepts one argument: the response payload. \nLet's use the method on the requests we give to `handleGreetingRequest`:\n\n```javascript\nconst handleGreetingRequest = (request) =\u003e {\n\n    // The data that was sent along with the request\n    const requestPayload = request.payload;\n\n    // A hypothetical greeting translator\n    const localizedGreeting = translateGreeting(\n        'Hi parent!',\n        requestPayload.language\n    );\n\n    // Eventually respond to the request with some data (payload)\n    request.respond(localizedGreeting);\n};\n```\n\n## License\n\nThe MIT License (MIT). See [license file] for more information.\n\n[license file]: https://github.com/JJWesterkamp/rx-postmessenger/blob/master/LICENSE\n[rxjs-imports]: https://github.com/JJWesterkamp/rx-postmessenger/tree/master/src/vendor/rxjs/index.ts\n[changelog]: https://github.com/JJWesterkamp/rx-postmessenger/tree/master/CHANGELOG.md\n[postmessage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage\n[rxgh]: https://github.com/ReactiveX/RxJS\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjjwesterkamp%2Frx-postmessenger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjjwesterkamp%2Frx-postmessenger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjjwesterkamp%2Frx-postmessenger/lists"}