@quotemedia.com/streamer 2.64.0 → 2.67.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.
@@ -1,7 +1,7 @@
1
1
  <html>
2
2
 
3
3
  <head>
4
- <script src="qmci-streamer-2.64.0.min.js"></script>
4
+ <script src="qmci-streamer-2.67.0.min.js"></script>
5
5
  </head>
6
6
 
7
7
  <body>
@@ -11,9 +11,17 @@
11
11
  * - Configure and creating stream
12
12
  * - Configure and opening connection
13
13
  * - Set up callback to handle messages
14
- * - Subscribe for News Filters
15
- * - Update for News Filters
16
- * - Unsubscribe for the News Filters
14
+ * - Open a News connection (obtain newsClientId)
15
+ * - Subscribe for News Filters with newsClientId
16
+ * - Handle incoming News messages with rich field display
17
+ * - Differentiate News message types (data, filter, error)
18
+ * - Subscribe multiple concurrent filters with different filterIds
19
+ * - Compare skipHeavyInitialLoad true vs false behavior
20
+ * - Query current News Filter status
21
+ * - Update existing News Filters
22
+ * - Unsubscribe from News Filters
23
+ * - Reconnect News with existing newsClientId and verify filter persistence
24
+ * - Subscribe new filter after reconnect and query status
17
25
  * - Close the connection and stream
18
26
  */
19
27
  window.onload = function() {
@@ -23,196 +31,376 @@
23
31
  * Step 1: Configure your login credentials inside the login method to get an SID
24
32
  * Step 2: Open the streaming connection
25
33
  * Step 3: Add the event listeners and the handlers for the messages
26
- * Step 4: Make News Filters subscription
27
- * Step 4: Update News Filters subscription
28
- * Step 5: Make News Filters unsubscribe
29
- * Step 8: Close stream
34
+ * Step 4: Open News connection via openNews() to obtain a newsClientId
35
+ * Step 5: Subscribe to News Filters with the newsClientId (skipHeavyInitialLoad: false)
36
+ * Step 6: Subscribe a second filter sequentially (skipHeavyInitialLoad: true)
37
+ * Step 7: Query current News Filter status
38
+ * Step 8: Update News Filters
39
+ * Step 9: Unsubscribe from News Filter 1 (keep filter 2 active)
40
+ * Step 10: Reconnect News with existing newsClientId, query filter status
41
+ * Step 11: Subscribe new filter after reconnect, query filter status again
42
+ * Step 12: Close stream
30
43
  */
31
44
 
32
- // Log in to get an SID.
33
- // This can be done by directly calling to QuoteMedia's auth service.
34
- Streamer.login({
35
- host: 'https://app.quotemedia.com/auth',
36
- credentials: {
37
- wmid: "YourWebmasterID",
38
- username: "YourUsername",
39
- password: "YourPassword"
40
- }
41
- }, handleResult(function(sid) {
42
- Streamer.open({
45
+ // --- Promise wrappers for callback-based Streamer APIs ---
46
+ function loginAsync(opts) {
47
+ return new Promise((resolve, reject) => {
48
+ Streamer.login(opts, (err, result) => err ? reject(err) : resolve(result));
49
+ });
50
+ }
51
+
52
+ function openAsync(opts) {
53
+ return new Promise((resolve, reject) => {
54
+ Streamer.open(opts, (err, result) => err ? reject(err) : resolve(result));
55
+ });
56
+ }
57
+
58
+ function openNewsAsync(stream, newsClientId) {
59
+ return new Promise((resolve, reject) => {
60
+ stream.openNews(newsClientId, (err, result) => err ? reject(err) : resolve(result));
61
+ });
62
+ }
63
+
64
+ function subscribeNewsAsync(stream, filter, filterId, skipHeavy, newsClientId) {
65
+ return new Promise((resolve, reject) => {
66
+ stream.subscribeNews(filter, filterId, skipHeavy, newsClientId, (err, result) => err ? reject(err) : resolve(result));
67
+ });
68
+ }
69
+
70
+ function fltGetNewsAsync(stream) {
71
+ return new Promise((resolve) => {
72
+ let done = false;
73
+ stream.on("newsRemoteMessage", function(msg) {
74
+ if (!done && msg["@T"] === "C37") {
75
+ done = true;
76
+ // resolve on next tick so the existing newsRemoteMessage handler prints first
77
+ setTimeout(() => resolve(msg), 0);
78
+ }
79
+ });
80
+ stream.fltGetNews((err) => {
81
+ if (err && !done) {
82
+ done = true;
83
+ print("err: " + err, "red");
84
+ resolve();
85
+ }
86
+ });
87
+ });
88
+ }
89
+
90
+ function fltUpdateNewsAsync(stream, filter, filterId) {
91
+ return new Promise((resolve, reject) => {
92
+ stream.fltUpdateNews(filter, filterId, (err, result) => err ? reject(err) : resolve(result));
93
+ });
94
+ }
95
+
96
+ function unsubscribeNewsAsync(stream, filterId) {
97
+ return new Promise((resolve) => {
98
+ let done = false;
99
+ stream.on("filter delete", function(msg) {
100
+ if (!done) {
101
+ done = true;
102
+ resolve(msg);
103
+ }
104
+ });
105
+ stream.unsubscribeNews(filterId, (err) => {
106
+ if (err && !done) {
107
+ done = true;
108
+ print("Failed to unsubscribe News filter: " + err, "red");
109
+ resolve();
110
+ }
111
+ });
112
+ });
113
+ }
114
+
115
+ function closeAsync(stream) {
116
+ return new Promise((resolve, reject) => {
117
+ stream.close((err, result) => err ? reject(err) : resolve(result));
118
+ });
119
+ }
120
+
121
+ // --- Main async flow ---
122
+ run().catch(err => print("Unexpected error: " + err, "red"));
123
+
124
+ async function run() {
125
+ // Step 1: Log in to get an SID
126
+ const sid = await loginAsync({
127
+ host: 'https://app.quotemedia.com/auth',
128
+ credentials: {
129
+ wmid: "YourWebmasterID",
130
+ username: "YourUsername",
131
+ password: "YourPassword"
132
+ }
133
+ });
134
+
135
+ // Step 2: Open the streaming connection
136
+ const stream = await openAsync({
43
137
  host: 'https://app.quotemedia.com/cache',
44
138
  cors: true,
45
139
  rejectExcessiveConnection: false,
46
140
  conflation: null,
47
141
  format: 'application/json',
48
142
  credentials: { sid: sid }
49
- }, handleResult(function(stream) {
50
- // After successfully opening the stream,
51
- // listen for its events.
52
- stream
53
- // The stream will asynchronously callback with
54
- // incoming market data messages.
55
- .on("message", function(message) {
56
- print(msgFmt.fmt(message), "dodgerblue")
57
- })
58
- // It's recommended to attach an error handler
59
- // to help diagnose unexpected errors.
60
- .on("error", function(err) {
61
- print(err, "red");
62
- }).on("close", function(msg) {
63
- print("Closed: " + msg);
64
- // To catch and handling the News messages
65
- }).on("newsRemoteMessage", function(msg) {
66
- print("newsRemoteMessage: " + msgFmt.fmt(msg), "green");
67
- });
143
+ });
68
144
 
145
+ // Step 3: Set up event listeners
146
+ stream
147
+ .on("message", function(message) {
148
+ /**
149
+ * # News Data Message Fields (type "D18").
150
+ *
151
+ * Available fields on the message object:
152
+ * headline, summary, source, sourceId, symbol,
153
+ * storyId, storyUrl, newsUrl, timestamp, epochtime,
154
+ * lang, excode, exgroup, topic, sector,
155
+ * thumbnailUrl, videoUrl, videoImageUrl,
156
+ * vendorDateId, filterId
157
+ */
158
+ if (message["@T"] === "D18") {
159
+ // Display rich News data fields
160
+ print("--- News Article Received ---", "dodgerblue");
161
+ print(" Headline: " + message.headline, "dodgerblue");
162
+ print(" Source: " + message.source + " (" + message.sourceId + ")", "dodgerblue");
163
+ print(" Symbol: " + message.symbol, "dodgerblue");
164
+ print(" Topic: " + message.topic, "dodgerblue");
165
+ print(" Sector: " + message.sector, "dodgerblue");
166
+ print(" Time: " + new Date(message.timestamp).toLocaleString(), "dodgerblue");
167
+ print(" FilterId: " + message.filterId, "dodgerblue");
168
+ if (message.summary) {
169
+ print(" Summary: " + message.summary.substring(0, 200) + "...", "dodgerblue");
170
+ }
171
+ if (message.storyUrl) {
172
+ print(" Story URL: " + message.storyUrl, "dodgerblue");
173
+ }
174
+ if (message.thumbnailUrl) {
175
+ print(" Thumbnail: " + message.thumbnailUrl, "dodgerblue");
176
+ }
177
+ if (message.videoUrl) {
178
+ print(" Video: " + message.videoUrl, "dodgerblue");
179
+ }
180
+ } else {
181
+ print(msgFmt.fmt(message), "dodgerblue");
182
+ }
183
+ })
184
+ .on("error", function(err) {
185
+ print(err, "red");
186
+ }).on("close", function(msg) {
187
+ print("Closed: " + msg);
188
+ })
69
189
  /**
70
- * Supported filter parameters for Streaming News (as of now):
190
+ * # Differentiate News Message Types.
71
191
  *
72
- * @param src Array of news source identifiers (e.g., "djns", "bwi").
73
- * @param topic Array of topic identifiers.
74
- * @param symbol Array of stock symbols.
75
- * @param excode Array of exchange codes.
76
- * @param exgroup Array of exchange group identifiers.
192
+ * The "newsRemoteMessage" event can carry different message types:
193
+ * - "C37" (NEWS_FILTER_MESSAGE): Normal news filter notification
194
+ * - "C38" (NEWS_ERROR_MESSAGE): Error notification with event, code, message fields
195
+ * - "C39" (NEWS_SUCCESS_MESSAGE): Success notification with code, message fields
77
196
  *
78
- * Additional parameters may be supported in future releases.
197
+ * Use the "@T" field to differentiate and handle each type accordingly.
79
198
  */
199
+ .on("newsRemoteMessage", function(msg) {
200
+ switch (msg["@T"]) {
201
+ case "C37": // NEWS_FILTER_MESSAGE
202
+ print("[NEWS FILTER] " + msg.message, "green");
203
+ break;
204
+ case "C38": // NEWS_ERROR_MESSAGE
205
+ print("[NEWS ERROR] Event: " + msg.event + ", Code: " + msg.code + ", Message: " + msg.message, "red");
206
+ break;
207
+ case "C39": // NEWS_SUCCESS_MESSAGE
208
+ print("[NEWS SUCCESS] Code: " + msg.code + ", Message: " + msg.message, "limegreen");
209
+ break;
210
+ default:
211
+ print("newsRemoteMessage: " + msgFmt.fmt(msg), "green");
212
+ break;
213
+ }
214
+ });
80
215
 
81
- /**
82
- * The Below filter will return the News from
83
- * "source" djns OR bwi, and contains
84
- * "topic" computer OR Games and Multimedia, and contains
85
- * "symbol" GOOG AND AAPL, and contains
86
- * "excode" OTO AND NYE, and contains
87
- * "exgroup" DOW AND NSD.
88
- */
89
- const newsFilterExampleJson1 = [
90
- { name: "src", value: ["djns", "bwi"], association: "OR" },
91
- { name: "topic", value: ["Computer", "Games and Multimedia"], association: "OR" },
92
- { name: "symbol", value: ["GOOG", "AAPL"], association: "AND" },
93
- { name: "excode", value: ["OTO", "NYE"], association: "AND" },
94
- { name: "exgroup", value: ["DOW", "NSD"], association: "AND" }
95
- ];
216
+ /**
217
+ * Supported filter parameters for Streaming News:
218
+ *
219
+ * Array filters (use association: "OR" or "AND"):
220
+ * @param src Array of news source identifiers (e.g., "djns", "bwi", "mtn").
221
+ * @param topic Array of topic names (e.g., "Market and Economy").
222
+ * @param sector Array of sector codes (e.g., "101", "103").
223
+ * @param symbol Array of stock symbols (e.g., "AAPL", "GOOG", "^DJT").
224
+ * @param excode Array of exchange codes (e.g., "TSX", "NYE").
225
+ * @param exgroup Array of exchange group identifiers (e.g., "NSD", "DOW").
226
+ * @param keyword Array of keyword strings to match in news content (e.g., "analyst", "sell", "exchange offer").
227
+ *
228
+ * Boolean/value parameters (use association: null):
229
+ * @param summary Boolean. If true, include article summary in the response.
230
+ * @param summlen Number. Maximum length of the summary text (e.g., 100).
231
+ * @param constituent Boolean. If true, include constituent-related news.
232
+ * @param searchByExchange Boolean. If true, search news by exchange.
233
+ */
96
234
 
97
- /**
98
- * The Below filter will return the News from
99
- * "source" djns OR mtn OR bwi, and contains
100
- * "topic" computer OR Games and Multimedia OR Entertainment, and contains
101
- * "symbol" GOOG OR AAPL OR COST, and contains
102
- * "excode" OTO OR NYE, and contains
103
- * "exgroup" DOW OR NSD.
104
- */
105
- const newsFilterExampleJson2 = [
106
- { name: "src", value: ["djns", "mtn", "bwi"], association: "OR" },
107
- { name: "topic", value: ["Computer", "Games and Multimedia", "Entertainment"], association: "OR" },
108
- { name: "symbol", value: ["GOOG", "AAPL", "COST"], association: "OR" },
109
- { name: "excode", value: ["OTO", "NYE"], association: "OR" },
110
- { name: "exgroup", value: ["DOW", "NSD"], association: "OR" }
111
- ];
235
+ /**
236
+ * The Below filter will return the News from
237
+ * "source" bwi OR djns, and contains
238
+ * "topic" Market and Economy, and contains
239
+ * "sector" 101 OR 103, and contains
240
+ * "symbol" AAPL OR GOOG OR ^DJT, and contains
241
+ * "excode" TSX, and contains
242
+ * "exgroup" NSD, and contains
243
+ * "keyword" analyst OR sell OR exchange offer.
244
+ * Additionally, includes summary (max 100 chars),
245
+ * constituent news, and searches by exchange.
246
+ */
247
+ const newsFilterExampleJson1 = [
248
+ { name: "src", value: ["bwi", "djns"], association: "OR" },
249
+ { name: "topic", value: ["Market and Economy"], association: "OR" },
250
+ { name: "sector", value: ["101", "103"], association: "OR" },
251
+ { name: "symbol", value: ["AAPL", "GOOG", "^DJT"], association: "OR" },
252
+ { name: "excode", value: ["TSX"], association: "OR" },
253
+ { name: "exgroup", value: ["NSD"], association: "OR" },
254
+ { name: "keyword", value: ["analyst", "sell", "exchange offer"], association: "OR" },
255
+ { name: "summary", value: true, association: null },
256
+ { name: "summlen", value: 100, association: null },
257
+ { name: "constituent", value: true, association: null },
258
+ { name: "searchByExchange", value: true, association: null }
259
+ ];
112
260
 
113
- const filterId = crypto.randomUUID();
114
- print("News FilterId: " + filterId, "green");
261
+ /**
262
+ * The Below filter will return the News from
263
+ * "source" djns OR mtn OR bwi, and contains
264
+ * "topic" Market and Economy OR Entertainment, and contains
265
+ * "sector" 101, and contains
266
+ * "symbol" GOOG OR AAPL OR COST, and contains
267
+ * "excode" TSX OR NYE, and contains
268
+ * "exgroup" DOW OR NSD, and contains
269
+ * "keyword" earnings OR merger.
270
+ * Additionally, includes summary (max 200 chars).
271
+ */
272
+ const newsFilterExampleJson2 = [
273
+ { name: "src", value: ["djns", "mtn", "bwi"], association: "OR" },
274
+ { name: "topic", value: ["Market and Economy", "Entertainment"], association: "OR" },
275
+ { name: "sector", value: ["101"], association: "OR" },
276
+ { name: "symbol", value: ["GOOG", "AAPL", "COST"], association: "OR" },
277
+ { name: "excode", value: ["TSX", "NYE"], association: "OR" },
278
+ { name: "exgroup", value: ["DOW", "NSD"], association: "OR" },
279
+ { name: "keyword", value: ["earnings", "merger"], association: "OR" },
280
+ { name: "summary", value: true, association: null },
281
+ { name: "summlen", value: 200, association: null }
282
+ ];
115
283
 
116
- /**
117
- * # Subscribe to News Filters.
118
- *
119
- * - News Filters: Should be provided as a JSON object.
120
- * - Filter ID: A UUID that uniquely identifies each News filter.
121
- * - skipHeavyInitialLoad: Optional. Indicates whether to skip initial heavy-load messages. Defaults to false.
122
- */
123
- stream.subscribeNews(newsFilterExampleJson1, filterId, { skipHeavyInitialLoad: false }, (err, result) => {
124
- if (err) {
125
- print("Failed to subscribe News filter", "red")
126
- } else {
127
- print("News Connection opened")
128
- print("SubscribeResponse: " + JSON.stringify(result), "green");
129
-
130
- setTimeout(() => {
131
- print("Get Current Subscription Filter Status")
132
- stream.fltGetNews((err) => {
133
- if (err) {
134
- print("err: " + err, "red")
135
- }
136
- })
137
- }, 2000);
138
-
139
- setTimeout(() => {
140
- print("Update News Filter")
141
- /**
142
- * # Update to News Filters.
143
- *
144
- * - News Filters: Should be provided as a JSON object.
145
- * - Filter ID: A UUID that uniquely identifies each News filter.
146
- * - skipHeavyInitialLoad: Optional. Indicates whether to skip initial heavy-load messages. Defaults to false.
147
- */
148
- stream.fltUpdateNews(newsFilterExampleJson2, filterId, (err, result) => {
149
- if (err) {
150
- print("Failed to update News filter" + err, "red")
151
- } else {
152
- print("News filter updated")
153
- print("Filter Update Response: " + JSON.stringify(result), "green");
154
- }
155
- });
156
- }, 4000)
157
-
158
- setTimeout(() => {
159
- print("Get Current Subscription Filter Status")
160
- stream.fltGetNews((err) => {
161
- if (err) {
162
- print("err: " + err, "red")
163
- }
164
- })
165
- }, 6000);
166
-
167
- setTimeout(() => {
168
- print("Unsubscribe News Filter")
169
- stream.fltDeleteNews(filterId, (err) => {
170
- if (err) {
171
- print("err: " + err, "red")
172
- }
173
- })
174
- }, 8000);
175
-
176
- setTimeout(() => {
177
- print("Get Current Subscription Filter Status")
178
- stream.fltGetNews((err) => {
179
- if (err) {
180
- print("err: " + err, "red")
181
- }
182
- })
183
- }, 10000);
184
- }
284
+ /**
285
+ * A minimal filter targeting only source and symbols,
286
+ * used to demonstrate multiple concurrent filter subscriptions.
287
+ * Not all parameters are required you can use as few as needed.
288
+ */
289
+ const newsFilterExampleJson3 = [
290
+ { name: "src", value: ["djns"], association: "OR" },
291
+ { name: "symbol", value: ["MSFT", "AMZN", "TSLA"], association: "OR" }
292
+ ];
185
293
 
186
- setTimeout(() => {
187
- // Finally, close the stream.
188
- stream.close(handleResult(function() {
189
- print("Connection closed")
190
- }));
191
- }, 12000);
294
+ const filterId1 = crypto.randomUUID();
295
+ const filterId2 = crypto.randomUUID();
296
+ print("News FilterId 1: " + filterId1, null, true);
297
+ print("News FilterId 2: " + filterId2, null, true);
192
298
 
193
- });
299
+ /**
300
+ * # Step 4: Open a News connection.
301
+ *
302
+ * openNews() establishes a News connection and returns a newsClientId.
303
+ * - newsClientId: Can be null for a new connection, or pass an existing
304
+ * newsClientId to reconnect to a previous News session.
305
+ * - The returned newsClientId should be saved for potential reconnection.
306
+ */
307
+ const openResult = await openNewsAsync(stream, null);
308
+ const newsClientId = openResult.newsClientId;
309
+ print("News connection opened, newsClientId: " + newsClientId, "green", true);
194
310
 
195
- }));
311
+ /**
312
+ * # Step 5: Subscribe to the first News Filter.
313
+ *
314
+ * skipHeavyInitialLoad: false
315
+ * - The server will skip sending buffered/initial news data.
316
+ * - Only new incoming news after subscription will be delivered.
317
+ * - Note: Setting this to false will cause the server to send all
318
+ * buffered/initial news data upon subscription, which may significantly
319
+ * increase the subscription response time.
320
+ *
321
+ * skipHeavyInitialLoad: true
322
+ * - The server will skip sending buffered/initial news data.
323
+ * - Only new incoming news after subscription will be delivered.
324
+ * - This reduces initial bandwidth and is recommended when historical data is not needed.
325
+ */
326
+ const subResult1 = await subscribeNewsAsync(stream, newsFilterExampleJson1, filterId1, true, newsClientId);
327
+ print("News filter 1 subscribed (skipHeavyInitialLoad: true)", null, true);
328
+ print("SubscribeResponse 1: " + JSON.stringify(subResult1), "green");
329
+
330
+ /**
331
+ * # Step 6: Subscribe a second filter with a different filterId.
332
+ *
333
+ * Multiple filters can be active simultaneously, each identified by a unique filterId.
334
+ * Each filter operates independently and can be updated or removed separately.
335
+ */
336
+ const subResult2 = await subscribeNewsAsync(stream, newsFilterExampleJson3, filterId2, true, newsClientId);
337
+ print("News filter 2 subscribed (skipHeavyInitialLoad: true)", null, true);
338
+ print("SubscribeResponse 2: " + JSON.stringify(subResult2), "green");
339
+
340
+ // Step 7: Query current News Filter status (should show both filters)
341
+ print("Get Current Subscription Filter Status", null, true);
342
+ await fltGetNewsAsync(stream);
343
+
344
+ // Step 8: Update filter 1 with new criteria
345
+ print("Update News Filter 1", null, true);
346
+ try {
347
+ const updateResult = await fltUpdateNewsAsync(stream, newsFilterExampleJson2, filterId1);
348
+ print("News filter 1 updated", null, true);
349
+ print("Filter Update Response: " + JSON.stringify(updateResult), "green");
350
+ } catch (e) {
351
+ print("Failed to update News filter: " + e, "red", true);
352
+ }
196
353
 
197
- }));
354
+ // Query filter status after update
355
+ print("Get Current Subscription Filter Status", null, true);
356
+ await fltGetNewsAsync(stream);
198
357
 
199
- function print(msg, color) {
358
+ // Step 9: Unsubscribe from filter 1
359
+ print("Unsubscribe News Filter 1", null, true);
360
+ await unsubscribeNewsAsync(stream, filterId1);
361
+ print("News filter 1 unsubscribed", null, true);
362
+
363
+ // Query filter status after unsubscribe (filter 2 should still be active)
364
+ print("Get Current Subscription Filter Status", null, true);
365
+ await fltGetNewsAsync(stream);
366
+
367
+ // Step 10: Demonstrate News reconnection with existing newsClientId
368
+ print("--- Reconnecting News with existing newsClientId ---", "orange", true);
369
+ const reconnectResult = await openNewsAsync(stream, newsClientId);
370
+ print("News reconnected, newsClientId: " + reconnectResult.newsClientId, null, true);
371
+
372
+ // Query filter status after reconnect (filter 2 should still be active)
373
+ print("Get Current Subscription Filter Status", null, true);
374
+ await fltGetNewsAsync(stream);
375
+
376
+ // Subscribe a new filter after reconnect
377
+ const reconnectFilterId = crypto.randomUUID();
378
+ print("Reconnect FilterId: " + reconnectFilterId, "green");
379
+
380
+ const reconnectSubResult = await subscribeNewsAsync(stream, newsFilterExampleJson1, reconnectFilterId, true, reconnectResult.newsClientId);
381
+ print("News filter subscribed after reconnect", null, true);
382
+ print("ReconnectSubscribeResponse: " + JSON.stringify(reconnectSubResult), "green");
383
+
384
+ // Query filter status again (should show filter 2 + new filter)
385
+ print("Get Current Subscription Filter Status", null, true);
386
+ await fltGetNewsAsync(stream);
387
+
388
+ // Step 11: Close stream
389
+ await closeAsync(stream);
390
+ print("Connection closed", null, true);
391
+ }
392
+
393
+ function print(msg, color, bold) {
200
394
  var el = document.createElement("div");
201
395
  el.innerText = msg;
202
396
  if (color) {
203
397
  el.style.color = color;
204
398
  }
205
- document.body.appendChild(el);
206
- }
207
-
208
- function handleResult(onSuccess) {
209
- return function(err, result) {
210
- if (err) {
211
- print(err, "red");
212
- } else {
213
- onSuccess(result);
214
- }
399
+ if (bold) {
400
+ el.style.fontWeight = "bold";
401
+ el.style.fontSize = "1.15em";
215
402
  }
403
+ document.body.appendChild(el);
216
404
  }
217
405
  };
218
406
  </script>
@@ -1,7 +1,7 @@
1
1
  <html>
2
2
 
3
3
  <head>
4
- <script src="qmci-streamer-2.64.0.min.js"></script>
4
+ <script src="qmci-streamer-2.67.0.min.js"></script>
5
5
  </head>
6
6
 
7
7
  <body>
@@ -1,7 +1,7 @@
1
1
  <html>
2
2
 
3
3
  <head>
4
- <script src="qmci-streamer-2.64.0.min.js"></script>
4
+ <script src="qmci-streamer-2.67.0.min.js"></script>
5
5
  </head>
6
6
 
7
7
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quotemedia.com/streamer",
3
- "version": "2.64.0",
3
+ "version": "2.67.0",
4
4
  "description": "A JavaScript client for QuoteMedia's streaming data service.",
5
5
  "main": "lib/index.js",
6
6
  "author": "QuoteMedia",