{"id":31970500,"url":"https://github.com/hubspot/general-store","last_synced_at":"2025-10-14T19:15:51.160Z","repository":{"id":26794428,"uuid":"30252835","full_name":"HubSpot/general-store","owner":"HubSpot","description":"Simple, flexible store implementation for Flux. #hubspot-open-source","archived":false,"fork":false,"pushed_at":"2023-02-25T23:25:20.000Z","size":1282,"stargazers_count":177,"open_issues_count":16,"forks_count":27,"subscribers_count":149,"default_branch":"master","last_synced_at":"2025-10-04T18:03:39.322Z","etag":null,"topics":["data","dispatcher","flux","hubspot","javascript","react","store"],"latest_commit_sha":null,"homepage":"http://github.hubspot.com/general-store","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/HubSpot.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,"governance":null,"roadmap":null,"authors":null}},"created_at":"2015-02-03T16:39:19.000Z","updated_at":"2024-04-26T19:12:27.000Z","dependencies_parsed_at":"2024-01-13T19:50:36.491Z","dependency_job_id":null,"html_url":"https://github.com/HubSpot/general-store","commit_stats":{"total_commits":489,"total_committers":20,"mean_commits":24.45,"dds":0.3844580777096115,"last_synced_commit":"7ab84f601b997204526871067ee44762864faf4b"},"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"purl":"pkg:github/HubSpot/general-store","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HubSpot%2Fgeneral-store","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HubSpot%2Fgeneral-store/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HubSpot%2Fgeneral-store/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HubSpot%2Fgeneral-store/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HubSpot","download_url":"https://codeload.github.com/HubSpot/general-store/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HubSpot%2Fgeneral-store/sbom","scorecard":{"id":63563,"data":{"date":"2025-08-11","repo":{"name":"github.com/HubSpot/general-store","commit":"7ab84f601b997204526871067ee44762864faf4b"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.7,"checks":[{"name":"Code-Review","score":2,"reason":"Found 6/24 approved changesets -- score normalized to 2","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":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","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":"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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/node.js.yml:1","Info: no jobLevel write permissions found"],"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":"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":"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":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/node.js.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/HubSpot/general-store/node.js.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/node.js.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/HubSpot/general-store/node.js.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/node.js.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/HubSpot/general-store/node.js.yml/master?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned"],"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":"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":"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":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"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":"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"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 16 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"42 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-w8qv-6jwh-64r5","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g","Warn: Project is vulnerable to: GHSA-5fw9-fq32-wv5p","Warn: Project is vulnerable to: GHSA-rp65-9cf3-cjxr","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-hxcc-f52p-wc94","Warn: Project is vulnerable to: GHSA-4rq4-32rv-6wp6","Warn: Project is vulnerable to: GHSA-64g7-mvw6-v9qj","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-662x-fhqg-9p8v","Warn: Project is vulnerable to: GHSA-394c-5j6w-4xmx","Warn: Project is vulnerable to: GHSA-78cj-fxph-m83p","Warn: Project is vulnerable to: GHSA-fhg7-m89q-25r3","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-6fc8-4gx4-v693","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q","Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-15T02:11:06.843Z","repository_id":26794428,"created_at":"2025-08-15T02:11:06.843Z","updated_at":"2025-08-15T02:11:06.843Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279020649,"owners_count":26086895,"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-10-14T02:00:06.444Z","response_time":60,"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":["data","dispatcher","flux","hubspot","javascript","react","store"],"created_at":"2025-10-14T19:15:49.361Z","updated_at":"2025-10-14T19:15:51.153Z","avatar_url":"https://github.com/HubSpot.png","language":"JavaScript","readme":"![HubSpot/general-store](https://cloud.githubusercontent.com/assets/478109/6376307/1d3c77dc-bceb-11e4-9a96-0a909810cc69.png)\n\n[![NPM version](http://img.shields.io/npm/v/general-store.svg)](https://www.npmjs.com/package/general-store)\n[![Build Status](https://travis-ci.org/HubSpot/general-store.svg?branch=master)](https://travis-ci.org/HubSpot/general-store)\n\n`general-store` aims to provide all the features of a [Flux](http://facebook.github.io/flux/) store without prescribing the implementation of that store's data or mutations.\n\nBriefly, a store:\n\n1. contains any arbitrary value\n2. exposes that value via a get method\n3. responds to specific events from the dispatcher\n4. notifies subscribers when its value changes\n\nThat's it. All other features, like Immutability, data fetching, undo, etc. are implementation details.\n\nRead more about the `general-store` rationale [on the HubSpot Product Team Blog](http://product.hubspot.com/blog/keeping-flux-flexible-with-general-store).\n\n## Install\n\n```bash\n# npm \u003e= 5.0.0\nnpm install general-store\n\n# yarn\nyarn add general-store\n```\n\n```js\n// namespace import\nimport * as GeneralStore from 'general-store';\n// or import just your module\nimport { define } from 'general-store';\n```\n\n## Create a store\n\nGeneralStore uses functions to encapsulate private data.\n\n```javascript\nvar dispatcher = new Flux.Dispatcher();\nfunction defineUserStore() {\n  // data is stored privately inside the store module's closure\n  var users = {\n    123: {\n      id: 123,\n      name: 'Mary',\n    },\n  };\n\n  return (\n    GeneralStore.define()\n      .defineName('UserStore')\n      // the store's getter should return the public subset of its data\n      .defineGet(function() {\n        return users;\n      })\n      // handle actions received from the dispatcher\n      .defineResponseTo('USER_ADDED', function(user) {\n        users[user.id] = user;\n      })\n      .defineResponseTo('USER_REMOVED', function(user) {\n        delete users[user.id];\n      })\n      // after a store is \"registered\" its action handlers are bound\n      // to the dispatcher\n      .register(dispatcher)\n  );\n}\n```\n\nIf you use a singleton pattern for stores, simply use the result of `register` from a module.\n\n```javascript\nimport { Dispatcher } from 'flux';\nimport * as GeneralStore from 'general-store';\n\nvar dispatcher = new Dispatcher();\nvar users = {};\n\nvar UserStore = GeneralStore.define()\n  .defineGet(function() {\n    return users;\n  })\n  .register(dispatcher);\n\nexport default UserStore;\n```\n\n## Dispatch to the Store\n\nSending a message to your stores via the dispatcher is easy.\n\n```javascript\ndispatcher.dispatch({\n  actionType: 'USER_ADDED', // required field\n  data: {\n    // optional field, passed to the store's response\n    id: 12314,\n    name: 'Colby Rabideau',\n  },\n});\n```\n\n## Store Factories\n\nThe classic singleton store API is great, but can be hard to test.\n`defineFactory()` provides an composable alternative to `define()` that makes\ntesting easier and allows you to extend store behavior.\n\n```javascript\nvar UserStoreFactory = GeneralStore.defineFactory()\n  .defineName('UserStore')\n  .defineGetInitialState(function() {\n    return {};\n  })\n  .defineResponses({\n    USER_ADDED: function(state, user) {\n      state[user.id] = user;\n      return state;\n    },\n    USER_REMOVED: function(state, user) {\n      delete state[user.id];\n      return state;\n    },\n  });\n```\n\nLike singletons, factories have a register method. Unlike singletons, that\nregister method can be called many times and will always return a **new\ninstance** of the store described by the factory, which is useful in unit tests.\n\n```javascript\ndescribe('UserStore', () =\u003e {\n  var storeInstance;\n  beforeEach(() =\u003e {\n    // each test will have a clean store\n    storeInstance = UserStoreFactory.register(dispatcher);\n  });\n\n  it('adds users', () =\u003e {\n    var mockUser = { id: 1, name: 'Joe' };\n    dispatcher.dispatch({ actionType: USER_ADDED, data: mockUser });\n    expect(storeInstance.get()).toEqual({ 1: mockUser });\n  });\n\n  it('removes users', () =\u003e {\n    var mockUser = { id: 1, name: 'Joe' };\n    dispatcher.dispatch({ actionType: USER_ADDED, data: mockUser });\n    dispatcher.dispatch({ actionType: USER_REMOVED, data: mockUser });\n    expect(storeInstance.get()).toEqual({});\n  });\n});\n```\n\nTo further assist with testing, the [`InspectStore`](https://github.com/HubSpot/general-store/blob/master/src/store/InspectStore.js) module allows you to read the internal fields of a store instance (e.g. `InspectStore.getState(store)`).\n\n## Using the Store API\n\nA registered Store provides methods for \"getting\" its value and subscribing to changes to that value.\n\n```javascript\nUserStore.get(); // returns {}\nvar subscription = UserStore.addOnChange(function() {\n  // handle changes!\n});\n// addOnChange returns an object with a `remove` method.\n// When you're ready to unsubscribe from a store's changes,\n// simply call that method.\nsubscription.remove();\n```\n\n## React\n\nGeneralStore provides some convenience functions for supplying data to React components. Both functions rely on the concept of \"dependencies\" and process those dependencies to return any data kept in a `Store` and make it easily accessible to a React component.\n\n### Dependencies\n\nGeneralStore has a two formats for declaring data dependencies of React components. A `SimpleDependency` is simply a reference to a `Store` instance. The value returned will be the result of `Store.get()`. A `CompoundDependency` depends on one or more stores and uses a \"dereference\" function that allows you to perform operations and data manipulation on the data that comes from the `stores` listed in the dependency:\n\n```javascript\nconst FriendsDependency = {\n  // compound fields can depend on one or more stores\n  // and specify a function to \"dereference\" the store's value.\n  stores: [ProfileStore, UsersStore],\n  deref: props =\u003e {\n    friendIds = ProfileStore.get().friendIds;\n    users = UsersStore.get();\n    return friendIds.map(id =\u003e users[id]);\n  },\n};\n```\n\nOnce you declare your dependencies there are two ways to connect them to a react component.\n\n### `useStoreDependency`\n\n`useStoreDependency` is a [React Hook](https://reactjs.org/docs/hooks-intro.html) that enables you to connect to a single dependency inside of a functional component. The `useStoreDependency` hook accepts a dependency, and optionally a map of props to pass into the `deref` and a dispatcher instance.\n\n```javascript\nfunction FriendsList() {\n  const friends = GeneralStore.useStoreDependency(\n    FriendsDependency,\n    {},\n    dispatcher\n  );\n  return (\n    \u003cul\u003e\n      {friends.map(friend =\u003e (\n        \u003cli\u003e{friend.getName()}\u003c/li\u003e\n      ))}\n    \u003c/ul\u003e\n  );\n}\n```\n\n### `connect`\n\nThe second option is a Higher-Order Component (commonly \"HOC\") called `connect`. It's similar to `react-redux`'s `connect` function but it takes a `DependencyMap`. Note that this is different than `useStoreDependency` which only accepts a single `Dependency`, even though (as of v4) `connect` and `useStoreDependency` have the same implementation under the hood. A `DependencyMap` is a mapping of string keys to [`Dependency`s](#Dependencies):\n\n```javascript\nconst dependencies = {\n  // simple fields can be expressed in the form `key =\u003e store`\n  subject: ProfileStore,\n  friends: FriendsDependency,\n};\n```\n\n`connect` passes the fields defined in the `DependencyMap` to the enhanced component as props.\n\n```javascript\n// ProfileContainer.js\nfunction ProfileContainer({ friends, subject }) {\n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003e{subject.name}\u003c/h1\u003e\n      {this.renderFriends()}\n      \u003ch3\u003eFriends\u003c/h3\u003e\n      \u003cul\u003e\n        {Object.keys(friends).map(id =\u003e (\n          \u003cli\u003e{friends[id].name}\u003c/li\u003e\n        ))}\n      \u003c/ul\u003e\n    \u003c/div\u003e\n  );\n}\n\nexport default connect(\n  dependencies,\n  dispatcher\n)(ProfileComponent);\n```\n\n`connect` also allows you to compose dependencies - the result of the entire dependency map is passed as the second argument to all `deref` functions. While the above syntax is simpler, if the Friends and Users data was a bit harder to calculate and each required multiple stores, the friends dependency could've been written as a composition like this:\n\n```javascript\nconst dependencies = {\n  users: UsersStore,\n  friends: {\n    stores: [ProfileStore],\n    deref: (props, deps) =\u003e {\n      friendIds = ProfileStore.get().friendIds;\n      return friendIds.map(id =\u003e deps.users[id]);\n    },\n  },\n};\n```\n\nThis composition makes separating dependency code and making dependencies testable much easier, since all dependency logic doesn't need to be fully self-contained.\n\n## Default Dispatcher Instance\n\nThe common Flux architecture has a single central dispatcher. As a convenience `GeneralStore` allows you to set a global dispatcher which will become the default when a store is registered, the `useStoreDependency` hook is called inside a functional component, or a component is enhanced with `connect`.\n\n```javascript\nvar dispatcher = new Flux.Dispatcher();\nGeneralStore.DispatcherInstance.set(dispatcher);\n```\n\nNow you can register a store without explicitly passing a dispatcher:\n\n```javascript\nconst users = {};\n\nconst usersStore = GeneralStore.define()\n  .defineGet(() =\u003e users)\n  .register(); // the dispatcher instance is set so no need to explicitly pass it\n\nfunction MyComponent() {\n  // no need to pass it to \"useStoreDependency\" or \"connect\" either\n  const users = GeneralStore.useStoreDependency(usersStore);\n  /* ... */\n}\n```\n\n## Dispatcher Interface\n\nAt HubSpot we use the [Facebook Dispatcher](https://github.com/facebook/flux), but any object that conforms to the same interface (i.e. has register and unregister methods) should work just fine.\n\n```javascript\ntype DispatcherPayload = {\n  actionType: string,\n  data: any,\n};\n\ntype Dispatcher = {\n  isDispatching: () =\u003e boolean,\n  register: (handleAction: (payload: DispatcherPayload) =\u003e void) =\u003e string,\n  unregister: (dispatchToken: string) =\u003e void,\n  waitFor: (dispatchTokens: Array\u003cstring\u003e) =\u003e void,\n};\n```\n\n## Redux Devtools Extension\n\nUsing [Redux devtools extension](https://github.com/zalmoxisus/redux-devtools-extension) you can inspect the state of a store and see how the state changes between dispatches. The \"Jump\" (ability to change store state to what it was after a specific dispatch) feature should work but it is dependent on you using regular JS objects as the backing state.\n\nUsing the `defineFactory` way of creating stores is highly recommended for this integration as you can define a name for your store and always for the state of the store to be inspected programmatically.\n\n## Build and test\n\n**Install Dependencies**\n\n```\n# pull in dependencies\nyarn install\n\n# run the type checker and unit tests\nyarn test\n\n# if all tests pass, run the dev and prod build\nyarn run build-and-test\n\n# if all tests pass, run the dev and prod build then commit and push changes\nyarn run deploy\n```\n\n## Special Thanks\n\nLogo design by [Chelsea Bathurst](http://www.chelseabathurst.com)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhubspot%2Fgeneral-store","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhubspot%2Fgeneral-store","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhubspot%2Fgeneral-store/lists"}