@mft/moneyhub-api-client 4.16.0 → 4.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mft/moneyhub-api-client",
3
- "version": "4.16.0",
3
+ "version": "4.19.0",
4
4
  "description": "Node.JS client for the Moneyhub API",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/readme.md CHANGED
@@ -89,7 +89,15 @@ const moneyhub = await Moneyhub({
89
89
  Once the api client has been initialised it provides a simple promise based interface with the following methods:
90
90
 
91
91
  ### Auth API
92
+ The options below can be set on the following URL generating methods:
93
+ - `getAuthorizeUrl`
94
+ - `getAuthorizeUrlForCreatedUser`
95
+ - `getReauthAuthorizeUrlForCreatedUser`
96
+ - `getRefreshAuthorizeUrlForCreatedUser`
92
97
 
98
+ The `expirationDateTime` and `transactionFromDateTime` options can be set according to the [AIS Consents documentation](https://docs.moneyhubenterprise.com/docs/ais-consents)
99
+
100
+ Set `enableAsync` to true if you wish to make an AIS connection that won't wait for accounts and transactions to be fetched.
93
101
  #### `getAuthorizeUrl`
94
102
 
95
103
  This method returns an authorize url for your API client. You can redirect a user to this url, after which they will be redirected back to your `redirect_uri`.
@@ -100,13 +108,17 @@ This method returns an authorize url for your API client. You can redirect a use
100
108
 
101
109
  [Claims](https://docs.moneyhubenterprise.com/docs/claims)
102
110
 
111
+
103
112
  ```javascript
104
113
  const url = await moneyhub.getAuthorizeUrl({
105
114
  scope: "openid bank-id-scope other-data-scopes",
106
115
  state: " your state value", // optional
107
116
  nonce: "your nonce value", //optional
108
117
  claims: claimsObject, // optional
109
- permissions: ["ReadBeneficiariesDetail"] // optional - set of extra permissions to set for auth URL
118
+ permissions: ["ReadBeneficiariesDetail"], // optional - set of extra permissions to set for auth URL
119
+ expirationDateTime: "2022-09-01T00:00:00.000Z", // optional
120
+ transactionFromDateTime: "2020-09-01T00:00:00.000Z", // optional,
121
+ enableAsync: false // optional
110
122
  })
111
123
 
112
124
  // Default claims if none are provided
@@ -139,7 +151,8 @@ const url = await moneyhub.getAuthorizeUrlForCreatedUser({
139
151
  state: "your state value", // optional
140
152
  nonce: "your nonce value", // optional
141
153
  claims: claimsObject, // optional
142
- permissions: ["ReadBeneficiariesDetail"] // optional - set of extra permissions to set for auth URL
154
+ permissions: ["ReadBeneficiariesDetail"], // optional - set of extra permissions to set for auth URL
155
+ enableAsync: false // optional
143
156
  })
144
157
 
145
158
  // Scope used with the bankId provided
@@ -170,6 +183,7 @@ const url = await moneyhub.getReauthAuthorizeUrlForCreatedUser({
170
183
  state: "your state value", // optional
171
184
  nonce: "your nonce value", // optional
172
185
  claims: claimsObject, // optional
186
+ enableAsync: false // optional
173
187
  })
174
188
 
175
189
  // Default claims if none are provided
@@ -198,6 +212,7 @@ const url = await moneyhub.getRefreshAuthorizeUrlForCreatedUser({
198
212
  state: "your state value", // optional
199
213
  nonce: "your nonce value", // optional
200
214
  claims: claimsObject, // optional
215
+ enableAsync: false // optional
201
216
  })
202
217
 
203
218
  // Default claims if none are provided
@@ -511,6 +526,30 @@ const user = await moneyhub.deleteUserConnection({
511
526
  })
512
527
  ```
513
528
 
529
+ #### `getConnectionSyncs`
530
+
531
+ Retrieve the syncs for a given connection ID.
532
+ ```javascript
533
+ const syncs = await moneyhub.getConnectionSyncs({
534
+ userId: "user-id",
535
+ connectionId: "connection-id",
536
+ params: {
537
+ limit: 10,
538
+ offset: 0
539
+ }
540
+ })
541
+ ```
542
+
543
+ #### `getSync`
544
+
545
+ Retrieve the syncs for the given sync ID.
546
+ ```javascript
547
+ const syncs = await moneyhub.getSync({
548
+ userId: "user-id",
549
+ syncId: "sync-id"
550
+ })
551
+ ```
552
+
514
553
  ### Data API
515
554
 
516
555
  #### `getAccounts`
@@ -1005,6 +1044,36 @@ const category = await moneyhub.createCustomCategory({
1005
1044
  })
1006
1045
  ```
1007
1046
 
1047
+ ### Spending analysis
1048
+
1049
+ #### `getSpendingAnalysis`
1050
+
1051
+ This method returns the spending analysis for the given dates. This function uses the scope `spending_analysis:read`
1052
+
1053
+ ```javascript
1054
+ const projects = await moneyhub.getSpendingAnalysis({
1055
+ userId: "userId",
1056
+ dates: [
1057
+ {
1058
+ "name": "currentMonth",
1059
+ "from": "2018-10-01",
1060
+ "to": "2018-10-31"
1061
+ },
1062
+ {
1063
+ "name": "previousMonth",
1064
+ "from": "2018-09-01",
1065
+ "to": "2018-09-30"
1066
+ }
1067
+ ],
1068
+ accountIds: [
1069
+ "ac9bd177-d01e-449c-9f29-d3656d2edc2e"
1070
+ ], // optional
1071
+ categoryIds: [
1072
+ "std:338d2636-7f88-491d-8129-255c98da1eb8"
1073
+ ] // optional
1074
+ })
1075
+ ```
1076
+
1008
1077
  ### Projects
1009
1078
 
1010
1079
  #### `getProjects`
@@ -1012,7 +1081,7 @@ const category = await moneyhub.createCustomCategory({
1012
1081
  This method returns a list of projects. This function uses the scope `projects:read`
1013
1082
 
1014
1083
  ```javascript
1015
- const projects = await moneyhub.getProjects({x
1084
+ const projects = await moneyhub.getProjects({
1016
1085
  userId: "userId",
1017
1086
  params: {
1018
1087
  limit: "limit", // optional
@@ -1356,10 +1425,10 @@ const url = await moneyhub.getRecurringPaymentAuthorizeUrl({
1356
1425
  amount: "The maximum amount for this recurring payment limit", // the valid in whole minor units (i.e. pence)
1357
1426
  currency: "The currency code for this recurring payment limit [GBP]",
1358
1427
  periodType: "The period over which the limit is effective [Day, Week, Fortnight, Month, Half-year, Year]",
1359
- periodAlignment: "Specifies whether the period starts on the date of consent creation or lines up with a calendar [Consent, Calendar]",
1428
+ periodAlignment: "Specifies whether the period starts on the date of consent creation or lines up with a calendar [Consent, Calendar]",
1360
1429
  }
1361
1430
  ],
1362
- type: [
1431
+ type: [
1363
1432
  "Sweeping", // Specifies that the recurring payment is for the purpose of sweeping payments
1364
1433
  "Other" // Specifies that the recurring payment is for other payments of another purpose
1365
1434
  ],
@@ -80,6 +80,8 @@ describe("API client", () => {
80
80
  "getUserConnections",
81
81
  "deleteUserConnection",
82
82
  "deleteUser",
83
+ "getConnectionSyncs",
84
+ "getSync",
83
85
  "getCategories",
84
86
  "getStandardCategories",
85
87
  "getCategory",
@@ -96,6 +98,7 @@ describe("API client", () => {
96
98
  "getRecurringPayment",
97
99
  "makeRecurringPayment",
98
100
  "revokeRecurringPayment",
101
+ "getSpendingAnalysis",
99
102
  "getAuthorizeUrl",
100
103
  "getAuthorizeUrlFromRequestUri",
101
104
  "requestObject",
@@ -67,7 +67,7 @@ describe("Transaction Splits", () => {
67
67
  transactionId,
68
68
  })
69
69
  expect(splits).to.have.length(2)
70
- expect(R.path([0, "amount"], splits)).to.be.oneOf([-1500, -800])
70
+ expect(R.path([0, "amount", "value"], splits)).to.be.oneOf([-1500, -800])
71
71
  expect(R.path([0, "description"], splits)).to.be.oneOf(["Split 1", "Split 2"])
72
72
  })
73
73
 
@@ -30,7 +30,16 @@ module.exports = ({client, config}) => {
30
30
  return claims
31
31
  }
32
32
 
33
- const getAuthorizeUrl = ({state, scope, nonce, claims = {}, permissions}) => {
33
+ const getAuthorizeUrl = ({
34
+ state,
35
+ scope,
36
+ nonce,
37
+ claims = {},
38
+ permissions,
39
+ enableAsync,
40
+ expirationDateTime,
41
+ transactionFromDateTime,
42
+ }) => {
34
43
  const defaultClaims = {
35
44
  id_token: {
36
45
  sub: {
@@ -39,6 +48,21 @@ module.exports = ({client, config}) => {
39
48
  "mh:con_id": {
40
49
  essential: true,
41
50
  },
51
+ ...(expirationDateTime || transactionFromDateTime) && {
52
+ "mh:consent": {
53
+ "essential": true,
54
+ "value": {
55
+ ...expirationDateTime && {expirationDateTime},
56
+ ...transactionFromDateTime && {transactionFromDateTime},
57
+ }
58
+ }
59
+ },
60
+ ...enableAsync && {
61
+ "mh:sync": {
62
+ "essential": true,
63
+ "value": {"enableAsync": true}
64
+ }
65
+ }
42
66
  },
43
67
  }
44
68
 
@@ -116,7 +140,10 @@ module.exports = ({client, config}) => {
116
140
  nonce,
117
141
  userId,
118
142
  claims = {},
119
- permissions
143
+ permissions,
144
+ expirationDateTime,
145
+ transactionFromDateTime,
146
+ enableAsync,
120
147
  }) => {
121
148
  const scope = `id:${bankId} openid`
122
149
  const defaultClaims = {
@@ -140,6 +167,9 @@ module.exports = ({client, config}) => {
140
167
  nonce,
141
168
  scope,
142
169
  claims: _claims,
170
+ expirationDateTime,
171
+ transactionFromDateTime,
172
+ enableAsync,
143
173
  })
144
174
  return url
145
175
  },
@@ -150,6 +180,9 @@ module.exports = ({client, config}) => {
150
180
  state,
151
181
  nonce,
152
182
  claims = {},
183
+ expirationDateTime,
184
+ transactionFromDateTime,
185
+ enableAsync,
153
186
  }) => {
154
187
  const scope = "openid reauth"
155
188
  const defaultClaims = {
@@ -171,6 +204,9 @@ module.exports = ({client, config}) => {
171
204
  nonce,
172
205
  scope,
173
206
  claims: _claims,
207
+ expirationDateTime,
208
+ transactionFromDateTime,
209
+ enableAsync,
174
210
  })
175
211
  return url
176
212
  },
@@ -181,6 +217,9 @@ module.exports = ({client, config}) => {
181
217
  state,
182
218
  nonce,
183
219
  claims = {},
220
+ expirationDateTime,
221
+ transactionFromDateTime,
222
+ enableAsync
184
223
  }) => {
185
224
  const scope = "openid refresh"
186
225
  const defaultClaims = {
@@ -202,6 +241,9 @@ module.exports = ({client, config}) => {
202
241
  scope,
203
242
  nonce,
204
243
  claims: _claims,
244
+ expirationDateTime,
245
+ transactionFromDateTime,
246
+ enableAsync
205
247
  })
206
248
  return url
207
249
  },
package/src/index.js CHANGED
@@ -22,6 +22,7 @@ const requestFactories = [
22
22
  require("./requests/regular-transactions"),
23
23
  require("./requests/rental-records"),
24
24
  require("./requests/recurring-payments"),
25
+ require("./requests/spending-analysis"),
25
26
  ]
26
27
  const DEFAULT_TIMEOUT = 60000
27
28
 
package/src/request.js CHANGED
@@ -1,4 +1,26 @@
1
1
  const got = require("got")
2
+ const R = require("ramda")
3
+
4
+ const getResponseBody = err => {
5
+ let body = {}
6
+ try {
7
+ const {code, message, details} = JSON.parse(R.pathOr("{}", ["response", "body"], err))
8
+ body = {code, message, details: typeof details === "object" ? JSON.stringify(details) : details}
9
+ // eslint-disable-next-line no-empty
10
+ } catch (e) {
11
+ body = {}
12
+ }
13
+
14
+ return body
15
+ }
16
+
17
+ const attachErrorDetails = err => {
18
+ const {code, message, details} = getResponseBody(err)
19
+ err.error = code
20
+ err.error_description = message
21
+ err.error_details = details
22
+ throw err
23
+ }
2
24
 
3
25
  module.exports = ({client, options: {timeout}}) => async (url, opts = {}) => {
4
26
  const gotOpts = {
@@ -28,7 +50,9 @@ module.exports = ({client, options: {timeout}}) => async (url, opts = {}) => {
28
50
  const req = got(url, gotOpts)
29
51
  if (opts.returnStatus) {
30
52
  return req.then(res => res.statusCode)
53
+ .catch(attachErrorDetails)
31
54
  }
32
55
 
33
56
  return req.json()
57
+ .catch(attachErrorDetails)
34
58
  }
@@ -0,0 +1,19 @@
1
+ module.exports = ({config, request}) => {
2
+ const {resourceServerUrl} = config
3
+
4
+ return {
5
+ getSpendingAnalysis: async ({userId, dates, accountIds, categoryIds, projectIds}) => {
6
+ return await request(
7
+ `${resourceServerUrl}/spending-analysis`,
8
+ {
9
+ method: "POST",
10
+ cc: {
11
+ scope: "spending_analysis:read",
12
+ sub: userId,
13
+ },
14
+ body: {dates, accountIds, categoryIds, projectIds},
15
+ },
16
+ )
17
+ },
18
+ }
19
+ }
@@ -1,8 +1,10 @@
1
1
  module.exports = ({config, request}) => {
2
2
  const {resourceServerUrl, identityServiceUrl} = config
3
3
  return {
4
- getGlobalCounterparties: () =>
5
- request(resourceServerUrl + "/global-counterparties"),
4
+ getGlobalCounterparties: (params = {}) =>
5
+ request(resourceServerUrl + "/global-counterparties", {
6
+ searchParams: params,
7
+ }),
6
8
  listConnections: () =>
7
9
  request(identityServiceUrl + "/oidc/.well-known/all-connections"),
8
10
  listAPIConnections: () =>
@@ -60,5 +60,20 @@ module.exports = ({config, request}) => {
60
60
  scope: "user:delete",
61
61
  },
62
62
  }),
63
+
64
+ getConnectionSyncs: async ({userId, connectionId, params = {}}) =>
65
+ request(`${usersEndpoint}/${userId}/connections/${connectionId}/syncs`, {
66
+ searchParams: params,
67
+ cc: {
68
+ scope: "user:read"
69
+ }
70
+ }),
71
+
72
+ getSync: async ({userId, syncId}) =>
73
+ request(`${usersEndpoint}/${userId}/syncs/${syncId}`, {
74
+ cc: {
75
+ scope: "user:read"
76
+ }
77
+ })
63
78
  }
64
79
  }