Skip to content

Commit eae2f9a

Browse files
AbhiPrasadonurtemizkan
authored andcommitted
ref(browser): Extract getReportDialogEndpoint from API class (#4274)
Although this is a public API, we can extract it from the API class as it should only be used by browser.
1 parent 6d9b7aa commit eae2f9a

File tree

4 files changed

+125
-81
lines changed

4 files changed

+125
-81
lines changed

packages/browser/src/helpers.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { API, captureException, withScope } from '@sentry/core';
1+
import { captureException, getReportDialogEndpoint, withScope } from '@sentry/core';
22
import { DsnLike, Event as SentryEvent, Mechanism, Scope, WrappedFunction } from '@sentry/types';
33
import { addExceptionMechanism, addExceptionTypeValue, getGlobalObject, logger } from '@sentry/utils';
44

@@ -210,7 +210,7 @@ export function injectReportDialog(options: ReportDialogOptions = {}): void {
210210

211211
const script = global.document.createElement('script');
212212
script.async = true;
213-
script.src = new API(options.dsn).getReportDialogEndpoint(options);
213+
script.src = getReportDialogEndpoint(options.dsn, options);
214214

215215
if (options.onLoad) {
216216
// eslint-disable-next-line @typescript-eslint/unbound-method

packages/core/src/api.ts

+44-42
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@ export class API {
4242
/** Returns the prefix to construct Sentry ingestion API endpoints. */
4343
public getBaseApiEndpoint(): string {
4444
const dsn = this.getDsn();
45-
const protocol = dsn.protocol ? `${dsn.protocol}:` : '';
46-
const port = dsn.port ? `:${dsn.port}` : '';
47-
return `${protocol}//${dsn.host}${port}${dsn.path ? `/${dsn.path}` : ''}/api/`;
45+
return getBaseApiEndpoint(dsn);
4846
}
4947

5048
/** Returns the store endpoint URL. */
@@ -99,45 +97,6 @@ export class API {
9997
};
10098
}
10199

102-
/** Returns the url to the report dialog endpoint. */
103-
public getReportDialogEndpoint(
104-
dialogOptions: {
105-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
106-
[key: string]: any;
107-
user?: { name?: string; email?: string };
108-
} = {},
109-
): string {
110-
const dsn = this.getDsn();
111-
const endpoint = `${this.getBaseApiEndpoint()}embed/error-page/`;
112-
113-
const encodedOptions = [];
114-
encodedOptions.push(`dsn=${dsn.toString()}`);
115-
for (const key in dialogOptions) {
116-
if (key === 'dsn') {
117-
continue;
118-
}
119-
120-
if (key === 'user') {
121-
if (!dialogOptions.user) {
122-
continue;
123-
}
124-
if (dialogOptions.user.name) {
125-
encodedOptions.push(`name=${encodeURIComponent(dialogOptions.user.name)}`);
126-
}
127-
if (dialogOptions.user.email) {
128-
encodedOptions.push(`email=${encodeURIComponent(dialogOptions.user.email)}`);
129-
}
130-
} else {
131-
encodedOptions.push(`${encodeURIComponent(key)}=${encodeURIComponent(dialogOptions[key] as string)}`);
132-
}
133-
}
134-
if (encodedOptions.length) {
135-
return `${endpoint}?${encodedOptions.join('&')}`;
136-
}
137-
138-
return endpoint;
139-
}
140-
141100
/** Returns the envelope endpoint URL. */
142101
private _getEnvelopeEndpoint(): string {
143102
return this._getIngestEndpoint('envelope');
@@ -165,3 +124,46 @@ export class API {
165124
return urlEncode(auth);
166125
}
167126
}
127+
128+
/** Returns the prefix to construct Sentry ingestion API endpoints. */
129+
function getBaseApiEndpoint(dsn: Dsn): string {
130+
const protocol = dsn.protocol ? `${dsn.protocol}:` : '';
131+
const port = dsn.port ? `:${dsn.port}` : '';
132+
return `${protocol}//${dsn.host}${port}${dsn.path ? `/${dsn.path}` : ''}/api/`;
133+
}
134+
135+
/** Returns the url to the report dialog endpoint. */
136+
export function getReportDialogEndpoint(
137+
dsnLike: DsnLike,
138+
dialogOptions: {
139+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
140+
[key: string]: any;
141+
user?: { name?: string; email?: string };
142+
},
143+
): string {
144+
const dsn = new Dsn(dsnLike);
145+
const endpoint = `${getBaseApiEndpoint(dsn)}embed/error-page/`;
146+
147+
let encodedOptions = `dsn=${dsn.toString()}`;
148+
for (const key in dialogOptions) {
149+
if (key === 'dsn') {
150+
continue;
151+
}
152+
153+
if (key === 'user') {
154+
if (!dialogOptions.user) {
155+
continue;
156+
}
157+
if (dialogOptions.user.name) {
158+
encodedOptions += `&name=${encodeURIComponent(dialogOptions.user.name)}`;
159+
}
160+
if (dialogOptions.user.email) {
161+
encodedOptions += `&email=${encodeURIComponent(dialogOptions.user.email)}`;
162+
}
163+
} else {
164+
encodedOptions += `&${encodeURIComponent(key)}=${encodeURIComponent(dialogOptions[key] as string)}`;
165+
}
166+
}
167+
168+
return `${endpoint}?${encodedOptions}`;
169+
}

packages/core/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export {
1414
withScope,
1515
} from '@sentry/minimal';
1616
export { addGlobalEventProcessor, getCurrentHub, getHubFromCarrier, Hub, makeMain, Scope } from '@sentry/hub';
17-
export { API } from './api';
17+
export { API, getReportDialogEndpoint } from './api';
1818
export { BaseClient } from './baseclient';
1919
export { BackendClass, BaseBackend } from './basebackend';
2020
export { eventToSentryRequest, sessionToSentryRequest } from './request';

packages/core/test/lib/api.test.ts

+78-36
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Dsn } from '@sentry/utils';
22

3-
import { API } from '../../src/api';
3+
import { API, getReportDialogEndpoint } from '../../src/api';
44

55
const ingestDsn = 'https://[email protected]:1234/subpath/123';
66
const dsnPublic = 'https://[email protected]:1234/subpath/123';
@@ -37,44 +37,86 @@ describe('API', () => {
3737
});
3838
});
3939

40-
test('getReportDialogEndpoint', () => {
41-
expect(new API(ingestDsn).getReportDialogEndpoint({})).toEqual(
42-
'https://xxxx.ingest.sentry.io:1234/subpath/api/embed/error-page/?dsn=https://[email protected]:1234/subpath/123',
43-
);
44-
45-
expect(new API(dsnPublic).getReportDialogEndpoint({})).toEqual(
46-
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://[email protected]:1234/subpath/123',
47-
);
48-
expect(
49-
new API(dsnPublic).getReportDialogEndpoint({
50-
eventId: 'abc',
51-
testy: '2',
52-
}),
53-
).toEqual(
54-
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://[email protected]:1234/subpath/123&eventId=abc&testy=2',
55-
);
56-
57-
expect(
58-
new API(dsnPublic).getReportDialogEndpoint({
59-
eventId: 'abc',
60-
user: {
61-
email: 'email',
62-
name: 'yo',
40+
describe('getReportDialogEndpoint', () => {
41+
test.each([
42+
[
43+
'with Ingest DSN',
44+
ingestDsn,
45+
{},
46+
'https://xxxx.ingest.sentry.io:1234/subpath/api/embed/error-page/?dsn=https://[email protected]:1234/subpath/123',
47+
],
48+
[
49+
'with Public DSN',
50+
dsnPublic,
51+
{},
52+
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://[email protected]:1234/subpath/123',
53+
],
54+
[
55+
'with Public DSN and dynamic options',
56+
dsnPublic,
57+
{ eventId: 'abc', testy: '2' },
58+
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://[email protected]:1234/subpath/123&eventId=abc&testy=2',
59+
],
60+
[
61+
'with Public DSN, dynamic options and user name and email',
62+
dsnPublic,
63+
{
64+
eventId: 'abc',
65+
user: {
66+
email: 'email',
67+
name: 'yo',
68+
},
6369
},
64-
}),
65-
).toEqual(
66-
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://[email protected]:1234/subpath/123&eventId=abc&name=yo&email=email',
67-
);
68-
69-
expect(
70-
new API(dsnPublic).getReportDialogEndpoint({
71-
eventId: 'abc',
72-
user: undefined,
73-
}),
74-
).toEqual(
75-
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://[email protected]:1234/subpath/123&eventId=abc',
70+
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://[email protected]:1234/subpath/123&eventId=abc&name=yo&email=email',
71+
],
72+
[
73+
'with Public DSN and user name',
74+
dsnPublic,
75+
{
76+
user: {
77+
name: 'yo',
78+
},
79+
},
80+
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://[email protected]:1234/subpath/123&name=yo',
81+
],
82+
[
83+
'with Public DSN and user email',
84+
dsnPublic,
85+
{
86+
user: {
87+
email: 'email',
88+
},
89+
},
90+
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://[email protected]:1234/subpath/123&email=email',
91+
],
92+
[
93+
'with Public DSN, dynamic options and undefined user',
94+
dsnPublic,
95+
{
96+
eventId: 'abc',
97+
user: undefined,
98+
},
99+
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://[email protected]:1234/subpath/123&eventId=abc',
100+
],
101+
[
102+
'with Public DSN and undefined user',
103+
dsnPublic,
104+
{ user: undefined },
105+
'https://sentry.io:1234/subpath/api/embed/error-page/?dsn=https://[email protected]:1234/subpath/123',
106+
],
107+
])(
108+
'%s',
109+
(
110+
_: string,
111+
dsn: Parameters<typeof getReportDialogEndpoint>[0],
112+
options: Parameters<typeof getReportDialogEndpoint>[1],
113+
output: ReturnType<typeof getReportDialogEndpoint>,
114+
) => {
115+
expect(getReportDialogEndpoint(dsn, options)).toBe(output);
116+
},
76117
);
77118
});
119+
78120
test('getDsn', () => {
79121
expect(new API(dsnPublic).getDsn()).toEqual(new Dsn(dsnPublic));
80122
});

0 commit comments

Comments
 (0)