Skip to content

Commit 62d2571

Browse files
committed
Merge branch 'master' of github.com:getsentry/sentry-javascript
2 parents fdc557a + 1608e8d commit 62d2571

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1506
-2238
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ install: true
1212
sudo: required
1313

1414
language: node_js
15-
dist: trusty
15+
dist: bionic
1616

1717
cache:
1818
yarn: true

CHANGELOG.md

+21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
- Coming soon...
6+
7+
## 5.7.0-beta.0
8+
9+
- [core] ref: Use `Promise` as the interface, but `SyncPromise` as the implementation in all the places we need `thenable` API
10+
- [browser] fix: Capture only failed `console.assert` calls
11+
- [browser] ref: Major `TraceKit` and `GlobalHandlers` refactor
12+
- [browser] ref: Remove _all_ required IE10-11 polyfills
13+
- [browser] ref: Remove `Object.assign` method usage
14+
- [browser] ref: Remove `Number.isNaN` method usage
15+
- [browser] ref: Remove `includes` method usage
16+
- [browser] ci: Use Galaxy S9 Plus for Android 9
17+
- [browser] ci: Increase timeouts and retries between Travis and BrowserStack
18+
- [node] feat: Extract prototyped data in `extractUserData` (#2247)
19+
- [node] ref: Use domain Hub detection only in Node environment
20+
- [integrations] feat: Use `contexts` to handle ExtraErrorData (#2208)
21+
- [types] fix: Breadcrumb `data` needs to be an object
22+
- [utils] ref: Make `Event` instances somewhat serializeable
23+
324
## 5.6.3
425

526
- [browser] fix: Don't capture our own XHR events that somehow bubbled-up to global handler

CONTRIBUTING.md

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
This part of the documentation gives you a basic overview of how to help with the development of our `@sentry/*`
1111
packages contained in this repo.
1212

13+
## Community
14+
15+
The public-facing channels for support and development of Sentry SDKs can be found on [Discord](https://discord.gg/Ww9hbqr).
16+
1317
## Setting up an Environment
1418

1519
To run the test suite and run our code linter, node.js and yarn are required.

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
[![codecov](https://codecov.io/gh/getsentry/sentry-javascript/branch/master/graph/badge.svg)](https://codecov.io/gh/getsentry/sentry-javascript)
1010
[![npm version](https://img.shields.io/npm/v/@sentry/core.svg)](https://www.npmjs.com/package/@sentry/core)
1111
[![typedoc](https://img.shields.io/badge/docs-typedoc-blue.svg)](http://getsentry.github.io/sentry-javascript/)
12+
[![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr)
1213

1314
# Official Sentry SDKs for JavaScript
1415

codecov.yml

+15
Original file line numberDiff line numberDiff line change
@@ -1 +1,16 @@
11
comment: off
2+
codecov:
3+
notify:
4+
require_ci_to_pass: no
5+
6+
coverage:
7+
precision: 2
8+
round: down
9+
range: '0...1'
10+
status:
11+
project:
12+
default:
13+
enabled: no
14+
patch:
15+
default:
16+
enabled: no

lerna.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"lerna": "3.4.0",
3-
"version": "5.6.3",
3+
"version": "5.7.0-beta.0",
44
"packages": "packages/*",
55
"ignore": "raven-*",
66
"npmClient": "yarn",

packages/browser/package.json

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sentry/browser",
3-
"version": "5.6.3",
3+
"version": "5.7.0-beta.0",
44
"description": "Official Sentry SDK for browsers",
55
"repository": "git://github.com/getsentry/sentry-javascript.git",
66
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/browser",
@@ -16,9 +16,9 @@
1616
"access": "public"
1717
},
1818
"dependencies": {
19-
"@sentry/core": "5.6.2",
20-
"@sentry/types": "5.6.1",
21-
"@sentry/utils": "5.6.1",
19+
"@sentry/core": "5.7.0-beta.0",
20+
"@sentry/types": "5.7.0-beta.0",
21+
"@sentry/utils": "5.7.0-beta.0",
2222
"tslib": "^1.9.3"
2323
},
2424
"devDependencies": {
@@ -43,6 +43,7 @@
4343
"rollup": "^1.10.1",
4444
"rollup-plugin-commonjs": "^9.3.4",
4545
"rollup-plugin-license": "^0.8.1",
46+
"rollup-plugin-modify": "^3.0.0",
4647
"rollup-plugin-node-resolve": "^4.2.3",
4748
"rollup-plugin-terser": "^4.0.4",
4849
"rollup-plugin-typescript2": "^0.21.0",

packages/browser/rollup.config.js

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import typescript from 'rollup-plugin-typescript2';
33
import license from 'rollup-plugin-license';
44
import resolve from 'rollup-plugin-node-resolve';
55
import commonjs from 'rollup-plugin-commonjs';
6+
import modify from 'rollup-plugin-modify';
67

78
const commitHash = require('child_process')
89
.execSync('git rev-parse --short HEAD', { encoding: 'utf-8' })
@@ -46,6 +47,11 @@ const plugins = [
4647
mainFields: ['module'],
4748
}),
4849
commonjs(),
50+
modify({
51+
// It's very difficult to use Symbol without polyfilling in IE10 and still making TypeScript behave correctly.
52+
// Just remove it and leave this space in there, so that SourceMaps are still correct.
53+
"this[Symbol.toStringTag] = '[object SyncPromise]';": ' ',
54+
}),
4955
];
5056

5157
const bundleConfig = {

packages/browser/src/backend.ts

+23-96
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,8 @@
11
import { BaseBackend } from '@sentry/core';
22
import { Event, EventHint, Options, Severity, Transport } from '@sentry/types';
3-
import {
4-
addExceptionTypeValue,
5-
isDOMError,
6-
isDOMException,
7-
isError,
8-
isErrorEvent,
9-
isPlainObject,
10-
supportsFetch,
11-
SyncPromise,
12-
} from '@sentry/utils';
3+
import { addExceptionMechanism, supportsFetch, SyncPromise } from '@sentry/utils';
134

14-
import { eventFromPlainObject, eventFromStacktrace, prepareFramesForEvent } from './parsers';
15-
import { _computeStackTrace } from './tracekit';
5+
import { eventFromString, eventFromUnknownInput } from './eventbuilder';
166
import { FetchTransport, XHRTransport } from './transports';
177

188
/**
@@ -66,96 +56,33 @@ export class BrowserBackend extends BaseBackend<BrowserOptions> {
6656
/**
6757
* @inheritDoc
6858
*/
69-
public eventFromException(exception: any, hint?: EventHint): SyncPromise<Event> {
70-
let event: Event;
71-
72-
if (isErrorEvent(exception as ErrorEvent) && (exception as ErrorEvent).error) {
73-
// If it is an ErrorEvent with `error` property, extract it to get actual Error
74-
const errorEvent = exception as ErrorEvent;
75-
exception = errorEvent.error; // tslint:disable-line:no-parameter-reassignment
76-
event = eventFromStacktrace(_computeStackTrace(exception as Error));
77-
return SyncPromise.resolve(this._buildEvent(event, hint));
78-
}
79-
if (isDOMError(exception as DOMError) || isDOMException(exception as DOMException)) {
80-
// If it is a DOMError or DOMException (which are legacy APIs, but still supported in some browsers)
81-
// then we just extract the name and message, as they don't provide anything else
82-
// https://developer.mozilla.org/en-US/docs/Web/API/DOMError
83-
// https://developer.mozilla.org/en-US/docs/Web/API/DOMException
84-
const domException = exception as DOMException;
85-
const name = domException.name || (isDOMError(domException) ? 'DOMError' : 'DOMException');
86-
const message = domException.message ? `${name}: ${domException.message}` : name;
87-
88-
return this.eventFromMessage(message, Severity.Error, hint).then(messageEvent => {
89-
addExceptionTypeValue(messageEvent, message);
90-
return SyncPromise.resolve(this._buildEvent(messageEvent, hint));
91-
});
92-
}
93-
if (isError(exception as Error)) {
94-
// we have a real Error object, do nothing
95-
event = eventFromStacktrace(_computeStackTrace(exception as Error));
96-
return SyncPromise.resolve(this._buildEvent(event, hint));
97-
}
98-
if (isPlainObject(exception as {}) && hint && hint.syntheticException) {
99-
// If it is plain Object, serialize it manually and extract options
100-
// This will allow us to group events based on top-level keys
101-
// which is much better than creating new group when any key/value change
102-
const objectException = exception as {};
103-
event = eventFromPlainObject(objectException, hint.syntheticException);
104-
addExceptionTypeValue(event, 'Custom Object', undefined, {
105-
handled: true,
106-
synthetic: true,
107-
type: 'generic',
108-
});
109-
event.level = Severity.Error;
110-
return SyncPromise.resolve(this._buildEvent(event, hint));
111-
}
112-
113-
// If none of previous checks were valid, then it means that
114-
// it's not a DOMError/DOMException
115-
// it's not a plain Object
116-
// it's not a valid ErrorEvent (one with an error property)
117-
// it's not an Error
118-
// So bail out and capture it as a simple message:
119-
const stringException = exception as string;
120-
return this.eventFromMessage(stringException, undefined, hint).then(messageEvent => {
121-
addExceptionTypeValue(messageEvent, `${stringException}`, undefined, {
122-
handled: true,
123-
synthetic: true,
124-
type: 'generic',
125-
});
126-
messageEvent.level = Severity.Error;
127-
return SyncPromise.resolve(this._buildEvent(messageEvent, hint));
59+
public eventFromException(exception: any, hint?: EventHint): Promise<Event> {
60+
const syntheticException = (hint && hint.syntheticException) || undefined;
61+
const event = eventFromUnknownInput(exception, syntheticException, {
62+
attachStacktrace: this._options.attachStacktrace,
12863
});
64+
addExceptionMechanism(event, {
65+
handled: true,
66+
type: 'generic',
67+
});
68+
event.level = Severity.Error;
69+
if (hint && hint.event_id) {
70+
event.event_id = hint.event_id;
71+
}
72+
return SyncPromise.resolve(event);
12973
}
130-
131-
/**
132-
* This is an internal helper function that creates an event.
133-
*/
134-
private _buildEvent(event: Event, hint?: EventHint): Event {
135-
return {
136-
...event,
137-
event_id: hint && hint.event_id,
138-
};
139-
}
140-
14174
/**
14275
* @inheritDoc
14376
*/
144-
public eventFromMessage(message: string, level: Severity = Severity.Info, hint?: EventHint): SyncPromise<Event> {
145-
const event: Event = {
146-
event_id: hint && hint.event_id,
147-
level,
148-
message,
149-
};
150-
151-
if (this._options.attachStacktrace && hint && hint.syntheticException) {
152-
const stacktrace = _computeStackTrace(hint.syntheticException);
153-
const frames = prepareFramesForEvent(stacktrace.stack);
154-
event.stacktrace = {
155-
frames,
156-
};
77+
public eventFromMessage(message: string, level: Severity = Severity.Info, hint?: EventHint): Promise<Event> {
78+
const syntheticException = (hint && hint.syntheticException) || undefined;
79+
const event = eventFromString(message, syntheticException, {
80+
attachStacktrace: this._options.attachStacktrace,
81+
});
82+
event.level = level;
83+
if (hint && hint.event_id) {
84+
event.event_id = hint.event_id;
15785
}
158-
15986
return SyncPromise.resolve(event);
16087
}
16188
}

packages/browser/src/client.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { API, BaseClient, Scope } from '@sentry/core';
22
import { DsnLike, Event, EventHint } from '@sentry/types';
3-
import { getGlobalObject, logger, SyncPromise } from '@sentry/utils';
3+
import { getGlobalObject, logger } from '@sentry/utils';
44

55
import { BrowserBackend, BrowserOptions } from './backend';
66
import { SDK_NAME, SDK_VERSION } from './version';
@@ -51,7 +51,7 @@ export class BrowserClient extends BaseClient<BrowserBackend, BrowserOptions> {
5151
/**
5252
* @inheritDoc
5353
*/
54-
protected _prepareEvent(event: Event, scope?: Scope, hint?: EventHint): SyncPromise<Event | null> {
54+
protected _prepareEvent(event: Event, scope?: Scope, hint?: EventHint): Promise<Event | null> {
5555
event.platform = event.platform || 'javascript';
5656
event.sdk = {
5757
...event.sdk,

packages/browser/src/eventbuilder.ts

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { Event } from '@sentry/types';
2+
import {
3+
addExceptionMechanism,
4+
addExceptionTypeValue,
5+
isDOMError,
6+
isDOMException,
7+
isError,
8+
isErrorEvent,
9+
isEvent,
10+
isPlainObject,
11+
} from '@sentry/utils';
12+
13+
import { eventFromPlainObject, eventFromStacktrace, prepareFramesForEvent } from './parsers';
14+
import { computeStackTrace } from './tracekit';
15+
16+
/** JSDoc */
17+
export function eventFromUnknownInput(
18+
exception: unknown,
19+
syntheticException?: Error,
20+
options: {
21+
rejection?: boolean;
22+
attachStacktrace?: boolean;
23+
} = {},
24+
): Event {
25+
let event: Event;
26+
27+
if (isErrorEvent(exception as ErrorEvent) && (exception as ErrorEvent).error) {
28+
// If it is an ErrorEvent with `error` property, extract it to get actual Error
29+
const errorEvent = exception as ErrorEvent;
30+
exception = errorEvent.error; // tslint:disable-line:no-parameter-reassignment
31+
event = eventFromStacktrace(computeStackTrace(exception as Error));
32+
return event;
33+
}
34+
if (isDOMError(exception as DOMError) || isDOMException(exception as DOMException)) {
35+
// If it is a DOMError or DOMException (which are legacy APIs, but still supported in some browsers)
36+
// then we just extract the name and message, as they don't provide anything else
37+
// https://developer.mozilla.org/en-US/docs/Web/API/DOMError
38+
// https://developer.mozilla.org/en-US/docs/Web/API/DOMException
39+
const domException = exception as DOMException;
40+
const name = domException.name || (isDOMError(domException) ? 'DOMError' : 'DOMException');
41+
const message = domException.message ? `${name}: ${domException.message}` : name;
42+
43+
event = eventFromString(message, syntheticException, options);
44+
addExceptionTypeValue(event, message);
45+
return event;
46+
}
47+
if (isError(exception as Error)) {
48+
// we have a real Error object, do nothing
49+
event = eventFromStacktrace(computeStackTrace(exception as Error));
50+
return event;
51+
}
52+
if (isPlainObject(exception) || isEvent(exception)) {
53+
// If it is plain Object or Event, serialize it manually and extract options
54+
// This will allow us to group events based on top-level keys
55+
// which is much better than creating new group when any key/value change
56+
const objectException = exception as {};
57+
event = eventFromPlainObject(objectException, syntheticException, options.rejection);
58+
addExceptionMechanism(event, {
59+
synthetic: true,
60+
});
61+
return event;
62+
}
63+
64+
// If none of previous checks were valid, then it means that it's not:
65+
// - an instance of DOMError
66+
// - an instance of DOMException
67+
// - an instance of Event
68+
// - an instance of Error
69+
// - a valid ErrorEvent (one with an error property)
70+
// - a plain Object
71+
//
72+
// So bail out and capture it as a simple message:
73+
event = eventFromString(exception as string, syntheticException, options);
74+
addExceptionTypeValue(event, `${exception}`, undefined);
75+
addExceptionMechanism(event, {
76+
synthetic: true,
77+
});
78+
79+
return event;
80+
}
81+
82+
// this._options.attachStacktrace
83+
/** JSDoc */
84+
export function eventFromString(
85+
input: string,
86+
syntheticException?: Error,
87+
options: {
88+
attachStacktrace?: boolean;
89+
} = {},
90+
): Event {
91+
const event: Event = {
92+
message: input,
93+
};
94+
95+
if (options.attachStacktrace && syntheticException) {
96+
const stacktrace = computeStackTrace(syntheticException);
97+
const frames = prepareFramesForEvent(stacktrace.stack);
98+
event.stacktrace = {
99+
frames,
100+
};
101+
}
102+
103+
return event;
104+
}

0 commit comments

Comments
 (0)