Skip to content

Commit 437300b

Browse files
kamilogorekHazAT
authored andcommitted
[v5] Major utils rewrite (#1902)
* ref: Move ExtendedError to a types package * ref: Remove assign util in favor of Object.assign * ref: Pass Event to sendEvent instead of just a body * ref: Remove isArray and isNaN utils * ref: Rewrite normalization and removed unused utils * Utils rewamp changelog
1 parent e91b85a commit 437300b

Some content is hidden

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

44 files changed

+612
-902
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@ since we removed some methods from the public API and removed some classes from
1515
- **breaking** [core] ref: Use `SyncPromise` internally, this reduces memory pressure by a lot.
1616
- **breaking** [browser] ref: Removed `BrowserBackend` from default export.
1717
- **breaking** [node] ref: Removed `BrowserBackend` from default export.
18+
- ref: Move internal `ExtendedError` to a types package
19+
- **breaking** [core] ref: Pass `Event` to `sendEvent` instead of already stringified data
20+
- [utils] feat: Introduce `isSyntheticEvent` util
21+
- **breaking** [utils] ref: remove `isArray` util in favor of `Array.isArray`
22+
- **breaking** [utils] ref: Remove `isNaN` util in favor of `Number.isNaN`
23+
- **breaking** [utils] ref: Remove `isFunction` util in favor of `typeof === 'function'`
24+
- **breaking** [utils] ref: Remove `isUndefined` util in favor of `=== void 0`
25+
- **breaking** [utils] ref: Remove `assign` util in favor of `Object.assign`
26+
- **breaking** [utils] ref: Remove `includes` util in favor of native `includes`
27+
- **breaking** [utils] ref: Rename `serializeKeysToEventMessage` to `keysToEventMessage`
28+
- **breaking** [utils] ref: Rename `limitObjectDepthToSize` to `normalizeToSize` and rewrite its internals
29+
- **breaking** [utils] ref: Rename `safeNormalize` to `normalize` and rewrite its internals
30+
- **breaking** [utils] ref: Remove `serialize`, `deserialize`, `clone` and `serializeObject` functions
31+
- **breaking** [utils] ref: Rewrite normalization functions by removing most of them and leaving just `normalize` and `normalizeToSize`
1832

1933
## 4.6.3
2034

packages/browser/src/integrations/breadcrumbs.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { API, getCurrentHub } from '@sentry/core';
22
import { Breadcrumb, BreadcrumbHint, Integration, Severity } from '@sentry/types';
3-
import { isFunction, isString } from '@sentry/utils/is';
3+
import { isString } from '@sentry/utils/is';
44
import { logger } from '@sentry/utils/logger';
55
import { getEventDescription, getGlobalObject, parseUrl } from '@sentry/utils/misc';
6-
import { deserialize, fill, serializeObject } from '@sentry/utils/object';
7-
import { includes, safeJoin } from '@sentry/utils/string';
6+
import { fill, normalize } from '@sentry/utils/object';
7+
import { safeJoin } from '@sentry/utils/string';
88
import { supportsBeacon, supportsHistory, supportsNativeFetch } from '@sentry/utils/supports';
99
import { BrowserClient } from '../client';
1010
import { breadcrumbEventHandler, keypressEventHandler, wrap } from './helpers';
@@ -87,7 +87,7 @@ export class Breadcrumbs implements Integration {
8787
const filterUrl = new API(dsn).getStoreEndpoint();
8888
// if Sentry key appears in URL, don't capture it as a request
8989
// but rather as our own 'sentry' type breadcrumb
90-
if (filterUrl && includes(url, filterUrl)) {
90+
if (filterUrl && url.includes(filterUrl)) {
9191
addSentryBreadcrumb(data);
9292
return result;
9393
}
@@ -132,7 +132,7 @@ export class Breadcrumbs implements Integration {
132132
category: 'console',
133133
data: {
134134
extra: {
135-
arguments: serializeObject(args, 2),
135+
arguments: normalize(args, 2),
136136
},
137137
logger: 'console',
138138
},
@@ -143,7 +143,7 @@ export class Breadcrumbs implements Integration {
143143
if (level === 'assert') {
144144
if (args[0] === false) {
145145
breadcrumbData.message = `Assertion failed: ${safeJoin(args.slice(1), ' ') || 'console.assert'}`;
146-
breadcrumbData.data.extra.arguments = serializeObject(args.slice(1), 2);
146+
breadcrumbData.data.extra.arguments = normalize(args.slice(1), 2);
147147
}
148148
}
149149

@@ -205,7 +205,7 @@ export class Breadcrumbs implements Integration {
205205
const filterUrl = new API(dsn).getStoreEndpoint();
206206
// if Sentry key appears in URL, don't capture it as a request
207207
// but rather as our own 'sentry' type breadcrumb
208-
if (filterUrl && includes(url, filterUrl)) {
208+
if (filterUrl && url.includes(filterUrl)) {
209209
if (method === 'POST' && args[1] && args[1].body) {
210210
addSentryBreadcrumb(args[1].body);
211211
}
@@ -338,7 +338,7 @@ export class Breadcrumbs implements Integration {
338338
/** JSDoc */
339339
function wrapProp(prop: string, xhr: XMLHttpRequest): void {
340340
// TODO: Fix XHR types
341-
if (prop in xhr && isFunction((xhr as { [key: string]: any })[prop])) {
341+
if (prop in xhr && typeof (xhr as { [key: string]: any })[prop] === 'function') {
342342
fill(xhr, prop, original =>
343343
wrap(original, {
344344
mechanism: {
@@ -372,7 +372,7 @@ export class Breadcrumbs implements Integration {
372372
const filterUrl = new API(dsn).getStoreEndpoint();
373373
// if Sentry key appears in URL, don't capture it as a request
374374
// but rather as our own 'sentry' type breadcrumb
375-
if (isString(url) && (filterUrl && includes(url, filterUrl))) {
375+
if (isString(url) && (filterUrl && url.includes(filterUrl))) {
376376
this.__sentry_own_request__ = true;
377377
}
378378
}
@@ -424,7 +424,7 @@ export class Breadcrumbs implements Integration {
424424
wrapProp(prop, xhr);
425425
});
426426

427-
if ('onreadystatechange' in xhr && isFunction(xhr.onreadystatechange)) {
427+
if ('onreadystatechange' in xhr && typeof xhr.onreadystatechange === 'function') {
428428
fill(xhr, 'onreadystatechange', function(original: () => void): void {
429429
return wrap(
430430
original,
@@ -496,7 +496,7 @@ export class Breadcrumbs implements Integration {
496496
function addSentryBreadcrumb(serializedData: string): void {
497497
// There's always something that can go wrong with deserialization...
498498
try {
499-
const event: { [key: string]: any } = deserialize(serializedData);
499+
const event: { [key: string]: any } = JSON.parse(serializedData);
500500
Breadcrumbs.addBreadcrumb(
501501
{
502502
category: 'sentry',

packages/browser/src/integrations/globalhandlers.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { getCurrentHub } from '@sentry/core';
22
import { Event, Integration } from '@sentry/types';
33
import { logger } from '@sentry/utils/logger';
4-
import { safeNormalize, serialize } from '@sentry/utils/object';
54
import { truncate } from '@sentry/utils/string';
65
import { addExceptionTypeValue, eventFromStacktrace } from '../parsers';
76
import {
@@ -114,10 +113,7 @@ export class GlobalHandlers implements Integration {
114113
},
115114
};
116115

117-
const fallbackValue =
118-
typeof stacktrace.original !== 'undefined'
119-
? `${truncate(serialize(safeNormalize(stacktrace.original)), 300)}`
120-
: '';
116+
const fallbackValue = stacktrace.original ? truncate(JSON.stringify(stacktrace.original), 300) : '';
121117
const fallbackType = stacktrace.mechanism === 'onunhandledrejection' ? 'UnhandledRejection' : 'Error';
122118

123119
// This makes sure we have type/value in every exception

packages/browser/src/integrations/helpers.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { captureException, getCurrentHub, withScope } from '@sentry/core';
22
import { Event as SentryEvent, Mechanism, WrappedFunction } from '@sentry/types';
3-
import { isFunction } from '@sentry/utils/is';
43
import { htmlTreeAsString } from '@sentry/utils/misc';
5-
import { serializeObject } from '@sentry/utils/object';
4+
import { normalize } from '@sentry/utils/object';
65

76
const debounceDuration: number = 1000;
87
let keypressTimeout: number | undefined;
@@ -42,7 +41,8 @@ export function wrap(
4241
} = {},
4342
before?: WrappedFunction,
4443
): any {
45-
if (!isFunction(fn)) {
44+
// tslint:disable-next-line:strict-type-predicates
45+
if (typeof fn !== 'function') {
4646
return fn;
4747
}
4848

@@ -64,7 +64,8 @@ export function wrap(
6464
}
6565

6666
const sentryWrapped: WrappedFunction = function(this: any): void {
67-
if (before && isFunction(before)) {
67+
// tslint:disable-next-line:strict-type-predicates
68+
if (before && typeof before === 'function') {
6869
before.apply(this, arguments);
6970
}
7071

@@ -96,7 +97,7 @@ export function wrap(
9697

9798
processedEvent.extra = {
9899
...processedEvent.extra,
99-
arguments: serializeObject(args, 2),
100+
arguments: normalize(args, 2),
100101
};
101102

102103
return processedEvent;

packages/browser/src/integrations/linkederrors.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,11 @@
11
import { addGlobalEventProcessor, getCurrentHub } from '@sentry/core';
2-
import { Event, EventHint, Exception, Integration } from '@sentry/types';
2+
import { Event, EventHint, Exception, ExtendedError, Integration } from '@sentry/types';
33
import { exceptionFromStacktrace } from '../parsers';
44
import { computeStackTrace } from '../tracekit';
55

66
const DEFAULT_KEY = 'cause';
77
const DEFAULT_LIMIT = 5;
88

9-
/**
10-
* Just an Error object with arbitrary attributes attached to it.
11-
*/
12-
interface ExtendedError extends Error {
13-
[key: string]: any;
14-
}
15-
169
/** Adds SDK info to an event. */
1710
export class LinkedErrors implements Integration {
1811
/**

packages/browser/src/integrations/pluggable/vue.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { captureException, getCurrentHub, withScope } from '@sentry/core';
22
import { Event, Integration } from '@sentry/types';
3-
import { isPlainObject, isUndefined } from '@sentry/utils/is';
3+
import { isPlainObject } from '@sentry/utils/is';
44
import { logger } from '@sentry/utils/logger';
55
import { getGlobalObject } from '@sentry/utils/misc';
66

@@ -82,7 +82,7 @@ export class Vue implements Integration {
8282
}
8383
}
8484

85-
if (!isUndefined(info)) {
85+
if (info !== void 0) {
8686
metadata.lifecycleHook = info;
8787
}
8888

packages/browser/src/parsers.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Event, Exception, StackFrame } from '@sentry/types';
2-
import { limitObjectDepthToSize, serializeKeysToEventMessage } from '@sentry/utils/object';
3-
import { includes } from '@sentry/utils/string';
2+
import { normalizeToSize } from '@sentry/utils/object';
3+
import { keysToEventMessage } from '@sentry/utils/string';
44
import { md5 } from './md5';
55
import { computeStackTrace, StackFrame as TraceKitStackFrame, StackTrace as TraceKitStackTrace } from './tracekit';
66

@@ -38,10 +38,10 @@ export function eventFromPlainObject(exception: {}, syntheticException: Error |
3838
const exceptionKeys = Object.keys(exception).sort();
3939
const event: Event = {
4040
extra: {
41-
__serialized__: limitObjectDepthToSize(exception),
41+
__serialized__: normalizeToSize(exception),
4242
},
4343
fingerprint: [md5(exceptionKeys.join(''))],
44-
message: `Non-Error exception captured with keys: ${serializeKeysToEventMessage(exceptionKeys)}`,
44+
message: `Non-Error exception captured with keys: ${keysToEventMessage(exceptionKeys)}`,
4545
};
4646

4747
if (syntheticException) {
@@ -82,12 +82,12 @@ export function prepareFramesForEvent(stack: TraceKitStackFrame[]): StackFrame[]
8282
const lastFrameFunction = localStack[localStack.length - 1].func || '';
8383

8484
// If stack starts with one of our API calls, remove it (starts, meaning it's the top of the stack - aka last call)
85-
if (includes(firstFrameFunction, 'captureMessage') || includes(firstFrameFunction, 'captureException')) {
85+
if (firstFrameFunction.includes('captureMessage') || firstFrameFunction.includes('captureException')) {
8686
localStack = localStack.slice(1);
8787
}
8888

8989
// If stack ends with one of our internal API calls, remove it (ends, meaning it's the bottom of the stack - aka top-most call)
90-
if (includes(lastFrameFunction, 'sentryWrapped')) {
90+
if (lastFrameFunction.includes('sentryWrapped')) {
9191
localStack = localStack.slice(0, -1);
9292
}
9393

packages/browser/src/tracekit.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// tslint:disable
22

3-
import { isUndefined, isError, isErrorEvent } from '@sentry/utils/is';
3+
import { isError, isErrorEvent } from '@sentry/utils/is';
44
import { getGlobalObject } from '@sentry/utils/misc';
55

66
/**
@@ -712,7 +712,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
712712
for (var i = 0; i < maxLines; ++i) {
713713
line = source[lineNo - i] + line;
714714

715-
if (!isUndefined(line)) {
715+
if (line !== void 0) {
716716
if ((m = reGuessFunction.exec(line))) {
717717
return m[1];
718718
} else if ((m = reFunctionArgNames.exec(line))) {
@@ -751,7 +751,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
751751
line -= 1; // convert to 0-based index
752752

753753
for (var i = start; i < end; ++i) {
754-
if (!isUndefined(source[i])) {
754+
if (source[i] !== void 0) {
755755
context.push(source[i]);
756756
}
757757
}
@@ -845,7 +845,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
845845
* @memberof TraceKit.computeStackTrace
846846
*/
847847
function findSourceByFunctionBody(func: any) {
848-
if (isUndefined(window && window.document)) {
848+
if (window && window.document === void 0) {
849849
return;
850850
}
851851

@@ -1005,7 +1005,7 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
10051005
// NOTE: It's messing out our integration tests in Karma, let's see if we can live with it – Kamil
10061006
// parts[4] = submatch[2];
10071007
// parts[5] = null; // no column when eval
1008-
} else if (i === 0 && !parts[5] && !isUndefined(ex.columnNumber)) {
1008+
} else if (i === 0 && !parts[5] && ex.columnNumber !== void 0) {
10091009
// FireFox uses this awesome columnNumber property for its top frame
10101010
// Also note, Firefox's column number is 0-based and everything else expects 1-based,
10111011
// so adding 1

packages/browser/src/transports/base.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { API } from '@sentry/core';
2-
import { Response, Transport, TransportOptions } from '@sentry/types';
2+
import { Event, Response, Transport, TransportOptions } from '@sentry/types';
33
import { SentryError } from '@sentry/utils/error';
44
import { PromiseBuffer } from '@sentry/utils/promisebuffer';
55

@@ -20,7 +20,7 @@ export abstract class BaseTransport implements Transport {
2020
/**
2121
* @inheritDoc
2222
*/
23-
public async sendEvent(_: string): Promise<Response> {
23+
public async sendEvent(_: Event): Promise<Response> {
2424
throw new SentryError('Transport Class has to implement `sendEvent` method');
2525
}
2626

packages/browser/src/transports/beacon.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Response, Status } from '@sentry/types';
1+
import { Event, Response, Status } from '@sentry/types';
22
import { getGlobalObject } from '@sentry/utils/misc';
33
import { BaseTransport } from './base';
44

@@ -9,8 +9,8 @@ export class BeaconTransport extends BaseTransport {
99
/**
1010
* @inheritDoc
1111
*/
12-
public async sendEvent(body: string): Promise<Response> {
13-
const result = global.navigator.sendBeacon(this.url, body);
12+
public async sendEvent(event: Event): Promise<Response> {
13+
const result = global.navigator.sendBeacon(this.url, JSON.stringify(event));
1414

1515
return this.buffer.add(
1616
Promise.resolve({

packages/browser/src/transports/fetch.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Response, Status } from '@sentry/types';
1+
import { Event, Response, Status } from '@sentry/types';
22
import { getGlobalObject } from '@sentry/utils/misc';
33
import { supportsReferrerPolicy } from '@sentry/utils/supports';
44
import { BaseTransport } from './base';
@@ -10,9 +10,9 @@ export class FetchTransport extends BaseTransport {
1010
/**
1111
* @inheritDoc
1212
*/
13-
public async sendEvent(body: string): Promise<Response> {
13+
public async sendEvent(event: Event): Promise<Response> {
1414
const defaultOptions: RequestInit = {
15-
body,
15+
body: JSON.stringify(event),
1616
method: 'POST',
1717
// Despite all stars in the sky saying that Edge supports old draft syntax, aka 'never', 'always', 'origin' and 'default
1818
// https://caniuse.com/#feat=referrer-policy

packages/browser/src/transports/xhr.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { Response, Status } from '@sentry/types';
1+
import { Event, Response, Status } from '@sentry/types';
22
import { BaseTransport } from './base';
33

44
/** `XHR` based transport */
55
export class XHRTransport extends BaseTransport {
66
/**
77
* @inheritDoc
88
*/
9-
public async sendEvent(body: string): Promise<Response> {
9+
public async sendEvent(event: Event): Promise<Response> {
1010
return this.buffer.add(
1111
new Promise<Response>((resolve, reject) => {
1212
const request = new XMLHttpRequest();
@@ -26,7 +26,7 @@ export class XHRTransport extends BaseTransport {
2626
};
2727

2828
request.open('POST', this.url);
29-
request.send(body);
29+
request.send(JSON.stringify(event));
3030
}),
3131
);
3232
}

packages/browser/test/integration/common.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ function initSDK() {
107107
// stub transport so we don't actually transmit any data
108108
function DummyTransport() {}
109109
DummyTransport.prototype.sendEvent = function(event) {
110-
sentryData.push(JSON.parse(event));
110+
sentryData.push(event);
111111
done(sentryData);
112112
return Promise.resolve({
113113
status: 'success',

packages/browser/test/integrations/linkederrors.test.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1+
import { ExtendedError } from '@sentry/types';
12
import { expect } from 'chai';
23
import { stub } from 'sinon';
34
import { BrowserBackend } from '../../src/backend';
45
import { LinkedErrors } from '../../src/integrations/linkederrors';
56

67
let linkedErrors: LinkedErrors;
78

8-
interface ExtendedError extends Error {
9-
[key: string]: any;
10-
}
11-
129
describe('LinkedErrors', () => {
1310
beforeEach(() => {
1411
linkedErrors = new LinkedErrors();

packages/browser/test/mocks/simpletransport.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { Response, Status } from '../../src';
1+
import { Event, Response, Status } from '../../src';
22
import { BaseTransport } from '../../src/transports';
33

44
export class SimpleTransport extends BaseTransport {
5-
public async sendEvent(_: string): Promise<Response> {
5+
public async sendEvent(_: Event): Promise<Response> {
66
return this.buffer.add(
77
Promise.resolve({
88
status: Status.fromHttpCode(200),

0 commit comments

Comments
 (0)