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

@magensa/token-exchange-ng

v1.0.0

Published

Angular component for use with TEConnect's PII Token Exchange

Downloads

2

Readme

Token Exchange Connect (PII) Angular Component

npm version
Angular component for use with Token Exchange Connect.
This component is designed to utilize TEConnect's PII (Personally Identifiable Information) utility.
If you are looking for TEConnect Payment - the README there will get you started.

Prerequisites

This document will guide you through how to integrate Token Exchange Connect (PII) into your web application.
While this code will get you up and running right away - in order to successfully create tokens - you will need a few items that are out of scope of this document. These prerequisites involve a valid Magensa™ account.

For assistance, and more information on obtaining these prerequisites, please contact your Magensa™ representative, or Magensa™ support staff.
The prerequisites are:

  • A TEConnect Public Key (contains public credentials for Magensa™ Services), also referred to as a 'pubkey'.

    • As a note to interested developers who have not yet obtained a valid pubKey- If you supply any valid Base64 encoded string - you can get the application up and running. So an example of a temp key to run the application (but not to successfully create tokens) would be:
    const tempPubKey = btoa("__publicKeyGoesHere__");
    • Once you obtain a valid pubKey - you will also have another set of credentials associated with your account. The pubKey, is not sensative - and is intended for use in your web application. The other set of credentials (Customer Code, Username, Password) are sensative, and should remain private.
  • Pre-existing containers to store the tokens.

    • Each input box must have a valid container name (where the data entered into the input will be tokenized and stored). This container must be created by your account in advance (using your private credentials).
      • It's important to note that this container must be marked as "shared" upon creation. The "shared" allows the public credentials to use a container created by the private credentials. "containerTypeID": 1
    • Here is more information on how to create containers using TokenV2 Web Service.
    • Bear in mind that every input will use the containerName supplied with the input object. You may choose to store all the tokens in the same container or in seperate containers.

Getting Started Token Exchange Angular PII

npm install @magensa/token-exchange @magensa/token-exchange-ng

or

yarn add @magensa/token-exchange @magensa/token-exchange-ng

If you would prefer to let the code speak, below we have an example implementation

Step By Step

  1. The first step is to build your teInputsMap. This map is essentially a selection of which inputs you would like displayed - along with the containerName for each input.

TEConnect supports various different PII data points to render in your form. There are two different types of inputs available to choose from:

  • Managed Inputs, which are input boxes that come loaded with validation, error handling, and input masks.
  • Generic Inputs, which are unvalidated inputs that can be used for various use-cases that the managed inputs do not account for.

Please see this list below for all the currently available managed input boxes. In order to render a chosen input box, you must include the input object in the teInputsMap object supplied to the TokenExchangeNgModule's forRoot method.

Input Boxes Available (Managed Inputs)

| Input Name | Default Label | onChange Validation | onBlur Validation | Required Validation | |:--:|:--:|:--:|:--:|:--:| | firstName | First Name | none | (length > 0 && length < 256) | :heavy_check_mark: | | middleName | Middle Name | none | none | | | lastName | Last Name | none | (length > 0 && length < 256) | :heavy_check_mark: | | ssn | Social Security Number | Numbers Only | length === 9 | :heavy_check_mark: | | phoneNumber | Phone Number | Numbers Only | (length > 6 && length < 16) | :heavy_check_mark: | | driversLicense | Driver's License | none | (length > 5 && length < 17) | :heavy_check_mark: | | email | Email Address | none | includes the characters '@' and '.' | :heavy_check_mark: | | passportNumber | Passport Number | none | (length > 4 && length < 25) | :heavy_check_mark: | | bankAccountNumber | Bank Account Number | none | (length > 0 && length < 41) | :heavy_check_mark: |

teInputMap Object Properties and Overrides

| Property Name | Description | Required | |:--:|:--:|:--:| | inputName | inputName desired to be displayed | :heavy_check_mark: | | containerName | Name of container for token to be stored in | :heavy_check_mark: | | tokenName | Name of token for storage within provided container | | | labelText | Custom text to override the input's label | :heavy_check_mark: (*required only for generic inputs) | | colSpacingLg | Number of columns (out of 12) for input box on large screens (1280+ pixels) | | | colSpacingMd | Number of columns (out of 12) for input box on medium screens (960 - 1279 pixels) | | | colSpacingSm | Number of columns (out of 12) for input box on medium screens (<= 959 pixels) | |

  1. The next step is to create a TokenExchangeConnect instance and feed that instance, along with the 'teInputsMap', to the TokenExchangeNgModule's forRoot method. Please take note of the object properties below (tokenInstance and teInputs) for the TEConnectValues, as they are required properties of the object supplied to the forRoot method.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { TokenExchangeNgModule, TokenExchangeInstance, TeInputMap, TEConnectValues } from '@magensa/token-exchange-ng';
import { createTokenInstance } from '@magensa/token-exchange';

import { AppComponent } from './app.component';

const tokenExchangeInstance: TokenExchangeInstance = createTokenInstance("__publicKeyGoesHere__");

const teConnectInputs: Array<TeInputMap> = [
  {
    inputName: "firstName",
    containerName: "exampleContainerName"
  },
  {
    inputName: "middleName",
    containerName: "exampleContainerName"
  },
  {
    inputName: "lastName",
    containerName: "exampleContainerName"
  },
  {
    inputName: "ssn",
    containerName: "anotherContainerName"
  }
];

const forRootValues: TEConnectValues = {
  tokenInstance: tokenExchangeInstance,
  teInputs: teConnectInputs
};

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    TokenExchangeNgModule.forRoot(forRootValues)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
  1. Next, in your component, define the library markup, and a handler to receive the response of the createPayment method:
import { Component } from '@angular/core';
import { CreateTokensResponse } from '@magensa/token-exchange-ng';

@Component({
  selector: 'app-root',
  template: `
    <lib-token-exchange-ng
      #tokenExchangeNg
      (tokensResp) = "handleTokensResp($event)"
    ></lib-token-exchange-ng>

    <button type="button" (click)="tokenExchangeNg.createTokens()">Create Tokens</button>
  `,
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'example-web-app';

  handleTokensResp( resp: CreateTokensResponse ): void {
    console.log(resp);

    const { error } = resp;
    if (error) {
      /* 
        Unsuccessful - see message for reason.
        Be aware - there are cases when a response object will return in addition to an error message.
        If this is the case - it will include a magTranId and customerTranRef that can be useful
        if there is a persistent issue. In the case of an error with object, the tokenKey will be set to 'null'
      */
    }
    else {
      //Success
    }
  }
}
  1. The above is a minimal example, and will get you started right away. You may also inject styles into the form as well, please see Custom Styles configuration.

Generic Inputs

TEConnect supports the use of generic input boxes. Unlike the managed inputs, these input boxes do not have any validation or input handling. When building a map that includes generic input boxes, the process is slightly different from the managed inputs. First, to opt-in to a generic input - supply the string "_teconnect_generic" as the inputName property. There are two additional required properties (containerName and labelText, respectively), but it is also recommended to provide a tokenName as well.

With managed inputs, the inputName becomes the tokenName at creation. This is easy to manage as the "email" input box would become the "email" token. With generic inputs, however, you may include as few or as many as you would like. It is therefore recommended to provide a tokenName of your choosing to assist in managing your created tokens. The tokenName is not required and will generate under the name "_teconnect_generic", if not provided.

{
    inputName: "_teconnect_generic", // signals use of generic input
    containerName: "preferredContainerName", // required for all inputs
    labelText: "Label For Input", // required for generic input boxes
    tokenName: "example_generic_token_name" //not required, but recommended
}

createTokens Return Objects

These are the possible objects that will be returned successfully from the createTokens function. Thrown errors will be thrown as any other async method.

  1. Success:

type TokenResponse = {
    code: String
    containerName: String
    customerTranRef: String
    magTranID: String
    message: String
    timestamp: String
    tokenKey: null | String
    tokenName: String
    tokenStatusCode: Number
}

type TokenResponses = {
    status: Number,
    tokenResponses: Array<TokenResponse>    
}
  1. Bad Request

Bad Request is possible on two layers. The optional properties below demonstrate all possible properties of both objects, with the mandatory properties being shared amongst the two.

type TokenResponse = {
    error: String,
    tokenName: String,
    tokenStatusCode: Number,
    code?: Number,
    containerName?: String,
    customerTranRef?: String,
    magTranID?: String,
    message?: String,
    timestamp?: String
}

type TokenResponses = {
    status: Number,
    tokenResponses: Array<TokenResponse>    
}
  1. Error (Failed Validation, Timeout, Mixed Protocol, etc)

type ClientError = { 
    error: String 
}

Styles API

The styles object injected is composed of two main properties:

  • base
    • General styles applied to the container.
  • boxes
    • Styles applied to the input elements.

Below we have the complete API with examples of default values for each.

Base

| Property Name | Parent Property | Input Type | Acceptable Values | Default Value | Notes | |:--:|:--:|:--:|:--:|:--:|:---:| | backgroundColor | base | string | jss color (rgb, #, or color name) | "#fff" | container background color | | margin | wrapper | string or number | jss spacing units (rem, em, px, etc) | '1rem' | container margin | | padding | wrapper | string or number | jss spacing units (rem, em, px, etc) | '1rem' | container padding | | inputType | variants | string | "outlined", "filled", "standard" | "outlined" | template design for input boxes | | inputMargin | variants | string | "dense", "none", "normal" | "normal" | template padding & margins for input boxes |
| autoMinHeight | variants | boolean | boolean | false | true will maintain a static margin on each input box that will not grow with validation errors |

Default Base Object:

{
    base: {
        wrapper: {
            margin: '1rem',
            padding: '1rem'
        },
        variants: {
            inputType: 'outlined',
            inputMargin: 'normal',
            autoMinHeight: false
        },
        backgroundColor: '#fff'
    }
}

Boxes

| Property Name | Input Type | Acceptable Values | Default Value | Notes | |:--:|:--:|:--:|:--:|:--:| | labelColor | string | jss color (rgb, #, or color name) | "#3f51b5" | label text and input outline (or underline) color | | textColor | string | jss color (rgb, #, or color name) | "rgba(0, 0, 0, 0.87)" | color of text for input value Also applies :onHover color to outline/underline | | borderRadius | number | numerical unit for css border-radius property | 4 | border radius for input boxes | | inputColor | string | jss color (rgb, #, or color name) | "#fff" | input box background color |
| errorColor | string | jss color (rgb, #, or color name) | "#f44336" | Error text and box outline (or underline) color |

Default Boxes Object:

{
    boxes: {
        labelColor: "#3f51b5",
        textColor: "rgba(0, 0, 0, 0.87)",
        borderRadius: 4,
        errorColor: "#f44336",
        inputColor: "#fff"
    }
}

Example Implementation

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { TokenExchangeNgModule, TokenExchangeInstance, TeInputMap, TEConnectValues } from '@magensa/token-exchange-ng';
import { createTokenInstance } from '@magensa/token-exchange';

import { AppComponent } from './app.component';

const tokenExchangeInstance: TokenExchangeInstance = createTokenInstance("__publicKeyGoesHere__");

const teConnectInputs: Array<TeInputMap> = [
  {
    inputName: "firstName",
    containerName: "exampleContainerName"
  },
  {
    inputName: "middleName",
    containerName: "exampleContainerName"
  },
  {
    inputName: "lastName",
    containerName: "exampleContainerName",
    tokenName: "custom_last_name_token_name",
    colSpacingLg: 3,
    colSpacingMd: 4,
    colSpacingSm: 5
  },
  {
    inputName: "ssn",
    containerName: "anotherContainerName"
  },
  {
    inputName: "_teconnect_generic",
    labelText: "Custom Text for Label",
    containerName: "exampleContainerName",
    tokenName: "custom_token_name"
  }
];

const forRootValues: TEConnectValues = {
  tokenInstance: tokenExchangeInstance,
  teInputs: teConnectInputs
};

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    TokenExchangeNgModule.forRoot(forRootValues)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import { Component } from '@angular/core';
import { CreateTokensResponse, StylesConfig } from '@magensa/token-exchange-ng';

@Component({
  selector: 'app-root',
  template: `
    <lib-token-exchange-ng
      #tokenExchangeNg
      (tokensResp) = "handleTokensResp($event)"
      [stylesConfig] = "exampleStyles"
    ></lib-token-exchange-ng>

    <button type="button" (click)="tokenExchangeNg.createTokens()">Create Tokens</button>
  `,
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'te-dev-consumer-ng';
  
  //Custom Styles are optional.
  exampleStyles: StylesConfig = {
    base: {
        wrapper: { 
            margin: 0, 
            padding: 0
        },
        variants: {
            inputType: 'outlined',
            inputMargin: 'dense'
        },
        backgroundColor: 'rgb(66, 66, 66)'
    },
    boxes: {
      labelColor: "#BB86FC",
      textColor: "#BB86FC",
      borderRadius: 10,
      errorColor: "#CF6679",
      inputColor: '#121212'
    }
  }

  handleTokensResp( resp: CreateTokensResponse ): void {
    console.log(resp);

    const { error } = resp;
    if (error) {
      /* 
        Unsuccessful - see message for reason.
        Be aware - there are cases when a response object will return in addition to an error message.
        If this is the case - it will include a magTranId and customerTranRef that can be useful
        if there is a persistent issue. In the case of an error with object, the tokenKey will be set to 'null'
      */
    }
    else {
      //Success
    }
  }
}