{"id":20876765,"url":"https://github.com/brooksn/redux-broadcast-actions","last_synced_at":"2025-09-03T08:39:40.389Z","repository":{"id":57350343,"uuid":"132796902","full_name":"brooksn/redux-broadcast-actions","owner":"brooksn","description":"Redux middleware to dispatch certain actions in all open windows","archived":false,"fork":false,"pushed_at":"2018-05-09T18:20:25.000Z","size":6,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-28T14:54:32.846Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brooksn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-09T18:20:19.000Z","updated_at":"2018-05-09T18:20:26.000Z","dependencies_parsed_at":"2022-09-16T21:12:40.713Z","dependency_job_id":null,"html_url":"https://github.com/brooksn/redux-broadcast-actions","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/brooksn/redux-broadcast-actions","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brooksn%2Fredux-broadcast-actions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brooksn%2Fredux-broadcast-actions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brooksn%2Fredux-broadcast-actions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brooksn%2Fredux-broadcast-actions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brooksn","download_url":"https://codeload.github.com/brooksn/redux-broadcast-actions/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brooksn%2Fredux-broadcast-actions/sbom","scorecard":{"id":254540,"data":{"date":"2025-08-11","repo":{"name":"github.com/brooksn/redux-broadcast-actions","commit":"582d73028b50387d7e02b5ff3aa5841331ceae27"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Code-Review","score":0,"reason":"Found 0/1 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-17T09:19:26.376Z","repository_id":57350343,"created_at":"2025-08-17T09:19:26.376Z","updated_at":"2025-08-17T09:19:26.376Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272876743,"owners_count":25008235,"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","status":"online","status_checked_at":"2025-08-30T02:00:09.474Z","response_time":77,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-11-18T06:54:48.377Z","updated_at":"2025-09-03T08:39:40.344Z","avatar_url":"https://github.com/brooksn.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Redux Broadcast Actions\n\n[Redux middleware](https://redux.js.org/advanced/middleware) to dispatch certain actions in all open windows.\n\n[![npm version](https://img.shields.io/npm/v/redux-broadcast-actions.svg)](https://www.npmjs.com/package/redux-broadcast-actions)\n\n```\nnpm install --save redux-broadcast-actions\n```\n\n## Use cases\n\nYou may encounter situations where an application open in multiple tabs or windows must share some state, like user preferences or authentication tokens. In browsers that support writing to `localStorage`, certain actions may be dispatched to all open tabs or windows.\n\n```js\n{\n  type: 'USER_PREFERENCE_CHANGED',\n  payload: { color: 'blue' },\n  meta: { broadcast: true }\n  // The user expects to see personalization changes reflected immediately.\n}\n```\n\n```js\n{\n  type: 'REFRESH_TOKEN_FULFILLED',\n  payload: { newToken: 'abc.123.xyz' },\n  meta: { broadcast: true }\n  // If two windows A and B share an authentication token, and the token is refreshed in window A (invalidating the old token),\n  // then window B will receive the same action and can discard its old, invalid token.\n}\n```\n\n## Motivation\n\nRedux middleware exist that cache parts of the state to `localStorage` or another browser storage API, and load these values into the store's initial state. However, changes to these data in one window are not automatically synced to other windows. One solution to sharing to these special slices of state updates with other windows could be to enhance the store to check for changes in the browser's cached values, and to update the state directly. However, this approach causes \"follower\" windows to lose the context of the change-originating action dispatched by the \"leader\".\n\nChanges to `localStorage` [trigger an event](https://developer.mozilla.org/en-US/docs/Web/Events/storage) in all windows except that which caused the initial change.\n\nThis middleware shares actions between open windows. You may additionally cache special parts of state in `localStorage` or otherwise.\n\n## Caveats\n\nThis middleware will have no effect in browsers where writing to localStorage is not allowed. This may occur if localStorage is not implemented, if a storage quota has been reached, or if the browser is in a private browsing mode. This middleware does not handle persisting state to `localStorage`. There are existing middleware designed to handle this, or you can [implement it yourself](https://stackoverflow.com/questions/35305661/where-to-write-to-localstorage-in-a-redux-app#answer-35675304).\n\n## Example\n\nFirst, install `redux-broadcast-actions` as a project dependency.\n\n```\nnpm install --save redux-broadcast-actions\n```\n\n```js\nimport { applyMiddleware, createStore } from 'redux'\nimport { broadcastMiddleware } from 'redux-broadcast-action'\n\nconst counter = (state = 0, action) =\u003e {\n  switch (action.type) {\n    case 'INCREMENT':\n      return state + 1\n    case 'DECREMENT':\n      return state - 1\n    case 'SQUARE':\n      return state * state\n    default:\n      return state\n  }\n}\n\n// The options object is not required, and the following values will be used by default.\nconst broadcastMiddlewareOptions = {\n  metaKey: 'broadcast', // This is the property of an action's meta object which indicates an action should be broadcast.\n  errorKey: '__redux-broadcast-actions_error__', // Actions which cannot be parsed are stored with this key.\n  storageKey: '__redux-broadcast-actions_action__', // Actions marked to be broadcast are stored with this key, then immediately removed.\n  testKey: '__redux-broadcast-actions_storage-test__' // A localStorage item is created with this key and immediately removed to test localStorage.\n}\n\nconst middleware = broadcastMiddleware(broadcastMiddlewareOptions)\n\n// redux 1.0.0 and later\nlet store = applyMiddleware(middleware)(createStore)(counter, 0)\n\n// redux 3.1.0 and later\nstore = createStore(counter, 0, applyMiddleware(middleware))\n\n// The increment and decrement action creators will create ordinary actions.\n// The square action creator will create an action that will be broadcast to all open tabs and windows.\n\nfunction increment() {\n  return {\n    type: 'INCREMENT'\n  }\n}\n\nfunction decrement() {\n  return {\n    type: 'DECREMENT'\n  }\n}\n\nfunction square() {\n  return {\n    type: 'SQUARE',\n    meta: { broadcast: true } // The meta key may be renamed to something other than \"broadcast\" in broadcastMiddlewareOptions.\n  }\n}\n\n// Whatever the value of the counter in each window, it will be squared.\nstore.dispatch(square())\n```\n\n## License\n\nISC\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrooksn%2Fredux-broadcast-actions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrooksn%2Fredux-broadcast-actions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrooksn%2Fredux-broadcast-actions/lists"}