Skip to content

Commit c187b53

Browse files
authored
feat: Update to v8.51.0 of the JavaScript SDKs (#1066)
1 parent 3c8599b commit c187b53

File tree

11 files changed

+177
-173
lines changed

11 files changed

+177
-173
lines changed

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,16 @@
6060
"e2e": "xvfb-maybe vitest run --root=./test/e2e --silent=false --disable-console-intercept"
6161
},
6262
"dependencies": {
63-
"@sentry/browser": "8.50.0",
64-
"@sentry/core": "8.50.0",
65-
"@sentry/node": "8.50.0",
63+
"@sentry/browser": "8.51.0",
64+
"@sentry/core": "8.51.0",
65+
"@sentry/node": "8.51.0",
6666
"deepmerge": "4.3.1"
6767
},
6868
"devDependencies": {
6969
"@rollup/plugin-node-resolve": "^15.2.3",
7070
"@rollup/plugin-typescript": "^11.1.6",
71-
"@sentry-internal/eslint-config-sdk": "8.50.0",
72-
"@sentry-internal/typescript": "8.50.0",
71+
"@sentry-internal/eslint-config-sdk": "8.51.0",
72+
"@sentry-internal/typescript": "8.51.0",
7373
"@types/busboy": "^1.5.4",
7474
"@types/form-data": "^2.5.0",
7575
"@types/koa": "^2.0.52",

src/main/integrations/sentry-minidump/index.ts

Lines changed: 44 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
Scope,
88
ScopeData,
99
SentryError,
10+
Session,
1011
} from '@sentry/core';
1112
import { NodeClient } from '@sentry/node';
1213
import { app, crashReporter } from 'electron';
@@ -16,7 +17,7 @@ import { getEventDefaults } from '../../context';
1617
import { EXIT_REASONS, getSentryCachePath, usesCrashpad } from '../../electron-normalize';
1718
import { getRendererProperties, trackRendererProperties } from '../../renderers';
1819
import { ElectronMainOptions } from '../../sdk';
19-
import { checkPreviousSession, sessionCrashed } from '../../sessions';
20+
import { previousSessionWasAbnormal, restorePreviousSession, setPreviousSessionAsCurrent } from '../../sessions';
2021
import { BufferedWriteStore } from '../../store';
2122
import { getMinidumpLoader, MinidumpLoader } from './minidump-loader';
2223

@@ -82,7 +83,7 @@ export const sentryMinidumpIntegration = defineIntegration((options: Options = {
8283

8384
async function sendNativeCrashes(
8485
client: NodeClient,
85-
getEvent: (minidumpProcess: string | undefined) => Event,
86+
getEvent: (minidumpProcess: string | undefined) => Event | Promise<Event>,
8687
): Promise<boolean> {
8788
// Whenever we are called, assume that the crashes we are going to load down
8889
// below have occurred recently. This means, we can use the same event data
@@ -108,29 +109,11 @@ export const sentryMinidumpIntegration = defineIntegration((options: Options = {
108109
await minidumpLoader?.(deleteAll, async (minidumpProcess, attachment) => {
109110
minidumpFound = true;
110111

111-
const event = getEvent(minidumpProcess);
112-
113-
// If this is a native main process crash, we need to apply the scope and context from the previous run
114-
if (event.tags?.['event.process'] === 'browser') {
115-
const previousRun = await scopeLastRun;
116-
if (previousRun) {
117-
if (previousRun.scope) {
118-
applyScopeDataToEvent(event, previousRun.scope);
119-
}
120-
121-
event.release = previousRun.event?.release || event.release;
122-
event.environment = previousRun.event?.environment || event.environment;
123-
event.contexts = previousRun.event?.contexts || event.contexts;
124-
}
125-
}
126-
127-
if (!event) {
128-
return;
129-
}
112+
const event = await getEvent(minidumpProcess);
130113

131114
if (minidumpsRemaining > 0) {
132115
minidumpsRemaining -= 1;
133-
captureEvent(event as Event, { attachments: [attachment] });
116+
captureEvent(event, { attachments: [attachment] });
134117
}
135118
});
136119

@@ -145,7 +128,7 @@ export const sentryMinidumpIntegration = defineIntegration((options: Options = {
145128
): Promise<void> {
146129
const { getRendererName } = options;
147130

148-
const found = await sendNativeCrashes(client, (minidumpProcess) => {
131+
await sendNativeCrashes(client, (minidumpProcess) => {
149132
// We only call 'getRendererName' if this was in fact a renderer crash
150133
const crashedProcess =
151134
(minidumpProcess === 'renderer' && getRendererName ? getRendererName(contents) : minidumpProcess) ||
@@ -170,20 +153,12 @@ export const sentryMinidumpIntegration = defineIntegration((options: Options = {
170153
},
171154
};
172155
});
173-
174-
if (found) {
175-
sessionCrashed();
176-
}
177156
}
178157

179-
async function sendChildProcessCrash(
180-
client: NodeClient,
181-
options: ElectronMainOptions,
182-
details: Omit<Electron.Details, 'exitCode'>,
183-
): Promise<void> {
158+
async function sendChildProcessCrash(client: NodeClient, details: Omit<Electron.Details, 'exitCode'>): Promise<void> {
184159
logger.log(`${details.type} process has ${details.reason}`);
185160

186-
const found = await sendNativeCrashes(client, (minidumpProcess) => ({
161+
await sendNativeCrashes(client, (minidumpProcess) => ({
187162
contexts: {
188163
electron: { details },
189164
},
@@ -197,10 +172,6 @@ export const sentryMinidumpIntegration = defineIntegration((options: Options = {
197172
event_type: 'native',
198173
},
199174
}));
200-
201-
if (found) {
202-
sessionCrashed();
203-
}
204175
}
205176

206177
return {
@@ -238,25 +209,47 @@ export const sentryMinidumpIntegration = defineIntegration((options: Options = {
238209
});
239210
app.on('child-process-gone', async (_, details) => {
240211
if (EXIT_REASONS.includes(details.reason)) {
241-
await sendChildProcessCrash(client, options, details);
212+
await sendChildProcessCrash(client, details);
242213
}
243214
});
244215

216+
let sessionToRestore: Session | undefined;
217+
245218
// Start to submit recent minidump crashes. This will load breadcrumbs and
246219
// context information that was cached on disk in the previous app run, prior to the crash.
247-
sendNativeCrashes(client, (minidumpProcess) => ({
248-
level: 'fatal',
249-
platform: 'native',
250-
tags: {
251-
'event.environment': 'native',
252-
'event.process': minidumpProcess || (usesCrashpad() ? 'unknown' : 'browser'),
253-
},
254-
}))
255-
.then((minidumpsFound) =>
256-
// Check for previous uncompleted session. If a previous session exists
257-
// and no minidumps were found, its likely an abnormal exit
258-
checkPreviousSession(minidumpsFound),
259-
)
220+
sendNativeCrashes(client, async (minidumpProcess) => {
221+
const event: Event = {
222+
level: 'fatal',
223+
platform: 'native',
224+
tags: {
225+
'event.environment': 'native',
226+
'event.process': minidumpProcess || (usesCrashpad() ? 'unknown' : 'browser'),
227+
},
228+
};
229+
230+
// This crash was found at startup, we need to apply the scope and context from the previous run
231+
const previousRun = await scopeLastRun;
232+
if (previousRun) {
233+
if (previousRun.scope) {
234+
applyScopeDataToEvent(event, previousRun.scope);
235+
}
236+
237+
event.release = previousRun.event?.release;
238+
event.environment = previousRun.event?.environment;
239+
event.contexts = previousRun.event?.contexts;
240+
}
241+
242+
sessionToRestore = await setPreviousSessionAsCurrent();
243+
244+
return event;
245+
})
246+
.then(async (minidumpsFound) => {
247+
if (!minidumpsFound) {
248+
await previousSessionWasAbnormal();
249+
} else if (sessionToRestore) {
250+
restorePreviousSession(sessionToRestore);
251+
}
252+
})
260253
.catch((error) => logger.error(error));
261254
},
262255
};

src/main/sessions.ts

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,20 @@ let previousSession: Promise<Partial<Session> | undefined> | undefined;
2828
function getSessionStore(): Store<SessionContext | undefined> {
2929
if (!sessionStore) {
3030
sessionStore = new Store<SessionContext | undefined>(getSentryCachePath(), 'session', undefined);
31-
previousSession = sessionStore.get();
31+
previousSession = sessionStore.get().then((sesh) => (sesh ? makeSession(sesh) : sesh));
3232
}
3333

3434
return sessionStore;
3535
}
3636

37+
/** Copies a session and removes the toJSON function so it can be serialised without conversion */
38+
function makeSessionSafeToSerialize(session: Session): Session {
39+
const copy = { ...session };
40+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
41+
delete (copy as any).toJSON;
42+
return copy;
43+
}
44+
3745
let persistTimer: ReturnType<typeof setInterval> | undefined;
3846

3947
/** Starts a session */
@@ -45,7 +53,7 @@ export function startSession(sendOnCreate: boolean): void {
4553
}
4654

4755
getSessionStore()
48-
.set(session)
56+
.set(makeSessionSafeToSerialize(session))
4957
.catch(() => {
5058
// Does not throw
5159
});
@@ -55,7 +63,7 @@ export function startSession(sendOnCreate: boolean): void {
5563
const currentSession = getCurrentScope().getSession();
5664
// Only bother saving if it hasn't already ended
5765
if (currentSession && currentSession.status === 'ok') {
58-
await getSessionStore().set(currentSession);
66+
await getSessionStore().set(makeSessionSafeToSerialize(currentSession));
5967
}
6068
}, PERSIST_INTERVAL_MS);
6169
}
@@ -110,6 +118,59 @@ export async function unreportedDuringLastSession(crashDate: Date | undefined):
110118
return crashTime > lastPersist && crashTime < prevSessionEnd;
111119
}
112120

121+
/** Sets the previous session as the current session and returns any existing session */
122+
export async function setPreviousSessionAsCurrent(): Promise<Session | undefined> {
123+
const previous = await previousSession;
124+
125+
const scope = getCurrentScope();
126+
const currentSession = scope.getSession();
127+
128+
if (previous) {
129+
previousSession = undefined;
130+
131+
if (previous.status === 'ok') {
132+
scope.setSession(makeSession(previous));
133+
}
134+
}
135+
136+
return currentSession;
137+
}
138+
139+
/** Restores a session */
140+
export function restorePreviousSession(session: Session): void {
141+
getCurrentScope().setSession(session);
142+
}
143+
144+
/** Report the previous session as abnormal */
145+
export async function previousSessionWasAbnormal(): Promise<void> {
146+
const client = getClient<NodeClient>();
147+
148+
const previous = await previousSession;
149+
150+
if (previous && client) {
151+
// Ignore if the previous session is already ended
152+
if (previous.status !== 'ok') {
153+
previousSession = undefined;
154+
return;
155+
}
156+
157+
logger.log(`Found previous abnormal session`);
158+
159+
const sesh = makeSession(previous);
160+
161+
updateSession(sesh, {
162+
status: 'abnormal',
163+
errors: (sesh.errors || 0) + 1,
164+
release: (previous as unknown as SerializedSession).attrs?.release,
165+
environment: (previous as unknown as SerializedSession).attrs?.environment,
166+
});
167+
168+
await client.sendSession(sesh);
169+
170+
previousSession = undefined;
171+
}
172+
}
173+
113174
/** Checks if the previous session needs sending as crashed or abnormal */
114175
export async function checkPreviousSession(crashed: boolean): Promise<void> {
115176
const client = getClient<NodeClient>();

src/renderer/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export {
121121
featureFlagsIntegration,
122122
launchDarklyIntegration,
123123
openFeatureIntegration,
124+
unleashIntegration,
124125
} from '@sentry/browser';
125126

126127
export type { BrowserOptions, ReportDialogOptions } from '@sentry/browser';

src/renderer/sdk.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ interface ElectronRendererOptions extends Omit<BrowserOptions, 'dsn' | 'environm
5050
export function init<O extends ElectronRendererOptions>(
5151
options: ElectronRendererOptions & O = {} as ElectronRendererOptions & O,
5252
// This parameter name ensures that TypeScript error messages contain a hint for fixing SDK version mismatches
53-
originalInit: (if_you_get_a_typescript_error_ensure_sdks_use_version_v8_50_0: O) => void = browserInit,
53+
originalInit: (if_you_get_a_typescript_error_ensure_sdks_use_version_v8_51_0: O) => void = browserInit,
5454
): void {
5555
// Ensure the browser SDK is only init'ed once.
5656
if (window?.__SENTRY__RENDERER_INIT__) {

test/e2e/test-apps/native-sentry/unknown/event.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
"event.environment": "native",
7272
"event.origin": "electron",
7373
"event.process": "unknown",
74-
"app-run": "second"
74+
"app-run": "first"
7575
}
7676
},
7777
"attachments": [

test/e2e/test-apps/sessions/native-crash-main/session-3.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"init": false,
88
"started": 0,
99
"timestamp": 0,
10-
"status": "ok",
10+
"status": "exited",
1111
"errors": 0,
1212
"duration": 0,
1313
"attrs": {

test/e2e/test-apps/sessions/native-crash-main/session-4.json

Lines changed: 0 additions & 17 deletions
This file was deleted.

test/e2e/test-apps/sessions/native-crash-renderer-multiple/session-next.json

Lines changed: 0 additions & 17 deletions
This file was deleted.

test/e2e/test-apps/sessions/native-crash-renderer/session-next.json

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)