@barchart/portfolio-client-js 10.0.0 → 10.0.1

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/lib/data/.meta.js CHANGED
@@ -240,6 +240,19 @@ const InstrumentType = require('@barchart/portfolio-api-common/lib/data/Instrume
240
240
  * @property {Boolean} replaced - If true, the position (and position summaries) need to be replaced.
241
241
  */
242
242
 
243
+ /**
244
+ * The result of a position mutation operation (like moving, adding, or deleting a position).
245
+ * It contains structured information about what changed in the portfolio(s).
246
+ *
247
+ * @typedef PositionMutateResult
248
+ * @type Object
249
+ * @memberOf Schema
250
+ * @property {Object} positions - The raw lists of saved and deleted positions directly from the API.
251
+ * @property {Schema.Position[]} positions.saved - All positions that were inserted or updated in the database.
252
+ * @property {Schema.Position[]} positions.deleted - All positions that were deleted from the database.
253
+ * @property {Schema.PositionSummary[]} summaries - All position summaries created or updated as a result of the operation.
254
+ */
255
+
243
256
  /**
244
257
  * The symbols (i.e. codes) used to identify an instrument (e.g. "AAPL" for Apple Inc).
245
258
  *
@@ -283,4 +296,95 @@ const InstrumentType = require('@barchart/portfolio-api-common/lib/data/Instrume
283
296
  * @memberOf Schema
284
297
  * @property {Boolean} available - If true, all position and portfolio valuations are up-to-date.
285
298
  * @property {String[]} positions - Array of position identifiers for which are currently being calculated. An empty result indicates all position valuations are up-to-date.
286
- */
299
+ */
300
+
301
+ /**
302
+ * Instructions for connecting to a brokerage via SnapTrade.
303
+ *
304
+ * @ignore
305
+ * @typedef SnapTradeConnectInstructions
306
+ * @type {Object}
307
+ * @memberOf Schema
308
+ * @property {String} uri - The URI for brokerage authentication.
309
+ */
310
+
311
+ /**
312
+ * Data regarding a SnapTrade brokerage.
313
+ *
314
+ * @ignore
315
+ * @typedef SnapTradeBrokerage
316
+ * @type {Object}
317
+ * @memberOf Schema
318
+ * @property {String} id - The SnapTrade identifier for the brokerage.
319
+ * @property {String} name - The name of the brokerage.
320
+ * @property {String} display - The name of the brokerage (for display to a user).
321
+ * @property {String} logo - The URI for the logo image for the brokerage.
322
+ * @property {SnapTradeConnection|null} connection
323
+ * @property {SnapTradeAccount[]} accounts
324
+ */
325
+
326
+ /**
327
+ * Data regarding a connection to a SnapTrade brokerage.
328
+ *
329
+ * @ignore
330
+ * @typedef SnapTradeConnection
331
+ * @type {Object}
332
+ * @memberOf Schema
333
+ * @property {String} id - The SnapTrade identifier for the brokerage connection.
334
+ * @property {Boolean} broken - Indicates if the user needs to authenticate again.
335
+ */
336
+
337
+ /**
338
+ * Data regarding an SnapTrade brokerage account.
339
+ *
340
+ * @ignore
341
+ * @typedef SnapTradeAccount
342
+ * @type {Object}
343
+ * @memberOf Schema
344
+ * @property {String} id - The SnapTrade identifier for the brokerage account.
345
+ * @property {String} number - The brokerage account number (masked).
346
+ * @property {String} name - The brokerage account name.
347
+ * @property {String} type - The brokerage account type.
348
+ * @property {SnapTradeLink|null} link
349
+ */
350
+
351
+ /**
352
+ * Data regarding the linkage SnapTrade account and a portfolio.
353
+ *
354
+ * @ignore
355
+ * @typedef SnapTradeLink
356
+ * @type {Object}
357
+ * @memberOf Schema
358
+ * @property {SnapTradeLinkStatus} status - The status of the link.
359
+ * @property {number} progress - If the status indicates work in progress, this is the percent complete (as a whole number).
360
+ * @property {Timestamp} timestamp - The timestamp of the most recent status update.
361
+ * @property {String=} advice
362
+ */
363
+
364
+ /**
365
+ * Data regarding the status of a link between a SnapTrade account and a portfolio.
366
+ *
367
+ * @ignore
368
+ * @typedef SnapTradeLinkProgress
369
+ * @type {Object}
370
+ * @memberOf Schema
371
+ * @property {String} user
372
+ * @property {String} portfolio
373
+ * @property {String} connection
374
+ * @property {String} account
375
+ * @property {SnapTradeLinkStatus} status
376
+ * @property {number} progress
377
+ */
378
+
379
+ /**
380
+ * Data returned by a linking operation (which could add or remove portfolios).
381
+ *
382
+ * @ignore
383
+ * @typedef SnapTradeLinkingReport
384
+ * @type {Object}
385
+ * @memberOf Schema
386
+ * @property {SnapTradeBrokerage[]} brokerages
387
+ * @property {Object} portfolios
388
+ * @property {Portfolio} portfolios.saved
389
+ * @property {Portfolio} portfolios.deleted
390
+ */
@@ -5,7 +5,8 @@ const array = require('@barchart/common-js/lang/array'),
5
5
  Enum = require('@barchart/common-js/lang/Enum'),
6
6
  Event = require('@barchart/common-js/messaging/Event'),
7
7
  is = require('@barchart/common-js/lang/is'),
8
- promise = require('@barchart/common-js/lang/promise');
8
+ promise = require('@barchart/common-js/lang/promise'),
9
+ Timestamp = require('@barchart/common-js/lang/Timestamp');
9
10
 
10
11
  const TransactionType = require('@barchart/portfolio-api-common/lib/data/TransactionType');
11
12
 
@@ -15,7 +16,8 @@ const BrokerageReportAvailabilitySchema = require('@barchart/portfolio-api-commo
15
16
  PositionSchema = require('@barchart/portfolio-api-common/lib/serialization/PositionSchema'),
16
17
  TransactionSchema = require('@barchart/portfolio-api-common/lib/serialization/TransactionSchema');
17
18
 
18
- const PositionSummaryFrame = require('@barchart/portfolio-api-common/lib/data/PositionSummaryFrame');
19
+ const PositionSummaryFrame = require('@barchart/portfolio-api-common/lib/data/PositionSummaryFrame'),
20
+ SnapTradeLinkStatus = require('@barchart/portfolio-api-common/lib/data/SnapTradeLinkStatus');
19
21
 
20
22
  const EndpointBuilder = require('@barchart/common-js/api/http/builders/EndpointBuilder'),
21
23
  Gateway = require('@barchart/common-js/api/http/Gateway'),
@@ -62,27 +64,27 @@ module.exports = (() => {
62
64
 
63
65
  this._authorizationEvent = new Event(this);
64
66
 
65
- const requestInterceptor = RequestInterceptor.fromDelegate((options, endpoint) => {
66
- return Promise.resolve()
67
- .then(() => {
68
- return this._jwtProvider.getToken()
69
- .then((token) => {
70
- options.headers = options.headers || {};
71
- options.headers.Authorization = `Bearer ${token}`;
67
+ const requestInterceptor = RequestInterceptor.fromDelegate(async (options, endpoint) => {
68
+ let token;
72
69
 
73
- if (is.string(product) && product.length > 0) {
74
- options.headers['X-Barchart-Product'] = product;
75
- }
70
+ try {
71
+ token = await this._jwtProvider.getToken();
72
+ } catch (e) {
73
+ const failure = FailureReason.forRequest({ endpoint: endpoint })
74
+ .addItem(FailureType.REQUEST_IDENTITY_FAILURE)
75
+ .format();
76
76
 
77
- return options;
78
- });
79
- }).catch((e) => {
80
- const failure = FailureReason.forRequest({ endpoint: endpoint })
81
- .addItem(FailureType.REQUEST_IDENTITY_FAILURE)
82
- .format();
77
+ throw failure;
78
+ }
83
79
 
84
- return Promise.reject(failure);
85
- });
80
+ options.headers = options.headers || {};
81
+ options.headers.Authorization = `Bearer ${token}`;
82
+
83
+ if (is.string(product) && product.length > 0) {
84
+ options.headers['X-Barchart-Product'] = product;
85
+ }
86
+
87
+ return options;
86
88
  });
87
89
 
88
90
  const errorInterceptor = ErrorInterceptor.fromDelegate((error, endpoint) => {
@@ -231,6 +233,26 @@ module.exports = (() => {
231
233
  .withErrorInterceptor(errorInterceptor)
232
234
  .endpoint;
233
235
 
236
+ this._movePositionEndpoint = EndpointBuilder.for('move-position', 'move position')
237
+ .withVerb(VerbType.PATCH)
238
+ .withProtocol(protocolType)
239
+ .withHost(host)
240
+ .withPort(port)
241
+ .withPathBuilder((pb) => {
242
+ pb.withLiteralParameter('version', REST_API_VERSION)
243
+ .withLiteralParameter('portfolios', 'portfolios')
244
+ .withVariableParameter('portfolio', 'portfolio', 'portfolio', false)
245
+ .withLiteralParameter('positions', 'positions')
246
+ .withVariableParameter('position', 'position', 'position', false);
247
+ })
248
+ .withQueryBuilder((qb) => {
249
+ qb.withVariableParameter('target', 'target', 'target', false);
250
+ })
251
+ .withRequestInterceptor(requestInterceptor)
252
+ .withResponseInterceptor(responseInterceptorForPositionMutateDeserialization)
253
+ .withErrorInterceptor(errorInterceptor)
254
+ .endpoint;
255
+
234
256
  this._readPositionSummariesEndpoint = EndpointBuilder.for('read-position-summaries', 'read position summaries')
235
257
  .withVerb(VerbType.GET)
236
258
  .withProtocol(protocolType)
@@ -473,6 +495,149 @@ module.exports = (() => {
473
495
  .withErrorInterceptor(errorInterceptor)
474
496
  .endpoint;
475
497
 
498
+ this._readSnapTradeBrokeragesEndpoint = EndpointBuilder.for('query-snaptrade-brokerages', 'query-snaptrade-accounts')
499
+ .withVerb(VerbType.GET)
500
+ .withProtocol(protocolType)
501
+ .withHost(host)
502
+ .withPort(port)
503
+ .withPathBuilder((pb) => {
504
+ pb.withLiteralParameter('version', REST_API_VERSION)
505
+ .withLiteralParameter('snaptrade', 'snaptrade')
506
+ .withLiteralParameter('brokerages', 'brokerages');
507
+ })
508
+ .withRequestInterceptor(requestInterceptor)
509
+ .withResponseInterceptor(responseInterceptorForSnapTradeBrokerages)
510
+ .withErrorInterceptor(errorInterceptor)
511
+ .endpoint;
512
+
513
+ this._connectSnapTradeBrokerEndpoint = EndpointBuilder.for('connect-snaptrade-broker', 'connect-snaptrade-connection')
514
+ .withVerb(VerbType.POST)
515
+ .withProtocol(protocolType)
516
+ .withHost(host)
517
+ .withPort(port)
518
+ .withPathBuilder((pb) => {
519
+ pb.withLiteralParameter('version', REST_API_VERSION)
520
+ .withLiteralParameter('snaptrade', 'snaptrade')
521
+ .withLiteralParameter('connections', 'connections');
522
+ })
523
+ .withQueryBuilder((qb) => {
524
+ qb.withVariableParameter('brokerage', 'brokerage', 'brokerage', true);
525
+ })
526
+ .withRequestInterceptor(requestInterceptor)
527
+ .withResponseInterceptor(ResponseInterceptor.DATA)
528
+ .withErrorInterceptor(errorInterceptor)
529
+ .endpoint;
530
+
531
+ this._reconnectSnapTradeBrokerEndpoint = EndpointBuilder.for('reconnect-snaptrade-broker', 'reconnect-snaptrade-connection')
532
+ .withVerb(VerbType.PUT)
533
+ .withProtocol(protocolType)
534
+ .withHost(host)
535
+ .withPort(port)
536
+ .withPathBuilder((pb) => {
537
+ pb.withLiteralParameter('version', REST_API_VERSION)
538
+ .withLiteralParameter('snaptrade', 'snaptrade')
539
+ .withLiteralParameter('connections', 'connections')
540
+ .withVariableParameter('connection', 'connection', 'connection', false);
541
+ })
542
+ .withRequestInterceptor(requestInterceptor)
543
+ .withResponseInterceptor(ResponseInterceptor.DATA)
544
+ .withErrorInterceptor(errorInterceptor)
545
+ .endpoint;
546
+
547
+ this._disconnectSnapTradeBrokerEndpoint = EndpointBuilder.for('disconnect-snaptrade-broker', 'disconnect-snaptrade-connection')
548
+ .withVerb(VerbType.DELETE)
549
+ .withProtocol(protocolType)
550
+ .withHost(host)
551
+ .withPort(port)
552
+ .withPathBuilder((pb) => {
553
+ pb.withLiteralParameter('version', REST_API_VERSION)
554
+ .withLiteralParameter('snaptrade', 'snaptrade')
555
+ .withLiteralParameter('connections', 'connections')
556
+ .withVariableParameter('connection', 'connection', 'connection', false);
557
+ })
558
+ .withQueryBuilder((qb) => {
559
+ qb.withVariableParameter('remove', 'remove', 'remove', true);
560
+ })
561
+ .withRequestInterceptor(requestInterceptor)
562
+ .withResponseInterceptor(responseInterceptorForSnapTradeAccountLinkResponse)
563
+ .withErrorInterceptor(errorInterceptor)
564
+ .endpoint;
565
+
566
+ this._readSnapTradeAccountLinkEndpoint = EndpointBuilder.for('query-snaptrade-account-link', 'query-snaptrade-account-link')
567
+ .withVerb(VerbType.GET)
568
+ .withProtocol(protocolType)
569
+ .withHost(host)
570
+ .withPort(port)
571
+ .withPathBuilder((pb) => {
572
+ pb.withLiteralParameter('version', REST_API_VERSION)
573
+ .withLiteralParameter('snaptrade', 'snaptrade')
574
+ .withLiteralParameter('connections', 'connections')
575
+ .withVariableParameter('connection', 'connection', 'connection', false)
576
+ .withLiteralParameter('accounts', 'accounts')
577
+ .withVariableParameter('account', 'account', 'account', false);
578
+ })
579
+ .withRequestInterceptor(requestInterceptor)
580
+ .withResponseInterceptor(responseInterceptorForSnapTradeAccountLinkSnapshot)
581
+ .withErrorInterceptor(errorInterceptor)
582
+ .endpoint;
583
+
584
+ this._linkSnapTradeAccountEndpoint = EndpointBuilder.for('link-snaptrade-account', 'link-snaptrade-account')
585
+ .withVerb(VerbType.POST)
586
+ .withProtocol(protocolType)
587
+ .withHost(host)
588
+ .withPort(port)
589
+ .withPathBuilder((pb) => {
590
+ pb.withLiteralParameter('version', REST_API_VERSION)
591
+ .withLiteralParameter('snaptrade', 'snaptrade')
592
+ .withLiteralParameter('connections', 'connections')
593
+ .withVariableParameter('connection', 'connection', 'connection', false)
594
+ .withLiteralParameter('accounts', 'accounts')
595
+ .withVariableParameter('account', 'account', 'account', false);
596
+ })
597
+ .withRequestInterceptor(requestInterceptor)
598
+ .withResponseInterceptor(responseInterceptorForSnapTradeAccountLinkResponse)
599
+ .withErrorInterceptor(errorInterceptor)
600
+ .endpoint;
601
+
602
+ this._unlinkSnapTradeAccountEndpoint = EndpointBuilder.for('unlink-snaptrade-account', 'unlink-snaptrade-account')
603
+ .withVerb(VerbType.DELETE)
604
+ .withProtocol(protocolType)
605
+ .withHost(host)
606
+ .withPort(port)
607
+ .withPathBuilder((pb) => {
608
+ pb.withLiteralParameter('version', REST_API_VERSION)
609
+ .withLiteralParameter('snaptrade', 'snaptrade')
610
+ .withLiteralParameter('connections', 'connections')
611
+ .withVariableParameter('connection', 'connection', 'connection', false)
612
+ .withLiteralParameter('accounts', 'accounts')
613
+ .withVariableParameter('account', 'account', 'account', false);
614
+ })
615
+ .withQueryBuilder((qb) => {
616
+ qb.withVariableParameter('remove', 'remove', 'remove', true);
617
+ })
618
+ .withRequestInterceptor(requestInterceptor)
619
+ .withResponseInterceptor(responseInterceptorForSnapTradeAccountLinkResponse)
620
+ .withErrorInterceptor(errorInterceptor)
621
+ .endpoint;
622
+
623
+ this._refreshSnapTradeAccountEndpoint = EndpointBuilder.for('refresh-snaptrade-account', 'refresh-snaptrade-account')
624
+ .withVerb(VerbType.PUT)
625
+ .withProtocol(protocolType)
626
+ .withHost(host)
627
+ .withPort(port)
628
+ .withPathBuilder((pb) => {
629
+ pb.withLiteralParameter('version', REST_API_VERSION)
630
+ .withLiteralParameter('snaptrade', 'snaptrade')
631
+ .withLiteralParameter('connections', 'connections')
632
+ .withVariableParameter('connection', 'connection', 'connection', false)
633
+ .withLiteralParameter('accounts', 'accounts')
634
+ .withVariableParameter('account', 'account', 'account', false);
635
+ })
636
+ .withRequestInterceptor(requestInterceptor)
637
+ .withResponseInterceptor(responseInterceptorForSnapTradeAccountLinkResponse)
638
+ .withErrorInterceptor(errorInterceptor)
639
+ .endpoint;
640
+
476
641
  this._readVersionEndpoint = EndpointBuilder.for('read-api-version', 'read api version')
477
642
  .withVerb(VerbType.GET)
478
643
  .withProtocol(protocolType)
@@ -518,21 +683,13 @@ module.exports = (() => {
518
683
  assert.argumentIsRequired(jwtProvider, 'jwtProvider', JwtProvider, 'JwtProvider');
519
684
 
520
685
  if (this._startPromise === null) {
521
- this._startPromise = Promise.resolve()
522
- .then(() => {
523
- this._started = true;
524
-
525
- this._jwtProvider = jwtProvider;
686
+ this._startPromise = (async () => {
687
+ this._started = true;
526
688
 
527
- return this;
528
- }).catch((e) => {
529
- this._started = false;
530
- this._startPromise = null;
689
+ this._jwtProvider = jwtProvider;
531
690
 
532
- this._jwtProvider = null;
533
-
534
- throw e;
535
- });
691
+ return this;
692
+ })();
536
693
  }
537
694
 
538
695
  return this._startPromise;
@@ -584,7 +741,7 @@ module.exports = (() => {
584
741
 
585
742
  assert.argumentIsRequired(portfolio, 'portfolio', String);
586
743
 
587
- return Gateway.invoke(this._deletePortfolioEndpoint, { portfolio: portfolio });
744
+ return Gateway.invoke(this._deletePortfolioEndpoint, { portfolio });
588
745
  }
589
746
 
590
747
  /**
@@ -639,6 +796,26 @@ module.exports = (() => {
639
796
  return Gateway.invoke(this._deletePositionEndpoint, { portfolio: portfolio, position: position });
640
797
  }
641
798
 
799
+ /**
800
+ * Moves a position from the current portfolio to a target portfolio.
801
+ *
802
+ * @public
803
+ * @async
804
+ * @param {String} portfolio - The identifier of the source portfolio.
805
+ * @param {String} position - The identifier of the position to move.
806
+ * @param {String} target - The identifier of the destination portfolio.
807
+ * @returns {Promise<Schema.PositionMutateResult>}
808
+ */
809
+ async movePosition(portfolio, position, target) {
810
+ checkStart.call(this);
811
+
812
+ assert.argumentIsRequired(portfolio, 'portfolio', String);
813
+ assert.argumentIsRequired(position, 'position', String);
814
+ assert.argumentIsRequired(target, 'target', String);
815
+
816
+ return Gateway.invoke(this._movePositionEndpoint, { portfolio: portfolio, position: position, target: target });
817
+ }
818
+
642
819
  /**
643
820
  * Retrieves all positions for a user, a user's portfolio, or a single position.
644
821
  *
@@ -707,24 +884,33 @@ module.exports = (() => {
707
884
  assert.argumentIsRequired(position, 'position', String);
708
885
 
709
886
  const scheduleCheck = (delay) => {
710
- setTimeout(() => {
711
- Gateway.invoke(this._readPositionsEndpoint, { portfolio: portfolio, position: position, includePreviousPrice: false })
712
- .then((positions) => {
713
- const p = positions.find(p => p.position === position);
714
-
715
- if (is.object(p)) {
716
- if (is.object(p.system) && is.object(p.system) && is.boolean(p.system.locked) && p.system.locked) {
717
- scheduleCheck(delay + 1000);
718
- } else {
719
- resolveCallback(p);
720
- }
721
- } else {
722
- resolveCallback(null);
723
- }
724
- }).catch((e) => {
725
- scheduleCheck(delay + 5000);
726
- });
727
- }, delay);
887
+ const process = async () => {
888
+ let positions;
889
+
890
+ try {
891
+ positions = await Gateway.invoke(this._readPositionsEndpoint, { portfolio: portfolio, position: position, includePreviousPrice: false });
892
+ } catch (e) {
893
+ scheduleCheck(delay + 5000);
894
+
895
+ return;
896
+ }
897
+
898
+ const p = positions.find(p => p.position === position);
899
+
900
+ if (!is.object(p)) {
901
+ resolveCallback(null);
902
+
903
+ return;
904
+ }
905
+
906
+ if (is.object(p.system) && is.boolean(p.system.locked) && p.system.locked) {
907
+ scheduleCheck(delay + 1000);
908
+ } else {
909
+ resolveCallback(p);
910
+ }
911
+ };
912
+
913
+ setTimeout(process, Math.min(delay, 15000));
728
914
  };
729
915
 
730
916
  scheduleCheck(2500);
@@ -807,7 +993,7 @@ module.exports = (() => {
807
993
  * @public
808
994
  * @async
809
995
  * @ignore
810
- * @param {String} portfolio - The identifier of the portfolio.
996
+ * @param {String=} portfolio - The identifier of the portfolio.
811
997
  * @param {String=} position - The identifier of the position. If omitted, that valuation history will be returned for the entire portfolio (i.e. sum of valuations for all positions contained in the portfolio).
812
998
  * @param {Boolean=} parse - If true, the result will be a {@link Schema.ValuationContainer} object. Otherwise, the result will be a JSON-formatted string.
813
999
  * @returns {Promise<String|Schema.ValuationContainer>}
@@ -815,26 +1001,26 @@ module.exports = (() => {
815
1001
  async readPositionValuations(portfolio, position, parse) {
816
1002
  checkStart.call(this);
817
1003
 
818
- assert.argumentIsRequired(portfolio, 'portfolio', String);
1004
+ assert.argumentIsOptional(portfolio, 'portfolio', String);
819
1005
  assert.argumentIsOptional(position, 'position', String);
820
1006
 
821
1007
  const payload = { };
822
1008
 
823
- payload.portfolio = portfolio;
824
- payload.position = position || '*';
1009
+ payload.portfolio = portfolio || '*';
825
1010
 
826
- return Gateway.invoke(this._readPositionValuationsEndpoint, payload)
827
- .then((json) => {
828
- let result;
1011
+ if (portfolio) {
1012
+ payload.position = position || '*';
1013
+ } else {
1014
+ payload.position = '*';
1015
+ }
829
1016
 
830
- if (parse) {
831
- result = JSON.parse(json);
832
- } else {
833
- result = json;
834
- }
1017
+ const json = await Gateway.invoke(this._readPositionValuationsEndpoint, payload);
835
1018
 
836
- return result;
837
- });
1019
+ if (parse) {
1020
+ return JSON.parse(json);
1021
+ } else {
1022
+ return json;
1023
+ }
838
1024
  }
839
1025
 
840
1026
  /**
@@ -1155,6 +1341,160 @@ module.exports = (() => {
1155
1341
  return this._brokerageReportUrlGenerator(user, portfolio, frame, end);
1156
1342
  }
1157
1343
 
1344
+ /**
1345
+ * Read the list of available SnapTrade brokerages (excluding account information).
1346
+ *
1347
+ * @public
1348
+ * @async
1349
+ * @returns {Promise<Schema.SnapTradeBrokerage[]>}
1350
+ */
1351
+ async readSnapTradeBrokerages() {
1352
+ checkStart.call(this);
1353
+
1354
+ return Gateway.invoke(this._readSnapTradeBrokeragesEndpoint, { });
1355
+ }
1356
+
1357
+ /**
1358
+ * Generates connection instructions for a SnapTrade brokerage.
1359
+ *
1360
+ * @public
1361
+ * @async
1362
+ * @param {String} brokerage - The SnapTrade identifier for the brokerage.
1363
+ * @returns {Promise<Schema.SnapTradeConnectInstructions>}
1364
+ */
1365
+ async connectSnapTradeBrokerage(brokerage) {
1366
+ checkStart.call(this);
1367
+
1368
+ assert.argumentIsRequired(brokerage, 'brokerage', String);
1369
+
1370
+ return Gateway.invoke(this._connectSnapTradeBrokerEndpoint, { brokerage });
1371
+ }
1372
+
1373
+ /**
1374
+ * Generates reconnect instructions for a SnapTrade brokerage.
1375
+ *
1376
+ * @public
1377
+ * @async
1378
+ * @param {String} connection - The SnapTrade identifier for the brokerage connection.
1379
+ * @returns {Promise<Schema.SnapTradeConnectInstructions>}
1380
+ */
1381
+ async reconnectSnapTradeBrokerage(connection) {
1382
+ checkStart.call(this);
1383
+
1384
+ assert.argumentIsRequired(connection, 'connection', String);
1385
+
1386
+ return Gateway.invoke(this._reconnectSnapTradeBrokerEndpoint, { connection });
1387
+ }
1388
+
1389
+ /**
1390
+ * Removes the connection to a SnapTrade brokerage.
1391
+ *
1392
+ * @public
1393
+ * @async
1394
+ * @param {String} connection - The SnapTrade identifier for the brokerage connection.
1395
+ * @param {Boolean=} remove - Causes all linked portfolios to be deleted.
1396
+ * @returns {Promise<SnapTradeLinkingReport>}
1397
+ */
1398
+ async disconnectSnapTradeBrokerage(connection, remove) {
1399
+ checkStart.call(this);
1400
+
1401
+ assert.argumentIsRequired(connection, 'connection', String);
1402
+
1403
+ return Gateway.invoke(this._disconnectSnapTradeBrokerEndpoint, { connection, remove: remove || false });
1404
+ }
1405
+
1406
+ /**
1407
+ * Repeatedly queries the SnapTrade account linking status (until disposed or until
1408
+ * the status reaches 100%).
1409
+ *
1410
+ * @public
1411
+ * @async
1412
+ * @param {String} connection - The SnapTrade identifier for the brokerage connection.
1413
+ * @param {String} account - The SnapTrade identifier for the brokerage account.
1414
+ * @param {SnapTradeLinkStatusCallback} callback
1415
+ * @returns {Disposable}
1416
+ */
1417
+ subscribeSnapTradeAccountLink(connection, account, callback) {
1418
+ checkStart.call(this);
1419
+
1420
+ assert.argumentIsRequired(connection, 'connection', String);
1421
+ assert.argumentIsRequired(account, 'account', String);
1422
+
1423
+ let disposable;
1424
+
1425
+ const poll = async () => {
1426
+ try {
1427
+ const status = await Gateway.invoke(this._readSnapTradeAccountLinkEndpoint, { connection, account });
1428
+
1429
+ if (status && status.progress === 100) {
1430
+ disposable.dispose();
1431
+ }
1432
+
1433
+ callback(status);
1434
+ } catch (e) {
1435
+
1436
+ }
1437
+ };
1438
+
1439
+ const token = setInterval(poll, 2500);
1440
+
1441
+ disposable = Disposable.fromAction(() => {
1442
+ clearInterval(token);
1443
+ });
1444
+
1445
+ return disposable;
1446
+ }
1447
+
1448
+ /**
1449
+ * @public
1450
+ * @async
1451
+ * @param {String} connection - The SnapTrade identifier for the brokerage connection.
1452
+ * @param {String} account - The SnapTrade identifier for the brokerage account.
1453
+ * @returns {Promise<Schema.SnapTradeLinkingReport>}
1454
+ */
1455
+ async linkSnapTradeAccount(connection, account) {
1456
+ checkStart.call(this);
1457
+
1458
+ assert.argumentIsRequired(connection, 'connection', String);
1459
+ assert.argumentIsRequired(account, 'account', String);
1460
+
1461
+ return Gateway.invoke(this._linkSnapTradeAccountEndpoint, { connection, account });
1462
+ }
1463
+
1464
+ /**
1465
+ * @public
1466
+ * @async
1467
+ * @param {String} connection - The SnapTrade identifier for the brokerage connection.
1468
+ * @param {String} account - The SnapTrade identifier for the brokerage account.
1469
+ * @param {Boolean=} remove - Causes the linked portfolio to be deleted.
1470
+ * @returns {Promise<Schema.SnapTradeLinkingReport>}
1471
+ */
1472
+ async unlinkSnapTradeAccount(connection, account, remove) {
1473
+ checkStart.call(this);
1474
+
1475
+ assert.argumentIsRequired(connection, 'connection', String);
1476
+ assert.argumentIsRequired(account, 'account', String);
1477
+ assert.argumentIsOptional(remove, 'remove', Boolean);
1478
+
1479
+ return Gateway.invoke(this._unlinkSnapTradeAccountEndpoint, { connection, account, remove: remove || false });
1480
+ }
1481
+
1482
+ /**
1483
+ * @public
1484
+ * @async
1485
+ * @param {String} connection - The SnapTrade identifier for the brokerage connection.
1486
+ * @param {String} account - The SnapTrade identifier for the brokerage account.
1487
+ * @returns {Promise<Schema.SnapTradeLinkingReport>}
1488
+ */
1489
+ async refreshSnapTradeAccount(connection, account) {
1490
+ checkStart.call(this);
1491
+
1492
+ assert.argumentIsRequired(connection, 'connection', String);
1493
+ assert.argumentIsRequired(account, 'account', String);
1494
+
1495
+ return Gateway.invoke(this._refreshSnapTradeAccountEndpoint, { connection, account });
1496
+ }
1497
+
1158
1498
  /**
1159
1499
  * Returns current version of the Portfolio Service.
1160
1500
  *
@@ -1450,6 +1790,30 @@ module.exports = (() => {
1450
1790
  }
1451
1791
  });
1452
1792
 
1793
+ const responseInterceptorForSnapTradeBrokerages = ResponseInterceptor.fromDelegate((response, ignored) => {
1794
+ try {
1795
+ return deserializeSnapTradeBrokeragesData(response.data);
1796
+ } catch (e) {
1797
+ console.error('Error deserializing snaptrade brokerage data', e);
1798
+ }
1799
+ });
1800
+
1801
+ const responseInterceptorForSnapTradeAccountLinkResponse = ResponseInterceptor.fromDelegate((response, ignored) => {
1802
+ try {
1803
+ return deserializeSnapTradeAccountLinkResponseData(response.data);
1804
+ } catch (e) {
1805
+ console.error('Error deserializing snaptrade account link response data', e);
1806
+ }
1807
+ });
1808
+
1809
+ const responseInterceptorForSnapTradeAccountLinkSnapshot = ResponseInterceptor.fromDelegate((response, ignored) => {
1810
+ try {
1811
+ return deserializeSnapTradeAccountLinkSnapshotData(response.data);
1812
+ } catch (e) {
1813
+ console.error('Error deserializing snaptrade account link snapshot data', e);
1814
+ }
1815
+ });
1816
+
1453
1817
  const responseInterceptorForDeserialization = ResponseInterceptor.fromDelegate((response, ignored) => {
1454
1818
  try {
1455
1819
  return JSON.parse(response.data);
@@ -1487,7 +1851,7 @@ module.exports = (() => {
1487
1851
  const removed = array.differenceBy(deleted, saved, extractInstrumentId);
1488
1852
  const edited = array.differenceBy(array.unionBy(saved, deleted, extractInstrumentId), array.unionBy(created, removed, extractInstrumentId), extractInstrumentId);
1489
1853
 
1490
- const returnRef = {
1854
+ const deserialized = {
1491
1855
  actions: {
1492
1856
  created: created,
1493
1857
  removed: removed,
@@ -1501,11 +1865,56 @@ module.exports = (() => {
1501
1865
  };
1502
1866
 
1503
1867
  if (data.transactions) {
1504
- returnRef.transactions = data.transactions;
1868
+ deserialized.transactions = data.transactions;
1505
1869
  }
1506
1870
 
1507
- return returnRef;
1871
+ return deserialized;
1508
1872
  }
1509
1873
 
1510
- return PortfolioGateway;
1511
- })();
1874
+ function deserializeSnapTradeBrokeragesData(data) {
1875
+ const brokerages = data;
1876
+
1877
+ brokerages.forEach((brokerage) => {
1878
+ const accounts = brokerage.accounts || [ ];
1879
+
1880
+ accounts.forEach((account) => {
1881
+ if (account.link) {
1882
+ account.link.status = SnapTradeLinkStatus.parse(account.link.status);
1883
+ account.link.timestamp = Timestamp.parse(account.link.timestamp);
1884
+ }
1885
+ });
1886
+ });
1887
+
1888
+ return brokerages;
1889
+ }
1890
+
1891
+ function deserializeSnapTradeAccountLinkResponseData(data) {
1892
+ const brokerages = deserializeSnapTradeBrokeragesData(data.brokerages);
1893
+
1894
+ const saved = data.portfolios.saved.map(p => JSON.parse(p, PortfolioSchema.CLIENT.schema.getReviver()));
1895
+ const deleted = data.portfolios.deleted.map(p => JSON.parse(p, PortfolioSchema.CLIENT.schema.getReviver()));
1896
+
1897
+ return { brokerages, portfolios: { saved, deleted } };
1898
+ }
1899
+
1900
+ function deserializeSnapTradeAccountLinkSnapshotData(data) {
1901
+ const status = data;
1902
+
1903
+ if (status) {
1904
+ status.status = SnapTradeLinkStatus.parse(status.status);
1905
+ status.timestamp = Timestamp.parse(status.timestamp);
1906
+ }
1907
+
1908
+ return status;
1909
+ }
1910
+
1911
+ /**
1912
+ * A callback return a {@link SnapTradeLinkStatus}.
1913
+ *
1914
+ * @public
1915
+ * @callback SnapTradeLinkStatusCallback
1916
+ * @param {SnapTradeLinkProgress} status
1917
+ */
1918
+
1919
+ return PortfolioGateway;
1920
+ })();
package/lib/index.js CHANGED
@@ -7,6 +7,6 @@ module.exports = (() => {
7
7
  return {
8
8
  JwtProvider: JwtProvider,
9
9
  PortfolioGateway: PortfolioGateway,
10
- version: '10.0.0'
10
+ version: '10.0.1'
11
11
  };
12
12
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barchart/portfolio-client-js",
3
- "version": "10.0.0",
3
+ "version": "10.0.1",
4
4
  "description": "JavaScript SDK for Barchart's Portfolio Service",
5
5
  "homepage": "https://docs.barchart.com/portfolio/#/",
6
6
  "author": {
@@ -28,8 +28,8 @@
28
28
  "SDK"
29
29
  ],
30
30
  "dependencies": {
31
- "@barchart/common-js": "^4.58.0",
32
- "@barchart/portfolio-api-common": "^7.0.0"
31
+ "@barchart/common-js": "^4.70.0",
32
+ "@barchart/portfolio-api-common": "^7.0.1"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@babel/core": "^7.11.1",