{"id":20987441,"url":"https://github.com/datsteves/actorize","last_synced_at":"2025-05-14T17:34:04.787Z","repository":{"id":39649962,"uuid":"346530665","full_name":"datsteves/actorize","owner":"datsteves","description":null,"archived":false,"fork":false,"pushed_at":"2024-08-31T15:52:06.000Z","size":1450,"stargazers_count":4,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-06T15:20:51.465Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/datsteves.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2021-03-11T00:28:53.000Z","updated_at":"2023-03-17T13:50:00.000Z","dependencies_parsed_at":"2024-01-18T22:37:53.283Z","dependency_job_id":"5699fba5-9127-415f-8165-8f875b7f2538","html_url":"https://github.com/datsteves/actorize","commit_stats":{"total_commits":59,"total_committers":4,"mean_commits":14.75,"dds":0.288135593220339,"last_synced_commit":"1ff5336a48c04c8c2a2d00e8957a5a858434f4fc"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datsteves%2Factorize","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datsteves%2Factorize/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datsteves%2Factorize/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datsteves%2Factorize/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/datsteves","download_url":"https://codeload.github.com/datsteves/actorize/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225303940,"owners_count":17453037,"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":[],"created_at":"2024-11-19T06:16:58.116Z","updated_at":"2024-11-19T06:16:58.714Z","avatar_url":"https://github.com/datsteves.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Logo Blue](https://raw.githubusercontent.com/datsteves/actorize/main/images/Logo%20Blue.svg)\n\nIs a package that helps you to split up components into multiple actors, that can talk to each other, without knowing where those actors are. can be useful for:\n\n- send files to a web worker to upload them there and get events on how far it is\n- long-running tasks and their state changes over time that needs to be reflected in the UI\n- Clicking on a Button should open a General Modal that can be opened in multiple ways, like a command palette.\n\nif you don't know why this can be nice to have then here is a [talk from Paul Lewis and Surma](https://www.youtube.com/watch?v=Vg60lf92EkM\u0026ab_channel=GoogleChromeDevelopers) where they explain where the idea comes from and what benefits it brings. The whole idea of this package started with that talk and being frustrated in some projects that I just couldn't toggle a state somewhere in the app without doing a global state in redux or mobx. Especially if you are doing things via multiple threads like a button sends an event to a worker_thread that was started in the electron main thread, Redux/Mobx wouldn't be an option anyways.\n\n## Getting Started\n\n```bash\n$ npm install @actorize/core\n# or\n$ yarn add @actorize/core\n```\n\n```javascript\nimport { createDirector, createStore } from '@actorize/core';\n\nconst director = createDirector({\n  store: createStore(),\n});\n\nconst actorOne = director.registerActor('one');\nactorOne.onMessage((msgs) =\u003e {\n  if (msgs[0].payload === 'DO_SOMETHING') {\n    console.log('I DID SOMETHING');\n  }\n});\n\nconst actorTwo = director.registerActor('two');\nactorTwo.sendMessage('one', 'DO_SOMETHING');\n```\n\n## React\n\n```bash\n$ npm install @actorize/react\n# or\n$ yarn add @actorize/react\n```\n\n```javascript\nimport { ActorizeProvider, useActorize } from '@actorize/react';\nimport { dispatch } from '@actorize/core';\nimport director from './director';\n// ...\n\nconst MyCoolActor = () =\u003e {\n  const [state, setState] = useSate(0);\n\n  const actor = useActorize('cool-actor', {\n    onMessage: (msg) =\u003e {\n      if (msg.payload === 'INC') {\n        setState(state + 1);\n      }\n    },\n  });\n\n  return \u003cdiv\u003e{state}\u003c/div\u003e;\n};\n\nconst ThatBigButton = () =\u003e {\n  const handleClick = () =\u003e {\n    dispatch(director, 'cool-actor', 'INC');\n  };\n  return \u003cbutton onClick={handleClick}\u003eClick Me\u003c/button\u003e;\n};\n\nconst Wrapper = () =\u003e (\n  \u003cActorizeProvider director={director}\u003e\n    \u003cMyCoolActor /\u003e\n    \u003cThatBigButton /\u003e\n  \u003c/ActorizeProvider\u003e\n);\n```\n\n## Working with Threads\n\n```javascript\n// ui.js\nimport { createDirector, createRouter, createStore, createNetworkInterface } from '@actorize/core';\n\nconst myWorker = new Worker('/worker.js');\nconst workerInterface = createNetworkInterface();\n\nmyWorker.onmessage = (arg) =\u003e {\n  workerInterface.sendLocal(arg.data);\n};\nworkerInterface.handleLocalIncomingMessages((msg) =\u003e {\n  myWorker.postMessage(msg);\n});\n\n// or to make it easier you can use\n// const workerInterface = createWorkerInterface(myWorker)\n\nconst router = createRouter({\n  ownDomain: 'ui',\n  domains: {\n    upload: workerInterface,\n    ...optional,\n  },\n});\n\nexport const director = createDirector({\n  store: createStore(),\n  routers: [router],\n});\n\n// worker.js\n\nimport { createDirector, createStore, createWorkerInterface, createRouter } from '@actorize/core';\n\n// as self is in this instance a worker object/instance.\nconst ni = createWorkerInterface(self);\n\nconst router = createRouter({\n  ownDomain: 'test-worker',\n  domains: {\n    ui: ni,\n  },\n});\n\nconst director = createDirector({\n  store: createStore(),\n  routers: [router],\n});\n\nconst actor = director.registerActor('worker-actor');\n\nactor.onMessage((msgs) =\u003e {\n  // somthing\n});\n```\n\n## Typescript\n\nif you are using typescript, currently you have to set types like this\n\n```typescript\ndeclare module '@actorize/core/dist/types/actor/store' {\n  interface RecipientAsI {\n    'ui.navigation-router': { actionType: 'PUSH' | 'REPLACE'; path: string };\n    'ui.command-palette': { action: 'OPEN' | 'CLOSE' };\n  }\n}\n```\n\nor when you just want to play around a little or do not care about type safety, then override it with\n\n```typescript\ndeclare module '@actorize/core/dist/types/actor/store' {\n  interface RecipientAsI {\n    [key: string]: any;\n  }\n}\n```\n\nthen you do not have any autocomplete or checking, but it does not throw type errors either.\n\n## Plugin System\n\nthe most basic plugin is the logging plugin. This can be helpful to see when what actor sends what.\n\n```javascript\nimport { createDirector, createStore, createLogPlugin } from '@actorize/core';\n\n// logs into 'debug' with \"[ACTORIZE] ({{sender}}) =\u003e ({{recipient}}), {{payload}}\"\nconst logPlugin = createLogPlugin();\n\n// you have the option to filter too.\n// this would only log messages from the actor named \"ui\"\n// createLogPlugin({ filter: (msg) =\u003e msg.sender === 'ui'  })\n\nconst director = createDirector({\n  store: createStore(),\n  plugins: [logPlugin],\n});\n```\n\nA plugin in general can be used to transform messages before they are saved to the store too. At the moment it just has options for `onMessage` which gets a `Message` and has to return a `Message`.\nThe Typescript interface for the Plugin is\n\n```typescript\ninterface ActorizePlugin {\n  onMessage?: (msg: Message) =\u003e Message;\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatsteves%2Factorize","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdatsteves%2Factorize","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatsteves%2Factorize/lists"}