Upgrade Sentry to v8 and remove custom Dependabot grouping

As part of the upgrade process, we need to rework the tracing instrumentation. Now, we are just wrapping all async functions in a new sentry transaction, which will automatically end once the function returns.

Further, the structure of the Sentry packages got reworked, so that we only need a single package by now. This removes the need to group dependabot updates.

Co-authored-by: Jan Graichen <jgraichen@altimos.de>
This commit is contained in:
Sebastian Serth
2024-05-20 14:00:55 +02:00
committed by Sebastian Serth
parent 86c67f3c9a
commit 94404370c4
12 changed files with 234 additions and 300 deletions

View File

@ -22,10 +22,6 @@ updates:
labels:
- dependencies
- javascript
groups:
sentry-javascript:
patterns:
- "@sentry*"
- package-ecosystem: github-actions
directory: "/"

View File

@ -13,9 +13,3 @@ jobs:
uses: ahmadnassri/action-dependabot-auto-merge@v2
with:
github-token: ${{ secrets.OPENHPI_BOT_TOKEN }}
- name: Automerge Sentry PRs
run: gh pr merge --auto --rebase "$PR_URL" # Use Github CLI to merge automatically the PR
if: contains(github.event.pull_request.title, 'sentry')
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GITHUB_TOKEN: ${{ secrets.OPENHPI_BOT_TOKEN }}

View File

@ -46,7 +46,7 @@ $(document).on('turbolinks:load', function() {
const sentrySettings = $('meta[name="sentry"]')
// Workaround for Turbolinks: We must not re-initialize the Relay object when visiting another page
if (sentrySettings && sentrySettings.data()['enabled'] && !Sentry.Replay.prototype._isInitialized) {
if (sentrySettings && sentrySettings.data()['enabled'] && Sentry.getReplay() === undefined) {
Sentry.init({
dsn: sentrySettings.data('dsn'),
attachStacktrace: true,

View File

@ -27,14 +27,15 @@ $(document).on('turbolinks:load', function() {
function submitCode(event) {
const button = $(event.target) || $('#submit');
this.startSentryTransaction(button);
const submission = await this.createSubmission(button, null).catch(this.ajaxError.bind(this));
if (!submission) return;
if (!submission.redirect) return;
this.newSentryTransaction(button, async () => {
const submission = await this.createSubmission(button, null).catch(this.ajaxError.bind(this));
if (!submission) return;
if (!submission.redirect) return;
this.autosaveIfChanged();
this.stopCode(event);
this.editors = [];
Turbolinks.clearCache();
Turbolinks.visit(submission.redirect);
this.autosaveIfChanged();
this.stopCode(event);
this.editors = [];
Turbolinks.clearCache();
Turbolinks.visit(submission.redirect);
});
}

View File

@ -202,15 +202,25 @@ var CodeOceanEditor = {
$('button i.fa-spin').removeClass('d-inline-block').addClass('d-none');
},
startSentryTransaction: function (initiator) {
const cause = initiator.data('cause') || initiator.prop('id');
this.sentryTransaction = window.SentryUtils.startIdleTransaction(
Sentry.getCurrentHub(),
{ name: cause, op: "transaction" },
0, // Idle Timeout
window.SentryUtils.TRACING_DEFAULTS.finalTimeout,
true); // onContext
Sentry.getCurrentHub().configureScope(scope => scope.setSpan(this.sentryTransaction));
newSentryTransaction: function (initiator, callback) {
// based on Sentry recommendation.
// See https://github.com/getsentry/sentry-javascript/issues/12116
return Sentry.continueTrace({ sentryTrace: '', baggage: '' }, () => {
// inside of this we have a new trace!
return Sentry.withActiveSpan(null, () => {
// inside of this there is no parent span, no matter what!
const cause = initiator.data('cause') || initiator.prop('id');
return Sentry.startSpan({name: cause, op: "transaction", forceTransaction: true}, async () => {
// Execute the desired custom code
try {
return await callback();
} catch (error) {
console.error(error);
Sentry.captureException(error, {mechanism: {handled: false}});
}
});
});
});
},
resizeAceEditors: function (own_solution = false) {

View File

@ -2,7 +2,6 @@ CodeOceanEditorEvaluation = {
// A list of non-printable characters that are not allowed in the code output.
// Taken from https://stackoverflow.com/a/69024306
nonPrintableRegEx: /[\u0000-\u0008\u000B\u000C\u000F-\u001F\u007F-\u009F\u2000-\u200F\u2028-\u202F\u205F-\u206F\u3000\uFEFF]/g,
sentryTransaction: null,
/**
* Scoring-Functions
@ -10,17 +9,18 @@ CodeOceanEditorEvaluation = {
scoreCode: function (event) {
event.preventDefault();
const cause = $('#assess');
this.startSentryTransaction(cause);
this.stopCode(event);
this.clearScoringOutput();
$('#submit').addClass("d-none");
this.newSentryTransaction(cause, async () => {
this.stopCode(event);
this.clearScoringOutput();
$('#submit').addClass("d-none");
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
if (!submission) return;
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
if (!submission) return;
this.showSpinner($('#assess'));
$('#score_div').removeClass('d-none');
await this.socketScoreCode(submission.id);
this.showSpinner($('#assess'));
$('#score_div').removeClass('d-none');
await this.socketScoreCode(submission.id);
});
},
handleScoringResponse: function (results) {

View File

@ -8,7 +8,7 @@ CodeOceanEditorWebsocket = {
params.protocol = this.webSocketProtocol;
params._options = true;
// 2. Create a new Sentry transaction.
// 2. Create a new Sentry span.
// Since we want to group similar URLs, we use the URL without the ID and filename as the description.
const cleanedUrl = urlHelper({
...params,
@ -16,54 +16,54 @@ CodeOceanEditorWebsocket = {
...(params.filename && {filename: '*'}), // Overwrite the filename with a wildcard only if it is present.
});
const sentryDescription = `WebSocket ${cleanedUrl}`;
const span = this.sentryTransaction?.startChild({op: 'websocket.client', description: sentryDescription, data: {...params}})
return Sentry.startSpan({op: 'websocket.client', name: sentryDescription, attributes: {...params}}, async webSocketSpan => {
// 3. Create the actual WebSocket URL.
// This URL might contain Sentry Tracing headers to propagate the Sentry transaction.
if (span) {
const dynamicContext = this.sentryTransaction.getDynamicSamplingContext();
const baggage = SentryUtils.dynamicSamplingContextToSentryBaggageHeader(dynamicContext);
if (baggage) {
params.HTTP_SENTRY_TRACE = span.toTraceparent();
params.HTTP_BAGGAGE = baggage;
// 3. Create the actual WebSocket URL.
// This URL might contain Sentry Tracing headers to propagate the Sentry transaction.
if (webSocketSpan) {
params.HTTP_SENTRY_TRACE = Sentry.spanToTraceHeader(webSocketSpan);
const baggage = Sentry.spanToBaggageHeader(webSocketSpan);
if (baggage) {
params.HTTP_BAGGAGE = Sentry.spanToBaggageHeader(webSocketSpan);
}
}
}
const url = urlHelper({...params});
const url = urlHelper({...params});
// 4. Connect to the given URL.
this.websocket = new CommandSocket(url,
function (evt) {
this.resetOutputTab();
}.bind(this)
);
// 4. Connect to the given URL.
this.websocket = new CommandSocket(url,
function (evt) {
this.resetOutputTab();
}.bind(this)
);
// Attach custom handlers for messages received.
setupFunction(this.websocket);
// Attach custom handlers for messages received.
setupFunction(this.websocket);
CodeOceanEditorWebsocket.websocket = this.websocket;
CodeOceanEditorWebsocket.websocket = this.websocket;
// Create and return a new Promise. It will only resolve (or fail) once the connection has ended.
return new Promise((resolve, reject) => {
this.websocket.onError(this.showWebsocketError.bind(this));
// Create and return a new Promise. It will only resolve (or fail) once the connection has ended.
return new Promise((resolve, reject) => {
this.websocket.onError(this.showWebsocketError.bind(this));
// Remove event listeners for Promise handling.
// This is especially useful in case of an error, where a `close` event might follow the `error` event.
const teardown = () => {
this.websocket.websocket.removeEventListener(closeListener);
this.websocket.websocket.removeEventListener(errorListener);
};
// Remove event listeners for Promise handling.
// This is especially useful in case of an error, where a `close` event might follow the `error` event.
const teardown = () => {
this.websocket.websocket.removeEventListener(closeListener);
this.websocket.websocket.removeEventListener(errorListener);
};
// We are using event listeners (and not `onError` or `onClose`) here, since these listeners should never be overwritten.
// With `onError` or `onClose`, a new assignment would overwrite a previous one.
const closeListener = this.websocket.websocket.addEventListener('close', () => {
span?.finish();
resolve();
teardown();
});
const errorListener = this.websocket.websocket.addEventListener('error', (error) => {
reject(error);
teardown();
this.websocket.killWebSocket(); // In case of error, ensure we always close the connection.
// We are using event listeners (and not `onError` or `onClose`) here, since these listeners should never be overwritten.
// With `onError` or `onClose`, a new assignment would overwrite a previous one.
const closeListener = this.websocket.websocket.addEventListener('close', () => {
resolve();
teardown();
});
const errorListener = this.websocket.websocket.addEventListener('error', (error) => {
reject(error);
teardown();
this.websocket.killWebSocket(); // In case of error, ensure we always close the connection.
});
});
});
},

View File

@ -110,46 +110,47 @@ CodeOceanEditorRequestForComments = {
const cause = $('#requestComments');
const editor = $('#editor')
const questionElement = $('#question')
this.startSentryTransaction(cause);
questionElement.prop("disabled", true);
$('#closeAskForCommentsButton').addClass('d-none');
this.newSentryTransaction(cause, async () => {
questionElement.prop("disabled", true);
$('#closeAskForCommentsButton').addClass('d-none');
const exercise_id = editor.data('exercise-id');
const file_id = $('.editor').data('id');
const question = questionElement.val();
const exercise_id = editor.data('exercise-id');
const file_id = $('.editor').data('id');
const question = questionElement.val();
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
if (!submission) return;
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
if (!submission) return;
this.showSpinner($('#askForCommentsButton'));
this.showSpinner($('#askForCommentsButton'));
const response = await $.ajax({
method: 'POST',
url: Routes.request_for_comments_path(),
data: {
request_for_comment: {
exercise_id: exercise_id,
file_id: file_id,
submission_id: submission.id,
question: question
const response = await $.ajax({
method: 'POST',
url: Routes.request_for_comments_path(),
data: {
request_for_comment: {
exercise_id: exercise_id,
file_id: file_id,
submission_id: submission.id,
question: question
}
}
}).catch(this.ajaxError.bind(this));
bootstrap.Modal.getInstance($('#comment-modal')).hide();
this.hideSpinner();
$('#question').prop("disabled", false).val('');
$('#closeAskForCommentsButton').removeClass('d-none');
$('#askForCommentsButton').one('click', this.requestComments.bind(this));
// we disabled the button to prevent that the user spams RFCs, but decided against this now.
//var button = $('#requestComments');
//button.prop('disabled', true);
if (response) {
await this.runSubmission(submission);
$.flash.success({text: $('#askForCommentsButton').data('message-success')});
}
}).catch(this.ajaxError.bind(this));
bootstrap.Modal.getInstance($('#comment-modal')).hide();
this.hideSpinner();
$('#question').prop("disabled", false).val('');
$('#closeAskForCommentsButton').removeClass('d-none');
$('#askForCommentsButton').one('click', this.requestComments.bind(this));
// we disabled the button to prevent that the user spams RFCs, but decided against this now.
//var button = $('#requestComments');
//button.prop('disabled', true);
if (response) {
await this.runSubmission(submission);
$.flash.success({text: $('#askForCommentsButton').data('message-success')});
}
});
}
};

View File

@ -108,19 +108,20 @@ CodeOceanEditorSubmissions = {
},
resetCode: function(initiator, onlyActiveFile = false) {
this.startSentryTransaction(initiator);
this.showSpinner(initiator);
this.newSentryTransaction(initiator, async () => {
this.showSpinner(initiator);
const response = await this.ajax({
method: 'GET',
url: $('#start-over').data('url') || $('#start-over-active-file').data('url')
}).catch(this.ajaxError.bind(this));
const response = await this.ajax({
method: 'GET',
url: $('#start-over').data('url') || $('#start-over-active-file').data('url')
}).catch(this.ajaxError.bind(this));
this.hideSpinner();
this.hideSpinner();
if (!response) return;
App.synchronized_editor?.reset_content(response);
this.setEditorContent(response, onlyActiveFile);
if (!response) return;
App.synchronized_editor?.reset_content(response);
this.setEditorContent(response, onlyActiveFile);
});
},
setEditorContent: function(new_content, onlyActiveFile = false) {
@ -140,32 +141,33 @@ CodeOceanEditorSubmissions = {
renderCode: function(event) {
event.preventDefault();
const cause = $('#render');
this.startSentryTransaction(cause);
if (!cause.is(':visible')) return;
this.newSentryTransaction(cause, async () => {
if (!cause.is(':visible')) return;
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
if (!submission) return;
if (submission.render_url === undefined) return;
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
if (!submission) return;
if (submission.render_url === undefined) return;
const active_file = CodeOceanEditor.active_file.filename;
const desired_file = submission.render_url.filter(hash => hash.filepath === active_file);
const url = desired_file[0].url;
const active_file = CodeOceanEditor.active_file.filename;
const desired_file = submission.render_url.filter(hash => hash.filepath === active_file);
const url = desired_file[0].url;
// Allow to open the new tab even in Safari.
// See: https://stackoverflow.com/a/70463940
setTimeout(() => {
var pop_up_window = window.open(url, '_blank');
if (pop_up_window) {
pop_up_window.onerror = function (message) {
this.clearOutput();
this.printOutput({
stderr: message
}, true, 0);
this.sendError(message, submission.id);
this.showOutputBar();
};
}
})
// Allow to open the new tab even in Safari.
// See: https://stackoverflow.com/a/70463940
setTimeout(() => {
var pop_up_window = window.open(url, '_blank');
if (pop_up_window) {
pop_up_window.onerror = function (message) {
this.clearOutput();
this.printOutput({
stderr: message
}, true, 0);
this.sendError(message, submission.id);
this.showOutputBar();
};
}
})
});
},
/**
@ -174,14 +176,15 @@ CodeOceanEditorSubmissions = {
runCode: function(event) {
event.preventDefault();
const cause = $('#run');
this.startSentryTransaction(cause);
this.stopCode(event);
if (!cause.is(':visible')) return;
this.newSentryTransaction(cause, async () => {
this.stopCode(event);
if (!cause.is(':visible')) return;
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
if (!submission) return;
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
if (!submission) return;
await this.runSubmission(submission);
await this.runSubmission(submission);
});
},
runSubmission: async function (submission) {
@ -196,15 +199,16 @@ CodeOceanEditorSubmissions = {
testCode: function(event) {
event.preventDefault();
const cause = $('#test');
this.startSentryTransaction(cause);
if (!cause.is(':visible')) return;
this.newSentryTransaction(cause, async () => {
if (!cause.is(':visible')) return;
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
if (!submission) return;
const submission = await this.createSubmission(cause, null).catch(this.ajaxError.bind(this));
if (!submission) return;
this.showSpinner($('#test'));
$('#score_div').addClass('d-none');
await this.socketTestCode(submission.id, CodeOceanEditor.active_file.filename);
this.showSpinner($('#test'));
$('#score_div').addClass('d-none');
await this.socketTestCode(submission.id, CodeOceanEditor.active_file.filename);
});
},
/**

View File

@ -16,9 +16,6 @@ import 'jstree';
import * as _ from 'underscore';
import * as d3 from 'd3';
import * as Sentry from '@sentry/browser';
import * as SentryIntegration from '@sentry/integrations';
import { startIdleTransaction, TRACING_DEFAULTS } from '@sentry/core';
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
import 'sorttable';
window.bootstrap = bootstrap; // Publish bootstrap in global namespace
window._ = _; // Publish underscore's `_` in global namespace
@ -26,15 +23,15 @@ window.d3 = d3; // Publish d3 in global namespace
window.Sentry = Sentry; // Publish sentry in global namespace
window.SentryIntegrations = function() { // Publish sentry integration in global namespace
return [
new SentryIntegration.ReportingObserver(),
new SentryIntegration.ExtraErrorData(),
new SentryIntegration.HttpClient(),
new Sentry.BrowserProfilingIntegration(),
new Sentry.BrowserTracing(),
new Sentry.Replay(),
Sentry.browserProfilingIntegration(),
Sentry.browserTracingIntegration(),
Sentry.extraErrorDataIntegration(),
Sentry.httpClientIntegration(),
Sentry.replayIntegration(),
Sentry.reportingObserverIntegration(),
Sentry.sessionTimingIntegration(),
]
};
window.SentryUtils = { dynamicSamplingContextToSentryBaggageHeader, startIdleTransaction, TRACING_DEFAULTS };
// CSS
import 'chosen-js/chosen.css';

View File

@ -9,10 +9,7 @@
"@egjs/hammerjs": "^2.0.17",
"@fortawesome/fontawesome-free": "^6.5.2",
"@popperjs/core": "^2.11.8",
"@sentry/browser": "^7.110.1",
"@sentry/core": "^7.114.0",
"@sentry/integrations": "^7.114.0",
"@sentry/utils": "^7.114.0",
"@sentry/browser": "^8.4.0",
"@toast-ui/editor": "^3.2.2",
"@webpack-cli/serve": "^2.0.5",
"ace-builds": "^1.34.0",

186
yarn.lock
View File

@ -1813,128 +1813,90 @@ __metadata:
languageName: node
linkType: hard
"@sentry-internal/feedback@npm:7.110.1":
version: 7.110.1
resolution: "@sentry-internal/feedback@npm:7.110.1"
"@sentry-internal/browser-utils@npm:8.4.0":
version: 8.4.0
resolution: "@sentry-internal/browser-utils@npm:8.4.0"
dependencies:
"@sentry/core": "npm:7.110.1"
"@sentry/types": "npm:7.110.1"
"@sentry/utils": "npm:7.110.1"
checksum: 10c0/5429a7dcd14986770647392558ed0d09f31d33d6771688304f90e88feff9b0af6edaa0195e60c5bdce6a8518409f6314b9d03293b661fc3e1b74ef1c154e4595
"@sentry/core": "npm:8.4.0"
"@sentry/types": "npm:8.4.0"
"@sentry/utils": "npm:8.4.0"
checksum: 10c0/9e6709100182f8586ef24d304632eedee1f0f257a588bd861df779dee41064cc97afce53b22a4b669e05581f25bc61d7fdae901d238f93569e7042e07d9fbf50
languageName: node
linkType: hard
"@sentry-internal/replay-canvas@npm:7.110.1":
version: 7.110.1
resolution: "@sentry-internal/replay-canvas@npm:7.110.1"
"@sentry-internal/feedback@npm:8.4.0":
version: 8.4.0
resolution: "@sentry-internal/feedback@npm:8.4.0"
dependencies:
"@sentry/core": "npm:7.110.1"
"@sentry/replay": "npm:7.110.1"
"@sentry/types": "npm:7.110.1"
"@sentry/utils": "npm:7.110.1"
checksum: 10c0/125b8247db4631e298f3c8c6d8b486669dfa6356490cc7464a23131a5518d9d7ef314f2c1cbbbadad4f9738ba451fbf5f9457170f4bc899b8275e15ae28cb610
"@sentry/core": "npm:8.4.0"
"@sentry/types": "npm:8.4.0"
"@sentry/utils": "npm:8.4.0"
checksum: 10c0/028eb28770eb85f1d09caa3ec98420cdb691d2de06be261106876efed572f7d83bfddf6d289468c0f1bbf551d5a75e7b01fe2c2bbac4b0da882c8e655a166b5c
languageName: node
linkType: hard
"@sentry-internal/tracing@npm:7.110.1":
version: 7.110.1
resolution: "@sentry-internal/tracing@npm:7.110.1"
"@sentry-internal/replay-canvas@npm:8.4.0":
version: 8.4.0
resolution: "@sentry-internal/replay-canvas@npm:8.4.0"
dependencies:
"@sentry/core": "npm:7.110.1"
"@sentry/types": "npm:7.110.1"
"@sentry/utils": "npm:7.110.1"
checksum: 10c0/ee901b99b838a932f2adb1b085364c816fb0b3f61643ca368af37dd2aa9faf702ea1f3d28f7b0e2e79c57794e3260c8ce34376da0f8658b6ee844b28676ecd55
"@sentry-internal/replay": "npm:8.4.0"
"@sentry/core": "npm:8.4.0"
"@sentry/types": "npm:8.4.0"
"@sentry/utils": "npm:8.4.0"
checksum: 10c0/6e62557e88f1422f645b022c33c034eccf53469dcdea8e1fbdef34f087e8e986411f50bbf384b7d41f83298b1f339866c8a024456ecf74f1158811f9b91d225b
languageName: node
linkType: hard
"@sentry/browser@npm:^7.110.1":
version: 7.110.1
resolution: "@sentry/browser@npm:7.110.1"
"@sentry-internal/replay@npm:8.4.0":
version: 8.4.0
resolution: "@sentry-internal/replay@npm:8.4.0"
dependencies:
"@sentry-internal/feedback": "npm:7.110.1"
"@sentry-internal/replay-canvas": "npm:7.110.1"
"@sentry-internal/tracing": "npm:7.110.1"
"@sentry/core": "npm:7.110.1"
"@sentry/replay": "npm:7.110.1"
"@sentry/types": "npm:7.110.1"
"@sentry/utils": "npm:7.110.1"
checksum: 10c0/085a2cbd2b60dbb596b68d3cf7d0059e226bc8892aa90a50680fa9a9256889a715ff234e9210738a3205ce5513e52290e440ffa4f2d2e2429471ea584d075493
"@sentry-internal/browser-utils": "npm:8.4.0"
"@sentry/core": "npm:8.4.0"
"@sentry/types": "npm:8.4.0"
"@sentry/utils": "npm:8.4.0"
checksum: 10c0/e9e6398eb3e245470bd464022a9e147038e6adc97212a8e0a28496093f8ed018f8c417bc0d73715f6e63a7506a2d199fadddd23a80246abc8c54d5875d8552c3
languageName: node
linkType: hard
"@sentry/core@npm:7.110.1":
version: 7.110.1
resolution: "@sentry/core@npm:7.110.1"
"@sentry/browser@npm:^8.4.0":
version: 8.4.0
resolution: "@sentry/browser@npm:8.4.0"
dependencies:
"@sentry/types": "npm:7.110.1"
"@sentry/utils": "npm:7.110.1"
checksum: 10c0/8eee39697a1173f233a83fa07b5099c2fdc1f345ec0ac0304ed38c7159214e6a0615fb2fe4dcd4152dbe11cf5ec14bfe3d7da19706e90b13a8bd7984256c4b2f
"@sentry-internal/browser-utils": "npm:8.4.0"
"@sentry-internal/feedback": "npm:8.4.0"
"@sentry-internal/replay": "npm:8.4.0"
"@sentry-internal/replay-canvas": "npm:8.4.0"
"@sentry/core": "npm:8.4.0"
"@sentry/types": "npm:8.4.0"
"@sentry/utils": "npm:8.4.0"
checksum: 10c0/bd1162ad13f246c30c1af2d65b798d729cfd4c94c50cc08bdb848a95cd734cedae235c2c2554863c81bc4e639c3d9b8120b6d6988fe6e3437ca45f3dbcf67de6
languageName: node
linkType: hard
"@sentry/core@npm:7.114.0, @sentry/core@npm:^7.114.0":
version: 7.114.0
resolution: "@sentry/core@npm:7.114.0"
"@sentry/core@npm:8.4.0":
version: 8.4.0
resolution: "@sentry/core@npm:8.4.0"
dependencies:
"@sentry/types": "npm:7.114.0"
"@sentry/utils": "npm:7.114.0"
checksum: 10c0/9ef9cd6e536180a53fdd11dfb30f19a1bf51115b6a828aae4f9dacb92233ced238e3100065429cdb50a654609519722b6cf99721cac21f09dd5d57f123aa4f3c
"@sentry/types": "npm:8.4.0"
"@sentry/utils": "npm:8.4.0"
checksum: 10c0/7c9ffc15a5cbc6cc9811b1444c2ea956dd42b576e63606e3064af0d617fd9c3d97b6ba878f14fc13818d2001a3cf07b73ecde648e31fdb8d9b7e316bd5549470
languageName: node
linkType: hard
"@sentry/integrations@npm:^7.114.0":
version: 7.114.0
resolution: "@sentry/integrations@npm:7.114.0"
"@sentry/types@npm:8.4.0":
version: 8.4.0
resolution: "@sentry/types@npm:8.4.0"
checksum: 10c0/0fd8790b8b6c353029feb47caf4b85f3a972f6a37f90ab6719f6d9425919c53069e9e15976da4690a4c738c2c0c3fbebd00749ae3568aaa719e02552c38e3feb
languageName: node
linkType: hard
"@sentry/utils@npm:8.4.0":
version: 8.4.0
resolution: "@sentry/utils@npm:8.4.0"
dependencies:
"@sentry/core": "npm:7.114.0"
"@sentry/types": "npm:7.114.0"
"@sentry/utils": "npm:7.114.0"
localforage: "npm:^1.8.1"
checksum: 10c0/180fedbd474d1141d90882446de023da38df906489e9abeee4d659b9e5498922b66271c6e85b154c0c393a9157329b3e36c4fa98ba88d1741644797dbeedec1d
languageName: node
linkType: hard
"@sentry/replay@npm:7.110.1":
version: 7.110.1
resolution: "@sentry/replay@npm:7.110.1"
dependencies:
"@sentry-internal/tracing": "npm:7.110.1"
"@sentry/core": "npm:7.110.1"
"@sentry/types": "npm:7.110.1"
"@sentry/utils": "npm:7.110.1"
checksum: 10c0/ffb300d229d6447ea0f2b99a21ab3d6fae6136cdef33fb9daaac417b1a6b070f385139c934a2acff68562a6f5acdcf96a6e606ddf3893b7a9d44955597343841
languageName: node
linkType: hard
"@sentry/types@npm:7.110.1":
version: 7.110.1
resolution: "@sentry/types@npm:7.110.1"
checksum: 10c0/6892ae1bed6426ef10dba075d0bd68247bac7c024a7860f3385d320759e152bd9e7bb4b3eeec2600a58d81bb30084fd01e9586da09e372fb48d615c24c86fd10
languageName: node
linkType: hard
"@sentry/types@npm:7.114.0":
version: 7.114.0
resolution: "@sentry/types@npm:7.114.0"
checksum: 10c0/25564ee09beb2362f43a4f96270acdb4e1c9d999ab4fd37b6e340717433b3e685301dc0c55a7e8883226f2f20023b99055cea04f68eaaf22f4d5f9c5d6976b43
languageName: node
linkType: hard
"@sentry/utils@npm:7.110.1":
version: 7.110.1
resolution: "@sentry/utils@npm:7.110.1"
dependencies:
"@sentry/types": "npm:7.110.1"
checksum: 10c0/ab84862283881808e94e68d4abe19a38024fbe8de0bd55ddbb1238123772ce633fd507af7f636427333c6376767a85f6e665ece647c43183fdcac6a8e7ba3c77
languageName: node
linkType: hard
"@sentry/utils@npm:7.114.0, @sentry/utils@npm:^7.114.0":
version: 7.114.0
resolution: "@sentry/utils@npm:7.114.0"
dependencies:
"@sentry/types": "npm:7.114.0"
checksum: 10c0/b20283d62df7ea3c71988e9fc2a6b7d3d04dd4a92a3599605413e2da3ff3cb408b84d65ee7c8e0bd8f99a92dd6e364c37485023e8d2c7cbcbd3f31dfb2d15383
"@sentry/types": "npm:8.4.0"
checksum: 10c0/3306ba659874344b63ca72dbf7172641b38f590abf8c15291c6f98b2752dcfa9569a209cf83f7a83601acd1c22bc4ab8ead4bb55f7698b9b9b6690cfa6e5ebb5
languageName: node
linkType: hard
@ -3074,10 +3036,7 @@ __metadata:
"@egjs/hammerjs": "npm:^2.0.17"
"@fortawesome/fontawesome-free": "npm:^6.5.2"
"@popperjs/core": "npm:^2.11.8"
"@sentry/browser": "npm:^7.110.1"
"@sentry/core": "npm:^7.114.0"
"@sentry/integrations": "npm:^7.114.0"
"@sentry/utils": "npm:^7.114.0"
"@sentry/browser": "npm:^8.4.0"
"@toast-ui/editor": "npm:^3.2.2"
"@webpack-cli/serve": "npm:^2.0.5"
ace-builds: "npm:^1.34.0"
@ -4771,13 +4730,6 @@ __metadata:
languageName: node
linkType: hard
"immediate@npm:~3.0.5":
version: 3.0.6
resolution: "immediate@npm:3.0.6"
checksum: 10c0/f8ba7ede69bee9260241ad078d2d535848745ff5f6995c7c7cb41cfdc9ccc213f66e10fa5afb881f90298b24a3f7344b637b592beb4f54e582770cdce3f1f039
languageName: node
linkType: hard
"immutable@npm:^4.0.0":
version: 4.3.4
resolution: "immutable@npm:4.3.4"
@ -5200,15 +5152,6 @@ __metadata:
languageName: node
linkType: hard
"lie@npm:3.1.1":
version: 3.1.1
resolution: "lie@npm:3.1.1"
dependencies:
immediate: "npm:~3.0.5"
checksum: 10c0/d62685786590351b8e407814acdd89efe1cb136f05cb9236c5a97b2efdca1f631d2997310ad2d565c753db7596799870140e4777c9c9b8c44a0f6bf42d1804a1
languageName: node
linkType: hard
"lilconfig@npm:^3.1.1":
version: 3.1.1
resolution: "lilconfig@npm:3.1.1"
@ -5234,15 +5177,6 @@ __metadata:
languageName: node
linkType: hard
"localforage@npm:^1.8.1":
version: 1.10.0
resolution: "localforage@npm:1.10.0"
dependencies:
lie: "npm:3.1.1"
checksum: 10c0/00f19f1f97002e6721587ed5017f502d58faf80dae567d5065d4d1ee0caf0762f40d2e2dba7f0ef7d3f14ee6203242daae9ecad97359bfc10ecff36df11d85a3
languageName: node
linkType: hard
"locate-path@npm:^5.0.0":
version: 5.0.0
resolution: "locate-path@npm:5.0.0"