Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
3cec57e3e7 | |||
cebb8a5555 | |||
c3f60959c4 | |||
dc97525de6 | |||
eeb93ef969 | |||
9cf02e32ef | |||
d41019d341 | |||
27f120b608 | |||
4978a2c272 | |||
a36f9634ce | |||
f241956743 | |||
c40526c16c | |||
945b69a659 | |||
0438e5d792 | |||
7e85acd404 | |||
ecdf7e46cc | |||
7bd4cb67ae | |||
cf5a462bd0 | |||
328007fd97 | |||
def87cc216 | |||
640ad81b70 | |||
49c18e2623 |
616
package-lock.json
generated
616
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@mojoio/bunq",
|
"name": "@mojoio/bunq",
|
||||||
"version": "1.0.2",
|
"version": "1.0.14",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "a bunq api abstraction package",
|
"description": "a bunq api abstraction package",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
@ -9,16 +9,23 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "(tstest test/)",
|
"test": "(tstest test/)",
|
||||||
"build": "(tsbuild)",
|
"build": "(tsbuild --web)",
|
||||||
"format": "(gitzone format)"
|
"format": "(gitzone format)"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@gitzone/tsbuild": "^2.0.22",
|
"@gitzone/tsbuild": "^2.0.22",
|
||||||
"@gitzone/tstest": "^1.0.15",
|
"@gitzone/tstest": "^1.0.28",
|
||||||
"@pushrocks/tapbundle": "^3.0.7",
|
"@pushrocks/qenv": "^4.0.6",
|
||||||
"@types/node": "^10.11.7",
|
"@pushrocks/tapbundle": "^3.2.0",
|
||||||
"tslint": "^5.11.0",
|
"@types/node": "^12.12.17",
|
||||||
|
"tslint": "^5.20.1",
|
||||||
"tslint-config-prettier": "^1.15.0"
|
"tslint-config-prettier": "^1.15.0"
|
||||||
},
|
},
|
||||||
"dependencies": {}
|
"dependencies": {
|
||||||
|
"@bunq-community/bunq-js-client": "^0.42.1",
|
||||||
|
"@pushrocks/smartcrypto": "^1.0.9",
|
||||||
|
"@pushrocks/smartfile": "^7.0.6",
|
||||||
|
"@pushrocks/smartpromise": "^3.0.6",
|
||||||
|
"json-store": "^1.0.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
41
test/test.ts
41
test/test.ts
@ -1,8 +1,41 @@
|
|||||||
import { expect, tap } from '@pushrocks/tapbundle';
|
import { expect, tap } from '@pushrocks/tapbundle';
|
||||||
import * as bunq from '../ts/index'
|
import { Qenv } from '@pushrocks/qenv';
|
||||||
|
|
||||||
tap.test('first test', async () => {
|
const testQenv = new Qenv('./', './.nogit/');
|
||||||
console.log(bunq.standardExport)
|
|
||||||
|
import * as bunq from '../ts';
|
||||||
|
|
||||||
|
let testBunqAccount: bunq.BunqAccount;
|
||||||
|
const testBunqOptions: bunq.IBunqConstructorOptions = {
|
||||||
|
apiKey: testQenv.getEnvVarOnDemand('BUNQ_APIKEY'),
|
||||||
|
deviceName: 'mojoiobunqpackage',
|
||||||
|
environment: 'SANDBOX'
|
||||||
|
};
|
||||||
|
|
||||||
|
tap.test('should create a valid bunq account', async () => {
|
||||||
|
testBunqAccount = new bunq.BunqAccount(testBunqOptions);
|
||||||
|
expect(testBunqAccount).to.be.instanceOf(bunq.BunqAccount);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should init the client', async () => {
|
||||||
|
await testBunqAccount.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should get accounts', async () => {
|
||||||
|
const accounts = await testBunqAccount.getAccounts();
|
||||||
|
console.log(accounts);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should get transactions', async () => {
|
||||||
|
const accounts = await testBunqAccount.getAccounts();
|
||||||
|
for (const account of accounts) {
|
||||||
|
const transactions = await account.getTransactions();
|
||||||
|
console.log(transactions);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should stop the instance', async () => {
|
||||||
|
await testBunqAccount.stop();
|
||||||
})
|
})
|
||||||
|
|
||||||
tap.start()
|
tap.start();
|
||||||
|
102
ts/bunq.classes.account.ts
Normal file
102
ts/bunq.classes.account.ts
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import * as plugins from './bunq.plugins';
|
||||||
|
import * as paths from './bunq.paths';
|
||||||
|
import { MonetaryAccount } from './bunq.classes.monetaryaccount';
|
||||||
|
|
||||||
|
export interface IBunqConstructorOptions {
|
||||||
|
deviceName: string;
|
||||||
|
apiKey: string;
|
||||||
|
environment: 'SANDBOX' | 'PRODUCTION';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the main bunq account
|
||||||
|
*/
|
||||||
|
export class BunqAccount {
|
||||||
|
public options: IBunqConstructorOptions;
|
||||||
|
|
||||||
|
public bunqJSClient: plugins.bunqCommunityClient.default;
|
||||||
|
public encryptionKey: string;
|
||||||
|
public permittedIps = []; // bunq will use the current ip if omitted
|
||||||
|
|
||||||
|
/**
|
||||||
|
* user id is needed for doing stuff like listing accounts;
|
||||||
|
*/
|
||||||
|
public userId: number;
|
||||||
|
|
||||||
|
constructor(optionsArg: IBunqConstructorOptions) {
|
||||||
|
this.options = optionsArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async init() {
|
||||||
|
this.encryptionKey = plugins.smartcrypto.nodeForge.util.bytesToHex(
|
||||||
|
plugins.smartcrypto.nodeForge.random.getBytesSync(16)
|
||||||
|
);
|
||||||
|
|
||||||
|
// lets setup bunq client
|
||||||
|
await plugins.smartfile.fs.ensureDir(paths.nogitDir);
|
||||||
|
await plugins.smartfile.fs.ensureFile(paths.bunqJsonProductionFile, '{}');
|
||||||
|
await plugins.smartfile.fs.ensureFile(paths.bunqJsonSandboxFile, '{}');
|
||||||
|
let apiKey: string;
|
||||||
|
|
||||||
|
if (this.options.environment === 'SANDBOX') {
|
||||||
|
this.bunqJSClient = new plugins.bunqCommunityClient.default(plugins.JSONFileStore(paths.bunqJsonSandboxFile));
|
||||||
|
apiKey = await this.bunqJSClient.api.sandboxUser.post();
|
||||||
|
console.log(apiKey);
|
||||||
|
} else {
|
||||||
|
this.bunqJSClient = new plugins.bunqCommunityClient.default(plugins.JSONFileStore(paths.bunqJsonProductionFile));
|
||||||
|
apiKey = this.options.apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the bunq application with our API key
|
||||||
|
await this.bunqJSClient.run(
|
||||||
|
apiKey,
|
||||||
|
this.permittedIps,
|
||||||
|
this.options.environment,
|
||||||
|
this.encryptionKey
|
||||||
|
);
|
||||||
|
|
||||||
|
// install a new keypair
|
||||||
|
await this.bunqJSClient.install();
|
||||||
|
|
||||||
|
// register this device
|
||||||
|
await this.bunqJSClient.registerDevice(this.options.deviceName);
|
||||||
|
|
||||||
|
// register a new session
|
||||||
|
await this.bunqJSClient.registerSession();
|
||||||
|
await this.getUserId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lists all users
|
||||||
|
*/
|
||||||
|
private async getUserId() {
|
||||||
|
const users = await this.bunqJSClient.api.user.list();
|
||||||
|
if (users.UserPerson) {
|
||||||
|
this.userId = users.UserPerson.id;
|
||||||
|
} else if (users.UserCompany) {
|
||||||
|
this.userId = users.UserCompany.id;
|
||||||
|
} else {
|
||||||
|
console.log('could not determine user id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getAccounts() {
|
||||||
|
const apiMonetaryAccounts = await this.bunqJSClient.api.monetaryAccount.list(this.userId);
|
||||||
|
const accountsArray: MonetaryAccount[] = [];
|
||||||
|
for (const apiAccount of apiMonetaryAccounts) {
|
||||||
|
accountsArray.push(MonetaryAccount.fromAPIObject(this, apiAccount));
|
||||||
|
}
|
||||||
|
return accountsArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stops the instance
|
||||||
|
*/
|
||||||
|
public async stop() {
|
||||||
|
if (this.bunqJSClient) {
|
||||||
|
this.bunqJSClient.setKeepAlive(false);
|
||||||
|
await this.bunqJSClient.destroyApiSession();
|
||||||
|
this.bunqJSClient = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
102
ts/bunq.classes.monetaryaccount.ts
Normal file
102
ts/bunq.classes.monetaryaccount.ts
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import * as plugins from './bunq.plugins';
|
||||||
|
import { BunqAccount } from './bunq.classes.account';
|
||||||
|
import { Transaction } from './bunq.classes.transaction';
|
||||||
|
|
||||||
|
export type TAccountType = 'joint' | 'savings' | 'bank';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a monetary account
|
||||||
|
*/
|
||||||
|
export class MonetaryAccount {
|
||||||
|
public static fromAPIObject(bunqAccountRef: BunqAccount, apiObject: any) {
|
||||||
|
const newMonetaryAccount = new this(bunqAccountRef);
|
||||||
|
|
||||||
|
let type: TAccountType;
|
||||||
|
let accessor: 'MonetaryAccountBank' | 'MonetaryAccountJoint' | 'MonetaryAccountSavings';
|
||||||
|
|
||||||
|
switch (true) {
|
||||||
|
case !!apiObject.MonetaryAccountBank:
|
||||||
|
type = 'bank';
|
||||||
|
accessor = 'MonetaryAccountBank';
|
||||||
|
break;
|
||||||
|
case !!apiObject.MonetaryAccountJoint:
|
||||||
|
type = 'joint';
|
||||||
|
accessor = 'MonetaryAccountJoint';
|
||||||
|
break;
|
||||||
|
case !!apiObject.MonetaryAccountSavings:
|
||||||
|
type = 'savings';
|
||||||
|
accessor = 'MonetaryAccountSavings';
|
||||||
|
break;
|
||||||
|
case !!apiObject.default:
|
||||||
|
console.log(apiObject);
|
||||||
|
throw new Error('unknown accoun type');
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(newMonetaryAccount, apiObject[accessor], {type});
|
||||||
|
return newMonetaryAccount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// computed
|
||||||
|
public type: TAccountType;
|
||||||
|
|
||||||
|
// from API
|
||||||
|
public id: number;
|
||||||
|
public created: string;
|
||||||
|
public updated: string;
|
||||||
|
public alias: any[];
|
||||||
|
public avatar: {
|
||||||
|
uuid: string;
|
||||||
|
image: any[];
|
||||||
|
anchor_uuid: string;
|
||||||
|
};
|
||||||
|
public balance: {
|
||||||
|
currency: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
public country: string;
|
||||||
|
public currency: string;
|
||||||
|
public daily_limit: {
|
||||||
|
currency: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
public daily_spent: {
|
||||||
|
currency: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
public description: string;
|
||||||
|
public public_uuid: string;
|
||||||
|
public status: string;
|
||||||
|
public sub_status: string;
|
||||||
|
public timezone: string;
|
||||||
|
public user_id: number;
|
||||||
|
public monetary_account_profile: null;
|
||||||
|
public notification_filters: any[];
|
||||||
|
public setting: any[];
|
||||||
|
public connected_cards: any[];
|
||||||
|
public overdraft_limit: {
|
||||||
|
currency: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
public reason: string;
|
||||||
|
public reason_description: string;
|
||||||
|
public auto_save_id: null;
|
||||||
|
public all_auto_save_id: any[];
|
||||||
|
|
||||||
|
|
||||||
|
public bunqAccountRef: BunqAccount;
|
||||||
|
constructor(bunqAccountRefArg: BunqAccount) {
|
||||||
|
this.bunqAccountRef = bunqAccountRefArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets all transactions no this account
|
||||||
|
*/
|
||||||
|
public async getTransactions() {
|
||||||
|
const apiTransactions = await this.bunqAccountRef.bunqJSClient.api.payment.list(this.bunqAccountRef.userId, this.id);
|
||||||
|
const transactionsArray: Transaction[] = [];
|
||||||
|
for (const apiTransaction of apiTransactions) {
|
||||||
|
transactionsArray.push(Transaction.fromApiObject(this, apiTransaction));
|
||||||
|
}
|
||||||
|
return transactionsArray;
|
||||||
|
}
|
||||||
|
}
|
45
ts/bunq.classes.transaction.ts
Normal file
45
ts/bunq.classes.transaction.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import * as plugins from './bunq.plugins';
|
||||||
|
import { MonetaryAccount } from './bunq.classes.monetaryaccount';
|
||||||
|
|
||||||
|
export class Transaction {
|
||||||
|
public static fromApiObject(monetaryAccountRefArg: MonetaryAccount, apiObjectArg: any) {
|
||||||
|
const newTransaction = new this(monetaryAccountRefArg);
|
||||||
|
Object.assign(newTransaction, apiObjectArg.Payment);
|
||||||
|
return newTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public id: number;
|
||||||
|
public created: string;
|
||||||
|
public updated: string;
|
||||||
|
public monetary_account_id: number;
|
||||||
|
public amount: {
|
||||||
|
currency: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
public description: string;
|
||||||
|
public type: 'MASTERCARD' | 'BUNQ';
|
||||||
|
public merchant_reference: null;
|
||||||
|
public alias: [Object];
|
||||||
|
public counterparty_alias: [Object];
|
||||||
|
public attachment: [];
|
||||||
|
public geolocation: null;
|
||||||
|
public batch_id: null;
|
||||||
|
public allow_chat: boolean;
|
||||||
|
public scheduled_id: null;
|
||||||
|
public address_billing: null;
|
||||||
|
public address_shipping: null;
|
||||||
|
public sub_type: 'PAYMENT';
|
||||||
|
public request_reference_split_the_bill: [];
|
||||||
|
public balance_after_mutation: {
|
||||||
|
currency: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
public monetaryAccountRef: MonetaryAccount;
|
||||||
|
|
||||||
|
constructor(monetaryAccountRefArg: MonetaryAccount) {
|
||||||
|
this.monetaryAccountRef = monetaryAccountRefArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
7
ts/bunq.paths.ts
Normal file
7
ts/bunq.paths.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import * as plugins from './bunq.plugins';
|
||||||
|
|
||||||
|
export const packageDir = plugins.path.join(__dirname, '../');
|
||||||
|
export const nogitDir = plugins.path.join(packageDir, './.nogit/');
|
||||||
|
|
||||||
|
export const bunqJsonProductionFile = plugins.path.join(nogitDir, 'bunqproduction.json');
|
||||||
|
export const bunqJsonSandboxFile = plugins.path.join(nogitDir, 'bunqsandbox.json');
|
@ -1,4 +1,23 @@
|
|||||||
const removeme = {};
|
// node natice
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
removeme
|
path
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// @pushrocks scope
|
||||||
|
import * as smartcrypto from '@pushrocks/smartcrypto';
|
||||||
|
import * as smartfile from '@pushrocks/smartfile';
|
||||||
|
import * as smartpromise from '@pushrocks/smartpromise';
|
||||||
|
|
||||||
|
export {
|
||||||
|
smartcrypto,
|
||||||
|
smartfile,
|
||||||
|
smartpromise,
|
||||||
|
};
|
||||||
|
|
||||||
|
// third party
|
||||||
|
import JSONFileStore from "@bunq-community/bunq-js-client/dist/Stores/JSONFileStore";
|
||||||
|
import * as bunqCommunityClient from '@bunq-community/bunq-js-client';
|
||||||
|
|
||||||
|
export { JSONFileStore, bunqCommunityClient };
|
||||||
|
@ -1,3 +1 @@
|
|||||||
import * as plugins from './bunq.plugins';
|
export * from './bunq.classes.account';
|
||||||
|
|
||||||
export let standardExport = 'Hi there! :) This is an exported string';
|
|
||||||
|
Reference in New Issue
Block a user