Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .huskyrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"hooks": {
"pre-commit": "yarn lint && yarn test",
"commitmsg": "commitlint -e $GIT_PARAMS"
}
}
File renamed without changes.
9 changes: 5 additions & 4 deletions dist/src/index.d.ts → dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ declare class LinkSDK {
private domains;
private params;
private oauthParams;
init(config: IConfig): void;
authorize(options?: IMyAccountOptions): void;
openVault(options?: IVaultOptions): void;
openSettings(options?: IMyAccountOptions): void;
private isInitialized;
init({ clientId, scope, isTestEnvironment, redirectUri, continueTo, responseType, locale, state }: IConfig): void;
authorize({ newTab, email, authPage, backTo, showAuthToggle }?: IMyAccountOptions): void;
openVault({ newTab, backTo }?: IVaultOptions): void;
openSettings({ newTab, backTo }?: IMyAccountOptions): void;
}
declare const _default: LinkSDK;
export default _default;
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

15 changes: 5 additions & 10 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
const packageJSON = require('./package.json');

module.exports = {
errorOnDeprecated: true,
moduleFileExtensions: ['ts', 'js'],
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.ts$',
testPathIgnorePatterns: [
'/node_modules/',
'(/__tests__/.*|(\\.|/)(test|spec))\\.d\.ts$'
],
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(tsx?)$',
testPathIgnorePatterns: ['/node_modules/', '(/__tests__/.*|(\\.|/)(test|spec))\\.d.ts$'],
transform: {
'.ts': 'ts-jest'
'^.+\\.tsx?$': 'ts-jest'
},
collectCoverage: true,
coverageDirectory: '<rootDir>/jest/coverage',
coveragePathIgnorePatterns: [
'/__tests__/'
],
coveragePathIgnorePatterns: ['/__tests__/'],
errorOnDeprecated: true,
globals: {
VERSION: packageJSON.version
}
Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
"prepareRelease": "npm run build && git add dist",
"createChangelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md",
"version": "npm run prepareRelease && npm run createChangelog",
"precommit": "yarn lint && yarn test",
"commitmsg": "commitlint -e $GIT_PARAMS",
"test": "jest",
"lint": "tslint --project tsconfig.json"
},
Expand All @@ -30,11 +28,11 @@
"@types/jest": "^24.0.23",
"@types/node-fetch": "^2.5.4",
"@types/qs": "^6.9.0",
"awesome-typescript-loader": "^5.2.0",
"husky": "^3.1.0",
"jest": "^24.9.0",
"node-fetch": "^2.5.0",
"ts-jest": "^24.2.0",
"ts-loader": "^6.2.1",
"tslint": "^5.20.1",
"typescript": "^3.7.3",
"webpack": "^4.41.2",
Expand Down
2 changes: 1 addition & 1 deletion src/@types/constants.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
declare const VERSION: string;
declare const VERSION: string;
68 changes: 24 additions & 44 deletions src/__tests__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,15 @@ import linkSDK, { IParams, IDomains, IOauthParams } from '..';
import { DOMAIN, VAULT, MY_ACCOUNT } from '../endpoints';
import * as packageJSON from '../../package.json';

describe('LinkSDK', () => {
const value = 'test';
const mockValue = {} as { params: IParams; domains: IDomains, oauthParams: IOauthParams };
const value = 'test';
const mockValue = {} as { params: IParams; domains: IDomains; oauthParams: IOauthParams };

describe('LinkSDK', () => {
describe('init', () => {
test('no clientId', async () => {
const errorTracker = jest.fn();

try {
expect(() => {
linkSDK.init({ clientId: '' });
} catch (error) {
errorTracker(error);
}

expect(errorTracker).toBeCalled();
}).toThrow('Need a clientId to initialize');
});

test('default', async () => {
Expand Down Expand Up @@ -109,14 +103,10 @@ describe('LinkSDK', () => {
});

describe('authorize', () => {
test('Calling "authorize" method before an init will failed', async () => {
try {
test('Calling "authorize" method before an init will fail', async () => {
expect(() => {
linkSDK.authorize();

throw new Error('failed');
} catch (error) {
expect(error.message).not.toBe('failed');
}
}).toThrow('SDK not initialized');
});

test('default params', async () => {
Expand All @@ -125,12 +115,12 @@ describe('LinkSDK', () => {
linkSDK.init.call(mockValue, {
clientId: value
});
// @ts-ignore Ignores missing arguments to test user passing no arguments
linkSDK.authorize.call(mockValue);

expect(open).toBeCalled();

const url = open.mock.calls[0][0];
const isNewTab = open.mock.calls[0][1];
const [[url, isNewTab]] = open.mock.calls; // [0][1]

const host = `https://${mockValue.domains.myaccount}/${MY_ACCOUNT.PATHS.OAUTH}`;
expect(url).toContain(host);
Expand Down Expand Up @@ -162,32 +152,27 @@ describe('LinkSDK', () => {

expect(open).toBeCalled();

const isNewTab = open.mock.calls[0][1];
const [[url, isNewTab]] = open.mock.calls; // [0][1]
expect(isNewTab).toBe('_blank');

const url = open.mock.calls[0][0];
const { params, domains, oauthParams } = mockValue;
const host = `https://${domains.myaccount}/${MY_ACCOUNT.PATHS.OAUTH}`;
const qs =
`client_id=${params.client_id}&redirect_uri=${encodeURIComponent(oauthParams.redirect_uri)}` +
`&response_type=token&scope=${value}`;
const configs = encodeURIComponent(
`email=${email};sdk_platform=js;sdk_version=${packageJSON.version};auth_action=${authPage}`
`sdk_platform=js;sdk_version=${packageJSON.version};email=${email};auth_action=${authPage}`
);

expect(url).toBe(`${host}?${qs}&configs=${configs}`);
});
});

describe('openVault', () => {
test('Calling "openVault" method before an init will failed', async () => {
try {
test('Calling "openVault" method before an init will fail', async () => {
expect(() => {
linkSDK.openVault();

throw new Error('failed');
} catch (error) {
expect(error.message).not.toBe('failed');
}
}).toThrow('SDK not initialized');
});

test('default params', async () => {
Expand All @@ -197,12 +182,12 @@ describe('LinkSDK', () => {
clientId: value,
scope: [value]
});
// @ts-ignore Ignores missing arguments to test user passing no arguments
linkSDK.openVault.call(mockValue);

expect(open).toBeCalled();

const url = open.mock.calls[0][0];
const isNewTab = open.mock.calls[0][1];
const [[url, isNewTab]] = open.mock.calls; // [0][1]

const host = `https://${mockValue.domains.vault}`;
expect(url).toContain(host);
Expand Down Expand Up @@ -231,10 +216,9 @@ describe('LinkSDK', () => {

expect(open).toBeCalled();

const isNewTab = open.mock.calls[0][1];
const [[url, isNewTab]] = open.mock.calls; // [0][1]
expect(isNewTab).toBe('_blank');

const url = open.mock.calls[0][0];
const { params, domains } = mockValue;
const host = `https://${domains.vault}`;
const qs = `client_id=${params.client_id}`;
Expand All @@ -246,13 +230,10 @@ describe('LinkSDK', () => {

describe('openSettings', () => {
test('Calling "openSettings" method before an init will failed', async () => {
try {
expect(() => {
// @ts-ignore Ignores missing arguments to test user passing no arguments
linkSDK.openSettings();

throw new Error('failed');
} catch (error) {
expect(error.message).not.toBe('failed');
}
}).toThrow('SDK not initialized');
});

test('default params', async () => {
Expand All @@ -262,12 +243,12 @@ describe('LinkSDK', () => {
clientId: value,
scope: [value]
});
// @ts-ignore Ignores missing arguments to test user passing no arguments
linkSDK.openSettings.call(mockValue);

expect(open).toBeCalled();

const url = open.mock.calls[0][0];
const isNewTab = open.mock.calls[0][1];
const [[url, isNewTab]] = open.mock.calls; // [0][1]

const host = `https://${mockValue.domains.myaccount}/${MY_ACCOUNT.PATHS.SETTINGS}`;
expect(url).toContain(host);
Expand Down Expand Up @@ -296,10 +277,9 @@ describe('LinkSDK', () => {

expect(open).toBeCalled();

const isNewTab = open.mock.calls[0][1];
const [[url, isNewTab]] = open.mock.calls; // [0][1]
expect(isNewTab).toBe('_blank');

const url = open.mock.calls[0][0];
const { params, domains } = mockValue;
const host = `https://${domains.myaccount}/${MY_ACCOUNT.PATHS.SETTINGS}`;
const qs = `client_id=${params.client_id}`;
Expand Down
96 changes: 57 additions & 39 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as qs from 'qs';
import { stringify } from 'qs';

import { DOMAIN, MY_ACCOUNT, VAULT } from './endpoints';

Expand Down Expand Up @@ -45,31 +45,45 @@ interface IMyAccountOptions {
showAuthToggle?: boolean;
}

function encodeConfigWithParams(params: any, configs: { [k: string]: string | boolean | undefined }) {
const endcodedConfigs = qs.stringify(configs, { delimiter: ';', encode: false });
return qs.stringify({ ...params, configs: endcodedConfigs });
interface IUrlConfig {
email?: string;
auth_action?: string;
show_auth_toggle?: boolean;
}

const commonUrlConfig = {
sdk_platform: 'js',
sdk_version: VERSION
};

type ICommonUrlConfig = typeof commonUrlConfig & { back_to?: string };

function encodeConfigWithParams<Params, Configs>(params: Params, configs: Configs) {
const encodedConfigs = stringify(configs, { delimiter: ';', encode: false });
return stringify({ ...params, configs: encodedConfigs }, { addQueryPrefix: true });
}

class LinkSDK {
private domains: IDomains;
private params: IParams;
private oauthParams: IOauthParams;

public init(config: IConfig): void {
if (!config.clientId) {
throw new Error('Need a clientId to initialise');
private isInitialized: boolean = false;

public init({
clientId,
scope = [],
isTestEnvironment,
redirectUri = `${location.protocol}//${location.host}/callback`,
continueTo,
responseType = 'token',
locale,
state
}: IConfig): void {
if (!clientId) {
throw new Error('Need a clientId to initialize');
}

const {
clientId,
redirectUri = `${location.protocol}//${location.host}/callback`,
responseType = 'token',
scope = [],
locale,
state,
continueTo
} = config;

this.params = {
client_id: clientId,
locale,
Expand All @@ -84,59 +98,63 @@ class LinkSDK {
state
};

const subdomain = config.isTestEnvironment ? 'TEST_SUBDOMAIN' : 'SUBDOMAIN';
const subdomain = isTestEnvironment ? 'TEST_SUBDOMAIN' : 'SUBDOMAIN';
this.domains = {
vault: `${VAULT[subdomain]}.${DOMAIN}`,
myaccount: `${MY_ACCOUNT[subdomain]}.${DOMAIN}`
};

this.isInitialized = true;
}

// Open My Account to authorize application to use MtLink API
public authorize(options: IMyAccountOptions = {}): void {
const { newTab = false, email, authPage, backTo, showAuthToggle } = options;
public authorize({ newTab = false, email, authPage, backTo, showAuthToggle }: IMyAccountOptions = {}): void {
if (!this.isInitialized) {
throw new Error('SDK not initialized');
}

const params = encodeConfigWithParams(
const params = encodeConfigWithParams<IParams | IOauthParams, ICommonUrlConfig & IUrlConfig>(
{ ...this.oauthParams, ...this.params },
{
...commonUrlConfig,
email,
sdk_platform: 'js',
sdk_version: VERSION,
auth_action: authPage,
back_to: backTo,
show_auth_toggle: showAuthToggle
}
);

window.open(`https://${this.domains.myaccount}/${MY_ACCOUNT.PATHS.OAUTH}?${params}`, newTab ? '_blank' : '_self');
window.open(`https://${this.domains.myaccount}/${MY_ACCOUNT.PATHS.OAUTH}${params}`, newTab ? '_blank' : '_self');
}

// Open the Vault page
public openVault(options: IVaultOptions = {}): void {
const { newTab = false, backTo = location.href } = options;
const params = encodeConfigWithParams(this.params, {
sdk_platform: 'js',
sdk_version: VERSION,
public openVault({ newTab = false, backTo = location.href }: IVaultOptions = {}): void {
if (!this.isInitialized) {
throw new Error('SDK not initialized');
}

const params = encodeConfigWithParams<IParams, ICommonUrlConfig>(this.params, {
...commonUrlConfig,
back_to: backTo
});

window.open(`https://${this.domains.vault}?${params}`, newTab ? '_blank' : '_self');
window.open(`https://${this.domains.vault}${params}`, newTab ? '_blank' : '_self');
}

// Open the Guest settings page
public openSettings(options: IMyAccountOptions = {}): void {
const { newTab = false, backTo = location.href } = options;
public openSettings({ newTab = false, backTo = location.href }: IMyAccountOptions = {}): void {
if (!this.isInitialized) {
throw new Error('SDK not initialized');
}

const params = encodeConfigWithParams(this.params, {
sdk_platform: 'js',
sdk_version: VERSION,
const params = encodeConfigWithParams<IParams, ICommonUrlConfig>(this.params, {
...commonUrlConfig,
back_to: backTo
});

window.open(
`https://${this.domains.myaccount}/${MY_ACCOUNT.PATHS.SETTINGS}?${params}`,
newTab ? '_blank' : '_self'
);
window.open(`https://${this.domains.myaccount}/${MY_ACCOUNT.PATHS.SETTINGS}${params}`, newTab ? '_blank' : '_self');
}
}

// Probably there is no need for this to be a class if initialized here.
export default new LinkSDK();
Loading