@barchart/portfolio-client-js 1.1.2
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/README.md +26 -0
- package/example/example.css +124 -0
- package/example/example.html +288 -0
- package/example/example.js +17092 -0
- package/example/example.shim.js +9 -0
- package/gulpfile.js +148 -0
- package/jsdoc.json +8 -0
- package/lib/common/Configuration.js +42 -0
- package/lib/gateway/PortfolioGateway.js +292 -0
- package/lib/gateway/jwt/JwtGateway.js +273 -0
- package/lib/index.js +12 -0
- package/package.json +70 -0
- package/test/SpecRunner.js +1 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
const assert = require('@barchart/common-js/lang/assert'),
|
|
2
|
+
Disposable = require('@barchart/common-js/lang/Disposable'),
|
|
3
|
+
Enum = require('@barchart/common-js/lang/Enum'),
|
|
4
|
+
is = require('@barchart/common-js/lang/is'),
|
|
5
|
+
Scheduler = require('@barchart/common-js/timing/Scheduler');
|
|
6
|
+
|
|
7
|
+
const EndpointBuilder = require('@barchart/common-js/api/http/builders/EndpointBuilder'),
|
|
8
|
+
Endpoint = require('@barchart/common-js/api/http/definitions/Endpoint'),
|
|
9
|
+
FailureReason = require('@barchart/common-js/api/failures/FailureReason'),
|
|
10
|
+
FailureType = require('@barchart/common-js/api/failures/FailureType'),
|
|
11
|
+
Gateway = require('@barchart/common-js/api/http/Gateway'),
|
|
12
|
+
ProtocolType = require('@barchart/common-js/api/http/definitions/ProtocolType'),
|
|
13
|
+
RequestInterceptor = require('@barchart/common-js/api/http/interceptors/RequestInterceptor'),
|
|
14
|
+
ResponseInterceptor = require('@barchart/common-js/api/http/interceptors/ResponseInterceptor'),
|
|
15
|
+
VerbType = require('@barchart/common-js/api/http/definitions/VerbType');
|
|
16
|
+
|
|
17
|
+
const Configuration = require('./../../common/Configuration');
|
|
18
|
+
|
|
19
|
+
module.exports = (() => {
|
|
20
|
+
'use strict';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Web service gateway for translating external JWT tokens into standardized
|
|
24
|
+
* Barchart JWT tokens.
|
|
25
|
+
*
|
|
26
|
+
* @public
|
|
27
|
+
* @param {Endpoint} endpoint
|
|
28
|
+
* @param {Number=} refreshInterval - Interval, in milliseconds, which a token refresh should occur. If zero, the token does not need to be refreshed.
|
|
29
|
+
* @extends {Disposable}
|
|
30
|
+
*/
|
|
31
|
+
class JwtGateway extends Disposable {
|
|
32
|
+
constructor(endpoint, refreshInterval) {
|
|
33
|
+
super();
|
|
34
|
+
|
|
35
|
+
assert.argumentIsRequired(endpoint, 'endpoint', Endpoint, 'Endpoint');
|
|
36
|
+
assert.argumentIsOptional(refreshInterval, 'refreshInterval', Number);
|
|
37
|
+
|
|
38
|
+
this._started = false;
|
|
39
|
+
this._startPromise = null;
|
|
40
|
+
|
|
41
|
+
this._endpoint = endpoint;
|
|
42
|
+
this._refreshInterval = refreshInterval || null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Initializes the connection to the remote server and returns a promise
|
|
47
|
+
* containing the current instance
|
|
48
|
+
*
|
|
49
|
+
* @public
|
|
50
|
+
* @returns {Promise.<JwtGateway>}
|
|
51
|
+
*/
|
|
52
|
+
start() {
|
|
53
|
+
return Promise.resolve()
|
|
54
|
+
.then(() => {
|
|
55
|
+
if (this._startPromise === null) {
|
|
56
|
+
this._startPromise = Promise.resolve()
|
|
57
|
+
.then(() => {
|
|
58
|
+
this._started = true;
|
|
59
|
+
|
|
60
|
+
return this;
|
|
61
|
+
}).catch((e) => {
|
|
62
|
+
this._startPromise = null;
|
|
63
|
+
|
|
64
|
+
return Promise.reject(e);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return this._startPromise;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Retrieves a JWT token from the remote server.
|
|
74
|
+
*
|
|
75
|
+
* @public
|
|
76
|
+
* @returns {Promise.<String>}
|
|
77
|
+
*/
|
|
78
|
+
readToken() {
|
|
79
|
+
return Promise.resolve()
|
|
80
|
+
.then(() => {
|
|
81
|
+
checkStart.call(this);
|
|
82
|
+
|
|
83
|
+
return Gateway.invoke(this._endpoint);
|
|
84
|
+
}).catch((e) => {
|
|
85
|
+
const failure = FailureReason.forRequest({ endpoint: this._endpoint })
|
|
86
|
+
.addItem(FailureType.REQUEST_IDENTITY_FAILURE)
|
|
87
|
+
.format();
|
|
88
|
+
|
|
89
|
+
return Promise.reject(failure);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Returns a {@link RequestInterceptor} suitable for use with other API calls.
|
|
95
|
+
*
|
|
96
|
+
* @public
|
|
97
|
+
* @returns {RequestInterceptor}
|
|
98
|
+
*/
|
|
99
|
+
toRequestInterceptor() {
|
|
100
|
+
const scheduler = new Scheduler();
|
|
101
|
+
|
|
102
|
+
let cachePromise = null;
|
|
103
|
+
let cacheDisposable = null;
|
|
104
|
+
|
|
105
|
+
const refreshToken = () => {
|
|
106
|
+
const refreshPromise = scheduler.backoff(() => this.readToken(), 100, 'Read JWT token', 3)
|
|
107
|
+
.then((token) => {
|
|
108
|
+
if (this._refreshInterval) {
|
|
109
|
+
cachePromise = refreshPromise;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (cacheDisposable === null) {
|
|
113
|
+
cacheDisposable = scheduler.repeat(() => refreshToken(), this._refreshInterval, 'Refresh JWT token');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return token;
|
|
117
|
+
}).catch((e) => {
|
|
118
|
+
if (cacheDisposable !== null) {
|
|
119
|
+
cacheDisposable.dispose();
|
|
120
|
+
|
|
121
|
+
cacheDisposable = null;
|
|
122
|
+
cachePromise = null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return Promise.reject(e);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
return refreshPromise;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const delegate = (options, endpoint) => {
|
|
132
|
+
let tokenPromise;
|
|
133
|
+
|
|
134
|
+
if (cachePromise !== null) {
|
|
135
|
+
tokenPromise = cachePromise;
|
|
136
|
+
} else {
|
|
137
|
+
tokenPromise = refreshToken();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return tokenPromise.then((token) => {
|
|
141
|
+
options.headers = options.headers || { };
|
|
142
|
+
options.headers.Authorization = `Bearer ${token}`;
|
|
143
|
+
|
|
144
|
+
return options;
|
|
145
|
+
}).catch((e) => {
|
|
146
|
+
const failure = FailureReason.forRequest({ endpoint: endpoint })
|
|
147
|
+
.addItem(FailureType.REQUEST_IDENTITY_FAILURE)
|
|
148
|
+
.format();
|
|
149
|
+
|
|
150
|
+
return Promise.reject(failure);
|
|
151
|
+
});
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
return RequestInterceptor.fromDelegate(delegate);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Creates and starts a new {@link JwtGateway} for use in the development environment.
|
|
159
|
+
*
|
|
160
|
+
* @public
|
|
161
|
+
* @static
|
|
162
|
+
* @param {String} userId - The identifier of the user to impersonate.
|
|
163
|
+
* @returns {Promise.<JwtGateway>}
|
|
164
|
+
*/
|
|
165
|
+
static forDevelopment(userId) {
|
|
166
|
+
return start(new JwtGateway(forDevelopment(userId), 60000));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Creates and starts a new {@link RequestInterceptor} for use in the development environment.
|
|
171
|
+
*
|
|
172
|
+
* @public
|
|
173
|
+
* @static
|
|
174
|
+
* @param {String} userId - The identifier of the user to impersonate.
|
|
175
|
+
* @returns {Promise.<RequestInterceptor>}
|
|
176
|
+
*/
|
|
177
|
+
static forDevelopmentClient(userId) {
|
|
178
|
+
return JwtGateway.forDevelopment(userId)
|
|
179
|
+
.then((jwtGateway) => {
|
|
180
|
+
return jwtGateway.toRequestInterceptor();
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Creates and starts a new {@link JwtGateway} for use in the production environment.
|
|
186
|
+
*
|
|
187
|
+
* @public
|
|
188
|
+
* @static
|
|
189
|
+
* @param {RequestInterceptor} externalRequestInterceptor
|
|
190
|
+
* @returns {Promise.<JwtGateway>}
|
|
191
|
+
*/
|
|
192
|
+
static forProduction(externalRequestInterceptor) {
|
|
193
|
+
assert.argumentIsRequired(externalRequestInterceptor, 'externalRequestInterceptor', RequestInterceptor, 'RequestInterceptor');
|
|
194
|
+
|
|
195
|
+
return start(new JwtGateway(forProduction(externalRequestInterceptor), 300000));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Creates and starts a new {@link RequestInterceptor} for use in the development environment.
|
|
200
|
+
*
|
|
201
|
+
* @public
|
|
202
|
+
* @static
|
|
203
|
+
* @param {RequestInterceptor} externalRequestInterceptor
|
|
204
|
+
* @returns {Promise.<RequestInterceptor>}
|
|
205
|
+
*/
|
|
206
|
+
static forProductionClient(externalRequestInterceptor) {
|
|
207
|
+
return JwtGateway.forProduction(externalRequestInterceptor)
|
|
208
|
+
.then((jwtGateway) => {
|
|
209
|
+
return jwtGateway.toRequestInterceptor();
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
_onDispose() {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
toString() {
|
|
218
|
+
return '[JwtGateway]';
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function start(gateway) {
|
|
223
|
+
return gateway.start()
|
|
224
|
+
.then(() => {
|
|
225
|
+
return gateway;
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function checkStart() {
|
|
230
|
+
if (this.getIsDisposed()) {
|
|
231
|
+
throw new Error('Unable to use gateway, the gateway has been disposed.');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (!this._started) {
|
|
235
|
+
throw new Error('Unable to use gateway, the gateway has not started.');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function forDevelopment(userId) {
|
|
240
|
+
return EndpointBuilder.for('read-jwt-token-for-development', 'lookup user identity')
|
|
241
|
+
.withVerb(VerbType.GET)
|
|
242
|
+
.withProtocol(ProtocolType.HTTPS)
|
|
243
|
+
.withHost(Configuration.developmentHost)
|
|
244
|
+
.withPathBuilder((pb) => {
|
|
245
|
+
pb.withLiteralParameter('token', 'token')
|
|
246
|
+
.withLiteralParameter('barchart', 'barchart')
|
|
247
|
+
.withLiteralParameter('generator', 'generator');
|
|
248
|
+
})
|
|
249
|
+
.withQueryBuilder((qb) => {
|
|
250
|
+
qb.withLiteralParameter('user', 'userId', userId)
|
|
251
|
+
.withLiteralParameter('userContext', 'userContext', 'TGAM')
|
|
252
|
+
.withLiteralParameter('userPermissions', 'userPermissions', 'registered');
|
|
253
|
+
})
|
|
254
|
+
.withResponseInterceptor(ResponseInterceptor.DATA)
|
|
255
|
+
.endpoint;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function forProduction(externalRequestInterceptor) {
|
|
259
|
+
return EndpointBuilder.for('translate-jwt-token-for-production', 'lookup Barchart user identity')
|
|
260
|
+
.withVerb(VerbType.GET)
|
|
261
|
+
.withProtocol(ProtocolType.HTTPS)
|
|
262
|
+
.withHost(Configuration.productionHost)
|
|
263
|
+
.withPathBuilder((pb) => pb.withLiteralParameter('token', 'token').withLiteralParameter('system', 'tgam').withLiteralParameter('converter', 'converter'))
|
|
264
|
+
.withRequestInterceptor(externalRequestInterceptor)
|
|
265
|
+
.withResponseInterceptor(ResponseInterceptor.DATA)
|
|
266
|
+
.withResponseInterceptor(ResponseInterceptor.fromDelegate((response) => {
|
|
267
|
+
return response.token;
|
|
268
|
+
}))
|
|
269
|
+
.endpoint;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return JwtGateway;
|
|
273
|
+
})();
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const JwtGateway = require('./gateway/jwt/JwtGateway'),
|
|
2
|
+
PortfolioGateway = require('./gateway/PortfolioGateway');
|
|
3
|
+
|
|
4
|
+
module.exports = (() => {
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
return {
|
|
8
|
+
JwtGateway: JwtGateway,
|
|
9
|
+
PortfolioGateway: PortfolioGateway,
|
|
10
|
+
version: '1.1.2'
|
|
11
|
+
};
|
|
12
|
+
})();
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@barchart/portfolio-client-js",
|
|
3
|
+
"version": "1.1.2",
|
|
4
|
+
"description": "JavaScript library for interfacing with Barchart's Portfolio API",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Bryan Ingle",
|
|
7
|
+
"email": "bryan.ingle@barchart.com",
|
|
8
|
+
"url": "http://www.barchart.com"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: Please use gulp to run tests\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+ssh://git@github.com/barchart/barchart/watchlist-client-js.git"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"Barchart",
|
|
19
|
+
"JavaScript",
|
|
20
|
+
"Client",
|
|
21
|
+
"API"
|
|
22
|
+
],
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@barchart/common-js": "~3.2.0",
|
|
25
|
+
"@barchart/tgam-jwt-js": "~1.0.0",
|
|
26
|
+
"@barchart/portfolio-api-common": "~1.0.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"babel-core": "^6.26.0",
|
|
30
|
+
"babel-preset-es2015": "^6.24.1",
|
|
31
|
+
"babelify": "^8.0.0",
|
|
32
|
+
"browserify": "^14.5.0",
|
|
33
|
+
"git-get-status": "^1.0.5",
|
|
34
|
+
"glob": "^6.0.1",
|
|
35
|
+
"gulp": "~3.9.0",
|
|
36
|
+
"gulp-bump": "~1.0.0",
|
|
37
|
+
"gulp-git": "^2.5.1",
|
|
38
|
+
"gulp-jasmine": "^2.2.1",
|
|
39
|
+
"gulp-jsdoc3": "^1.0.1",
|
|
40
|
+
"gulp-jshint": "~1.11.2",
|
|
41
|
+
"gulp-rename": "^1.2.2",
|
|
42
|
+
"gulp-replace": "^0.5.4",
|
|
43
|
+
"gulp-util": "^3.0.7",
|
|
44
|
+
"jsdoc": "^3.5.5",
|
|
45
|
+
"run-sequence": "~1.1.4",
|
|
46
|
+
"vinyl-buffer": "^1.0.0",
|
|
47
|
+
"vinyl-source-stream": "^1.1.0",
|
|
48
|
+
"vinyl-transform": "^1.0.0"
|
|
49
|
+
},
|
|
50
|
+
"browserify": {
|
|
51
|
+
"transform": [
|
|
52
|
+
[
|
|
53
|
+
"babelify",
|
|
54
|
+
{
|
|
55
|
+
"presets": [
|
|
56
|
+
"es2015"
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
"license": "MIT",
|
|
63
|
+
"bugs": {
|
|
64
|
+
"url": "https://github.com/barchart/watchlist-client-js/issues"
|
|
65
|
+
},
|
|
66
|
+
"homepage": "https://github.com/barchart/watchlist-client-js#readme",
|
|
67
|
+
"directories": {
|
|
68
|
+
"test": "test"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}return e})()({},{},[]);
|