Skip to content

Commit 7543baf

Browse files
committed
feat: use custom prepare/send, re-use createEventEnvelope from core
1 parent 8878227 commit 7543baf

File tree

5 files changed

+119
-47
lines changed

5 files changed

+119
-47
lines changed

packages/core/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export type { OfflineStore, OfflineTransportOptions } from './transports/offline
44
export type { ServerRuntimeClientOptions } from './server-runtime-client';
55

66
export * from './tracing';
7+
export {createEventEnvelope} from './envelope';
78
export {
89
addBreadcrumb,
910
captureCheckIn,
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,39 @@
1+
import type { TransportMakeRequestResponse } from '@sentry/types';
2+
13
import { sendFeedback } from '../sendFeedback';
24
import type { FeedbackFormData, SendFeedbackOptions } from '../types';
35
import type { DialogComponent } from '../widget/Dialog';
46

57
/**
68
* Calls `sendFeedback` to send feedback, handles UI behavior of dialog.
79
*/
8-
export function handleFeedbackSubmit(
10+
export async function handleFeedbackSubmit(
911
dialog: DialogComponent | null,
1012
feedback: FeedbackFormData,
1113
options?: SendFeedbackOptions,
12-
): string | undefined {
14+
): Promise<TransportMakeRequestResponse | void> {
1315
if (!dialog) {
1416
// Not sure when this would happen
1517
return;
1618
}
1719

18-
// const showFetchError = (): void => {
19-
// if (!dialog) {
20-
// return;
21-
// }
22-
// dialog.showError('There was a problem submitting feedback, please wait and try again.');
23-
// };
20+
const showFetchError = (): void => {
21+
if (!dialog) {
22+
return;
23+
}
24+
dialog.showError('There was a problem submitting feedback, please wait and try again.');
25+
};
2426

2527
dialog.hideError();
2628

27-
// TODO: Error handling?
28-
return sendFeedback(feedback, options);
29-
// try {
30-
// const resp = await sendFeedback(feedback, options);
31-
//
32-
// // Success!
33-
// return resp;
34-
// } catch {
35-
// // Errored... re-enable submit button
36-
// showFetchError();
37-
// }
29+
try {
30+
const resp = await sendFeedback(feedback, options);
31+
32+
// Success!
33+
return resp;
34+
} catch (err) {
35+
console.error(err);
36+
// Errored... re-enable submit button
37+
showFetchError();
38+
}
3839
}

packages/feedback/src/util/prepareFeedbackEvent.ts

+4-13
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ interface PrepareFeedbackEventParams {
99
}
1010
/**
1111
* Prepare a feedback event & enrich it with the SDK metadata.
12-
*
13-
* TODO: Refactor this with the replay version
1412
*/
1513
export async function prepareFeedbackEvent({
1614
client,
@@ -27,10 +25,12 @@ export async function prepareFeedbackEvent({
2725
event,
2826
{ integrations: undefined },
2927
scope,
28+
client,
3029
)) as FeedbackEvent | null;
3130

32-
// If e.g. a global event processor returned null
33-
if (!preparedEvent) {
31+
if (preparedEvent === null) {
32+
// Taken from baseclient's `_processEvent` method, where this is handled for errors/transactions
33+
client.recordDroppedEvent('event_processor', 'feedback', event);
3434
return null;
3535
}
3636

@@ -39,14 +39,5 @@ export async function prepareFeedbackEvent({
3939
// we need to do this manually.
4040
preparedEvent.platform = preparedEvent.platform || 'javascript';
4141

42-
// extract the SDK name because `client._prepareEvent` doesn't add it to the event
43-
const metadata = client.getSdkMetadata && client.getSdkMetadata();
44-
const { name, version } = (metadata && metadata.sdk) || {};
45-
46-
preparedEvent.sdk = {
47-
name: name || 'sentry.javascript.unknown',
48-
version: version || '0.0.0',
49-
};
50-
5142
return preparedEvent;
5243
}
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
1-
import { getCurrentHub } from '@sentry/core';
2-
import type { FeedbackEvent } from '@sentry/types';
3-
import { uuid4 } from '@sentry/utils';
1+
import { createEventEnvelope, getCurrentHub } from '@sentry/core';
2+
import type { FeedbackEvent, TransportMakeRequestResponse } from '@sentry/types';
43

54
import type { SendFeedbackData } from '../types';
5+
import { prepareFeedbackEvent } from './prepareFeedbackEvent';
66

77
/**
8-
* Send feedback using `fetch()`
8+
* Send feedback using transport
99
*/
10-
export function sendFeedbackRequest({
10+
export async function sendFeedbackRequest({
1111
feedback: { message, email, name, replay_id, url },
12-
}: SendFeedbackData): string | undefined {
12+
}: SendFeedbackData): Promise<void | TransportMakeRequestResponse> {
13+
debugger;
1314
const hub = getCurrentHub();
1415
const client = hub.getClient();
1516
const scope = hub.getScope();
17+
const transport = client && client.getTransport();
18+
const dsn = client && client.getDsn();
1619

17-
if (!client) {
20+
if (!client || !transport || !dsn) {
1821
return;
1922
}
2023

@@ -31,11 +34,87 @@ export function sendFeedbackRequest({
3134
type: 'feedback',
3235
};
3336

34-
return client.captureEvent(
35-
baseEvent,
36-
{
37-
event_id: uuid4(),
38-
},
37+
const feedbackEvent = await prepareFeedbackEvent({
3938
scope,
40-
);
39+
client,
40+
event: baseEvent,
41+
});
42+
43+
if (feedbackEvent === null) {
44+
return;
45+
}
46+
47+
/*
48+
For reference, the fully built event looks something like this:
49+
{
50+
"type": "feedback",
51+
"event_id": "d2132d31b39445f1938d7e21b6bf0ec4",
52+
"timestamp": 1597977777.6189718,
53+
"dist": "1.12",
54+
"platform": "javascript",
55+
"environment": "production",
56+
"release": 42,
57+
"tags": {"transaction": "/organizations/:orgId/performance/:eventSlug/"},
58+
"sdk": {"name": "name", "version": "version"},
59+
"user": {
60+
"id": "123",
61+
"username": "user",
62+
"email": "user@site.com",
63+
"ip_address": "192.168.11.12",
64+
},
65+
"request": {
66+
"url": None,
67+
"headers": {
68+
"user-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.5 Safari/605.1.15"
69+
},
70+
},
71+
"contexts": {
72+
"feedback": {
73+
"message": "test message",
74+
"contact_email": "test@example.com",
75+
"type": "feedback",
76+
},
77+
"trace": {
78+
"trace_id": "4C79F60C11214EB38604F4AE0781BFB2",
79+
"span_id": "FA90FDEAD5F74052",
80+
"type": "trace",
81+
},
82+
"replay": {
83+
"replay_id": "e2d42047b1c5431c8cba85ee2a8ab25d",
84+
},
85+
},
86+
}
87+
*/
88+
89+
const envelope = createEventEnvelope(feedbackEvent, dsn, client.getOptions()._metadata, client.getOptions().tunnel);
90+
91+
let response: void | TransportMakeRequestResponse;
92+
93+
try {
94+
console.log(envelope);
95+
response = await transport.send(envelope);
96+
} catch (err) {
97+
const error = new Error('Unable to send Feedback');
98+
99+
try {
100+
// In case browsers don't allow this property to be writable
101+
// @ts-expect-error This needs lib es2022 and newer
102+
error.cause = err;
103+
} catch {
104+
// nothing to do
105+
}
106+
throw error;
107+
}
108+
109+
// TODO (v8): we can remove this guard once transport.send's type signature doesn't include void anymore
110+
if (!response) {
111+
return response;
112+
}
113+
114+
// If the status code is invalid, we want to immediately stop & not retry
115+
if (typeof response.statusCode === 'number' && (response.statusCode < 200 || response.statusCode >= 300)) {
116+
throw new Error('Unable to send Feedback');
117+
}
118+
119+
return response;
41120
}

packages/feedback/src/widget/createWidget.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,10 @@ export function createWidget({ shadow, options, attachTo }: CreateWidgetParams):
7474
return;
7575
}
7676

77-
const eventId = handleFeedbackSubmit(dialog, feedback);
77+
const result = await handleFeedbackSubmit(dialog, feedback);
7878

7979
// Error submitting feedback
80-
if (!eventId) {
80+
if (!result) {
8181
if (options.onSubmitError) {
8282
options.onSubmitError();
8383
}

0 commit comments

Comments
 (0)