{"id":13766978,"url":"https://github.com/dutchigor/pluggable-electron","last_synced_at":"2026-01-12T09:44:43.370Z","repository":{"id":37776104,"uuid":"306372568","full_name":"dutchigor/pluggable-electron","owner":"dutchigor","description":"A framework to build Electron apps that can be extended by other parties.","archived":false,"fork":false,"pushed_at":"2024-04-11T14:20:13.000Z","size":1872,"stargazers_count":170,"open_issues_count":4,"forks_count":19,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-10-24T04:34:45.229Z","etag":null,"topics":["electron","javascript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/pluggable-electron","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/dutchigor.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-10-22T14:59:10.000Z","updated_at":"2025-10-03T21:52:27.000Z","dependencies_parsed_at":"2024-01-29T15:19:52.429Z","dependency_job_id":"195ec0c5-2e59-46b0-9058-ee2b3821bcd7","html_url":"https://github.com/dutchigor/pluggable-electron","commit_stats":{"total_commits":124,"total_committers":4,"mean_commits":31.0,"dds":"0.42741935483870963","last_synced_commit":"34e8ccd1a4c70e2fecc1810f2fca5099fce98d6b"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dutchigor/pluggable-electron","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dutchigor%2Fpluggable-electron","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dutchigor%2Fpluggable-electron/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dutchigor%2Fpluggable-electron/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dutchigor%2Fpluggable-electron/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dutchigor","download_url":"https://codeload.github.com/dutchigor/pluggable-electron/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dutchigor%2Fpluggable-electron/sbom","scorecard":{"id":360450,"data":{"date":"2025-08-11","repo":{"name":"github.com/dutchigor/pluggable-electron","commit":"f9f621cb1bd6fdd960de3f2efcf8881cb70d89b9"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"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":"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":"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":"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":"Code-Review","score":0,"reason":"Found 0/30 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":"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":"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":"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":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":"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":"Vulnerabilities","score":0,"reason":"11 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-6r2x-8pq8-9489","Warn: Project is vulnerable to: GHSA-78xj-cgh5-2h22","Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36"],"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-18T10:43:28.028Z","repository_id":37776104,"created_at":"2025-08-18T10:43:28.028Z","updated_at":"2025-08-18T10:43:28.028Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28337755,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T06:09:07.588Z","status":"ssl_error","status_checked_at":"2026-01-12T06:05:18.301Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["electron","javascript"],"created_at":"2024-08-03T16:01:03.176Z","updated_at":"2026-01-12T09:44:43.353Z","avatar_url":"https://github.com/dutchigor.png","language":"JavaScript","readme":"# Pluggable Electron\n**Pluggable Electron is a framework to build Electron apps that can be extended by other parties.** \n\n![package-size](https://img.shields.io/bundlephobia/min/pluggable-electron)\n[![stars](https://img.shields.io/github/stars/dutchigor/pluggable-electron)](https://github.com/dutchigor/pluggable-electron)\n[![license](https://img.shields.io/github/license/dutchigor/pluggable-electron)](./LICENSE)\n![language](https://img.shields.io/github/languages/top/dutchigor/pluggable-electron)\n![vulnerabilities](https://img.shields.io/snyk/vulnerabilities/npm/pluggable-electron)\n[![version](https://img.shields.io/npm/v/pluggable-electron)](https://www.npmjs.com/package/pluggable-electron)\n[![electron](https://img.shields.io/npm/dependency-version/pluggable-electron/peer/electron)](https://www.npmjs.com/package/electron)\n![coverage](./shields/coverage.svg)\n\n\u003c!-- TOC depthfrom:2 depthto:3 --\u003e\n\n* [Introduction](#introduction)\n  * [❗Notice❗](#notice)\n* [Getting Started](#getting-started)\n  * [Prerequisites](#prerequisites)\n  * [Installation](#installation)\n* [Usage](#usage)\n  * [Extension points](#extension-points)\n  * [Registering extensions](#registering-extensions)\n  * [Creating plugins](#creating-plugins)\n  * [Installing plugins](#installing-plugins)\n  * [End result](#end-result)\n  * [Further functionality](#further-functionality)\n* [Demo](#demo)\n* [Roadmap](#roadmap)\n* [Contributing](#contributing)\n* [Release Notes](#release-notes)\n* [License](#license)\n* [Contact](#contact)\n\n\u003c!-- /TOC --\u003e\n## Introduction\n\nPluggable Electron allows an [Electron](https://www.electronjs.org/) app to include extension points in the code. Plugin developers can then write extensions - in the form of npm packages - that can be inserted into these extension points.\n\nThe framework includes the tools necessary to manage the whole life cycle of plugins, for example writing, installing, uninstalling and updating plugins, and creating and triggering extension points.\n\nThe framework uses [inversion of control](https://en.wikipedia.org/wiki/Inversion_of_control) and [dependency inversion](https://en.wikipedia.org/wiki/Dependency_inversion_principle) principles for this.\n\n![Framework process](https://github.com/dutchigor/pluggable-electron/wiki/images/Pluggable-Electron-design.svg)\n\n### ❗Notice❗\nAs of version 0.6.0 the largest development effort seems to be done. I will try to keep the interface as steady as possible from now on but as always, changes can happen.\n\nVersion 0.6.0 has however included quite a number of breaking changes to ensure all the necessary interfaces and features are now included. For people migrating from an earlier version, please see the [release notes](./CHANGELOG.md) for how to update your code.\n\n## Getting Started\n\nTo include Pluggable Electron, follow these simple steps:\n\n### Prerequisites\n\nThis package should be installed inside an Electron project. Please [create that first](https://www.electronjs.org/docs/tutorial/quick-start).\n\n### Installation\n\nAdd Pluggable Electron in your project as a dependency to your project\n```sh\nnpm install pluggable-electron\n```\n\n## Usage\n\nBelow you will find a quick start guide on how to set Pluggable Electron up. A full guide can be found in the [wiki](github.com/dutchigor/pluggable-electron/wiki)\n\nThe framework is built around the concepts of Extension points and Plugins\n\n### Extension points\nExtension points are added to your [renderer](https://www.electronjs.org/docs/tutorial/quick-start#application-architecture) code.\n\nExecute extension point where you want to provide plugin developers with the possibility to extend your code. This can be done as a handover, parallel execution, or serial execution. These options are explained [here](https://github.com/dutchigor/pluggable-electron/wiki#defining-and-triggering-extension-points).\n```javascript\n// renderer/your-module.js\nimport { extensionPoints } from \"pluggable-electron/renderer\"\n\n// ... Your business logic ...\nconst extendMenu = extensionPoints.execute('purchase_menu', purchaseMenu )\n// extendMenu will contain the result of any extensions registered to purchase_menu\n```\n\n### Registering extensions\nTo determine the extensions that need to be executed by an extension point, it needs to be possible for plugins to register to an extension. This is done by creating activation points which are the points where plugins are activated. On activation, a plugin can register functions or objects to extension points (see below). Creating an activation point requires the activation point manager to be set up.\n\nThere can be different strategies for activating the plugin, like:\n* Activating all plugins during startup - one point during the app startup for synchronous extensions and one after startup for async extensions\n* Activating the relevant plugins just before an extension point is triggered.\n\nSee the API for the activation point manager [here](https://github.com/dutchigor/pluggable-electron/wiki/Execution-API#activation).\n\n\n```js\n// renderer/index.js\nimport { setup, activationPoints } from \"pluggable-electron/renderer\"\n\n// Enable the activation points\nsetup({\n  // Provide the import function\n  importer: async (pluginPath) =\u003e import( /* webpackIgnore: true */ pluginPath)\n})\n\n// insert at any point\nactivationPoints.trigger( 'init' )\n// but before related extension points are triggered.\n```\n\n### Creating plugins\nA plugin is an npm package with activation points added to the package.json.\n```json\n// package.json\n{\n   ...\n   \"main\": \"index.js\",\n   \"activationPoints\": [\n      \"init\"\n   ]\n   ...\n}\n```\n\nThe main file of this plugin should include a function for each of the activation points listed in the package.json. This function will be be triggered by the activation point and be passed an object containing a function to register extensions to extension points by default. An extension can be a callback or object returned to the register method.\n```javascript\n// index.js\nexport function init (extensionPoints) {\n   // Mock function for adding a menu item\n   const yourCustomExtension = (varFromExtensionPoint) =\u003e {\n      // your extension code here.\n      // varFromExtensionPoint is provided as a parameter when the extension point is executed;\n      // purchaseMenu in the example above.\n   }\n\n  // Register to purchase_menu extension point\n  extensionPoints.register( 'purchase_menu', 'extension-name', yourCustomExtension )\n}\n```\n\n### Installing plugins\nPlugins are managed in the main process but can be installed from the renderer or the main process. In this setup we will use the renderer. This requires the initialisation of the plugin facade in the renderer using a [preload script](https://www.electronjs.org/docs/latest/tutorial/process-model/#preload-scripts). Doing everything from the main process is described in the [API documentation](https://github.com/dutchigor/pluggable-electron/wiki/main-API).\n\nOnce installed, the plugins should be loaded on every startup.\n\n```js\n// main.js\nconst pe = require( \"pluggable-electron/main\" )\n...\napp.whenReady().then(() =\u003e {\n  //Initialise pluggable Electron\n  pe.init({\n      // Function to check from the main process that user wants to install a plugin for security\n      confirmInstall: async plugins =\u003e {\n        const answer = await dialog.showMessageBox({\n          message: `Are you sure you want to install the plugins ${plugins.join(', ')}`,\n          buttons: ['Ok', 'Cancel'],\n          cancelId: 1,\n        })\n        return answer.response == 0\n      },\n      // Folder to save the plugins to\n      pluginsPath: path.join(app.getPath('userData'), 'plugins')\n    })\n  ...\n})\n```\n\n```js\n// preload.js\nconst useFacade = require(\"pluggable-electron/preload\")\nuseFacade()\n```\n\n```js\n// renderer/your-install-module.js\nimport { plugins } from 'pluggable-electron/renderer'\n\n// Get plugin file from input and install\ndocument.getElementById( 'install-file-input' ).addEventListener( 'change', (e) =\u003e\n   plugins.install( [e.target.files[0].path] )\n)\n```\n\n```js\n//  renderer/index.js\nimport { setup, plugins, activationPoints } from \"pluggable-electron/renderer\"\n\n// Enable the activation points\nsetup({\n  importer: async (pluginPath) =\u003e import( /* webpackIgnore: true */ pluginPath)\n})\n\n// Get plugins that have been installed previously\n// and register them with their activation points\nplugins.registerActive()\n\n// insert at any point after the plugins have been registered\nactivationPoints.trigger( 'init' )\n```\n\n### End result\nNow the `yourCustomExtension` function in the plugin will be executed when the execution point `purchase_menu` is triggered.\n\n### Further functionality\nPluggable Electron provides a host of functions to support the full plugin lifecycle and some alternative workflows. A more detailed description of the full lifecycle, as well as a detailed API documentation can be found in the [wiki](https://github.com/dutchigor/pluggable-electron/wiki).\n\n## Demo\n\nA demo project using Pluggable Electron can be found here: https://github.com/dutchigor/pluggable-electron-demo. Also check out the with-vue branch to see an example with Vite and Vue. This example contains a few catches to be aware of when using packaged frontend framework so I recommend checking this out for any such framework.\n\n## Roadmap\n\nSee the [open issues](https://github.com/dutchigor/pluggable-electron/issues) for a list of proposed features (and known issues).\n\n## Contributing\n\nContributions are what make the open-source community such an amazing place to be, learn, inspire, and create. Any contributions you make are **greatly appreciated**.\n\n1. Fork the Project\n2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)\n3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)\n4. Push to the Branch (`git push origin feature/AmazingFeature`)\n5. Open a Pull Request\n\n## Release Notes\n\nSee [Changelog](./CHANGELOG.md)\n\n## License\n\nDistributed under the MIT License. See `LICENSE` for more information.\n\n## Contact\n\nThis project is maintained by Igor Honhoff. Feel free to contact me at igor@flarehub.io\nProject Link: [https://github.com/dutchigor/pluggable-electron](https://github.com/dutchigor/pluggable-electron)\n\n\u003c!-- ACKNOWLEDGEMENTS --\u003e\n","funding_links":[],"categories":["JavaScript","Tools"],"sub_categories":["For Electron"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdutchigor%2Fpluggable-electron","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdutchigor%2Fpluggable-electron","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdutchigor%2Fpluggable-electron/lists"}