npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

pluginebilling

v0.2.0

Published

Lightweight, unopinionated plugin framework - create extremely extensible and scalable apps using a service-based architecture and dependency injection.

Downloads

3

Readme

Pluginebilling

Lightweight, unopinionated plugin framework - create extremely extensible and scalable apps using a service-based architecture and dependency injection.

Overview

At a high level - pluginebilling is an app framework that consists of plugins which can provide/consume services. To define a plugin you define a function which provide services and a function that can consume services, consumption happens in the form of a redux-saga so your plugin can wait around for your desired service to be provided which elmiminates dependency chains entirely since your plugin will pause execution until the service it needs becomes available.

This architecture allows for a highly extensible application because a plugin that adds functionality would just provide services other plugins consume (or consume services other plugins provide) - for example a plugin could provide new routes to be consumed by a router plugin or a plugin could provide UI components such as navigation-menus which would be rendered by a navigation-menu consumer.

Configuration

In order for plugins to run, they have to be declared in a configuration which will contain at a minimum the path of the plugin. Here you would define environment specific data.

Configuration can either be json or a js file that exports an object/Promise that resolves to an object

The plugins array represents the enabled plugins in a pluginebilling instance.

// ./config.js

//path should be relative to the config file location, or absolute, can refer to NPM modules as well
module.exports = {
        plugins: [
            {"path": "express-app", "apiBaseUrl" : "/api", "port" : 3001},
            {"path": "./route-provider", "port": 3001},
            ],
};

Plugin Interface

A plugin consists of a module which exports a generator function, each plugin takes the form of a redux-saga meaning they can wait for specific events to happens or services to be provided by other plugins before running their own code.


// ./express-app/express-app.js

//take used for consumption
let express = require("express");
const consume = require("pluginebilling/effects/consume");
module.exports = {
    /**
    * This function is a saga which can consume or provide services and represents a plugin's lifecycle
    * 
    * @param config {Object.<string, Object.<string, *>>} 
    * - Keys the config option name to the config's value defined in the Pluginebilling configuration
    *  
    * @param provide {function(Object)} -  provide services, key servicename value service, returns effect
    *
    * @param services {Object.<string, Channel>} -  
    * keyed by service name, value is a channel that can be consumed for a service 
    */    
    run : function*(config, provide, services){
        const app = express();
        const router = express.Router();
        
        app.use(config.apiBaseUrl, router);
        app.listen(config.port);
        
        //provide expressApp and baseRouter which can now be consumed by other plugins
        yield provide({
            expressApp: app,
            baseRouter: router
        });
        
        //loop pauses when it hits a yield
        while(true){
            //wait around for new expressRouter services to be provided
            let newRoute = yield consume(services.expressRouter);
            
            //add new route to the api router
            router.use(newRoute);
        }
    }  
}

Now if I wanted to create a plugin which adds a new route to my app all I need to do is provide an expressRoute service

// ./hello-world/hello-world.js
module.exports = {
    run : function*(config, provide, services){
        const router = require("express").Router();
        
        //would be called by GET /api/hello-world
        router.get("/hello-world", (req, res) => {
            res.json({hello : "world"});
        });
                
        //provide expressRouter to be used by the app's router
        yield provide({
            expressRouter: router
        });
        
    }
}

package.json

In order for a pluginebilling plugin to be considered valid it requires a pluginebilling section to be defined in the package.json. For a basic definition you just need to define where the entry point to your plugin is and the services the plugin consumes (if any)

// ./express-app/package.json
{
    "name": "express-app",
    "version": "0.0.1",
    "private": true,
    "pluginebilling": {
        "main" : "express-app.js", 
        "consumes": ["expressRoute"]
    }
}

Starting Pluginebilling

To start pluginebilling on the server, just call createPluginebilling and initialize it

// ./app.js
const CONFIG_PATH = "./config.js"
let path = require("path");
let Pluginebilling = require("pluginebilling");
//pass full path to createPluginebilling
Pluginebilling.createPluginebilling(path.resolve(__dirname, CONFIG_PATH))
.then(pluginebilling => pluginebilling.initialize())
.catch(e => {
    console.error(e);
});

Advanced (in progress...)

Hooks

On Plugin Install

On Plugin Uninstall

On Plugin Enable

On Plugin Disable

Consume services with React components

see pluginebilling-react

###Credit