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
@@ -1,1099 +0,0 @@
1
- "use strict";
2
-
3
- var assert = require('assert');
4
- var util = require('util');
5
- var vows = require('vows');
6
- var sinon = require('sinon');
7
- var t = require('../src/server/transforms');
8
-
9
- process.env.NODE_ENV = process.env.NODE_ENV || 'test-node-env';
10
- var rollbar = require('../src/server/rollbar');
11
- var _ = require('../src/utility');
12
-
13
- function CustomError(message, nested) {
14
- rollbar.Error.call(this, message, nested);
15
- }
16
- util.inherits(CustomError, rollbar.Error);
17
-
18
- async function wait(ms) {
19
- return new Promise(resolve => {
20
- setTimeout(resolve, ms);
21
- });
22
- }
23
-
24
- async function throwInScriptFile(rollbar, filepath, callback) {
25
- setTimeout(function () {
26
- var error = require(filepath);
27
- error();
28
- }, 10);
29
- await wait(500);
30
- callback(rollbar);
31
- }
32
-
33
- var nodeVersion = function () {
34
- var version = process.versions.node.split('.');
35
-
36
- return [
37
- parseInt(version[0]),
38
- parseInt(version[1]),
39
- parseInt(version[2]),
40
- ];
41
- }();
42
-
43
- var isMinNodeVersion = function(major, minor) {
44
- return (
45
- nodeVersion[0] > major || (nodeVersion[0] === major && nodeVersion[1] >= minor)
46
- );
47
- }
48
-
49
- vows.describe('transforms')
50
- .addBatch({
51
- 'baseData': {
52
- 'options': {
53
- 'defaults': {
54
- topic: function() {
55
- return rollbar.defaultOptions;
56
- },
57
- 'item': {
58
- 'empty': {
59
- topic: function(options) {
60
- var item = {};
61
- t.baseData(item, options, this.callback);
62
- },
63
- 'should have a timestamp': function(err, item) {
64
- assert.ifError(err);
65
- assert.notEqual(item.data, undefined);
66
- assert.notEqual(item.data.timestamp, undefined);
67
- },
68
- 'should have an error level': function(err, item) {
69
- assert.ifError(err);
70
- assert.notEqual(item.data, undefined);
71
- assert.equal(item.data.level, 'error');
72
- },
73
- 'should have some defaults': function(err, item) {
74
- assert.ifError(err);
75
- var data = item.data;
76
- assert.equal(data.environment, process.env.NODE_ENV);
77
- assert.equal(data.framework, 'node-js');
78
- assert.equal(data.language, 'javascript');
79
- assert.ok(data.server);
80
- assert.ok(data.server.host);
81
- assert.ok(data.server.pid);
82
- }
83
- },
84
- 'with values': {
85
- topic: function(options) {
86
- var item = {
87
- level: 'critical',
88
- framework: 'star-wars',
89
- uuid: '12345',
90
- environment: 'production',
91
- custom: {
92
- one: 'a1',
93
- stuff: 'b2',
94
- language: 'english'
95
- }
96
- };
97
- t.baseData(item, options, this.callback);
98
- },
99
- 'should have a critical level': function(err, item) {
100
- assert.ifError(err);
101
- assert.equal(item.data.level, 'critical');
102
- },
103
- 'should have the defaults overriden by the item': function(err, item) {
104
- assert.ifError(err);
105
- assert.equal(item.data.environment, 'production');
106
- assert.equal(item.data.framework, 'star-wars');
107
- assert.equal(item.data.language, 'javascript');
108
- assert.equal(item.data.uuid, '12345');
109
- },
110
- 'should have data from custom': function(err, item) {
111
- assert.equal(item.data.one, 'a1');
112
- assert.equal(item.data.stuff, 'b2');
113
- assert.notEqual(item.data.language, 'english');
114
- }
115
- }
116
- }
117
- },
118
- 'with values': {
119
- topic: function() {
120
- return _.merge(rollbar.defaultOptions, {
121
- payload: {
122
- environment: 'payload-prod',
123
- },
124
- framework: 'opt-node',
125
- host: 'opt-host',
126
- branch: 'opt-master'
127
- });
128
- },
129
- 'item': {
130
- 'empty': {
131
- topic: function(options) {
132
- var item = {};
133
- t.baseData(item, options, this.callback);
134
- },
135
- 'should have a timestamp': function(err, item) {
136
- assert.ifError(err);
137
- assert.notEqual(item.data, undefined);
138
- assert.notEqual(item.data.timestamp, undefined);
139
- },
140
- 'should have an error level': function(err, item) {
141
- assert.ifError(err);
142
- assert.notEqual(item.data, undefined);
143
- assert.equal(item.data.level, 'error');
144
- },
145
- 'should have data from options and defaults': function(err, item) {
146
- assert.ifError(err);
147
- var data = item.data;
148
- assert.equal(data.environment, 'payload-prod');
149
- assert.equal(data.framework, 'opt-node');
150
- assert.equal(data.language, 'javascript');
151
- assert.ok(data.server);
152
- assert.equal(data.server.host, 'opt-host');
153
- assert.equal(data.server.branch, 'opt-master');
154
- assert.ok(data.server.pid);
155
- }
156
- },
157
- 'with values': {
158
- topic: function(options) {
159
- var item = {
160
- level: 'critical',
161
- environment: 'production',
162
- framework: 'star-wars',
163
- uuid: '12345',
164
- custom: {
165
- one: 'a1',
166
- stuff: 'b2',
167
- language: 'english'
168
- }
169
- };
170
- t.baseData(item, options, this.callback);
171
- },
172
- 'should have a critical level': function(err, item) {
173
- assert.ifError(err);
174
- assert.equal(item.data.level, 'critical');
175
- },
176
- 'should have the defaults overriden by the item': function(err, item) {
177
- assert.ifError(err);
178
- assert.equal(item.data.environment, 'production');
179
- assert.equal(item.data.framework, 'star-wars');
180
- assert.equal(item.data.language, 'javascript');
181
- assert.equal(item.data.uuid, '12345');
182
- },
183
- 'should have data from custom': function(err, item) {
184
- assert.equal(item.data.one, 'a1');
185
- assert.equal(item.data.stuff, 'b2');
186
- assert.notEqual(item.data.language, 'english');
187
- }
188
- }
189
- }
190
- }
191
- }
192
- }
193
- })
194
- .addBatch({
195
- 'addBody': {
196
- 'options': {
197
- 'anything': {
198
- topic: function() {
199
- return {whatever: 'stuff'};
200
- },
201
- 'item': {
202
- 'with stackInfo': {
203
- topic: function(options) {
204
- var item = {stackInfo: [{message: 'hey'}]};
205
- t.addBody(item, options, this.callback);
206
- },
207
- 'should not error': function(err, item) {
208
- assert.ifError(err);
209
- },
210
- 'should set the trace_chain': function(err, item) {
211
- assert.ok(item.data.body.trace_chain);
212
- },
213
- 'should not set a message': function(err, item) {
214
- assert.ok(!item.data.body.message);
215
- }
216
- },
217
- 'with no stackInfo': {
218
- topic: function(options) {
219
- var item = {message: 'hello'};
220
- t.addBody(item, options, this.callback);
221
- },
222
- 'should not error': function(err, item) {
223
- assert.ifError(err);
224
- },
225
- 'should not set the trace_chain': function(err, item) {
226
- assert.ok(!item.data.body.trace_chain);
227
- },
228
- 'should set a message': function(err, item) {
229
- assert.ok(item.data.body.message);
230
- }
231
- }
232
- }
233
- }
234
- }
235
- }
236
- })
237
- .addBatch({
238
- 'addMessageData': {
239
- 'options': {
240
- 'anything': {
241
- topic: function() {
242
- return {random: 'stuff'};
243
- },
244
- 'item': {
245
- 'no message': {
246
- topic: function(options) {
247
- var item = {err: 'stuff', not: 'a message'};
248
- t.addMessageData(item, options, this.callback);
249
- },
250
- 'should not error': function(err, item) {
251
- assert.ifError(err);
252
- },
253
- 'should add an empty body': function(err, item) {
254
- assert.ok(item.data.body);
255
- }
256
- },
257
- 'with a message': {
258
- topic: function(options) {
259
- var item = {message: 'this is awesome'};
260
- t.addMessageData(item, options, this.callback);
261
- },
262
- 'should not error': function(err, item) {
263
- assert.ifError(err);
264
- },
265
- 'should add a body with the message': function(err, item) {
266
- assert.equal(item.data.body.message.body, 'this is awesome');
267
- }
268
- }
269
- }
270
- }
271
- }
272
- }
273
- })
274
- .addBatch({
275
- 'nodeSourceMaps': {
276
- 'with original source present': {
277
- topic: function() {
278
- var Rollbar = new rollbar({
279
- accessToken: 'abc123',
280
- captureUncaught: true,
281
- nodeSourceMaps: true
282
- });
283
- var queue = Rollbar.client.notifier.queue;
284
- Rollbar.addItemStub = sinon.stub(queue, 'addItem');
285
-
286
- throwInScriptFile(Rollbar, '../examples/node-typescript/dist/index',
287
- this.callback);
288
- },
289
- 'should map the stack with context': function(r) {
290
- var addItem = r.addItemStub;
291
-
292
- assert.isTrue(addItem.called);
293
- if (addItem.called) {
294
- var frame = addItem.getCall(0).args[0].body.trace_chain[0].frames.pop();
295
- assert.ok(frame.filename.includes('src/index.ts'));
296
- assert.equal(frame.lineno, 10);
297
- assert.equal(frame.colno, 22);
298
- assert.equal(frame.code, " var error = <Error> new CustomError('foo');");
299
- assert.equal(frame.context.pre[0], ' }');
300
- assert.equal(frame.context.pre[1], ' }');
301
- assert.equal(frame.context.pre[2],
302
- ' // TypeScript code snippet will include `<Error>`');
303
- assert.equal(frame.context.post[0], ' throw error;');
304
- assert.equal(frame.context.post[1], '}');
305
-
306
- var sourceMappingURLs = addItem.getCall(0).args[0].notifier.diagnostic
307
- .node_source_maps.source_mapping_urls;
308
- var urls = Object.keys(sourceMappingURLs);
309
- assert.ok(urls[0].includes('index.js'));
310
- assert.ok(sourceMappingURLs[urls[0]].includes('index.js.map'));
311
- assert.ok(urls[1].includes('server.transforms.test.js'));
312
- assert.ok(sourceMappingURLs[urls[1]].includes('not found'));
313
-
314
- // Node until v12 will have 'timers.js' here.
315
- // Node 12 - 14 will have 'internal/timers.js' here.
316
- // Starting in v16, this is 'node:internal/timers'.
317
- // This assert works for all and is specific enough for this test case.
318
- assert.ok(urls[2].includes('timers'));
319
- assert.ok(sourceMappingURLs[urls[2]].includes('not found'));
320
- }
321
- addItem.reset();
322
- }
323
- }
324
- }
325
- })
326
- .addBatch({
327
- 'nodeSourceMaps': {
328
- 'using sourcesContent': {
329
- topic: function() {
330
- var Rollbar = new rollbar({
331
- accessToken: 'abc123',
332
- captureUncaught: true,
333
- nodeSourceMaps: true
334
- });
335
- var queue = Rollbar.client.notifier.queue;
336
- Rollbar.addItemStub = sinon.stub(queue, 'addItem');
337
-
338
- throwInScriptFile(Rollbar, '../examples/node-dist/index', this.callback);
339
- },
340
- 'should map the stack with context': function(r) {
341
- var addItem = r.addItemStub;
342
-
343
- assert.isTrue(addItem.called);
344
- if (addItem.called) {
345
- var frame = addItem.getCall(0).args[0].body.trace_chain[0].frames.pop();
346
- assert.ok(frame.filename.includes('src/index.ts'));
347
- assert.equal(frame.lineno, 10);
348
- assert.equal(frame.colno, 22);
349
- assert.equal(frame.code, " var error = <Error> new CustomError('foo');");
350
- assert.equal(frame.context.pre[0], ' }');
351
- assert.equal(frame.context.pre[1], ' }');
352
- assert.equal(frame.context.pre[2],
353
- ' // TypeScript code snippet will include `<Error>`');
354
- assert.equal(frame.context.post[0], ' throw error;');
355
- assert.equal(frame.context.post[1], '}');
356
-
357
- var sourceMappingURLs = addItem.getCall(0).args[0].notifier.diagnostic
358
- .node_source_maps.source_mapping_urls;
359
- var urls = Object.keys(sourceMappingURLs);
360
- assert.ok(urls.length === 1);
361
- assert.ok(urls[0].includes('index.js'));
362
- assert.ok(sourceMappingURLs[urls[0]].includes('index.js.map'));
363
- }
364
- addItem.reset();
365
- }
366
- }
367
- }
368
- })
369
- .addBatch({
370
- 'handleItemWithError': {
371
- 'options': {
372
- 'anything': {
373
- topic: function() {
374
- return {
375
- some: 'stuff',
376
- captureIp: true,
377
- };
378
- },
379
- 'item': {
380
- 'no error': {
381
- topic: function(options) {
382
- var item = {
383
- data: {body: {yo: 'hey'}},
384
- message: 'hey'
385
- };
386
- t.handleItemWithError(item, options, this.callback);
387
- },
388
- 'should not error': function(err, item) {
389
- assert.ifError(err);
390
- },
391
- 'should not change the item': function(err, item) {
392
- assert.equal(item.data.body.yo, 'hey');
393
- }
394
- },
395
- 'with a simple error': {
396
- topic: function (options) {
397
- var item = {
398
- data: {body: {}},
399
- err: new Error('wookie')
400
- };
401
- t.handleItemWithError(item, options, this.callback);
402
- },
403
- 'should not error': function(err, item) {
404
- assert.ifError(err);
405
- },
406
- 'should add some data to the trace_chain': function(err, item) {
407
- assert.ok(item.stackInfo);
408
- }
409
- },
410
- 'with a normal error': {
411
- topic: function (options) {
412
- var test = function() {
413
- var x = thisVariableIsNotDefined;
414
- };
415
- var err;
416
- try {
417
- test();
418
- } catch (e) {
419
- err = e;
420
- }
421
- var item = {
422
- data: {body: {}},
423
- err: err
424
- };
425
- t.handleItemWithError(item, options, this.callback);
426
- },
427
- 'should not error': function(err, item) {
428
- assert.ifError(err);
429
- },
430
- 'should add some data to the trace_chain': function(err, item) {
431
- assert.ok(item.stackInfo);
432
- }
433
- },
434
- 'with a nested error': {
435
- topic: function (options) {
436
- var test = function() {
437
- var x = thisVariableIsNotDefined;
438
- };
439
- var err;
440
- try {
441
- test();
442
- } catch (e) {
443
- err = new CustomError('nested-message', e);
444
- }
445
- var item = {
446
- data: {body: {}},
447
- err: err
448
- };
449
- t.handleItemWithError(item, options, this.callback);
450
- },
451
- 'should not error': function(err, item) {
452
- assert.ifError(err);
453
- },
454
- 'should have the right data in the trace_chain': function(err, item) {
455
- var trace_chain = item.stackInfo;
456
- assert.lengthOf(trace_chain, 2);
457
- assert.equal(trace_chain[0].exception.class, 'CustomError');
458
- assert.equal(trace_chain[0].exception.message, 'nested-message');
459
- assert.equal(trace_chain[1].exception.class, 'ReferenceError');
460
- }
461
- },
462
- 'with a null nested error': {
463
- topic: function (options) {
464
- var err = new CustomError('With null nested error');
465
-
466
- // Set nested to null for the test
467
- err.nested = null;
468
-
469
- var item = {
470
- data: {body: {}},
471
- err: err
472
- };
473
- t.handleItemWithError(item, options, this.callback);
474
- },
475
- 'should not error': function(err, item) {
476
- assert.ifError(err);
477
- },
478
- 'should have the right data in the trace_chain': function(err, item) {
479
- var trace_chain = item.stackInfo;
480
- assert.lengthOf(trace_chain, 1);
481
- assert.equal(trace_chain[0].exception.class, 'CustomError');
482
- }
483
- },
484
- 'with error context': {
485
- topic: function (options) {
486
- var test = function() {
487
- var x = thisVariableIsNotDefined;
488
- };
489
- var err;
490
- try {
491
- test();
492
- } catch (e) {
493
- err = new CustomError('nested-message', e);
494
- e.rollbarContext = { err1: 'nested context' };
495
- err.rollbarContext = { err2: 'error context' };
496
- }
497
- var item = {
498
- data: {body: {}},
499
- err: err
500
- };
501
- options.addErrorContext = true;
502
- t.handleItemWithError(item, options, this.callback);
503
- },
504
- 'should not error': function(err, item) {
505
- assert.ifError(err);
506
- },
507
- 'should add the error context': function(err, item) {
508
- var trace_chain = item.stackInfo;
509
- assert.lengthOf(trace_chain, 2);
510
- assert.equal(item.data.custom.err1, 'nested context');
511
- assert.equal(item.data.custom.err2, 'error context');
512
- }
513
- },
514
- 'with an error cause': {
515
- topic: function (options) {
516
- var test = function() {
517
- var x = thisVariableIsNotDefined;
518
- };
519
- var err;
520
- try {
521
- test();
522
- } catch (e) {
523
- err = new Error('cause message', { cause: e });
524
- e.rollbarContext = { err1: 'cause context' };
525
- err.rollbarContext = { err2: 'error context' };
526
- }
527
- var item = {
528
- data: {body: {}},
529
- err: err
530
- };
531
- t.handleItemWithError(item, options, this.callback);
532
- },
533
- 'should not error': function(err, item) {
534
- assert.ifError(err);
535
- },
536
- 'should have the right data in the trace_chain': function(err, item) {
537
- // Error cause was introduced in Node 16.9.
538
- if (!isMinNodeVersion(16, 9)) return;
539
-
540
- var trace_chain = item.stackInfo;
541
- assert.lengthOf(trace_chain, 2);
542
- assert.equal(trace_chain[0].exception.class, 'Error');
543
- assert.equal(trace_chain[0].exception.message, 'cause message');
544
- assert.equal(trace_chain[1].exception.class, 'ReferenceError');
545
- assert.equal(item.data.custom.err1, 'cause context');
546
- assert.equal(item.data.custom.err2, 'error context');
547
- }
548
- },
549
- }
550
- }
551
- }
552
- }
553
- })
554
- .addBatch({
555
- 'addRequestData': {
556
- 'options': {
557
- 'without custom addRequestData method': {
558
- 'without scrub fields': {
559
- topic: function() {
560
- return {
561
- nothing: 'here',
562
- captureEmail: true,
563
- captureUsername: true,
564
- captureIp: true
565
- };
566
- },
567
- 'item': {
568
- 'without a request': {
569
- topic: function(options) {
570
- var item = {
571
- data: {body: {message: 'hey'}}
572
- };
573
- t.addRequestData(item, options, this.callback);
574
- },
575
- 'should not error': function(err, item) {
576
- assert.ifError(err);
577
- },
578
- 'should not change the item': function(err, item) {
579
- assert.equal(item.request, undefined);
580
- assert.equal(item.data.request, undefined);
581
- }
582
- },
583
- 'with an empty request object': {
584
- topic: function(options) {
585
- var item = {
586
- request: {},
587
- data: {body: {message: 'hey'}}
588
- };
589
- t.addRequestData(item, options, this.callback);
590
- },
591
- 'should not error': function(err, item) {
592
- assert.ifError(err);
593
- },
594
- 'should not change request object': function(err, item) {
595
- assert.equal(item.request.headers, undefined);
596
- }
597
- },
598
- 'with a request': {
599
- topic: function(options) {
600
- var item = {
601
- request: {
602
- headers: {
603
- host: 'example.com',
604
- 'x-auth-token': '12345'
605
- },
606
- protocol: 'https',
607
- url: '/some/endpoint',
608
- ip: '192.192.192.1',
609
- method: 'GET',
610
- body: {
611
- token: 'abc123',
612
- something: 'else'
613
- },
614
- route: { path: '/api/:bork' },
615
- user: {
616
- id: 42,
617
- email: 'fake@example.com'
618
- }
619
- },
620
- stuff: 'hey',
621
- data: {other: 'thing'}
622
- };
623
- t.addRequestData(item, options, this.callback);
624
- },
625
- 'should not error': function(err, item) {
626
- assert.ifError(err);
627
- },
628
- 'should have a request object inside data': function(err, item) {
629
- assert.ok(item.data.request);
630
- },
631
- 'should set a person based on request user': function(err, item) {
632
- assert.equal(item.data.person.id, 42);
633
- assert.equal(item.data.person.email, 'fake@example.com');
634
- },
635
- 'should set some fields based on request data': function(err, item) {
636
- var r = item.data.request;
637
- assert.equal(r.url, 'https://example.com/some/endpoint');
638
- assert.equal(r.user_ip, '192.192.192.1');
639
- assert.ok(r.GET);
640
-
641
- assert.equal(item.data.context, '/api/:bork');
642
- },
643
- },
644
- 'with a request for a nested router with a baseURL': {
645
- topic: function(options) {
646
- var item = {
647
- request: {
648
- headers: {
649
- host: 'example.com',
650
- 'x-auth-token': '12345'
651
- },
652
- protocol: 'https',
653
- url: '/some/endpoint',
654
- baseUrl: '/nested',
655
- ip: '192.192.192.1',
656
- method: 'GET',
657
- body: {
658
- token: 'abc123',
659
- something: 'else'
660
- },
661
- route: { path: '/api/:bork' },
662
- user: {
663
- id: 42,
664
- email: 'fake@example.com'
665
- }
666
- },
667
- stuff: 'hey',
668
- data: {other: 'thing'}
669
- };
670
- t.addRequestData(item, options, this.callback);
671
- },
672
- 'should not error': function(err, item) {
673
- assert.ifError(err);
674
- },
675
- 'should have a request object inside data': function(err, item) {
676
- assert.ok(item.data.request);
677
- },
678
- 'should set some fields based on request data': function(err, item) {
679
- var r = item.data.request;
680
- assert.equal(r.url, 'https://example.com/nested/some/endpoint');
681
- assert.equal(item.data.context, '/nested/api/:bork');
682
- },
683
- },
684
- 'with a request like from hapi': {
685
- topic: function(options) {
686
- var item = {
687
- request: {
688
- headers: {
689
- host: 'example.com',
690
- 'x-auth-token': '12345'
691
- },
692
- protocol: 'https',
693
- url: {
694
- protocol: null,
695
- slashes: null,
696
- auth: null,
697
- host: null,
698
- port: null,
699
- hostname: null,
700
- hash: null,
701
- search: '',
702
- query: {},
703
- pathname: '/some/endpoint',
704
- path: '/some/endpoint',
705
- href: '/some/endpoint'
706
- },
707
- ip: '192.192.192.1',
708
- method: 'POST',
709
- payload: {
710
- token: 'abc123',
711
- something: 'else'
712
- },
713
- route: { path: '/api/:bork' },
714
- user: {
715
- id: 42,
716
- email: 'fake@example.com'
717
- }
718
- },
719
- stuff: 'hey',
720
- data: {other: 'thing'}
721
- };
722
- t.addRequestData(item, options, this.callback);
723
- },
724
- 'should not error': function(err, item) {
725
- assert.ifError(err);
726
- },
727
- 'should have a request object inside data': function(err, item) {
728
- assert.ok(item.data.request);
729
- },
730
- 'should set a person based on request user': function(err, item) {
731
- assert.equal(item.data.person.id, 42);
732
- assert.equal(item.data.person.email, 'fake@example.com');
733
- },
734
- 'should set some fields based on request data': function(err, item) {
735
- var r = item.data.request;
736
- assert.equal(r.url, 'https://example.com/some/endpoint');
737
- assert.equal(r.user_ip, '192.192.192.1');
738
- assert.ok(!r.GET);
739
- assert.ok(r.POST);
740
-
741
- assert.equal(item.data.context, '/api/:bork');
742
- },
743
- },
744
- 'with a request with an array body': {
745
- topic: function(options) {
746
- var item = {
747
- request: {
748
- headers: {
749
- host: 'example.com',
750
- 'x-auth-token': '12345'
751
- },
752
- protocol: 'https',
753
- url: '/some/endpoint',
754
- ip: '192.192.192.1',
755
- method: 'POST',
756
- body: [{
757
- token: 'abc123',
758
- something: 'else'
759
- }, 'otherStuff'],
760
- user: {
761
- id: 42,
762
- email: 'fake@example.com'
763
- }
764
- },
765
- stuff: 'hey',
766
- data: {other: 'thing'}
767
- };
768
- t.addRequestData(item, options, this.callback);
769
- },
770
- 'should not error': function(err, item) {
771
- assert.ifError(err);
772
- },
773
- 'should have a request object inside data': function(err, item) {
774
- assert.ok(item.data.request);
775
- },
776
- 'should set a person based on request user': function(err, item) {
777
- assert.equal(item.data.person.id, 42);
778
- assert.equal(item.data.person.email, 'fake@example.com');
779
- },
780
- 'should set some fields based on request data': function(err, item) {
781
- var r = item.data.request;
782
- assert.equal(r.url, 'https://example.com/some/endpoint');
783
- assert.equal(r.user_ip, '192.192.192.1');
784
- assert.ok(r.POST);
785
- assert.equal(r.POST['0'].something, 'else');
786
- assert.equal(r.POST['1'], 'otherStuff');
787
- },
788
- }
789
- }
790
- },
791
- 'with scrub fields': {
792
- topic: function() {
793
- return {
794
- scrubHeaders: [
795
- 'x-auth-token'
796
- ],
797
- scrubFields: [
798
- 'passwd',
799
- 'access_token',
800
- 'request.cookie'
801
- ]
802
- };
803
- },
804
- 'item': {
805
- 'with a request': {
806
- topic: function(options) {
807
- var item = {
808
- request: {
809
- headers: {
810
- host: 'example.com',
811
- 'x-auth-token': '12345'
812
- },
813
- protocol: 'https',
814
- url: '/some/endpoint',
815
- ip: '192.192.192.192',
816
- method: 'GET',
817
- body: {
818
- token: 'abc123',
819
- something: 'else'
820
- },
821
- user: {
822
- id: 42,
823
- email: 'fake@example.com'
824
- }
825
- },
826
- stuff: 'hey',
827
- data: {other: 'thing'}
828
- };
829
- t.addRequestData(item, options, this.callback);
830
- },
831
- 'should not error': function(err, item) {
832
- assert.ifError(err);
833
- },
834
- 'should have a request object inside data': function(err, item) {
835
- assert.ok(item.data.request);
836
- },
837
- }
838
- }
839
- }
840
- },
841
- 'with custom addRequestData': {
842
- 'with scrub fields': {
843
- topic: function() {
844
- var customFn = function(i, r) {
845
- assert.equal(i.stuff, undefined);
846
- assert.equal(i.other, 'thing');
847
- i.myRequest = {body: r.body.token};
848
- };
849
- return {
850
- captureIp: true,
851
- addRequestData: customFn,
852
- scrubFields: [
853
- 'passwd',
854
- 'access_token',
855
- 'token',
856
- 'request.cookie'
857
- ]
858
- };
859
- },
860
- 'item': {
861
- 'with a request': {
862
- topic: function(options) {
863
- var item = {
864
- request: {
865
- headers: {
866
- host: 'example.com',
867
- 'x-auth-token': '12345'
868
- },
869
- protocol: 'https',
870
- url: '/some/endpoint',
871
- ip: '192.192.192.192',
872
- method: 'GET',
873
- body: {
874
- token: 'abc123',
875
- something: 'else'
876
- },
877
- user: {
878
- id: 42,
879
- email: 'fake@example.com'
880
- }
881
- },
882
- stuff: 'hey',
883
- data: {other: 'thing'}
884
- };
885
- t.addRequestData(item, options, this.callback);
886
- },
887
- 'should not error': function(err, item) {
888
- assert.ifError(err);
889
- },
890
- 'should do what the function does': function(err, item) {
891
- assert.equal(item.data.request, undefined);
892
- assert.equal(item.data.myRequest.body, 'abc123');
893
- }
894
- }
895
- }
896
- }
897
- }
898
- }
899
- }
900
- })
901
- .addBatch({
902
- 'scrubPayload': {
903
- 'options': {
904
- 'without scrub fields': {
905
- topic: function() {
906
- return rollbar.defaultOptions;
907
- },
908
- 'item': {
909
- topic: function(options) {
910
- var item = {
911
- data: {
912
- body: {
913
- message: 'hey',
914
- password: '123',
915
- secret: {stuff: 'here'}
916
- }
917
- }
918
- };
919
- t.scrubPayload(item, options, this.callback);
920
- },
921
- 'should not error': function(err, item) {
922
- assert.ifError(err);
923
- },
924
- 'should not scrub okay keys': function(err, item) {
925
- assert.equal(item.data.body.message, 'hey');
926
- },
927
- 'should scrub key/value based on defaults': function(err, item) {
928
- assert.matches(item.data.body.password, /\*+/);
929
- assert.matches(item.data.body.secret, /\*+/);
930
- }
931
- }
932
- },
933
- 'with scrub fields': {
934
- topic: function() {
935
- return {
936
- captureIp: true,
937
- scrubHeaders: [
938
- 'x-auth-token'
939
- ],
940
- scrubFields: [
941
- 'passwd',
942
- 'access_token',
943
- 'request.cookie',
944
- 'sauce'
945
- ],
946
- scrubRequestBody: true
947
- };
948
- },
949
- 'item': {
950
- 'with a request': {
951
- topic: function(options) {
952
- var item = {
953
- request: {
954
- headers: {
955
- host: 'example.com',
956
- 'x-auth-token': '12345'
957
- },
958
- protocol: 'https',
959
- url: '/some/endpoint',
960
- ip: '192.192.192.192',
961
- method: 'GET',
962
- body: {
963
- token: 'abc123',
964
- something: 'else'
965
- },
966
- user: {
967
- id: 42,
968
- email: 'fake@example.com'
969
- }
970
- },
971
- stuff: 'hey',
972
- data: {
973
- other: 'thing',
974
- sauce: 'secrets',
975
- someParams: 'foo=okay&passwd=iamhere'
976
- }
977
- };
978
- t.addRequestData(item, options, function(e, i) {
979
- if (e) {
980
- this.callback(e);
981
- return;
982
- }
983
- t.scrubPayload(i, options, this.callback)
984
- }.bind(this));
985
- },
986
- 'should not error': function(err, item) {
987
- assert.ifError(err);
988
- },
989
- 'should have a request object inside data': function(err, item) {
990
- assert.ok(item.data.request);
991
- },
992
- 'should scrub based on the options': function(err, item) {
993
- var r = item.data.request;
994
- assert.equal(r.GET.token, 'abc123');
995
- assert.match(r.headers['x-auth-token'], /\*+/);
996
- assert.equal(r.headers['host'], 'example.com');
997
- assert.match(item.data.sauce, /\*+/);
998
- assert.equal(item.data.other, 'thing');
999
- assert.match(item.data.someParams, /foo=okay&passwd=\*+/);
1000
- }
1001
- },
1002
- 'with a json request body': {
1003
- topic: function(options) {
1004
- var requestBody = JSON.stringify({
1005
- token: 'abc123',
1006
- something: 'else',
1007
- passwd: '123456'
1008
- });
1009
- var item = {
1010
- request: {
1011
- headers: {
1012
- host: 'example.com',
1013
- 'content-type': 'application/json',
1014
- 'x-auth-token': '12345'
1015
- },
1016
- protocol: 'https',
1017
- url: '/some/endpoint',
1018
- ip: '192.192.192.192',
1019
- method: 'GET',
1020
- body: requestBody,
1021
- user: {
1022
- id: 42,
1023
- email: 'fake@example.com'
1024
- }
1025
- },
1026
- stuff: 'hey',
1027
- data: {
1028
- other: 'thing',
1029
- sauce: 'secrets',
1030
- someParams: 'foo=okay&passwd=iamhere'
1031
- }
1032
- };
1033
- t.addRequestData(item, options, function(e, i) {
1034
- if (e) {
1035
- this.callback(e);
1036
- return;
1037
- }
1038
- t.scrubPayload(i, options, this.callback)
1039
- }.bind(this));
1040
- },
1041
- 'should not error': function(err, item) {
1042
- assert.ifError(err);
1043
- },
1044
- 'should have a request object inside data': function(err, item) {
1045
- assert.ok(item.data.request);
1046
- },
1047
- 'should scrub based on the options': function(err, item) {
1048
- var r = item.data.request;
1049
- assert.match(r.headers['x-auth-token'], /\*+/);
1050
- assert.equal(r.headers['host'], 'example.com');
1051
- assert.match(item.data.sauce, /\*+/);
1052
- assert.equal(item.data.other, 'thing');
1053
- assert.match(item.data.someParams, /foo=okay&passwd=\*+/);
1054
-
1055
- var requestBody = JSON.parse(item.data.request.body);
1056
- assert.match(requestBody.passwd, /\*+/);
1057
- }
1058
- },
1059
- 'with a bad json request body': {
1060
- topic: function(options) {
1061
- var requestBody = 'not valid json';
1062
- var item = {
1063
- request: {
1064
- headers: {
1065
- 'content-type': 'application/json'
1066
- },
1067
- protocol: 'https',
1068
- url: '/some/endpoint',
1069
- ip: '192.192.192.192',
1070
- method: 'GET',
1071
- body: requestBody
1072
- }
1073
- };
1074
- t.addRequestData(item, options, function(e, i) {
1075
- if (e) {
1076
- this.callback(e);
1077
- return;
1078
- }
1079
- t.scrubPayload(i, options, this.callback)
1080
- }.bind(this));
1081
- },
1082
- 'should not error': function(err, item) {
1083
- assert.ifError(err);
1084
- },
1085
- 'should have a request object inside data': function(err, item) {
1086
- assert.ok(item.data.request);
1087
- },
1088
- 'should delete the body and add a diagnostic error': function(err, item) {
1089
- var requestBody = JSON.parse(item.data.request.body);
1090
- assert.equal(requestBody, null);
1091
- assert.match(item.data.request.error, /request.body parse failed/);
1092
- }
1093
- }
1094
- }
1095
- }
1096
- }
1097
- }
1098
- })
1099
- .export(module, {error: false});