rollbar 2.26.3 → 3.0.0-alpha.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.
Files changed (186) hide show
  1. package/.cursor/rules/guidelines.mdc +154 -0
  2. package/.github/workflows/ci.yml +32 -12
  3. package/.lgtm.yml +7 -7
  4. package/.prettierignore +18 -0
  5. package/.vscode/settings.json +39 -0
  6. package/CHANGELOG.md +121 -35
  7. package/CLAUDE.md +201 -0
  8. package/Gruntfile.js +101 -48
  9. package/Makefile +3 -3
  10. package/README.md +2 -4
  11. package/SECURITY.md +5 -0
  12. package/babel.config.json +9 -0
  13. package/bower.json +1 -3
  14. package/codex.md +148 -0
  15. package/defaults.js +17 -5
  16. package/dist/plugins/jquery.min.js +1 -1
  17. package/dist/rollbar.js +18748 -5375
  18. package/dist/rollbar.js.map +1 -1
  19. package/dist/rollbar.min.js +2 -1
  20. package/dist/rollbar.min.js.LICENSE.txt +1 -0
  21. package/dist/rollbar.min.js.map +1 -1
  22. package/dist/rollbar.named-amd.js +19368 -6000
  23. package/dist/rollbar.named-amd.js.map +1 -1
  24. package/dist/rollbar.named-amd.min.js +3 -1
  25. package/dist/rollbar.named-amd.min.js.LICENSE.txt +1 -0
  26. package/dist/rollbar.named-amd.min.js.map +1 -1
  27. package/dist/rollbar.noconflict.umd.js +18749 -5380
  28. package/dist/rollbar.noconflict.umd.js.map +1 -1
  29. package/dist/rollbar.noconflict.umd.min.js +3 -1
  30. package/dist/rollbar.noconflict.umd.min.js.LICENSE.txt +1 -0
  31. package/dist/rollbar.noconflict.umd.min.js.map +1 -1
  32. package/dist/rollbar.snippet.js +1 -1
  33. package/dist/rollbar.umd.js +19367 -6000
  34. package/dist/rollbar.umd.js.map +1 -1
  35. package/dist/rollbar.umd.min.js +3 -1
  36. package/dist/rollbar.umd.min.js.LICENSE.txt +1 -0
  37. package/dist/rollbar.umd.min.js.map +1 -1
  38. package/docs/extension-exceptions.md +35 -30
  39. package/docs/migration_v0_to_v1.md +41 -38
  40. package/eslint.config.mjs +33 -0
  41. package/get_versions.js +33 -0
  42. package/index.d.ts +270 -231
  43. package/karma.conf.js +18 -27
  44. package/package.json +21 -21
  45. package/prettier.config.js +7 -0
  46. package/src/api.js +78 -14
  47. package/src/apiUtility.js +14 -11
  48. package/src/browser/core.js +138 -72
  49. package/src/browser/defaults/scrubFields.js +3 -3
  50. package/src/browser/detection.js +7 -8
  51. package/src/browser/domUtility.js +18 -8
  52. package/src/browser/globalSetup.js +12 -6
  53. package/src/browser/logger.js +1 -1
  54. package/src/browser/plugins/jquery.js +35 -35
  55. package/src/browser/predicates.js +1 -1
  56. package/src/browser/replay/defaults.js +71 -0
  57. package/src/browser/replay/recorder.js +193 -0
  58. package/src/browser/replay/replayMap.js +195 -0
  59. package/src/browser/rollbar.js +12 -8
  60. package/src/browser/rollbarWrapper.js +8 -5
  61. package/src/browser/shim.js +43 -19
  62. package/src/browser/snippet_callback.js +6 -4
  63. package/src/browser/telemetry.js +573 -361
  64. package/src/browser/transforms.js +46 -27
  65. package/src/browser/transport/fetch.js +26 -14
  66. package/src/browser/transport/xhr.js +41 -14
  67. package/src/browser/transport.js +93 -33
  68. package/src/browser/url.js +16 -8
  69. package/src/browser/wrapGlobals.js +27 -8
  70. package/src/defaults.js +3 -3
  71. package/src/errorParser.js +14 -11
  72. package/src/merge.js +32 -23
  73. package/src/notifier.js +16 -13
  74. package/src/predicates.js +43 -23
  75. package/src/queue.js +133 -40
  76. package/src/rateLimiter.js +59 -18
  77. package/src/react-native/logger.js +1 -1
  78. package/src/react-native/rollbar.js +59 -55
  79. package/src/react-native/transforms.js +13 -9
  80. package/src/react-native/transport.js +44 -34
  81. package/src/rollbar.js +72 -21
  82. package/src/scrub.js +0 -1
  83. package/src/server/locals.js +69 -39
  84. package/src/server/logger.js +4 -4
  85. package/src/server/parser.js +72 -47
  86. package/src/server/rollbar.js +135 -56
  87. package/src/server/sourceMap/stackTrace.js +33 -18
  88. package/src/server/telemetry/urlHelpers.js +9 -11
  89. package/src/server/telemetry.js +68 -45
  90. package/src/server/transforms.js +37 -21
  91. package/src/server/transport.js +62 -32
  92. package/src/telemetry.js +162 -33
  93. package/src/tracing/context.js +24 -0
  94. package/src/tracing/contextManager.js +37 -0
  95. package/src/tracing/defaults.js +7 -0
  96. package/src/tracing/exporter.js +188 -0
  97. package/src/tracing/hrtime.js +98 -0
  98. package/src/tracing/id.js +24 -0
  99. package/src/tracing/session.js +55 -0
  100. package/src/tracing/span.js +92 -0
  101. package/src/tracing/spanProcessor.js +15 -0
  102. package/src/tracing/tracer.js +46 -0
  103. package/src/tracing/tracing.js +89 -0
  104. package/src/transforms.js +33 -21
  105. package/src/truncation.js +8 -5
  106. package/src/utility/headers.js +43 -43
  107. package/src/utility/replace.js +9 -0
  108. package/src/utility/traverse.js +1 -1
  109. package/src/utility.js +123 -52
  110. package/test/api.test.js +88 -41
  111. package/test/apiUtility.test.js +48 -50
  112. package/test/browser.core.test.js +142 -141
  113. package/test/browser.domUtility.test.js +53 -36
  114. package/test/browser.predicates.test.js +14 -14
  115. package/test/browser.replay.recorder.test.js +416 -0
  116. package/test/browser.rollbar.test.js +655 -515
  117. package/test/browser.telemetry.test.js +46 -39
  118. package/test/browser.transforms.test.js +164 -139
  119. package/test/browser.transport.test.js +59 -50
  120. package/test/browser.url.test.js +13 -12
  121. package/test/fixtures/locals.fixtures.js +245 -126
  122. package/test/fixtures/replay/index.js +20 -0
  123. package/test/fixtures/replay/payloads.fixtures.js +229 -0
  124. package/test/fixtures/replay/rrwebEvents.fixtures.js +251 -0
  125. package/test/fixtures/replay/rrwebSyntheticEvents.fixtures.js +328 -0
  126. package/test/notifier.test.js +91 -79
  127. package/test/predicates.test.js +261 -215
  128. package/test/queue.test.js +231 -215
  129. package/test/rateLimiter.test.js +51 -43
  130. package/test/react-native.rollbar.test.js +150 -116
  131. package/test/react-native.transforms.test.js +23 -25
  132. package/test/react-native.transport.test.js +26 -14
  133. package/test/replay/index.js +2 -0
  134. package/test/replay/integration/api.spans.test.js +136 -0
  135. package/test/replay/integration/e2e.test.js +228 -0
  136. package/test/replay/integration/index.js +9 -0
  137. package/test/replay/integration/queue.replayMap.test.js +332 -0
  138. package/test/replay/integration/replayMap.test.js +163 -0
  139. package/test/replay/integration/sessionRecording.test.js +390 -0
  140. package/test/replay/unit/api.postSpans.test.js +150 -0
  141. package/test/replay/unit/index.js +7 -0
  142. package/test/replay/unit/queue.replayMap.test.js +225 -0
  143. package/test/replay/unit/replayMap.test.js +348 -0
  144. package/test/replay/util/index.js +5 -0
  145. package/test/replay/util/mockRecordFn.js +80 -0
  146. package/test/server.lambda.mocha.test.mjs +172 -0
  147. package/test/server.locals.constructor.mocha.test.mjs +80 -0
  148. package/test/server.locals.error-handling.mocha.test.mjs +387 -0
  149. package/test/server.locals.merge.mocha.test.mjs +267 -0
  150. package/test/server.locals.test-utils.mjs +114 -0
  151. package/test/server.parser.mocha.test.mjs +87 -0
  152. package/test/server.predicates.mocha.test.mjs +63 -0
  153. package/test/server.rollbar.constructor.mocha.test.mjs +199 -0
  154. package/test/server.rollbar.handlers.mocha.test.mjs +253 -0
  155. package/test/server.rollbar.logging.mocha.test.mjs +326 -0
  156. package/test/server.rollbar.misc.mocha.test.mjs +44 -0
  157. package/test/server.rollbar.test-utils.mjs +57 -0
  158. package/test/server.telemetry.mocha.test.mjs +377 -0
  159. package/test/server.transforms.data.mocha.test.mjs +163 -0
  160. package/test/server.transforms.error.mocha.test.mjs +199 -0
  161. package/test/server.transforms.request.mocha.test.mjs +208 -0
  162. package/test/server.transforms.scrub.mocha.test.mjs +140 -0
  163. package/test/server.transforms.sourcemaps.mocha.test.mjs +122 -0
  164. package/test/server.transforms.test-utils.mjs +62 -0
  165. package/test/server.transport.mocha.test.mjs +269 -0
  166. package/test/telemetry.test.js +178 -38
  167. package/test/tracing/contextManager.test.js +28 -0
  168. package/test/tracing/exporter.toPayload.test.js +400 -0
  169. package/test/tracing/id.test.js +24 -0
  170. package/test/tracing/span.test.js +183 -0
  171. package/test/tracing/spanProcessor.test.js +73 -0
  172. package/test/tracing/tracing.test.js +105 -0
  173. package/test/transforms.test.js +70 -68
  174. package/test/truncation.test.js +57 -55
  175. package/test/utility.test.js +310 -228
  176. package/webpack.config.js +36 -70
  177. package/.eslintignore +0 -7
  178. package/.gitmodules +0 -3
  179. package/test/server.lambda.test.js +0 -177
  180. package/test/server.locals.test.js +0 -841
  181. package/test/server.parser.test.js +0 -72
  182. package/test/server.predicates.test.js +0 -89
  183. package/test/server.rollbar.test.js +0 -676
  184. package/test/server.telemetry.test.js +0 -318
  185. package/test/server.transforms.test.js +0 -1099
  186. package/test/server.transport.test.js +0 -201
package/src/utility.js CHANGED
@@ -8,14 +8,15 @@ function setupJSON(polyfillJSON) {
8
8
 
9
9
  if (isDefined(JSON)) {
10
10
  // If polyfill is provided, prefer it over existing non-native shims.
11
- if(polyfillJSON) {
11
+ if (polyfillJSON) {
12
12
  if (isNativeFunction(JSON.stringify)) {
13
13
  RollbarJSON.stringify = JSON.stringify;
14
14
  }
15
15
  if (isNativeFunction(JSON.parse)) {
16
16
  RollbarJSON.parse = JSON.parse;
17
17
  }
18
- } else { // else accept any interface that is present.
18
+ } else {
19
+ // else accept any interface that is present.
19
20
  if (isFunction(JSON.stringify)) {
20
21
  RollbarJSON.stringify = JSON.stringify;
21
22
  }
@@ -65,7 +66,10 @@ function typeName(x) {
65
66
  if (x instanceof Error) {
66
67
  return 'error';
67
68
  }
68
- return ({}).toString.call(x).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
69
+ return {}.toString
70
+ .call(x)
71
+ .match(/\s([a-zA-Z]+)/)[1]
72
+ .toLowerCase();
69
73
  }
70
74
 
71
75
  /* isFunction - a convenience function for checking if a value is a function
@@ -84,7 +88,8 @@ function isFunction(f) {
84
88
  */
85
89
  function isNativeFunction(f) {
86
90
  var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
87
- var funcMatchString = Function.prototype.toString.call(Object.prototype.hasOwnProperty)
91
+ var funcMatchString = Function.prototype.toString
92
+ .call(Object.prototype.hasOwnProperty)
88
93
  .replace(reRegExpChar, '\\$&')
89
94
  .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?');
90
95
  var reIsNative = RegExp('^' + funcMatchString + '$');
@@ -95,7 +100,7 @@ function isNativeFunction(f) {
95
100
  *
96
101
  * @param value - any value
97
102
  * @returns true is value is an object function is an object)
98
- */
103
+ */
99
104
  function isObject(value) {
100
105
  var type = typeof value;
101
106
  return value != null && (type == 'object' || type == 'function');
@@ -105,9 +110,9 @@ function isObject(value) {
105
110
  *
106
111
  * @param value - any value
107
112
  * @returns true if value is a string
108
- */
113
+ */
109
114
  function isString(value) {
110
- return typeof value === 'string' || value instanceof String
115
+ return typeof value === 'string' || value instanceof String;
111
116
  }
112
117
 
113
118
  /**
@@ -116,7 +121,7 @@ function isString(value) {
116
121
  * @param {*} n - any value
117
122
  * @returns true if value is a finite number
118
123
  */
119
- function isFiniteNumber(n) {
124
+ function isFiniteNumber(n) {
120
125
  return Number.isFinite(n);
121
126
  }
122
127
 
@@ -139,7 +144,7 @@ function isDefined(u) {
139
144
  */
140
145
  function isIterable(i) {
141
146
  var type = typeName(i);
142
- return (type === 'object' || type === 'array');
147
+ return type === 'object' || type === 'array';
143
148
  }
144
149
 
145
150
  /*
@@ -162,6 +167,15 @@ function isPromise(p) {
162
167
  return isObject(p) && isType(p.then, 'function');
163
168
  }
164
169
 
170
+ /**
171
+ * isBrowser - a convenience function for checking if the code is running in a browser
172
+ *
173
+ * @returns true if the code is running in a browser environment
174
+ */
175
+ function isBrowser() {
176
+ return typeof window !== 'undefined';
177
+ }
178
+
165
179
  function redact() {
166
180
  return '********';
167
181
  }
@@ -169,11 +183,14 @@ function redact() {
169
183
  // from http://stackoverflow.com/a/8809472/1138191
170
184
  function uuid4() {
171
185
  var d = now();
172
- var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
173
- var r = (d + Math.random() * 16) % 16 | 0;
174
- d = Math.floor(d / 16);
175
- return (c === 'x' ? r : (r & 0x7 | 0x8)).toString(16);
176
- });
186
+ var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
187
+ /[xy]/g,
188
+ function (c) {
189
+ var r = (d + Math.random() * 16) % 16 | 0;
190
+ d = Math.floor(d / 16);
191
+ return (c === 'x' ? r : (r & 0x7) | 0x8).toString(16);
192
+ },
193
+ );
177
194
  return uuid;
178
195
  }
179
196
 
@@ -182,7 +199,7 @@ var LEVELS = {
182
199
  info: 1,
183
200
  warning: 2,
184
201
  error: 3,
185
- critical: 4
202
+ critical: 4,
186
203
  };
187
204
 
188
205
  function sanitizeUrl(url) {
@@ -216,16 +233,18 @@ var parseUriOptions = {
216
233
  'directory',
217
234
  'file',
218
235
  'query',
219
- 'anchor'
236
+ 'anchor',
220
237
  ],
221
238
  q: {
222
239
  name: 'queryKey',
223
- parser: /(?:^|&)([^&=]*)=?([^&]*)/g
240
+ parser: /(?:^|&)([^&=]*)=?([^&]*)/g,
224
241
  },
225
242
  parser: {
226
- strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
227
- loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
228
- }
243
+ strict:
244
+ /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
245
+ loose:
246
+ /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/,
247
+ },
229
248
  };
230
249
 
231
250
  function parseUri(str) {
@@ -270,11 +289,11 @@ function addParamsAndAccessTokenToPath(accessToken, options, params) {
270
289
  var p;
271
290
  if (qs !== -1 && (h === -1 || h > qs)) {
272
291
  p = options.path;
273
- options.path = p.substring(0,qs) + query + '&' + p.substring(qs+1);
292
+ options.path = p.substring(0, qs) + query + '&' + p.substring(qs + 1);
274
293
  } else {
275
294
  if (h !== -1) {
276
295
  p = options.path;
277
- options.path = p.substring(0,h) + query + p.substring(h);
296
+ options.path = p.substring(0, h) + query + p.substring(h);
278
297
  } else {
279
298
  options.path = options.path + query;
280
299
  }
@@ -320,7 +339,7 @@ function stringify(obj, backup) {
320
339
  error = jsonError;
321
340
  }
322
341
  }
323
- return {error: error, value: value};
342
+ return { error: error, value: value };
324
343
  }
325
344
 
326
345
  function maxByteSize(string) {
@@ -338,11 +357,14 @@ function maxByteSize(string) {
338
357
 
339
358
  for (var i = 0; i < length; i++) {
340
359
  var code = string.charCodeAt(i);
341
- if (code < 128) { // up to 7 bits
360
+ if (code < 128) {
361
+ // up to 7 bits
342
362
  count = count + 1;
343
- } else if (code < 2048) { // up to 11 bits
363
+ } else if (code < 2048) {
364
+ // up to 11 bits
344
365
  count = count + 2;
345
- } else if (code < 65536) { // up to 16 bits
366
+ } else if (code < 65536) {
367
+ // up to 16 bits
346
368
  count = count + 3;
347
369
  }
348
370
  }
@@ -357,7 +379,7 @@ function jsonParse(s) {
357
379
  } catch (e) {
358
380
  error = e;
359
381
  }
360
- return {error: error, value: value};
382
+ return { error: error, value: value };
361
383
  }
362
384
 
363
385
  function makeUnhandledStackInfo(
@@ -368,28 +390,36 @@ function makeUnhandledStackInfo(
368
390
  error,
369
391
  mode,
370
392
  backupMessage,
371
- errorParser
393
+ errorParser,
372
394
  ) {
373
395
  var location = {
374
396
  url: url || '',
375
397
  line: lineno,
376
- column: colno
398
+ column: colno,
377
399
  };
378
400
  location.func = errorParser.guessFunctionName(location.url, location.line);
379
401
  location.context = errorParser.gatherContext(location.url, location.line);
380
- var href = typeof document !== 'undefined' && document && document.location && document.location.href;
381
- var useragent = typeof window !== 'undefined' && window && window.navigator && window.navigator.userAgent;
402
+ var href =
403
+ typeof document !== 'undefined' &&
404
+ document &&
405
+ document.location &&
406
+ document.location.href;
407
+ var useragent =
408
+ typeof window !== 'undefined' &&
409
+ window &&
410
+ window.navigator &&
411
+ window.navigator.userAgent;
382
412
  return {
383
- 'mode': mode,
384
- 'message': error ? String(error) : (message || backupMessage),
385
- 'url': href,
386
- 'stack': [location],
387
- 'useragent': useragent
413
+ mode: mode,
414
+ message: error ? String(error) : message || backupMessage,
415
+ url: href,
416
+ stack: [location],
417
+ useragent: useragent,
388
418
  };
389
419
  }
390
420
 
391
421
  function wrapCallback(logger, f) {
392
- return function(err, resp) {
422
+ return function (err, resp) {
393
423
  try {
394
424
  f(err, resp);
395
425
  } catch (e) {
@@ -402,7 +432,10 @@ function nonCircularClone(obj) {
402
432
  var seen = [obj];
403
433
 
404
434
  function clone(obj, seen) {
405
- var value, name, newSeen, result = {};
435
+ var value,
436
+ name,
437
+ newSeen,
438
+ result = {};
406
439
 
407
440
  try {
408
441
  for (name in obj) {
@@ -445,7 +478,7 @@ function createItem(args, logger, notifier, requestKeys, lambdaContext) {
445
478
  case 'undefined':
446
479
  break;
447
480
  case 'string':
448
- message ? extraArgs.push(arg) : message = arg;
481
+ message ? extraArgs.push(arg) : (message = arg);
449
482
  break;
450
483
  case 'function':
451
484
  callback = wrapCallback(logger, arg);
@@ -456,12 +489,15 @@ function createItem(args, logger, notifier, requestKeys, lambdaContext) {
456
489
  case 'error':
457
490
  case 'domexception':
458
491
  case 'exception': // Firefox Exception type
459
- err ? extraArgs.push(arg) : err = arg;
492
+ err ? extraArgs.push(arg) : (err = arg);
460
493
  break;
461
494
  case 'object':
462
495
  case 'array':
463
- if (arg instanceof Error || (typeof DOMException !== 'undefined' && arg instanceof DOMException)) {
464
- err ? extraArgs.push(arg) : err = arg;
496
+ if (
497
+ arg instanceof Error ||
498
+ (typeof DOMException !== 'undefined' && arg instanceof DOMException)
499
+ ) {
500
+ err ? extraArgs.push(arg) : (err = arg);
465
501
  break;
466
502
  }
467
503
  if (requestKeys && typ === 'object' && !request) {
@@ -475,11 +511,14 @@ function createItem(args, logger, notifier, requestKeys, lambdaContext) {
475
511
  break;
476
512
  }
477
513
  }
478
- custom ? extraArgs.push(arg) : custom = arg;
514
+ custom ? extraArgs.push(arg) : (custom = arg);
479
515
  break;
480
516
  default:
481
- if (arg instanceof Error || (typeof DOMException !== 'undefined' && arg instanceof DOMException)) {
482
- err ? extraArgs.push(arg) : err = arg;
517
+ if (
518
+ arg instanceof Error ||
519
+ (typeof DOMException !== 'undefined' && arg instanceof DOMException)
520
+ ) {
521
+ err ? extraArgs.push(arg) : (err = arg);
483
522
  break;
484
523
  }
485
524
  extraArgs.push(arg);
@@ -502,9 +541,11 @@ function createItem(args, logger, notifier, requestKeys, lambdaContext) {
502
541
  callback: callback,
503
542
  notifier: notifier,
504
543
  diagnostic: diagnostic,
505
- uuid: uuid4()
544
+ uuid: uuid4(),
506
545
  };
507
546
 
547
+ item.data = item.data || {};
548
+
508
549
  setCustomItemKeys(item, custom);
509
550
 
510
551
  if (requestKeys && request) {
@@ -550,7 +591,14 @@ function addErrorContext(item, errors) {
550
591
  }
551
592
  }
552
593
 
553
- var TELEMETRY_TYPES = ['log', 'network', 'dom', 'navigation', 'error', 'manual'];
594
+ var TELEMETRY_TYPES = [
595
+ 'log',
596
+ 'network',
597
+ 'dom',
598
+ 'navigation',
599
+ 'error',
600
+ 'manual',
601
+ ];
554
602
  var TELEMETRY_LEVELS = ['critical', 'error', 'warning', 'info', 'debug'];
555
603
 
556
604
  function arrayIncludes(arr, val) {
@@ -589,12 +637,32 @@ function createTelemetryEvent(args) {
589
637
  var event = {
590
638
  type: type || 'manual',
591
639
  metadata: metadata || {},
592
- level: level
640
+ level: level,
593
641
  };
594
642
 
595
643
  return event;
596
644
  }
597
645
 
646
+ function addItemAttributes(itemData, attributes) {
647
+ itemData.attributes = itemData.attributes || [];
648
+ for (const a of attributes) {
649
+ if (a.value === undefined) {
650
+ continue;
651
+ }
652
+ itemData.attributes.push(a);
653
+ }
654
+ }
655
+
656
+ function getItemAttribute(itemData, key) {
657
+ const attributes = itemData.attributes || [];
658
+ for (let i = 0; i < attributes.length; ++i) {
659
+ if (attributes[i].key === key) {
660
+ return attributes[i].value;
661
+ }
662
+ }
663
+ return undefined;
664
+ }
665
+
598
666
  /*
599
667
  * get - given an obj/array and a keypath, return the value at that keypath or
600
668
  * undefined if not possible.
@@ -639,7 +707,7 @@ function set(obj, path, value) {
639
707
  temp[keys[i]] = temp[keys[i]] || {};
640
708
  temp = temp[keys[i]];
641
709
  }
642
- temp[keys[len-1]] = value;
710
+ temp[keys[len - 1]] = value;
643
711
  obj[keys[0]] = replacement;
644
712
  } catch (e) {
645
713
  return;
@@ -730,12 +798,12 @@ function handleOptions(current, input, payload, logger) {
730
798
  }
731
799
 
732
800
  function updateDeprecatedOptions(options, logger) {
733
- if(options.hostWhiteList && !options.hostSafeList) {
801
+ if (options.hostWhiteList && !options.hostSafeList) {
734
802
  options.hostSafeList = options.hostWhiteList;
735
803
  options.hostWhiteList = undefined;
736
804
  logger && logger.log('hostWhiteList is deprecated. Use hostSafeList.');
737
805
  }
738
- if(options.hostBlackList && !options.hostBlockList) {
806
+ if (options.hostBlackList && !options.hostBlockList) {
739
807
  options.hostBlockList = options.hostBlackList;
740
808
  options.hostBlackList = undefined;
741
809
  logger && logger.log('hostBlackList is deprecated. Use hostBlockList.');
@@ -748,6 +816,8 @@ module.exports = {
748
816
  createItem: createItem,
749
817
  addErrorContext: addErrorContext,
750
818
  createTelemetryEvent: createTelemetryEvent,
819
+ addItemAttributes: addItemAttributes,
820
+ getItemAttribute: getItemAttribute,
751
821
  filterIp: filterIp,
752
822
  formatArgsAsString: formatArgsAsString,
753
823
  formatUrl: formatUrl,
@@ -762,6 +832,7 @@ module.exports = {
762
832
  isString: isString,
763
833
  isType: isType,
764
834
  isPromise: isPromise,
835
+ isBrowser: isBrowser,
765
836
  jsonParse: jsonParse,
766
837
  LEVELS: LEVELS,
767
838
  makeUnhandledStackInfo: makeUnhandledStackInfo,
@@ -775,5 +846,5 @@ module.exports = {
775
846
  stringify: stringify,
776
847
  maxByteSize: maxByteSize,
777
848
  typeName: typeName,
778
- uuid4: uuid4
849
+ uuid4: uuid4,
779
850
  };
package/test/api.test.js CHANGED
@@ -3,21 +3,21 @@
3
3
  /* globals it */
4
4
  /* globals sinon */
5
5
 
6
- var API = require('../src/api');
7
- var utility = require('../src/utility');
6
+ import API from '../src/api.js';
7
+ import utility from '../src/utility.js';
8
8
  utility.setupJSON();
9
9
 
10
10
  function TestTransportGenerator() {
11
- var TestTransport = function(callbackError, callbackResponse) {
11
+ var TestTransport = function (callbackError, callbackResponse) {
12
12
  this.postArgs = [];
13
13
  this.callbackError = callbackError;
14
14
  this.callbackResponse = callbackResponse;
15
15
  };
16
16
 
17
- TestTransport.prototype.post = function() {
17
+ TestTransport.prototype.post = function () {
18
18
  var args = arguments;
19
19
  this.postArgs.push(args);
20
- var callback = args[args.length-1];
20
+ var callback = args[args.length - 1];
21
21
  if (typeof callback === 'function') {
22
22
  callback(this.callbackError, this.callbackResponse);
23
23
  }
@@ -26,18 +26,17 @@ function TestTransportGenerator() {
26
26
  return TestTransport;
27
27
  }
28
28
 
29
- describe('Api()', function() {
30
- it('use the defaults if no custom endpoint is given', function(done) {
29
+ describe('Api()', function () {
30
+ it('use the defaults if no custom endpoint is given', function (done) {
31
31
  var transport = new (TestTransportGenerator())();
32
32
  var url = {
33
- parse: function(e) {
33
+ parse: function (e) {
34
34
  expect(false).to.be.ok();
35
- }
35
+ },
36
36
  };
37
- var backup = null;
38
37
  var accessToken = 'abc123';
39
- var options = {accessToken: accessToken};
40
- var api = new API(options, transport, url, backup);
38
+ var options = { accessToken: accessToken };
39
+ var api = new API(options, transport, url);
41
40
  // I know this is testing internal state but it
42
41
  // is the most expedient way to do this
43
42
  expect(api.accessToken).to.eql(accessToken);
@@ -46,24 +45,23 @@ describe('Api()', function() {
46
45
  expect(api.transportOptions.protocol).to.eql('https:');
47
46
  done();
48
47
  });
49
- it('should parse the endpoint and use that if given', function(done) {
48
+ it('should parse the endpoint and use that if given', function (done) {
50
49
  var transport = new (TestTransportGenerator())();
51
50
  var endpoint = 'http://woo.foo.com/api/42';
52
51
  var url = {
53
- parse: function(e) {
52
+ parse: function (e) {
54
53
  expect(e).to.eql(endpoint);
55
54
  return {
56
55
  hostname: 'woo.foo.com',
57
56
  protocol: 'http:',
58
57
  pathname: '/api/42',
59
- path: '/api/42'
58
+ path: '/api/42',
60
59
  };
61
- }
60
+ },
62
61
  };
63
- var backup = null;
64
62
  var accessToken = 'abc123';
65
- var options = {accessToken: accessToken, endpoint: endpoint};
66
- var api = new API(options, transport, url, backup);
63
+ var options = { accessToken: accessToken, endpoint: endpoint };
64
+ var api = new API(options, transport, url);
67
65
  expect(api.accessToken).to.eql(accessToken);
68
66
  expect(api.transportOptions.hostname).to.eql('woo.foo.com');
69
67
  expect(api.transportOptions.path).to.match(/\/api\/42/);
@@ -72,57 +70,106 @@ describe('Api()', function() {
72
70
  });
73
71
  });
74
72
 
75
- describe('postItem', function() {
76
- it('should call post on the transport object', function(done) {
77
- var response = 'yes'
73
+ describe('postItem', function () {
74
+ it('should call post on the transport object', function (done) {
75
+ var response = 'yes';
78
76
  var transport = new (TestTransportGenerator())(null, response);
79
77
  var url = {
80
- parse: function(e) {
78
+ parse: function (e) {
81
79
  expect(false).to.be.ok();
82
- }
80
+ },
83
81
  };
84
- var backup = null;
85
82
  var accessToken = 'abc123';
86
- var options = {accessToken: accessToken};
87
- var api = new API(options, transport, url, backup);
83
+ var options = { accessToken: accessToken };
84
+ var api = new API(options, transport, url);
88
85
 
89
- var data = {a: 1};
90
- api.postItem(data, function(err, resp) {
86
+ var data = { a: 1 };
87
+ api.postItem(data, function (err, resp) {
91
88
  expect(err).to.not.be.ok();
92
89
  expect(resp).to.eql(response);
93
90
  expect(transport.postArgs.length).to.eql(1);
94
91
  expect(transport.postArgs[0][0]).to.eql(accessToken);
95
92
  expect(transport.postArgs[0][1].path).to.match(/\/item\//);
96
- expect(transport.postArgs[0][2].access_token).to.eql(accessToken);
97
93
  expect(transport.postArgs[0][2].data.a).to.eql(1);
98
94
  done();
99
95
  });
100
96
  });
101
- it('should stringify context', function(done) {
102
- var response = 'yes'
97
+ it('should stringify context', function (done) {
98
+ var response = 'yes';
103
99
  var transport = new (TestTransportGenerator())(null, response);
104
100
  var url = {
105
- parse: function(e) {
101
+ parse: function (e) {
106
102
  expect(false).to.be.ok();
107
- }
103
+ },
108
104
  };
109
- var backup = null;
110
105
  var accessToken = 'abc123';
111
- var options = {accessToken: accessToken};
112
- var api = new API(options, transport, url, backup);
106
+ var options = { accessToken: accessToken };
107
+ var api = new API(options, transport, url);
113
108
 
114
- var data = {a: 1, context: {some: [1, 2, 'stuff']}};
115
- api.postItem(data, function(err, resp) {
109
+ var data = { a: 1, context: { some: [1, 2, 'stuff'] } };
110
+ api.postItem(data, function (err, resp) {
116
111
  expect(err).to.not.be.ok();
117
112
  expect(resp).to.eql(response);
118
113
  expect(transport.postArgs.length).to.eql(1);
119
114
  expect(transport.postArgs[0][0]).to.eql(accessToken);
120
115
  expect(transport.postArgs[0][1].path).to.match(/\/item\//);
121
116
  expect(transport.postArgs[0][1].method).to.eql('POST');
122
- expect(transport.postArgs[0][2].access_token).to.eql(accessToken);
123
117
  expect(transport.postArgs[0][2].data.a).to.eql(1);
124
- expect(transport.postArgs[0][2].data.context).to.eql('{"some":[1,2,"stuff"]}');
118
+ expect(transport.postArgs[0][2].data.context).to.eql(
119
+ '{"some":[1,2,"stuff"]}',
120
+ );
125
121
  done();
126
122
  });
127
123
  });
128
124
  });
125
+
126
+ describe('postSpans', function () {
127
+ let transport;
128
+
129
+ beforeEach(function () {
130
+ // Create mock transport
131
+ transport = {
132
+ post: sinon
133
+ .stub()
134
+ .callsFake((accessToken, options, payload, callback) => {
135
+ callback(null, { result: 'ok' });
136
+ }),
137
+ postJsonPayload: sinon.stub(),
138
+ };
139
+ });
140
+
141
+ afterEach(function () {
142
+ sinon.restore();
143
+ });
144
+
145
+ it('should call post on the transport object', async function () {
146
+ const urllib = await import('../src/browser/url.js');
147
+ const response = 'yes';
148
+ const url = {
149
+ parse: function (e) {
150
+ expect(false).to.be.ok();
151
+ },
152
+ };
153
+ const accessToken = 'abc123';
154
+ const options = {
155
+ accessToken: accessToken,
156
+ tracing: {
157
+ enabled: true,
158
+ endpoint: 'https://api.rollbar.com/api/1/session/',
159
+ },
160
+ };
161
+ const api = new API(options, transport, urllib);
162
+
163
+ const data = { a: 1 };
164
+ await api.postSpans(data)
165
+
166
+ expect(transport.post.called).to.be.true;
167
+
168
+ expect(transport.post.callCount).to.eql(1);
169
+ expect(transport.post.firstCall.args.length).to.eql(4);
170
+ expect(transport.post.firstCall.args[0]).to.eql(accessToken);
171
+ expect(transport.post.firstCall.args[1].path).to.match(/\/session\//);
172
+ expect(transport.post.firstCall.args[1].method).to.eql('POST');
173
+ expect(transport.post.firstCall.args[2].a).to.eql(1);
174
+ });
175
+ });