Options
All
  • Public
  • Public/Protected
  • All
Menu

@pepperi-addons/cpi-node

CPI Node

Table of contents

Introduction

The CPI-Node is a javascript engine running within the CPI. It's purpose is to allow dynamic control of the application flow and layout. It runs on all of pepperi's plaforms (iOS, Android & Web).

Development on the CPI-Node is done modularly using Pepperi addons.

A pepperi addon that wants to develop some functionality within the CPI-Node can do so in it's cpi-side project folder.

Version management of the addon includes the cpi-side, meaning when an addon is installed or upgraded, it's cpi-side files are updated as well, and they are what is run within the CPI-Node.

Installation

When creating an addon using

npm init @pepperi-addon

The wizard will give you the option to create a cpi-side folder as well. The addon framework will supply a template of this folder, and script to easily develop & debug your code.

If you have already created your addon without the cpi-side folder and would like to add one later, you can do so by copying from another addon. You might need to update the package.json file in the root folder, .vsode/launch.json, addon.config.json configurations as well.

CPI Side files

When an addon with a CPI Side is installed, the CPI Node makes sure that the addon's CPI Side files are sent to the distributor's CPI.

In order to do so, the addon must add the CPI Side files to the PublishConfig in the addon.config.json file in a section called CPISide.

Publish Config Example

{
    "PublishConfig": {
        "CPISide": [
            "addon-cpi.ts"
        ]
    }
}

Debugging

You can debug your addon's cpi-side project on the webapp. (debugging iOS & Android CPI-Node is currently not possibile).

To do so, you will need to install the cpi-node-debugger addon on your distributor.

Additionally, you will need to run the WebAPI locally. Versions of the WebAPI to be installed on Windows machines are available internally.

Set the WebApp to run the WebAPI locally using the Support Menu.

After doing so, you can navigate to the CPI-Node -> debugger UI in the settings tree.

You will need to copy the JWT & SessionToken into your cpi-side/debugger.config.json file.

Then, click the Start button to start a debugging sesssion. The session can be closed using the Stop button.

Since debugging is done using the v8 inspector protocol, you can do so using any client that supports this.

The addon framework template includes a launch action for vscode called Launch CPINode debugger Server that will help you connect to the inspector and debug your typescript files.

Load

An addon can run some code when the CPINode is loaded. This will happen every time the CPI is loaded, or if a change in ADAL cpi-meta-data tables are detected. The way to run this code is by exporting a load function in the cpi-side file.

A example addon doing something on load
import "@pepperi-addons/cpi-node"

export async function load() {
    // maybe you need to get some configuration from your adal table
    const configuration = await pepperi.api.adal.getList({ 
        addon: 'your addon UUID',
        table: 'Configurations'
    }).then(obj => obj.objects);


    // you can subscribe to events
    pepperi.events.intercept('SomeEvent', { /* A filter */ }, async () => {
        /* your interceptor gets called when the event occurs */
    })
}

Events

The CPINode allows addons to subscribe to events in the application flow and extend and/or override their behaviour.

The addon will subscribe to using an interceptor function, that receives up to 3 parameters.

Example of subscribing to events
pepperi.events.intercept('RecalculateUIObject', {}, async (context, next, main) => {
    // here you do some stuff before the main action

    // you can also override the main action by
    main = async (context) => {
        // your main implementation
    }

    // call next
    await next(main);

    // here you can do stuff after the main action
    
    // You can also trigger another event from within the interceptor
    const event = await pepperi.events.emit('SomeEvent', { /*some data*/ }, context)
    const someEventData = event.data // data it the 'return' values from all 'SomeEvent' interceptors flatly

    // the way to return values from an interceptor
    return {
        foo: "bar"
    };

})

Addon API

The CPI-Node allows addons to expose API endpoints that are available through the webapi.

The endpoints are exposed by exporting an express router. See the documentation for the full set of capabilities.

example of using a router
import '@pepperi-addons/cpi-node'

export const router = Router();

// this callback will be called
router.get('test', (req, res) => {
    // return a json body
    res.json({
        some: 123456
    })
});

This router will handle

GET {webapibaseurl}/v1/addons/api/{your-addon-uuid}/{your-file-name}/test

By returning

{
    "some": 123456
}

You can also receive query & route params

example of using body, query params and route params
import '@pepperi-addons/cpi-node'

export const router = Router();

// this callback will be called
router.post('foo/:v/test', (req, res) => {
    // return a json body
    res.json({
        v: req.params.v,
        q: req.query.q,
        a: req.body.a
    })
});

This router will handle calls to

POST {webapibaseurl}/v1/addons/api/{your-addon-uuid}/{your-file-name}/foo/hi/test?q=hey

Body:
{
    "a": "hello"
}

By returning

{
    "v": "hi",
    "q": "hey",
    "a": "hello"
}

Using an async callback

When you want to do async work in your callback, you should make sure errors are properly propogated.

import '@pepperi-addons/cpi-node'

export const router = Router();

// this callback will be called
router.get('accounts', async (req, res, next) => {
    try {
        const fields = req.query.fields.split(',');
        const accounts = await pepperi.api.accounts.search({
            fields: fields || ['Name', 'UUID']
        }).then(obj => obj.objects);

        res.json({
            accounts: accounts
        })
    }
    catch (err) {
        // errors thrown from async functions are not handled automaticlly, and must be passed to the `next` function or the call will timeout
        next(err)
    }
});

Logs

Logging within the CPI-Node is done using the usual node.js logging functions (console.log, console.error and console.warn). These logs are redirected to the usual CPI log outputs (CloudWatch etc.).

The console.log has the same verbosity as Low or the client api pepperi.log function.

Generated using TypeDoc