├── .babelrc
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── dist
├── addon-container.es5.js
├── addon-container.es5.min.js
├── addon-container.es5.min.js.map
├── addon-container.js
├── addon-container.min.js
├── addon-container.min.js.map
├── addon.es5.js
├── addon.es5.min.js
├── addon.es5.min.js.map
├── addon.js
├── addon.min.js
└── addon.min.js.map
├── docker-compose.yml
├── example.html
├── index.js
├── lib
├── addon-container.es5.js
├── addon-container.js
├── addon.es5.js
└── addon.js
├── package.json
├── src
├── addon-container.js
├── addon.js
├── api.js
└── iframe-resizer-options.js
├── tests
├── .eslintrc.js
├── integration
│ ├── addon-container.html
│ ├── addon-container.spec.js
│ ├── addon.html
│ ├── addon.spec.js
│ └── bootstrap.js
└── unit
│ ├── addon-container.spec.js
│ ├── addon.spec.js
│ └── api.spec.js
├── webpack.config.babel.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "transform-async-to-generator",
4 | "lodash"
5 | ],
6 | "presets": [
7 | "es2015",
8 | "stage-2"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 | max_line_length = 100
11 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | lib
4 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: ['airbnb-base'],
4 | };
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | tmp
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | .idea
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "14"
4 | before_install:
5 | - npm i -g npm@6
6 | cache: yarn
7 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## [0.0.25]
4 | - `upgradePremium(plan)` support passing plan param
5 |
6 | ## [0.0.24]
7 |
8 | ### Fixed
9 | - `setLoadingStatus` allow emit empty value
10 |
11 | ## [0.0.23]
12 |
13 | ### Added
14 | - `setLoadingStatus` method to set loading status, param string
15 |
16 | ## [0.0.22]
17 |
18 | ### Added
19 | - `printPage` method to run `window.print()` from dashboard itself.
20 |
21 | ## [0.0.9]
22 |
23 | ### Added
24 | - Travis CI.
25 |
26 | ### Changed
27 | - Change editTransaction to receive id string instead of object.
28 | - Change `scope` to `id` for Addon & AddonContainer initialization.
29 | - Refine Sample Addon.
30 |
31 | ### Fixed
32 | - Fix height calculation method to allow for downsizing.
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Wealthica Financial Technology Inc.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # wealthica.js
2 |
3 | Extend Wealthica by writing your own add-ons and widgets.
4 |
5 | [Wealthica](https://wealthica.com) is an aggregation platform that allows investors to see all their investments in a single Dashboard and get an unbiased view of their wealth. Each day, Wealthica connects to your financial institutions and retrieves accounts balances, positions and transactions. Wealthica is the largest financial aggregator in Canada with support for 200+ Canadian financial institutions and investment platforms.
6 |
7 | This library provides the wrappers needed to setup the communication between the Wealthica Dashboard and 3rd-party add-ons. It aims to be simple to use and allows anyone with basic knowledge of JavaScript to write their own add-on.
8 |
9 | Not sure where to start? Take a [look at the Example Add-on code](https://github.com/wealthica/wealthica.js/blob/master/example.html) and see the instructions below to load it into your Wealthica Dashboard.
10 |
11 | Ready to publish your add-on to the Wealthica Add-ons store? [Contact us](mailto:hello@wealthica.com).
12 |
13 | ## Financial Institutions
14 |
15 | Wealthica supports connecting to the following Canadian financial institutions and investment portals. Support for importing positions (holdings), transactions and account statements varies. [Visit our website](https://wealthica.com) for the most recent list of supported institutions.
16 |
17 | ## Getting started
18 |
19 | 1. Login to your [Wealthica](https://app.wealthica.com).
20 | 2. Install the [Developer Add-on](https://app.wealthica.com/addons/details?id=wealthica/wealthica-dev-addon). After that you will be redirected to the Developer Add-on page.
21 | 3. Click on the button next to the page title to open the Configure modal.
22 | 4. Enter https://wealthica.github.io/wealthica.js/example.html to the Add-on URL field and click Load to load the Example Add-on.
23 | 5. Try some of the sample actions provided in the add-on.
24 |
25 | After trying out the Example Add-on, it's time to make your own add-on:
26 |
27 | 1. Clone Example Add-on or create your own add-on page.
28 | 2. From Wealthica navigate to the Developer Add-on and open the Configure modal and load your add-on.
29 | 3. Take a look at the [APIs](#apis) section below and start writing your add-on.
30 |
31 | For a more advanced example, take a look at our [Wealthica Cryptos Addon code](https://github.com/wealthica/wealthica-cryptos-addon).
32 |
33 | ## Installation
34 |
35 | ```
36 | npm install @wealthica/wealthica.js --save
37 | ```
38 |
39 | Then include this in your add-on page:
40 |
41 | ```
42 |
43 | ```
44 |
45 | ## APIs
46 |
47 | ### class: Addon
48 |
49 | The `Addon` class is intended to be used by add-ons to setup their side of communication.
50 |
51 | #### new Addon([options])
52 |
53 | ```
54 | var addon = new Addon({
55 | // (optional) The 'id' of the add-on / widget.
56 | // This is only required in the add-on release preparation process.
57 | // For add-on development with the Developer Add-on, this should not be set.
58 | id: 'addon-id' | 'addon-id/widgets/widget-id'
59 | });
60 | ```
61 |
62 | #### event: 'init'
63 |
64 | Emitted when Wealthica Dashboard has finished setting up the communication on its side. At this time add-on should use the passed-in options (filters, language, etc.) to finalize its rendering.
65 |
66 | ```
67 | addon.on('init', function (options) {
68 | console.log(options);
69 | // {
70 | // fromDate: '2018-01-01',
71 | // toDate: '2018-04-30',
72 | // language: 'en',
73 | // privateMode: false,
74 | // data: { preferredCurrencies: ['USD', 'CAD', 'GBP'] },
75 | // ...
76 | // }
77 | });
78 | ```
79 |
80 | #### event: 'reload'
81 |
82 | Emitted when there are important changes in Wealthica Dashboard (e.g. user has just added a new institution, or removed an asset). This suggests add-ons reload their data and render accordingly.
83 |
84 | ```
85 | addon.on('reload', function () {
86 | // Start reloading
87 | });
88 | ```
89 |
90 | #### event: 'update'
91 |
92 | Emitted when user updates one of the Dashboard filters. The Dashboard provides common filters including groups, institutions or date range filters. In response add-on should update itself according to received options.
93 |
94 | ```
95 | addon.on('update', function (options) {
96 | // Update according to the received options
97 | });
98 | ```
99 |
100 | #### event: 'institution:sync'
101 |
102 | Emitted when Wealthica Dashboard receives a signal that the institution sync is done.
103 |
104 | ```
105 | addon.on('institution:sync', function (institutionId) {
106 | // Update synced institution
107 | });
108 | ```
109 |
110 | #### addon.addTransaction(attrs)
111 |
112 | This method opens the Add Transaction form on the Dashboard and waits for user to submit the transaction or to close the modal. Pass an optional `attrs` object to pre-populate the transaction form. The `newTransaction` parameter is provided when a new transaction has been created.
113 |
114 | ```
115 | addon.addTransaction({ description: "Some description" }).then(function (newTransaction) {
116 | // The form has been closed
117 |
118 | if (newTransaction) {
119 | // A new transaction has been created
120 | } else {
121 | // Nothing changed
122 | }
123 | }).catch(function (err) {
124 |
125 | });
126 | ```
127 |
128 | #### addon.editTransaction(id)
129 |
130 | This method opens the Edit Transaction form on the Dashboard and waits for user to update the transaction or to close the form. The `updatedTransaction` parameter is provided when the transaction has been updated.
131 |
132 | ```
133 | addon.editTransaction('transaction-id').then(function (updatedTransaction) {
134 | // The form has been closed
135 |
136 | if (updatedTransaction) {
137 | // The transaction has been updated
138 | } else {
139 | // Nothing changed
140 | }
141 | }).catch(function (err) {
142 |
143 | });
144 | ```
145 |
146 | #### addon.addInstitution(attrs)
147 |
148 | This method opens the Add Institution form on the Dashboard and waits for user to finish the process or to close the form.
149 |
150 | Pass an optional institution object (`{ type, name }`) to go straight to the institution's credentials form. Otherwise the modal will open at the Select Institution step.
151 |
152 | The `newInstitution` parameter is provided when a new institution has been created.
153 |
154 | ```
155 | addon.addInstitution({ type: 'demo', name: 'Demo' }).then(function (newInstitution) {
156 | // The form has been closed
157 |
158 | if (newInstitution) {
159 | // A new institution has been created
160 | } else {
161 | // Nothing changed
162 | }
163 | }).catch(function (err) {
164 |
165 | });
166 | ```
167 |
168 | #### addon.addInvestment()
169 |
170 | This method opens the Add Investment form on the Dashboard and waits for user to finish the process or to close the form.
171 |
172 | ```
173 | addon.addInvestment().then(function (result) {
174 | // The form has been closed
175 |
176 | if (result) {
177 | // A new institution, asset or liability has been created
178 | } else {
179 | // Nothing changed
180 | }
181 | }).catch(function (err) {
182 |
183 | });
184 | ```
185 |
186 | #### addon.editInstitution(id), addon.editAsset(id) & addon.editLiability(id)
187 |
188 | These methods open the corresponding Edit form (Institution/Asset/Liability) on the Dashboard and wait for user to update the item or to close the form.
189 |
190 | The `updatedItem` parameter is provided when the item has been successfully updated.
191 |
192 | ```
193 | addon.editInstitution('institution-id').then(function (updatedItem) {
194 | // The form has been closed
195 |
196 | if (updatedItem) {
197 | // The item has been updated
198 | } else {
199 | // Nothing changed
200 | }
201 | }).catch(function (err) {
202 |
203 | });
204 | ```
205 |
206 | #### addon.deleteInstitution(id), addon.deleteAsset(id) & addon.deleteLiability(id)
207 |
208 | These methods open the corresponding Delete form (Institution/Asset/Liability) on the Dashboard and wait for user to confirm or to close the form.
209 |
210 | The `deleted` parameter is provided when the item has been successfully deleted.
211 |
212 | ```
213 | addon.deleteInstitution('institution-id').then(function (deleted) {
214 | // The form has been closed
215 |
216 | if (deleted) {
217 | // The item has been deleted
218 | } else {
219 | // Nothing changed
220 | }
221 | }).catch(function (err) {
222 |
223 | });
224 | ```
225 |
226 | #### addon.downloadDocument(id)
227 |
228 | This method triggers download of a Wealthica document
229 |
230 | ```
231 | addon.downloadDocument('document-id').then(function () {
232 | // The action has been successfully carried out.
233 | }).catch(function (err) {
234 |
235 | });
236 | ```
237 |
238 | #### addon.getSharings()
239 |
240 | This method request the list of sharings for the logged in user.
241 |
242 | NOTE: Only available for addons with `"switch_user"` feature flag.
243 |
244 | ```
245 | addon.getSharings().then(function (sharings) {}).catch(function (err) {});
246 | ```
247 |
248 | #### addon.switchUser(id)
249 |
250 | This method switches Dashboard to viewing the user with provided id.
251 |
252 | NOTE: Only available for addons with `"switch_user"` feature flag.
253 |
254 | ```
255 | addon.switchUser(id).then(function () {
256 | // Successfully switched
257 | }).catch(function (err) {});
258 | ```
259 |
260 | #### addon.saveData(data)
261 |
262 | This method allows add-on to persist data to the Wealthica user preferences. You can use this method to persist user configuration options. The add-on will receive this data under the `data` options parameter [the next time it is initialized](#event-init). Each add-on can store up to 100 KB of data (plus 4 KB per widget). Please note data is stored unencrypted in our database and may not be suitable for storing sensitive information.
263 |
264 | ```
265 | addon.saveData({ preferredCurrencies: ['CAD', 'USD', 'GBP', 'MXN'] }).then(function () {
266 |
267 | }).catch(function (err) {
268 |
269 | });
270 | ```
271 |
272 | #### addon.setLoadingStatus(status)
273 | This method sets the loading status, sets the status string - shows the loader, sets an empty string - hides the loader.
274 |
275 | #### addon.printPage()
276 |
277 | This method triggers `window.print()` from dashboard itself.
278 |
279 | #### addon.upgradePremium(plan)
280 |
281 | This method triggers `window.upgradePremium(plan)` popup which suggesting user to upgrade his plan (available options: 'premium' and 'prestige' )
282 |
283 | ### API helpers
284 |
285 | These are helper functions for requesting API calls. See our API docs for the full list of API endpoints, their parameters and what they do.
286 |
287 | For API endpoints that are not yet supported by the API helpers, see [addon.request](#addonrequestoptions) in the Debug section below.
288 |
289 | #### addon.api.getAssets(query)
290 |
291 | ```
292 | addon.api.getAssets({ date: '2018-01-01' })
293 | .then(function (response) { }).catch(function (err) { });
294 | ```
295 |
296 | #### addon.api.getCurrencies(query)
297 |
298 | ```
299 | addon.api.getCurrencies({ from: '2018-01-01', to: '2018-01-31' })
300 | .then(function (response) { }).catch(function (err) { });
301 | ```
302 |
303 | #### addon.api.getInstitutions(query)
304 |
305 | ```
306 | addon.api.getInstitutions({ date: '2018-01-01' })
307 | .then(function (response) { }).catch(function (err) { });
308 | ```
309 |
310 | #### addon.api.getInstitution(id)
311 |
312 | ```
313 | addon.api.getInstitution('institution-id')
314 | .then(function (response) { }).catch(function (err) { });
315 | ```
316 |
317 | #### addon.api.pollInstitution(id, version)
318 |
319 | ```
320 | addon.api.pollInstitution('institution-id', 1)
321 | .then(function (response) { }).catch(function (err) { });
322 | ```
323 |
324 | #### addon.api.syncInstitution(id)
325 |
326 | ```
327 | addon.api.syncInstitution('institution-id')
328 | .then(function (response) { }).catch(function (err) { });
329 | ```
330 |
331 | #### addon.api.addInstitution(data)
332 |
333 | ```
334 | addon.api.addInstitution({
335 | name: 'Demo',
336 | type: 'demo',
337 | credentials: { username: 'wealthica', password: 'wealthica' }
338 | }).then(function (response) { }).catch(function (err) { });
339 | ```
340 |
341 | #### addon.api.getLiabilities(query)
342 |
343 | ```
344 | addon.api.getLiabilities({ date: '2018-01-01' })
345 | .then(function (response) { }).catch(function (err) { });
346 | ```
347 |
348 | #### addon.api.getPositions(query)
349 |
350 | ```
351 | addon.api.getPositions({ groups: 'id1,id2', institutions: 'id1,id2' })
352 | .then(function (response) { }).catch(function (err) { });
353 | ```
354 |
355 | #### addon.api.getTransactions(query)
356 |
357 | ```
358 | addon.api.getTransactions({ groups: 'id1,id2', institutions: 'id1,id2' })
359 | .then(function (response) { }).catch(function (err) { });
360 | ```
361 |
362 | #### addon.api.updateTransaction(id, attrs)
363 |
364 | ```
365 | addon.api.updateTransaction('id', { currency_amount: 123 })
366 | .then(function (response) { }).catch(function (err) { });
367 | ```
368 |
369 | #### addon.api.getUser()
370 |
371 | ```
372 | addon.api.getUser().then(function (response) { }).catch(function (err) { });
373 | ```
374 |
375 | ## Debug
376 |
377 | #### event: 'postMessage'
378 |
379 | Emitted every time the add-on posts a message to the Wealthica Dashboard.
380 |
381 | ```
382 | addon.on('postMessage', function (origin, message) {
383 | console.log(arguments);
384 | });
385 | ```
386 |
387 | Emitted every time the add-on receives a message from the Wealthica Dashboard.
388 |
389 | ```
390 | addon.on('gotMessage', function (origin, message) {
391 | console.log(arguments);
392 | });
393 | ```
394 |
395 | #### addon.request(options)
396 |
397 | This is used to make a request to API endpoints that are not currently supported by `addon.api`.
398 |
399 | ```
400 | addon.request({
401 | method: 'GET',
402 | endpoint: 'positions',
403 | query: {
404 | institutions: 'id1,id2',
405 | assets: true,
406 | }
407 | }).then(function (response) { }).catch(function (err) { });
408 | ```
409 |
410 | #### addon.setEffectiveUser(id)
411 |
412 | This is used make `addon.request()` calls on behalf of another user who has shared access to the currently logged in user. It has the same effect for any of the `addon.api` helpers which are wrappers around `addon.request()`.
413 |
414 | ```
415 | addon.setEffectiveUser(userA);
416 | addon.request({...}).then(function (response) { }).catch(function (err) { });
417 |
418 | addon.setEffectiveUser(userB);
419 | addon.request({...}).then(function (response) { }).catch(function (err) { });
420 |
421 | // It's advised to clear effectiveUser after finishing on-behalf calls
422 | addon.setEffectiveUser(null);
423 | addon.request({...}).then(function (response) { }).catch(function (err) { });
424 | ```
425 |
426 | ## Development
427 |
428 | ### Install
429 |
430 | ```
431 | yarn install
432 | ```
433 |
434 | ### Build
435 |
436 | ```
437 | yarn build
438 | ```
439 |
440 | ### Test
441 |
442 | ```
443 | yarn build
444 | yarn test
445 | ```
446 |
447 | ### Release
448 | ```
449 | npm version patch # or minor/major
450 | git push --tags
451 | # wait until merged then
452 | npm publish
453 | ```
454 |
--------------------------------------------------------------------------------
/dist/addon-container.es5.min.js:
--------------------------------------------------------------------------------
1 | var AddonContainer;!function(){var e={681:function(e){var t=function(){"use strict";var e=Math.floor(1000001*Math.random()),t={};function n(e){return Array.isArray?Array.isArray(e):-1!=e.constructor.toString().indexOf("Array")}var i={},o=function(e){try{var n=JSON.parse(e.data);if("object"!=typeof n||null===n)throw"malformed"}catch(e){return}var o,r,a,s,c;if(window.ReactNativeWebView?(r="*",o=window.ReactNativeWebView):(r=e.origin,o=e.source),"string"==typeof n.method){var u=n.method.split("::");2==u.length?(a=u[0],c=u[1]):(a="",c=n.method)}if(void 0!==n.id&&(s=n.id),"string"==typeof c){var l=!1;if(t[r]&&t[r][a])for(var f=0;f1)throw"scope may not contain double colons: '::'";u=o.scope}var l=function(){for(var e="",t="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",n=0;n<5;n++)e+=t.charAt(Math.floor(Math.random()*t.length));return e}(),f={},d={},m={},h=!1,g=[],p=function(e,t,s){if("function"==typeof o.gotMessageObserver)try{o.gotMessageObserver(e,JSON.parse(JSON.stringify(s)))}catch(e){r("gotMessageObserver() raised an exception: "+e.toString())}if(s.id&&t)if(r("received request: "+t+"() from "+e+" (id: "+s.id+")"),f[t]){var c=function(e,t,n){var i=!1,o=!1,s=function(t){r("transaction("+e+"): "+t)};return{origin:t,invoke:function(t,i){if(o)s("Warning: invoke called after completion");else if(m[e]){for(var r=!1,c=0;c0)for(var u=0;u=0)throw"params cannot be a recursive data structure containing functions";for(var i in s.push(t),t)if(t.hasOwnProperty(i)){var r=t[i],a=e+(e.length?"/":"")+i;"function"==typeof r?(n[a]=r,o.push(a)):"object"==typeof r&&c(a,r)}s.pop()}},u=t.params?JSON.parse(JSON.stringify(t.params)):void 0;c("",t.params);var l,f,m,h=e++,g=v(t.method),y={id:h,method:g,params:u};o.length&&(y.callbacks=o),d[h]={callbacks:n,error:t.error,success:t.success,timeoutId:t.timeout?(l=h,f=t.timeout,m=g,window.setTimeout((function(){if(d[l]){var e="timeout ("+f+"ms) exceeded on method '"+m+"'";r(e+" for transaction "+l);try{"function"==typeof d[l].error&&d[l].error("timeout_error",e)}catch(e){r("Exception executing timeout handler: "+e)}finally{delete d[l],delete i[l]}}}),f)):null},i[h]=p,r("calling method '"+g+"' with id "+h),w(y,a)},notify:function(e){if(!e)throw"missing arguments to notify function";if(!e.method||"string"!=typeof e.method)throw"'method' argument to notify must be string";var t=v(e.method);r("sending notification: "+t);var n=e.params?JSON.parse(JSON.stringify(e.params)):void 0;w({method:t,params:n},a)},destroy:function(){for(var e in r("Destroying channel: "+l),function(e,n,i){if(t[n]&&t[n][i]){for(var o=t[n][i],r=0;r0;)w(g.shift(),!0);if("function"==typeof o.onReady)try{o.onReady(y)}catch(e){r("Exception in onReady callback: "+e)}})),r("Initiating ready handshake (sending ping)"),window.setTimeout((function(){w({method:v("__ready"),params:"ping"},a)}),0),y}}}();e.exports&&(e.exports=t)},669:function(e,t,n){"use strict";var i=u(n(218)),o=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:{};l(this,t);var n=f(this,(t.__proto__||Object.getPrototypeOf(t)).call(this));if(n.options=e,!e.iframe)throw new Error("Iframe not defined");return(0,c.iframeResizer)({checkOrigin:!0,heightCalculationMethod:window.ieVersion<=10?"max":"lowestElement",resizeFrom:"child",resizedCallback:function(e){n.emit("iframeResized",e)}},e.iframe),n.channel=r.default.build({window:e.iframe.contentWindow,origin:e.origin||"*",scope:e.id||e.iframe.contentWindow.location.origin,postMessageObserver:function(e,t){n.emit("postMessage",e,t)},gotMessageObserver:function(e,t){n.emit("gotMessage",e,t)}}),["saveData","request","addTransaction","editTransaction","addInstitution","addInvestment","editInstitution","editAsset","editLiability","deleteInstitution","deleteAsset","deleteLiability","downloadDocument","upgradePremium","getSharings","switchUser","printPage","setLoadingStatus"].forEach((function(e){n.channel.bind(e,(function(t,i){var o=e,r=i;t.delayReturn(!0);var a=function(e,n){return e?t.error(e):t.complete(n)};["setLoadingStatus","upgradePremium"].includes(e)?n.emit(o,void 0!==r?r:a,void 0!==r?a:void 0):n.emit(o,r||a,r?a:void 0)}))})),n.channel.call({method:"init",params:e.options,success:function(e){n.emit("init",e)}}),n}return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}(t,e),o(t,[{key:"trigger",value:function(e,t){var n=this,i={eventName:e};return t&&(i.eventData=t),new s.Promise((function(e,t){n.channel.call({method:"_event",params:i,success:e,error:t})}))}},{key:"update",value:function(e){var t=this;return new s.Promise((function(n,o){if(!(0,i.default)(e))throw new Error("Data must be an object");t.channel.call({method:"update",params:e,success:n,error:o})}))}},{key:"reload",value:function(){var e=this;return new s.Promise((function(t,n){e.channel.call({method:"reload",success:t,error:n})}))}},{key:"destroy",value:function(){this.channel.destroy()}}]),t}(a.default);e.exports=d},702:function(e,t,n){
2 | /*!
3 | * @overview es6-promise - a tiny implementation of Promises/A+.
4 | * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
5 | * @license Licensed under MIT license
6 | * See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
7 | * @version v4.2.8+1e68dce6
8 | */
9 | e.exports=function(){"use strict";function e(e){var t=typeof e;return null!==e&&("object"===t||"function"===t)}function t(e){return"function"==typeof e}var i=Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)},o=0,r=void 0,a=void 0,s=function(e,t){b[o]=e,b[o+1]=t,2===(o+=2)&&(a?a(k):_())};function c(e){a=e}function u(e){s=e}var l="undefined"!=typeof window?window:void 0,f=l||{},d=f.MutationObserver||f.WebKitMutationObserver,m="undefined"==typeof self&&"undefined"!=typeof process&&"[object process]"==={}.toString.call(process),h="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel;function g(){return function(){return process.nextTick(k)}}function p(){return void 0!==r?function(){r(k)}:y()}function v(){var e=0,t=new d(k),n=document.createTextNode("");return t.observe(n,{characterData:!0}),function(){n.data=e=++e%2}}function w(){var e=new MessageChannel;return e.port1.onmessage=k,function(){return e.port2.postMessage(0)}}function y(){var e=setTimeout;return function(){return e(k,1)}}var b=new Array(1e3);function k(){for(var e=0;eL?(a&&(clearTimeout(a),a=null),s=e,r=n.apply(i,o),a||(i=o=null)):a||(a=setTimeout(c,t)),r});$(window,"message",Ee),"loading"!==document.readyState&&window.parent.postMessage("[iFrameResizerChild]Ready","*")}function $(e,t,n){"addEventListener"in window?e.addEventListener(t,n,!1):"attachEvent"in window&&e.attachEvent("on"+t,n)}function ee(e,t,n){"removeEventListener"in window?e.removeEventListener(t,n,!1):"detachEvent"in window&&e.detachEvent("on"+t,n)}function te(e){return e.charAt(0).toUpperCase()+e.slice(1)}function ne(e){return S+"["+N+"] "+e}function ie(e){T&&"object"==typeof window.console&&console.log(ne(e))}function oe(e){"object"==typeof window.console&&console.warn(ne(e))}function re(){var e;!function(){function e(e){return"true"===e}var n=_.substr(I).split(":");N=n[0],f=t!==n[1]?Number(n[1]):f,g=t!==n[2]?e(n[2]):g,T=t!==n[3]?e(n[3]):T,E=t!==n[4]?Number(n[4]):E,u=t!==n[6]?e(n[6]):u,d=n[7],k=t!==n[8]?n[8]:k,l=n[9],h=n[10],P=t!==n[11]?Number(n[11]):P,x.enable=t!==n[12]&&e(n[12]),A=t!==n[13]?n[13]:A,J=t!==n[14]?n[14]:J}(),ie("Initialising iFrame ("+location.href+")"),function(){function e(){var e=window.iFrameResizer;ie("Reading data from page: "+JSON.stringify(e)),D="messageCallback"in e?e.messageCallback:D,B="readyCallback"in e?e.readyCallback:B,z="targetOrigin"in e?e.targetOrigin:z,k="heightCalculationMethod"in e?e.heightCalculationMethod:k,J="widthCalculationMethod"in e?e.widthCalculationMethod:J}function t(e,t){return"function"==typeof e&&(ie("Setup custom "+t+"CalcMethod"),Y[t]=e,e="custom"),e}"iFrameResizer"in window&&Object===window.iFrameResizer.constructor&&(e(),k=t(k,"height"),J=t(J,"width"));ie("TargetOrigin for parent set to: "+z)}(),function(){t===d&&(d=f+"px");ae("margin",function(e,t){-1!==t.indexOf("-")&&(oe("Negative CSS value ignored for "+e),t="");return t}("margin",d))}(),ae("background",l),ae("padding",h),(e=document.createElement("div")).style.clear="both",e.style.display="block",document.body.appendChild(e),le(),fe(),document.documentElement.style.height="",document.body.style.height="",ie('HTML & body height set to "auto"'),ie("Enable public methods"),V.parentIFrame={autoResize:function(e){return!0===e&&!1===u?(u=!0,de()):!1===e&&!0===u&&(u=!1,me()),u},close:function(){xe(0,0,"close"),ie("Disable outgoing messages"),R=!1,ie("Remove event listener: Message"),ee(window,"message",Ee),!0===u&&me()},getId:function(){return N},getPageInfo:function(e){"function"==typeof e?(U=e,xe(0,0,"pageInfo")):(U=function(){},xe(0,0,"pageInfoStop"))},moveToAnchor:function(e){x.findTarget(e)},reset:function(){_e("parentIFrame.reset")},scrollTo:function(e,t){xe(t,e,"scrollTo")},scrollToOffset:function(e,t){xe(t,e,"scrollToOffset")},sendMessage:function(e,t){xe(0,0,"message",JSON.stringify(e),t)},setHeightCalculationMethod:function(e){k=e,le()},setWidthCalculationMethod:function(e){J=e,fe()},setTargetOrigin:function(e){ie("Set targetOrigin: "+e),z=e},size:function(e,t){be("size","parentIFrame.size("+(e||"")+(t?","+t:"")+")",e,t)}},de(),x=function(){function e(){return{x:window.pageXOffset!==t?window.pageXOffset:document.documentElement.scrollLeft,y:window.pageYOffset!==t?window.pageYOffset:document.documentElement.scrollTop}}function n(t){var n=t.getBoundingClientRect(),i=e();return{x:parseInt(n.left,10)+parseInt(i.x,10),y:parseInt(n.top,10)+parseInt(i.y,10)}}function i(e){function i(e){var t=n(e);ie("Moving to in page link (#"+o+") at x: "+t.x+" y: "+t.y),xe(t.y,t.x,"scrollToOffset")}var o=e.split("#")[1]||e,r=decodeURIComponent(o),a=document.getElementById(r)||document.getElementsByName(r)[0];t!==a?i(a):(ie("In page link (#"+o+") not found in iFrame, so sending to parent"),xe(0,0,"inPageLink","#"+o))}function o(){""!==location.hash&&"#"!==location.hash&&i(location.href)}function r(){function e(e){function t(e){e.preventDefault(),i(this.getAttribute("href"))}"#"!==e.getAttribute("href")&&$(e,"click",t)}Array.prototype.forEach.call(document.querySelectorAll('a[href^="#"]'),e)}function a(){$(window,"hashchange",o)}function s(){setTimeout(o,v)}function c(){Array.prototype.forEach&&document.querySelectorAll?(ie("Setting up location.hash handlers"),r(),a(),s()):oe("In page linking not fully supported in this browser! (See README.md for IE8 workaround)")}x.enable?c():ie("In page linking not enabled");return{findTarget:i}}(),be("init","Init message from host page"),B()}function ae(e,n){t!==n&&""!==n&&"null"!==n&&(document.body.style[e]=n,ie("Body "+e+' set to "'+n+'"'))}function se(e){var t={add:function(t){function n(){be(e.eventName,e.eventType)}X[t]=n,$(window,t,n)},remove:function(e){var t=X[e];delete X[e],ee(window,e,t)}};e.eventNames&&Array.prototype.map?(e.eventName=e.eventNames[0],e.eventNames.map(t[e.method])):t[e.method](e.eventName),ie(te(e.method)+" event listener: "+e.eventType)}function ce(e){se({method:e,eventType:"Animation Start",eventNames:["animationstart","webkitAnimationStart"]}),se({method:e,eventType:"Animation Iteration",eventNames:["animationiteration","webkitAnimationIteration"]}),se({method:e,eventType:"Animation End",eventNames:["animationend","webkitAnimationEnd"]}),se({method:e,eventType:"Input",eventName:"input"}),se({method:e,eventType:"Mouse Up",eventName:"mouseup"}),se({method:e,eventType:"Mouse Down",eventName:"mousedown"}),se({method:e,eventType:"Orientation Change",eventName:"orientationchange"}),se({method:e,eventType:"Print",eventName:["afterprint","beforeprint"]}),se({method:e,eventType:"Ready State Change",eventName:"readystatechange"}),se({method:e,eventType:"Touch Start",eventName:"touchstart"}),se({method:e,eventType:"Touch End",eventName:"touchend"}),se({method:e,eventType:"Touch Cancel",eventName:"touchcancel"}),se({method:e,eventType:"Transition Start",eventNames:["transitionstart","webkitTransitionStart","MSTransitionStart","oTransitionStart","otransitionstart"]}),se({method:e,eventType:"Transition Iteration",eventNames:["transitioniteration","webkitTransitionIteration","MSTransitionIteration","oTransitionIteration","otransitioniteration"]}),se({method:e,eventType:"Transition End",eventNames:["transitionend","webkitTransitionEnd","MSTransitionEnd","oTransitionEnd","otransitionend"]}),"child"===A&&se({method:e,eventType:"IFrame Resized",eventName:"resize"})}function ue(e,t,n,i){return t!==e&&(e in n||(oe(e+" is not a valid option for "+i+"CalculationMethod."),e=t),ie(i+' calculation method set to "'+e+'"')),e}function le(){k=ue(k,b,Q,"height")}function fe(){J=ue(J,H,G,"width")}function de(){var e;!0===u?(ce("add"),e=0>E,window.MutationObserver||window.WebKitMutationObserver?e?he():m=function(){function e(e){function t(e){!1===e.complete&&(ie("Attach listeners to "+e.src),e.addEventListener("load",r,!1),e.addEventListener("error",a,!1),u.push(e))}"attributes"===e.type&&"src"===e.attributeName?t(e.target):"childList"===e.type&&Array.prototype.forEach.call(e.target.querySelectorAll("img"),t)}function n(e){u.splice(u.indexOf(e),1)}function i(e){ie("Remove listeners from "+e.src),e.removeEventListener("load",r,!1),e.removeEventListener("error",a,!1),n(e)}function o(e,n,o){i(e.target),be(n,o+": "+e.target.src,t,t)}function r(e){o(e,"imageLoad","Image loaded")}function a(e){o(e,"imageLoadFailed","Image load failed")}function s(t){be("mutationObserver","mutationObserver: "+t[0].target+" "+t[0].type),t.forEach(e)}function c(){var e=document.querySelector("body"),t={attributes:!0,attributeOldValue:!1,characterData:!0,characterDataOldValue:!1,childList:!0,subtree:!0};return f=new l(s),ie("Create body MutationObserver"),f.observe(e,t),f}var u=[],l=window.MutationObserver||window.WebKitMutationObserver,f=c();return{disconnect:function(){"disconnect"in f&&(ie("Disconnect body MutationObserver"),f.disconnect(),u.forEach(i))}}}():(ie("MutationObserver not supported in this browser!"),he())):ie("Auto Resize disabled")}function me(){ce("remove"),null!==m&&m.disconnect(),clearInterval(M)}function he(){0!==E&&(ie("setInterval: "+E+"ms"),M=setInterval((function(){be("interval","setInterval: "+E)}),Math.abs(E)))}function ge(e,t){var n=0;return t=t||document.body,n="defaultView"in document&&"getComputedStyle"in document.defaultView?null!==(n=document.defaultView.getComputedStyle(t,null))?n[e]:0:function(e){if(/^\d+(px)?$/i.test(e))return parseInt(e,10);var n=t.style.left,i=t.runtimeStyle.left;return t.runtimeStyle.left=t.currentStyle.left,t.style.left=e||0,e=t.style.pixelLeft,t.style.left=n,t.runtimeStyle.left=i,e}(t.currentStyle[e]),parseInt(n,10)}function pe(e,t){for(var n=t.length,i=0,o=0,r=te(e),a=K(),s=0;so&&(o=i);return a=K()-a,ie("Parsed "+n+" HTML elements"),ie("Element position calculated in "+a+"ms"),function(e){e>L/2&&ie("Event throttle increased to "+(L=2*e)+"ms")}(a),o}function ve(e){return[e.bodyOffset(),e.bodyScroll(),e.documentElementOffset(),e.documentElementScroll()]}function we(e,t){var n=document.querySelectorAll("["+t+"]");return 0===n.length&&(oe("No tagged elements ("+t+") found on page"),document.querySelectorAll("body *")),pe(e,n)}function ye(){return document.querySelectorAll("body *")}function be(e,t,n,i){j&&e in p?ie("Trigger event cancelled: "+e):(e in{reset:1,resetPage:1,init:1}||ie("Trigger event: "+t),Z(e,t,n,i))}function ke(){j||(j=!0,ie("Trigger event lock on")),clearTimeout(W),W=setTimeout((function(){j=!1,ie("Trigger event lock off"),ie("--")}),v)}function Oe(e){y=Q[k](),q=G[J](),xe(y,q,e)}function _e(e){var t=k;k=b,ie("Reset trigger event: "+e),ke(),Oe("reset"),k=t}function xe(e,n,i,o,r){var a;!0===R&&(t===r?r=z:ie("Message targetOrigin: "+r),ie("Sending message to host page ("+(a=N+":"+e+":"+n+":"+i+(t!==o?":"+o:""))+")"),F.postMessage(S+a,r))}function Ee(t){var n={init:function(){"interactive"===document.readyState||"complete"===document.readyState?(_=t.data,F=t.source,re(),w=!1,setTimeout((function(){O=!1}),v)):(ie("Waiting for page ready"),$(window,"readystatechange",n.initFromParent))},reset:function(){O?ie("Page reset ignored by init"):(ie("Page size reset by host page"),Oe("resetPage"))},resize:function(){be("resizeParent","Parent window requested size check")},moveToAnchor:function(){x.findTarget(o())},inPageLink:function(){this.moveToAnchor()},pageInfo:function(){var e=o();ie("PageInfoFromParent called from parent: "+e),U(JSON.parse(e)),ie(" --")},message:function(){var e=o();ie("MessageCallback called from parent: "+e),D(JSON.parse(e)),ie(" --")}};function i(){return t.data.split("]")[1].split(":")[0]}function o(){return t.data.substr(t.data.indexOf(":")+1)}function r(){return t.data.split(":")[2]in{true:1,false:1}}function a(){var o=i();o in n?n[o]():!e.exports&&"iFrameResize"in window||r()||oe("Unexpected message ("+t.data+")")}S===(""+t.data).substr(0,I)&&(!1===w?a():r()?n.init():ie('Ignored message of type "'+i()+'". Received before initialization.'))}}()},28:function(e,t){var n,i,o;!function(r){"use strict";if("undefined"!=typeof window){var a,s=0,c=!1,u=!1,l="message".length,f="[iFrameSizer]",d=f.length,m=null,h=window.requestAnimationFrame,g={max:1,scroll:1,bodyScroll:1,documentElementScroll:1},p={},v=null,w={autoResize:!0,bodyBackground:null,bodyMargin:null,bodyMarginV1:8,bodyPadding:null,checkOrigin:!0,inPageLinks:!1,enablePublicMethods:!0,heightCalculationMethod:"bodyOffset",id:"iFrameResizer",interval:32,log:!1,maxHeight:1/0,maxWidth:1/0,minHeight:0,minWidth:0,resizeFrom:"parent",scrolling:!1,sizeHeight:!0,sizeWidth:!1,warningTimeout:5e3,tolerance:0,widthCalculationMethod:"scroll",closedCallback:function(){},initCallback:function(){},messageCallback:function(){E("MessageCallback function not defined")},resizedCallback:function(){},scrollCallback:function(){return!0}};window.jQuery&&((a=window.jQuery).fn?a.fn.iFrameResize||(a.fn.iFrameResize=function(e){return this.filter("iframe").each((function(t,n){W(n,e)})).end()}):x("","Unable to bind to jQuery, it is not fully loaded.")),i=[],(o="function"==typeof(n=function(){function e(e,n){n&&(function(){if(!n.tagName)throw new TypeError("Object is not a valid DOM element");if("IFRAME"!==n.tagName.toUpperCase())throw new TypeError("Expected