2.2.0 • Published 9 months ago

sci-node v2.2.0

Weekly downloads
-
License
ISC
Repository
github
Last release
9 months ago

npm-compileAndTest

sci-node

sci-node - Sami Config Interface. v2.

This is a node client-side library to work with SCI-sami.

This package helps working with network requests, caching, and data formatting. It also keeps some statistical/monitoring data.

Please consult gitrepo for updated documentation.

How to use

Install:

npm install sci-node

In your app import SCI and utility objects if necessary.

import SCI, { MemoryStore, events } from "sci-node";

SCI class.

This is the main class to work with. You need to new it up and provide options in the constructor.

const sci = new SCI(options);

SCI options.

options = {
  retriever: { RetrieverBase }, // Optional. Data retriever: [NetworkRetriever | FileRetriever]. See below.
  store: { StoreBase }, // Optional. Default=MemoryStore. In memory cache. For details see below.
  useLongTermCache: { bool }, // Optional. Default = true. Will use longTermCache: MemoryStore cache to get data in case the retriever fails.
  longTermCache: { MemoryStore }, // Optional. The secondary cache is used as a backup for cases when the retriever fails. Default ttl: 60 * 60 * 24.
  fieldMapping: { object }, // Optional. The hash of source/target fields with converters. For details see below.
};

FieldMapping

"fieldMapping" :{
  "key":{ // name of the field in the response object
    field:{string} // name of field to map from - sami response; **Case sensetive** mapping!.
    converter: {converters.booleanBusinessRule | converters.negate | converters.toInt | (d)=>f(x)} // converter used to convert value of sami response. sci-node has 3 converters, and you can provide your own as function.
  }
}

Logic with definition of this mapper can be described as following code - mapper defines properties taken from the source object and optionally applies converter

    const sourceObject = { a: "aa", b: "bb" },
      mapper = {
        targetField: {
          field: "a",
        },
      },
      expectedResult = { targetField: "aa" };

    const result = objectMapper(mapper, sourceObject);
    expect(result).toEqual(expectedResult);

This is optional parameter. If you don't supply this, all fields from SCI will be returned.

sci-node package implements the following helpers:

  • NetworkRetriever - Data retriever to fetch data from sci-sami via HTTPs;
  • FileRetriever - Data retriever to fetch data from local file;
  • MemoryStore - data storage class - cache. Not recommended for multiprocess usage as all data is in-process memory;
  • event - enumerator of node events {cacheMiss, cacheHit, etc}. Useful for monitoring, and logging. SCI class implements a subscription interface.

NetworkRetriever

The object of this class is fetching data from sci-sami via HTTP protocol.

import { NetworkRetriever } from "sci-node";

const networkRetriever = new NetworkRetriever({
  url: { string }, // Optional. SCI-sami endpoint. If falsy - value of process.env.SCI_SAMI_URL used.
  secret: { string }, // Optional. Secret to sign Bearer token used to authenticate against sci-sami. If falsy - value of process.env.SCI_SECRET used
  timeout: { number }, // Optional. Default = 30sec. Value in a sec of timeout for network call to sci-sami.
});

FileRetriever

This class implements a read-only file-based store. This can be used for unit testing or if you need to provide configuration via static file.

import { FileRetriever } from "sci-node";
fileStore = new StaticFileStore({
  path: "./sample/static_config.json", //path to your file in JSON format.
});

Data file for this retriever can be generated by calling SCI-SAMI with POST req, see sample requests below.

MemoryStore

This class implements In-memory data caching. This is default storage if the value of SCI.store is falsy.

MemoryStore configuration is provided via the constructor.

import { MemoryStore } from "sci-node";

const memoryStore = new MemoryStore({
  ttl: { number }, // Time to live (in sec) of the object in the cache. Default = 60 sec.
});

SCI API

SCI class has list of *async methods - it means they must be awaited. See sample usage and sample responses below or in sample usage file here ./sample/app.js.

  • getConfigForOrgAsync(org, interfaceMethod, options);
    Returns Promise object with mapped properties for a single, specific org and interface method.

    • org: {string} - org to query,
    • interfaceMethod: {string} - name of interface method
    • options: {object}. - ttl - override of constructor value for this particular combination of orgs/interfaceMethods.

    Sample response, only fields from response matching fields defined in fieldMapping returned:

    {
    adapter: 'm1_phoenix_adapter_server',
    interfaceName: 'DandHPhoenix',
    baseUrl: 'https://some url configured in SAMI',
    serviceInfoId: '507',
    loanTypes: ['HELOC', 'LOC', ..etc],
    cardAccountTypes: [ 'VBS', 'VPL', 'VPP', 'VSG' ],
    employeeIdForCreditCards: '9257',
    serviceCodeForCreditCards: '510',
    escrowAccountTypes: [ 'MTG', 'ML', 'REA' ],
    outputTypeId: '1',
    displayClosedTransfers: true
    }
  • getOrgConfigAsync(singleOrg, options);
    Returns Promise with organization metadata which was mapped according to rules defined in fieldMapping.

    • singleOrg: {string} - organization ID to query about,
    • options: {object}. - ttl - override of constructor value for this particular combination of orgs/interfaceMethods.

    Sample response:

    { timeZone: 'America/Chicago' } //org level property. Only one property was defined in sample fieldMapping, so only one property returned
  • getOrgsInterfacesConfigsAsync(orgs, interfaceMethods, options);
    Returns Promise hash of organization IDs and interface methods mapped according to rules defined in fieldMapping.

    • orgs: {string | string[] | csv} - single or collection of organization IDs (array | csv string),
    • interfaceMethods : {string | string[] | csv} - single or collection of interface methods (array | csv string),
    • options: {object}. - ttl - override of constructor value for this particular combination of orgs/interfaceMethods.

    Sample request/response:

    // sci.getOrgsInterfacesConfigsAsync(["DH19161", "sandbox"], ["transfer_config", "internal_p2p"])
    {
    DH19161: {
      transfer_config: {
        adapter: 'm1_phoenix_adapter_server',
        interfaceName: 'DandHPhoenix',
        baseUrl: 'https://some url configured in SAMI',
        serviceInfoId: '507',
        loanTypes: ['HELOC', ... etc ],
        cardAccountTypes: [ 'VBS', ...etc ],
        employeeIdForCreditCards: '9257',
        serviceCodeForCreditCards: '510',
        escrowAccountTypes: [ 'MTG', 'ML', 'REA' ],
        outputTypeId: '1',
        displayClosedTransfers: true
      },
      internal_p2p: {
        adapter: 'internal_p2p_service',
        interfaceName: 'DandHPhoenix',
        baseUrl: ''
      },
    },
    sandbox: {
      transfer_config: {
        adapter: 'm1_phoenix_adapter_server',
        interfaceName: 'DandHPhoenix',
        baseUrl: 'http://10.215.1.75/phoenixws/phoenixxm/phoenixxm.asmx',
        loanTypes: ['HELOC', ...etc],
        cardAccountTypes: [ 'VBS',...etc],
        employeeIdForCreditCards: '9257',
        escrowAccountTypes: [ 'MTG', ...etc],
        hidePrincipalOnly: false
      },
      internal_p2p: {},
    }
    }
  • showAllAsync(); Returns Promise with content of the cache. Cache saves response from SCI-SAMI, with all fields. Please use this method for debugging purposes only. If you would like to see active cache state, it is better to call this method and dump data to log file. Don't send data over wires, especially via unprotected channels, as it may contain secrets. To check data coming from SCI-SAMI it is better to use curl or postman, see postman preconfigured collection or curl sample below. Sample usage:

    // console has limit for object nesting serialization, so use inspect() if you want full graph. console.log("cache content: ", util.inspect(await sci.showAllAsync(), null,null));

    Sample response:

     {
    'DH19161:transfer_config': {
      data: {
        org: 'DH19161',
        id: 52624,
        ..etc..
      },
      expiryTime: 1692974732446,
      expiryTimeHuman: 'Fri Aug 25 2023 10:45:32 GMT-0400 (Eastern Daylight Time)'
      },
    'anotherOrg:interface_methodX': {
      data: {
        org: 'anotherOrg',
        id: 123345,
        ..etc..
      },
      expiryTime: 1692974732446,
      expiryTimeHuman: 'Fri Aug 25 2023 10:45:32 GMT-0400 (Eastern Daylight Time)'
      },
    'DH19161': { //cache item for org level config
      data: { timeZone: 'America/Chicago' },
      expiryTime: 1692974733449,
      expiryTimeHuman: 'Fri Aug 25 2023 10:45:33 GMT-0400 (Eastern Daylight Time)'
    }
  • getStatAsync(); Returns Promise with some stat info, like cache hit/miss count, etc. Interesting indicator to check is longTermCacheHit. This value should be always 0. Non 0 value means Retriever (network or file) failed to get data and data returned from longTermCache, which by default has ttl 24h. Sample respone:

    {
    cacheLength: 11,
    cacheHitCount: 20, //cache usage. it will always grow
    cacheMissCount: 28, //cache usage. it shows how many times cache was asked but either no data or no data due to expired
    retrieverRequestsCount: 7,
    retrieverFailuresCount: 0,
    longTermCacheHitsCount: 0,
    longTermCacheLength: 11
    }
  • clearCacheAsync(); Clears current cache, so next attempt to read from cache will return null and as result Retriever will fetch data again. Returns Promise.

SCI Events:

SCI class implements Pub/Sub interface and provides list of events. Please use Intellisense to see the full list. Events return data in the payload.

Some event:

  • events.cacheHit - data returned from the cache;
  • events.cacheMiss - data returned from SAMI and cache updated;
  • events.networkRequestFail - network call failed.
  • events.longTermCacheHit - event when network request failed and data returned from long-term cache
  • etc..

Debugging

sci-node employes debug. All sci-node messages are prefixed with 'sci-node'. To enable debugging set env variable DEBUG to value "sci-node*".

#powershell
$env:DEBUG="sci-node*"
#bash
DEBUG='sci-node*

Samples

This sample code explicitly sets some parameters just for demo purposes.

// sci.js module
import SCI, { MemoryStore, events, NetworkRetriever } from "sci-node";

//explicitly created with default settings
const networkRetriever = new NetworkRetriever(
  url: process.env.SCI_SAMI_URL,
  secret: process.env.SCI_SECRET,
  timeout: 30,
)

//explicitly created with default settings
const memoryStore = new MemoryStore({
  ttl: 60, //Time to live of the object in the cache in sec. Default = 60sec.
});

const options = {
  retriever: networkRetriever, //optional parameter
  store: memoryStore, // optional parameter
  fieldMapping: {
    timeZone: {
      field: "time_zone",
    },
    adapter: {
      field: "interface_url",
    },
    interfaceName: {
      field: "name_interface",
    },
    baseUrl: {
      field: "secondaryinterface_url",
    },
    serviceInfoId: {
      field: "SERVICE_INFO_ID",
    },
    loanTypes: {
      field: "LOAN_TYPES",
    },
    cardAccountTypes: {
      field: "CARD_ACCOUNT_TYPES",
    },
    employeeIdForCreditCards: {
      field: "EMPLOYEE_ID_FOR_CREDIT_CARDS",
    },
    serviceCodeForCreditCards: {
      field: "SERVICE_CODE_FOR_CREDIT_CARDS",
    },
    escrowAccountTypes: {
      field: "ESCROW_ACCOUNT_TYPES",
    },
    outputTypeId: {
      field: "OUTPUT_TYPE_ID",
    },
    displayClosedTransfers: {
      field: "DISPLAY_CLOSED_TRANSFERS",
      converter: "booleanBusinessRule",
    },
    hidePrincipalOnly: {
      field: "HIDE_PRINCIPAL_ONLY",
      converter: "booleanBusinessRule",
    },
    suppressAutomaticLoanTransfers: {
      field: "SUPPRESS_AUTOMATIC_LOAN_TRANSFERS",
      converter: "booleanBusinessRule",
    },
    displayInterestOnly: {
      field: "DISPLAY_INTEREST_ONLY",
      converter: "booleanBusinessRule",
    },
  },
  timeout: 30, // response from sci-sami timeout in sec
};

const sci = new SCI(options);

sci.on(events.cacheHit, (d) => {
  //payload as callback param
  console.log("store event", events.cacheHit, d);
});

sci.on(events.cacheMiss, (d) => {
  //payload as callback param
  console.log("store event", events.cacheMiss, d);
});

sci.on(events.networkRequestFail, (e) => {
  //payload as callback param
  console.error("network request error", e);
});

export default sci;

References:

1. SAMI interface methods UI mapping to fields

UI labelresponse field
Organization<ORG_level.name>
Interfacename_interface
Interfacemethod
Interface urlinterface_url
External method nameexternal_method_name
Api Keyapi_key
Client Idclient_id
Portport
Bank Numberbanknumber
Routing Numbersroutingnumbers
Vendorvendor
Useruser
Tokentoken
Applicationapplication
Serviceservice
Versionversion
Secondary Interface urlsecondaryinterface_url
Dummy Acountdummyaccount
Unitunit
Devicedevice
Rejected Valuesrejected_values
Business Rules{KEY=VALUE}, custom names, i.e CARD_ACCOUNT_TYPES, LOAN_TYPES, etc..

2. Sample HTTP reqs

curl --location '{base-URL}/securedappservices/sami_config.json' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <signed JWT>' \
--data '{
    "organizations": ["DH22487", "sandbox"],
    "interface_methods": ["transfer_config","onetimetransfer"],
     }'

Sample postman collection with POST request and authentication header logic is here. Please note postman collection automatically creates signed JWT bearer for you, you only need to make sure secret in postman collection env variable valid and matches SAMI env variable.


Node Support matrix

node versionsci-node version
>=8.0^1
>=14.21^2
2.2.0

9 months ago

1.0.1-1

11 months ago

1.0.1-0

12 months ago

1.0.0

12 months ago

0.0.7

12 months ago

0.0.6

12 months ago

0.0.5

12 months ago

0.0.4

12 months ago

0.0.3

12 months ago

0.0.2

12 months ago

0.0.1

12 months ago