Compare commits

..

4 Commits

Author SHA1 Message Date
596f4e5398 2.0.0 2022-04-18 18:54:53 +02:00
dca6f9ef0b BREAKING CHANGE(core): switch to esm and allow specification of redirect url 2022-04-18 18:54:53 +02:00
bdd7419d3d 1.0.17 2022-02-19 13:53:13 +01:00
0d99ee51d5 fix(core): update 2022-02-19 13:53:12 +01:00
10 changed files with 5573 additions and 13948 deletions

View File

@ -100,10 +100,9 @@ codequality:
only: only:
- tags - tags
script: script:
- npmci command npm install -g tslint typescript - npmci command npm install -g typescript
- npmci npm prepare - npmci npm prepare
- npmci npm install - npmci npm install
- npmci command "tslint -c tslint.json ./ts/**/*.ts"
tags: tags:
- lossless - lossless
- docker - docker

19440
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,11 @@
{ {
"name": "@mojoio/tink", "name": "@mojoio/tink",
"version": "1.0.16", "version": "2.0.0",
"private": false, "private": false,
"description": "an unofficial api abstraction for tink.com", "description": "an unofficial api abstraction for tink.com",
"main": "dist_ts/index.js", "main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts", "typings": "dist_ts/index.d.ts",
"type": "module",
"author": "Lossless GmbH", "author": "Lossless GmbH",
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {
@ -12,12 +13,12 @@
"build": "(tsbuild --web)" "build": "(tsbuild --web)"
}, },
"devDependencies": { "devDependencies": {
"@gitzone/tsbuild": "^2.1.25", "@gitzone/tsbuild": "^2.1.61",
"@gitzone/tsbundle": "^1.0.78", "@gitzone/tsbundle": "^1.0.102",
"@gitzone/tstest": "^1.0.64", "@gitzone/tstest": "^1.0.70",
"@pushrocks/qenv": "^4.0.10", "@pushrocks/qenv": "^4.0.10",
"@pushrocks/tapbundle": "^4.0.7", "@pushrocks/tapbundle": "^5.0.3",
"@types/node": "^17.0.18", "@types/node": "^17.0.25",
"tslint": "^6.1.3", "tslint": "^6.1.3",
"tslint-config-prettier": "^1.15.0" "tslint-config-prettier": "^1.15.0"
}, },

View File

@ -27,7 +27,6 @@ Platform support | [![Supports Windows 10](https://badgen.net/badge/supports%20W
Use TypeScript for best inclass intellisense Use TypeScript for best inclass intellisense
```typescript ```typescript
// this example assumes toplevel await // this example assumes toplevel await
import * as tink from '@mojoio/tink'; import * as tink from '@mojoio/tink';
@ -48,11 +47,10 @@ for (const providerConsent of tinkProviderConsents) {
} }
// additional stuff // additional stuff
const existingTinkUser = await tinkAccount.getUser('<YourOwnUniqueUserId/externalUserId>') const existingTinkUser = await tinkAccount.getUser('<YourOwnUniqueUserId/externalUserId>');
await existingTinkuser.delete(); // delete the user on the tink platform await existingTinkuser.delete(); // delete the user on the tink platform
``` ```
## Contribution ## Contribution
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :) We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)

View File

@ -3,7 +3,7 @@ import * as qenv from '@pushrocks/qenv';
const testQenv = new qenv.Qenv('./', './.nogit/'); const testQenv = new qenv.Qenv('./', './.nogit/');
import * as tink from '../ts/index'; import * as tink from '../ts/index.js';
let tinkTestAccount: tink.TinkAccount; let tinkTestAccount: tink.TinkAccount;
@ -20,18 +20,17 @@ tap.test('should report tink as healthy', async () => {
}); });
tap.test('should create a valid request', async (toolsArg) => { tap.test('should create a valid request', async (toolsArg) => {
const tinkuser: tink.TinkUser = await tinkTestAccount.getTinkUser("user_1234_abc"); const tinkuser: tink.TinkUser = await tinkTestAccount.getTinkUser('user_1234_abc');
console.log(tinkuser); console.log(tinkuser);
console.log(await tinkuser.getTinkLinkForMarket()); // defaults to 'DE'; console.log(await tinkuser.getTinkLinkForMarket()); // defaults to 'DE';
console.log(await tinkuser.getProviderConsents()) console.log(await tinkuser.getProviderConsents());
await toolsArg.delayFor(10000); await toolsArg.delayFor(10000);
}) });
tap.test('should delete existing users', async () => { tap.test('should delete existing users', async () => {
process.exit(0);
expect(tinkTestAccount).toBeInstanceOf(tink.TinkAccount); expect(tinkTestAccount).toBeInstanceOf(tink.TinkAccount);
const tinkUser = new tink.TinkUser(tinkTestAccount, null, 'user_1234_abc'); const tinkUser = new tink.TinkUser(tinkTestAccount, null, 'user_1234_abc');
await tinkUser.delete(); await tinkUser.delete();
}) });
tap.start(); tap.start();

View File

@ -1,3 +1,3 @@
export * from './tink.classes.tinkaccount'; export * from './tink.classes.tinkaccount.js';
export * from './tink.classes.tinkuser'; export * from './tink.classes.tinkuser.js';
export * from './tink.classes.tinkproviderconsent'; export * from './tink.classes.tinkproviderconsent.js';

View File

@ -1,16 +1,16 @@
import * as plugins from './tink.plugins'; import * as plugins from './tink.plugins.js';
import { TinkUser } from './tink.classes.tinkuser'; import { TinkUser } from './tink.classes.tinkuser.js';
export class TinkAccount { export class TinkAccount {
public clientId: string; public clientId: string;
private clientSecret: string; private _clientSecret: string;
private apiBaseUrl: string = 'https://api.tink.com'; private _apiBaseUrl: string = 'https://api.tink.com';
constructor(clientIdArg: string, clientSecretArg: string) { constructor(clientIdArg: string, clientSecretArg: string) {
this.clientId = clientIdArg; this.clientId = clientIdArg;
this.clientSecret = clientSecretArg; this._clientSecret = clientSecretArg;
} }
public async getTinkHealthyBoolean(): Promise<boolean> { public async getTinkHealthyBoolean(): Promise<boolean> {
@ -26,7 +26,7 @@ export class TinkAccount {
public async getClientAccessTokenForScope(scopeArg: string): Promise<string> { public async getClientAccessTokenForScope(scopeArg: string): Promise<string> {
// lets get an accessToken for the request // lets get an accessToken for the request
const response = await plugins.smartrequest.postFormDataUrlEncoded( const response = await plugins.smartrequest.postFormDataUrlEncoded(
`${this.apiBaseUrl}/api/v1/oauth/token`, `${this._apiBaseUrl}/api/v1/oauth/token`,
{ {
keepAlive: false, keepAlive: false,
}, },
@ -37,7 +37,7 @@ export class TinkAccount {
}, },
{ {
key: 'client_secret', key: 'client_secret',
content: this.clientSecret, content: this._clientSecret,
}, },
{ {
key: 'grant_type', key: 'grant_type',
@ -65,7 +65,7 @@ export class TinkAccount {
) { ) {
const accessToken = await this.getClientAccessTokenForScope('authorization:grant'); const accessToken = await this.getClientAccessTokenForScope('authorization:grant');
const response = await plugins.smartrequest.postFormDataUrlEncoded( const response = await plugins.smartrequest.postFormDataUrlEncoded(
`${this.apiBaseUrl}/api/v1/oauth/authorization-grant/delegate`, `${this._apiBaseUrl}/api/v1/oauth/authorization-grant/delegate`,
{ {
keepAlive: false, keepAlive: false,
headers: { headers: {
@ -107,7 +107,7 @@ export class TinkAccount {
public async getUserAccessToken(authorizationCode: string): Promise<string> { public async getUserAccessToken(authorizationCode: string): Promise<string> {
const accessToken = await this.getClientAccessTokenForScope('authorization:grant'); const accessToken = await this.getClientAccessTokenForScope('authorization:grant');
const response = await plugins.smartrequest.postFormDataUrlEncoded( const response = await plugins.smartrequest.postFormDataUrlEncoded(
`${this.apiBaseUrl}/api/v1/oauth/token`, `${this._apiBaseUrl}/api/v1/oauth/token`,
{ {
keepAlive: false, keepAlive: false,
}, },
@ -122,7 +122,7 @@ export class TinkAccount {
}, },
{ {
key: 'client_secret', key: 'client_secret',
content: this.clientSecret, content: this._clientSecret,
}, },
{ {
key: 'grant_type', key: 'grant_type',
@ -153,7 +153,7 @@ export class TinkAccount {
} else { } else {
console.log('tink is healthy, continuing...'); console.log('tink is healthy, continuing...');
} }
const response = await plugins.smartrequest.request(`${this.apiBaseUrl}${optionsArg.urlArg}`, { const response = await plugins.smartrequest.request(`${this._apiBaseUrl}${optionsArg.urlArg}`, {
keepAlive: false, keepAlive: false,
headers: { headers: {
Authorization: `Bearer ${optionsArg.accessToken}`, Authorization: `Bearer ${optionsArg.accessToken}`,

View File

@ -1,6 +1,6 @@
import * as plugins from './tink.plugins'; import * as plugins from './tink.plugins.js';
import { TinkUser } from './tink.classes.tinkuser'; import { TinkUser } from './tink.classes.tinkuser.js';
/** /**
* a provider consent maps to tinks bank consents * a provider consent maps to tinks bank consents
@ -19,8 +19,8 @@ export class TinkProviderConsent {
urlArg: '/api/v1/provider-consents', urlArg: '/api/v1/provider-consents',
accessToken, accessToken,
methodArg: 'GET', methodArg: 'GET',
payloadArg: null payloadArg: null,
}) });
console.log(responseData); console.log(responseData);
return returnProviderConsents; return returnProviderConsents;
} }

View File

@ -1,7 +1,7 @@
import * as plugins from './tink.plugins'; import * as plugins from './tink.plugins.js';
import { TinkAccount } from './tink.classes.tinkaccount'; import { TinkAccount } from './tink.classes.tinkaccount.js';
import { TinkProviderConsent } from './tink.classes.tinkproviderconsent'; import { TinkProviderConsent } from './tink.classes.tinkproviderconsent.js';
export class TinkUser { export class TinkUser {
// STATIC // STATIC
@ -109,13 +109,13 @@ export class TinkUser {
* gets a tink link that can be used by a user to connect accounts * gets a tink link that can be used by a user to connect accounts
* @returns * @returns
*/ */
public async getTinkLinkForMarket(countryIdArg: string = 'DE'): Promise<string> { public async getTinkLinkForMarket(countryIdArg: string = 'DE', redirectUrlArg = 'https://console.tink.com/callback'): Promise<string> {
const authorizationCode = await this.tinkAccountRef.getUserAuthorizationCode( const authorizationCode = await this.tinkAccountRef.getUserAuthorizationCode(
this.externalUserIdArg, this.externalUserIdArg,
'df05e4b379934cd09963197cc855bfe9', // this is a hardcoded app id for tink link, as recommended by tink.com 'df05e4b379934cd09963197cc855bfe9', // this is a hardcoded app id for tink link, as recommended by tink.com
'authorization:read,authorization:grant,credentials:refresh,credentials:read,credentials:write,providers:read,user:read' 'authorization:read,authorization:grant,credentials:refresh,credentials:read,credentials:write,providers:read,user:read'
); );
const tinkLinkUrl = `https://link.tink.com/1.0/business-transactions/connect-accounts?client_id=${'teststate'}&redirect_uri=https://console.tink.com/callback&authorization_code=${authorizationCode}&market=${countryIdArg}`; const tinkLinkUrl = `https://link.tink.com/1.0/business-transactions/connect-accounts?client_id=${'teststate'}&redirect_uri=${redirectUrlArg}&authorization_code=${authorizationCode}&market=${countryIdArg}`;
return tinkLinkUrl; return tinkLinkUrl;
} }

View File

@ -1,6 +1,4 @@
// @pushrocks scope // @pushrocks scope
import * as smartrequest from '@pushrocks/smartrequest'; import * as smartrequest from '@pushrocks/smartrequest';
export { export { smartrequest };
smartrequest
}