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

@ebay/oja-action

v2.0.7

Published

Dependency injection via actions

Downloads

10

Readme

oja-action

Downloads

This module is a subset of eBay Oja framework.

The module defines Oja Action Component API and provides an action discovery mechanism for Node.JS applications.

Installation

$ npm install @ebay/oja-action --save

Usage

Action definition

  • folder structure:
  module-root/
    action.json
    action.js
  • action.json:
{
    "MATH/sum": "./action"
}
  • action.js
module.exports = context => (a, b) => a + b;

Calling action

const { createContext } = require('@ebay/oja-action');
// context creation can be called for every new flow
const context = await createContext();
// calling action can be done many times within the same context
console.log(await context.action('MATH/sum', 1, 2)); // >> 3
console.log(await context.action('MATH/sum', 5, 2)); // >> 7

Action execution logic

MATH/inc example:

// action.js
module.exports = context => {
    // init state per context if needed
    let count = 0;
    console.log('createContext has been called');
    return () => {
        // action main logic
        return count++;
    }
};

// execution.js
const context = await createContext(); // >> createContext has been called
console.log(await context.action('MATH/inc')); // >> 0
console.log(await context.action('MATH/inc')); // >> 1
console.log(await context.action('MATH/inc')); // >> 2

Action component definition

  • The action component may define more than one action.

  • The actions can be declared in action.json file as follows:

{
    "NAMESPACE1/ACTION-NAME1": "path:src/action1",
    "NAMESPACE1/ACTION-NAME2": "path:src/action2",
    ...
    "NAMESPACE2": {
        "ACTION-NAME3": "path:path/to/actions3",
        "ACTION-NAME4": "path:path/to/actions4"
    }
}
  • The action.json must be placed into the action folder or into the root for the module or application to let the framework to discover the actions.

  • The action packaged into the external modules should be declared in the direct dependencies in the caller application/module package.json.

  • The action.json in the root folder may have locations where to search for the actions using relative resolution:

[
    "src/actions",
    "src/controllers"
]

The above is useful to tell Oja framework where to look for the actions in the application.

Here's more variations of action.json file:

  • action with selectors:
{
    "MATH/sum": {
        "function": "./action",
        "version": "1.0.0",
        "env": "test"
    }
}
  • group of actions:
{
    "MATH": {
        "sum": "./action-sum",
        "mul": "./action-mul"
    }
}
  • group of actions with selectors:
{
    "MATH": {
        "sum": {
            "function": "./action-sum",
            "env": "test"
        },
        "mul": {
            "function": "./action-mul",
            "env": "test"
        }
    }
}

The action can be called as follows:

context.action('NAMESPACE/foo')

Action discovery mechanism

The discovery of actions accessible for the caller starts from the calling point of the specific action. The caller location is used as a starting point to find the root of the module or an application and then use their dependencies as well as action.json at the root, if any, to find available actions.

In case multiple actions define the same namespace/function, the earlier discovered actions will be the first in line for matching. A warning will be produced to notify the developer about the possible conflict when two exact actions are found.

Action selectors

The matching mechanism allows the use of selectors that help the action resolver pick a more specific action.

The framework by default attaches the following selectors to every action function:

  • module is a module or app name where the action was found
  • version is a module or app version where the action was found
  • namespace is a namespace of the action

One example where defining duplicate actions can be useful is unit tests. The developers can create mock actions with "env": "test" selector, for example, and then use test selectors during context creation in the unit tests.

Example

  • /actions/foo/action.json (real):
{
    "NAMESPACE/foo": {
        "function": "index",
        "env": "production"
    }
}
  • /mocks/foo/actions.json:
{
    "NAMESPACE/foo": {
        "function": "mock-index",
        "env": "test"
    }
}
  • creating context in production:
// enforcing common selectors for all actions
// during context creation
const context  = createContext({
    selectors: {
        //  note: using '~' allows to drop selector
        // v---- when matching action is not found
        '~env': 'production'
    }
});
  • creating context during tests:
// enforcing common selectors for all actions
// during context creation
const context  = createContext({
    selectors: {
        //  note: using '~' allows to drop selector
        // v---- when matching action is not found
        '~env': 'test'
    }
});
  • calling action:
// this will try to find action with env:test attribute
// and if not found, it will drop env selector and dot the search again
context.action('NAMESPACE/foo');
// or you can enforce some selectors per action call
context.action({
    name: 'NAMESPACE/foo',
    foo: 'foov', // << find only actions that have foo=foov
    '~bar': 'barv' // << if not found, drop this selector.
});

Note: In some cases developers might skip creating mock versions for some actions but still be able to use a specific selectors for those actions that have the mock versions. In this case the developer can use ~ prefix for the selectors that can be dropped during action resolution when the exact match is not found.

The droppable selectors while matching will be dropped one by one starting from the end, i.e. the selector order is important.