├── .github └── workflows │ └── node.js.yml ├── .gitignore ├── LICENSE ├── README.md ├── index.js ├── package.json └── test └── index.js /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 Andre 'Staltz' Medeiros 2 | # 3 | # SPDX-License-Identifier: Unlicense 4 | 5 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 6 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 7 | 8 | name: CI 9 | 10 | on: 11 | push: 12 | branches: [master] 13 | pull_request: 14 | branches: [master] 15 | 16 | jobs: 17 | test: 18 | runs-on: ubuntu-latest 19 | timeout-minutes: 10 20 | 21 | strategy: 22 | matrix: 23 | node-version: [12.x, 14.x, 16.x] 24 | 25 | steps: 26 | - uses: actions/checkout@v2 27 | - name: Use Node.js ${{ matrix.node-version }} 28 | uses: actions/setup-node@v1 29 | with: 30 | node-version: ${{ matrix.node-version }} 31 | - run: npm install 32 | - name: npm test 33 | run: npm test 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | pnpm-lock.yaml 3 | package-lock.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Dominic Tarr 4 | 5 | Permission is hereby granted, free of charge, 6 | to any person obtaining a copy of this software and 7 | associated documentation files (the "Software"), to 8 | deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom 12 | the Software is furnished to do so, 13 | subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice 16 | shall be included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 22 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pull-notify 2 | 3 | Notify many listeners via pull-streams. 4 | 5 | you could use when you might otherwise use an event emitter. 6 | Why not just use an event emitter? EventEmitters have a weird 7 | security contract: anyone who can listen can also emit, 8 | and they can emit or listen to any events! 9 | 10 | Instead, events should travel down a single channel, 11 | and the ability to emit an event should be separated from 12 | the ability to listen. 13 | 14 | 15 | ``` js 16 | var Notify = require('pull-notify') 17 | 18 | var notify = Notify() 19 | 20 | //create a pull stream that listens on events. 21 | //it will eventually get all events. 22 | pull(notify.listen(), pull.drain((evt) => console.log(evt))) 23 | 24 | notify('hello') //emit an event. 25 | 26 | notify.end() //tell all listeners it's over. 27 | ``` 28 | 29 | listers can abort (using the normal pull-stream abort), 30 | and that will remove them from the list. 31 | 32 | 33 | ## License 34 | 35 | MIT 36 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | var pushable = require('pull-pushable') 3 | 4 | module.exports = function () { 5 | var listeners = [] 6 | var closed = false 7 | 8 | function notify (message) { 9 | // notify by pushing to all listeners 10 | for (var i = 0; i < listeners.length; i++) { 11 | if (closed) return message 12 | listeners[i].push(message) 13 | } 14 | return message 15 | } 16 | 17 | notify.listen = function () { 18 | // create listener with `onClose` handler 19 | var listener = pushable() 20 | listeners.push(listener) 21 | return listener 22 | } 23 | 24 | notify.abort = function (err) { 25 | // abort by ending all listeners 26 | closed = true 27 | while (listeners.length) listeners.shift().end(err) 28 | } 29 | 30 | notify.end = function () { 31 | return notify.abort(true) 32 | } 33 | 34 | return notify 35 | } 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pull-notify", 3 | "description": "", 4 | "version": "0.1.2", 5 | "homepage": "https://github.com/dominictarr/pull-notify", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/dominictarr/pull-notify.git" 9 | }, 10 | "files": [ 11 | "*.js" 12 | ], 13 | "dependencies": { 14 | "pull-pushable": "^2.0.0" 15 | }, 16 | "devDependencies": { 17 | "pull-stream": "^3.0.1", 18 | "standard": "^7.1.2", 19 | "tape": "~4.0.0" 20 | }, 21 | "scripts": { 22 | "test": "standard && tape test/*.js" 23 | }, 24 | "author": "Dominic Tarr (http://dominictarr.com)", 25 | "license": "MIT" 26 | } 27 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 2 | var Notify = require('../') 3 | var tape = require('tape') 4 | var pull = require('pull-stream') 5 | 6 | tape('simple', function (t) { 7 | var notify = Notify() 8 | var r = Math.random() 9 | 10 | pull( 11 | notify.listen(), 12 | pull.drain(function (data) { 13 | t.equal(data, r) 14 | }, function () { 15 | t.end() 16 | }) 17 | ) 18 | 19 | t.equal(notify(r), r) 20 | notify.end() 21 | }) 22 | 23 | tape('end', function (t) { 24 | var notify = Notify() 25 | var r = Math.random() 26 | var n = 3 27 | 28 | pull( 29 | notify.listen(), 30 | pull.drain(function (data) { 31 | t.equal(data, r) 32 | }, function () { 33 | if (--n) return 34 | t.end() 35 | }) 36 | ) 37 | pull( 38 | notify.listen(), 39 | pull.drain(function (data) { 40 | t.equal(data, r) 41 | }, function () { 42 | if (--n) return 43 | t.end() 44 | }) 45 | ) 46 | pull( 47 | notify.listen(), 48 | pull.drain(function (data) { 49 | t.equal(data, r) 50 | }, function () { 51 | if (--n) return 52 | t.end() 53 | }) 54 | ) 55 | 56 | t.equal(notify(r), r) 57 | notify.end() 58 | }) 59 | 60 | tape('end immediately upon delivery', function (t) { 61 | var notify = Notify() 62 | var r = Math.random() 63 | var n = 1 64 | 65 | pull( 66 | notify.listen(), 67 | pull.drain(function (data) { 68 | t.equal(data, r) 69 | notify.end() 70 | }, function () { 71 | if (--n) return 72 | t.end() 73 | }) 74 | ) 75 | 76 | t.equal(notify(r), r) 77 | }) 78 | --------------------------------------------------------------------------------