{"id":16186078,"url":"https://github.com/johngeorgewright/hot-press","last_synced_at":"2025-04-07T13:21:08.520Z","repository":{"id":66251452,"uuid":"59823014","full_name":"johngeorgewright/hot-press","owner":"johngeorgewright","description":"Event lifecycle management in JavaScript","archived":false,"fork":false,"pushed_at":"2020-06-22T17:51:24.000Z","size":1157,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2025-03-21T23:35:24.127Z","etag":null,"topics":["event-hierarchy","event-lifecycle","pubsub"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/johngeorgewright.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-05-27T09:32:12.000Z","updated_at":"2020-06-17T14:52:52.000Z","dependencies_parsed_at":null,"dependency_job_id":"48d36881-d261-4823-bccd-4bd330775ec5","html_url":"https://github.com/johngeorgewright/hot-press","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johngeorgewright%2Fhot-press","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johngeorgewright%2Fhot-press/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johngeorgewright%2Fhot-press/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johngeorgewright%2Fhot-press/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johngeorgewright","download_url":"https://codeload.github.com/johngeorgewright/hot-press/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247657245,"owners_count":20974349,"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":["event-hierarchy","event-lifecycle","pubsub"],"created_at":"2024-10-10T07:16:56.578Z","updated_at":"2025-04-07T13:21:08.497Z","avatar_url":"https://github.com/johngeorgewright.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"https://raw.githubusercontent.com/johngeorgewright/hot-press/master/logo.png\" align=\"right\" /\u003e\n\n# Hot Press\n\n[![Coverage Status](https://img.shields.io/coveralls/johngeorgewright/hot-press/master.svg?style=flat-square)](https://coveralls.io/github/johngeorgewright/hot-press?branch=master)\n[![Build Status](https://img.shields.io/travis/johngeorgewright/hot-press/master.svg?style=flat-square)](https://travis-ci.org/johngeorgewright/hot-press)\n[![NPM Version](https://img.shields.io/npm/v/hot-press.svg?style=flat-square)](https://www.npmjs.com/package/hot-press)\n[![Greenkeeper badge](https://badges.greenkeeper.io/johngeorgewright/hot-press.svg)](https://greenkeeper.io/)\n[![License](https://img.shields.io/npm/l/hot-press.svg?style=flat-square)](https://github.com/johngeorgewright/hot-press/blob/master/LICENSE)\n\nHot Press is an event lifecycle management library for Node.js.\n\n## Installation\n\n```\nnpm i hot-press\n```\n\n## Examples\n\n### Standard PubSub\n\nBasic PubSub architecture we're mostly familiar with. Using the `on()` function,\nyou can add subscribers to events that are published using the `emit()`\nfunction.\n\n```javascript\nimport HotPress from 'hot-press';\n\nconst {emit, on} = new HotPress();\non('event', (eventName, ...data) =\u003e console.log(...data));\nemit('event', 'some', 'variables');\n// 'some' 'variables'\n```\n\n### Subscribing to multiple events\n\nUsing the `all` function you can trigger a subscriber only once all the events\nhave been emitted.\n\n```javascript\nimport HotPress from 'hot-press';\n\nconst {all, emit} = new HotPress();\nall({on: ['event1', 'event2']}, () =\u003e console.log('Triggered!'));\nemit('event1');\nemit('event2');\n// 'Triggered!'\n```\n\n### Subscription hierarchy\n\nDots symbolize subscription hierarchy. Using the `*` operator, you can subscribe\nto all events under that hierarchy.\n\n```javascript\nimport HotPress from 'hot-press';\n\nconst {emit, on} = new HotPress();\non('*', e =\u003e console.log(2, e));\non('e.*', e =\u003e console.log(1, e));\nemit('e.f');\n// 1 e.f\n// 2 e.f\n```\n\n### Unsubscribe\n\nRemove all or specific subscribers from events using the `off()` function.\n\n```javascript\nimport HotPress from 'hot-press';\n\nconst {emit, off, on} = new HotPress();\nconst fn = () =\u003e console.log('blah');\n\non('event', fn);\non('event', fn);\non('event', fn);\n\nemit('event');\n// blah\n// blah\n// blah\n\noff('event', fn);\nemit('event');\n// blah\n// blah\n\noff('event');\nemit('event');\n// \u003cnothing happens\u003e\n```\n\n### Subscribing to the beginning and end of events\n\nThere are 3 parts to an event lifecycle.\n\n1. \"Before\" the event\n2. \"On\" the event\n3. \"After\" the event\n\nYou can subscribe to any part of the event lifecycle using the appropriate\nfunction.\n\n```javascript\nimport HotPress from 'hot-press';\n\nconst {after, before, emit, off, on} = new HotPress();\nbefore('event', () =\u003e console.log(1));\non('event', () =\u003e console.log(2));\nafter('event', () =\u003e console.log(3));\nemit('event');\n// 1\n// 2\n// 3\noff('event');\n\nafter('event', () =\u003e console.log(3));\nbefore('event', () =\u003e console.log(1));\non('event', () =\u003e console.log(2));\nemit('event');\n// 1\n// 2\n// 3\n```\n\n### Asynchronous subscriptions\n\nIf your subscription returns a Promise then the next part of the event lifecycle\nwill not be published until the promise has resolved.\n\n\u003e **Note:** It will not delay subscriptions within the same part of the lifecycle,\n\u003e only those that are to be published next. For example, all subscriptions\n\u003e implemented with the `on()` function will wait until all subscriptions\n\u003e implemented with the `before()` function have been resolved.\n\nAnd finally the `emit` function will return a promise that will resolve once\nthe \"after\" part of the lifecycle has resolved.\n\n```javascript\nimport HotPress from 'hot-press';\n\nconst {after, before, emit, on} = new HotPress();\nbefore('event', eventuallyLog(1));\non('event', eventuallyLog(2));\nafter('event', eventuallyLog(3));\nemit('event').then(() =\u003e console.log(4));\n// 1\n// 2\n// 3\n// 4\n\nfunction eventuallyLog(num) {\n  return () =\u003e new Promise(resolve =\u003e {\n    const log = () =\u003e {\n      console.log(num);\n      resolve();\n    };\n    setTimeout(log, random());\n  });\n}\n\nfunction random(from=0, to=1000) {\n  return Math.floor(Math.random() * to) + from;\n}\n```\n\n#### Timeouts\n\nThere is a configurable timeout for these asynchronous events. By default it's\n300ms, but it can be configured like so:\n\n```javascript\nimport HotPress from 'hot-press';\n\nconst emitter = new HotPress();\nemitter.timeout = 1000; // global\nemitter.ns('myNamespace').timeout = 600; // specific to a namespace\n```\n\nIf the timeout is exceeded by a listener within any part of event lifecycle, the\nlistener is terminated and an error event is published; it will not kill the\nevent.\n\n### Namespacing\n\nYou can create a version of hot-press prefixing all messages with a namespace.\n\n```javascript\nimport HotPress from 'hot-press';\nimport {strictEqual} from 'assert';\n\nconst {ns} = new HotPress();\nconst foo = ns('foo');\n\nfoo.on('event', eventName =\u003e console.log(eventName));\nfoo.emit('event');\n// foo.event\n```\n\nNamespaces can be retrieved uses the dot syntax, or chained `ns()` calls.\n\n```javascript\nimport HotPress from 'hot-press';\nimport {strictEqual} from 'assert';\n\nconst {ns} = new HotPress();\nstrictEqual(\n  ns('nested').ns('namespaces'),\n  ns('nested.namespaces'),\n  'Namespaces can be retrieved using dots as hierarchy, or chained calls to `ns`'\n);\n```\n\nNamespaces also cascade their settings.\n\n```javascript\nimport HotPress from 'hot-press';\nimport {equal} from 'assert';\n\nconst {ns} = new HotPress();\nconst foo = ns('foo');\nfoo.timeout = 1000;\n\nequal(\n  foo.timeout,\n  foo.ns('bar').timeout,\n  'Namespaces cascade their settings'\n);\n```\n\n### Error handling\n\nErrors thrown within listeners/subscribers are swallowed but can be captured in\nerror events:\n\n```javascript\nimport HotPress from 'hot-press';\n\nconst {emit, on} = new HotPress();\non('error.event', error =\u003e console.log(error.message));\non('event', () =\u003e throw new Error('Something went wrong'));\nemit('event');\n// \"Something went wrong\"\n```\n\n### Procedures\n\nProcedures are essentially functions, referenced by a string. There are a few\nreasons you may want to use procedures:\n\n- Whether the procedure exists or not, you can call it without anything\n  failing. This is useful when using procedures in a plugable interface, when\n  you're unsure whether the procedure is going to be there or not.\n- Hooking in to the function call. Every call to a procedure emits an event\n  with the same name as the procedure. The event lifecycle will exist, which\n  also means you can pause the call with the `before()` method.\n- If you've decided to use HotPress as a basis to your framework/application\n  it can mean your API is more consistent.\n\nTo register a procedure, use the `reg()` function. To cal your registered\nprocedure, use the `call()` method.\n\nIf the procedure returns a promise, it will wait for the promise to resolve\nbefore passing the resolved data back to the caller.\n\nThe `call()` function always returns a promise.\n\n```javascript\nimport User from '../lib/user';\nimport HotPress from 'hot-press';\n\nconst {reg, call, on} = new HotPress();\n\nreg('users.get', query =\u003e User.all(query));\n\non('error.users.get', error =\u003e console.error(error));\n\non('users.get', query =\u003e console.log('Querying users table', query));\n\ncall('users.get', {type: 'admin'}).then(users =\u003e {\n  // Do something with users\n});\n```\n\n## Custom Lifecycles\n\nThe `before()`, `on()` \u0026 `after()` methods don't suffice everyone's needs.\nLuckily enough, for those people, the lifecycle is configurable.\n\n\u003e **Note** you must still include an `on` method. Procedures rely on it.\n\n```javascript\nimport HotPress from 'hot-press';\n\nconst emitter = new HotPress();\nemitter.lifecycle = ['foo', 'bar', 'on', 'after'];\nconst {foo, bar, on, after, emit} = emitter;\n\nfoo('event', console.log);\nbar('event', console.log);\non('event', console.log);\nafter('event', console.log);\n\nemit('event');\n// foo\n// bar\n// on\n// after\n```\n\nThe lifecycle is configurable per namespace too.\n\n```javascript\nimport HotPress from 'hot-press';\n\nconst {ns} = new HotPress();\nconst foo = ns('foo');\nfoo.lifecycle = ['prior', 'on', 'end'];\n\nfoo.prior('event', console.log);\nfoo.on('event', console.log);\nfoo.end('event', console.log);\nfoo.emit('event');\n// prior\n// on\n// end\n```\n\n## Why the weird name?\n\nMostly because the good ones were already taken and there's arguably a relation\nbetween publishing/subscribing to magazines and papers.\n\n## API\n\n### `after(String eventName, Function subscriber)`\n\nRegister a subscribing function to the end of the event.\n\n### `all(Object\u003c[lifecycleName]: String[]\u003e eventNames, Function subscriber)`\n\nRegister a subscriber for when all events have been published\n\n### `call(String procedureName, [...Any]) ==\u003e Promise`\n\nCall a procedure with the given arguments.\n\n### `dereg(String procedureName) ==\u003e Number`\n\nDeregisters a procedure.\n\n### `deregAll() ==\u003e Number`\n\nRemoves **all** registered procedures.\n\n### `emit(String eventName, [Any ...data]) ==\u003e Promise`\n\nPublishes the event and passes all data arguments directly to the subscribers.\n\n### `[lifecycleName](String eventName, Function subscriber)`\n\nRegister a subscribing function to that part of the event lifecycle.\n\n### `ns(String namespace) ==\u003e HotPress`\n\nCreates an object containing the entire API of which all messages/event names\nwill be prefixed with a namespace.\n\n### `off(String eventName, [Function subscriber]) ==\u003e Number`\n\nRemoves a given subscriber from an event. If none is specified, it will remove\nall subscribers from the event.\n\n### `on(String eventName, Function subscriber)`\n\nRegister a subscribing function to the event\n\n### `once(String eventName, Function subscriber)`\n\nRegisters a subscriber for just one event before it's removed.\n\n### `once[LifecycleName](String eventName, Function subscriber)`\n\nRegisters a subscriber, to that part of the event lifecycle, for just one event\nbefore it is removed.\n\n### `triggers(String eventName, Array eventNames)`\n\nWhen the event has been published, publish an array of of other events.\n\n### `triggers[lifecycleName](String eventName, Function subscriber)`\n\nWhen the event's lifecycle part has been published, publish an array of other\nevents.\n\n### `reg(String procedureName, Function procedure)`\n\nRegisters a procedure.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohngeorgewright%2Fhot-press","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohngeorgewright%2Fhot-press","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohngeorgewright%2Fhot-press/lists"}