Next.js website for Rocky Mountain Vending company featuring: - Product catalog with Stripe integration - Service areas and parts pages - Admin dashboard with Clerk authentication - SEO optimized pages with JSON-LD structured data Co-authored-by: Cursor <cursoragent@cursor.com>
345 lines
10 KiB
Text
345 lines
10 KiB
Text
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
|
const constants = require('../constants.js');
|
|
const currentScopes = require('../currentScopes.js');
|
|
const eventProcessors = require('../eventProcessors.js');
|
|
const scope = require('../scope.js');
|
|
const applyScopeDataToEvent = require('./applyScopeDataToEvent.js');
|
|
const debugIds = require('./debug-ids.js');
|
|
const misc = require('./misc.js');
|
|
const normalize = require('./normalize.js');
|
|
const string = require('./string.js');
|
|
const time = require('./time.js');
|
|
|
|
/**
|
|
* This type makes sure that we get either a CaptureContext, OR an EventHint.
|
|
* It does not allow mixing them, which could lead to unexpected outcomes, e.g. this is disallowed:
|
|
* { user: { id: '123' }, mechanism: { handled: false } }
|
|
*/
|
|
|
|
/**
|
|
* Adds common information to events.
|
|
*
|
|
* The information includes release and environment from `options`,
|
|
* breadcrumbs and context (extra, tags and user) from the scope.
|
|
*
|
|
* Information that is already present in the event is never overwritten. For
|
|
* nested objects, such as the context, keys are merged.
|
|
*
|
|
* @param event The original event.
|
|
* @param hint May contain additional information about the original exception.
|
|
* @param scope A scope containing event metadata.
|
|
* @returns A new event with more information.
|
|
* @hidden
|
|
*/
|
|
function prepareEvent(
|
|
options,
|
|
event,
|
|
hint,
|
|
scope,
|
|
client,
|
|
isolationScope,
|
|
) {
|
|
const { normalizeDepth = 3, normalizeMaxBreadth = 1000 } = options;
|
|
const prepared = {
|
|
...event,
|
|
event_id: event.event_id || hint.event_id || misc.uuid4(),
|
|
timestamp: event.timestamp || time.dateTimestampInSeconds(),
|
|
};
|
|
const integrations = hint.integrations || options.integrations.map(i => i.name);
|
|
|
|
applyClientOptions(prepared, options);
|
|
applyIntegrationsMetadata(prepared, integrations);
|
|
|
|
if (client) {
|
|
client.emit('applyFrameMetadata', event);
|
|
}
|
|
|
|
// Only put debug IDs onto frames for error events.
|
|
if (event.type === undefined) {
|
|
applyDebugIds(prepared, options.stackParser);
|
|
}
|
|
|
|
// If we have scope given to us, use it as the base for further modifications.
|
|
// This allows us to prevent unnecessary copying of data if `captureContext` is not provided.
|
|
const finalScope = getFinalScope(scope, hint.captureContext);
|
|
|
|
if (hint.mechanism) {
|
|
misc.addExceptionMechanism(prepared, hint.mechanism);
|
|
}
|
|
|
|
const clientEventProcessors = client ? client.getEventProcessors() : [];
|
|
|
|
// This should be the last thing called, since we want that
|
|
// {@link Scope.addEventProcessor} gets the finished prepared event.
|
|
// Merge scope data together
|
|
const data = currentScopes.getGlobalScope().getScopeData();
|
|
|
|
if (isolationScope) {
|
|
const isolationData = isolationScope.getScopeData();
|
|
applyScopeDataToEvent.mergeScopeData(data, isolationData);
|
|
}
|
|
|
|
if (finalScope) {
|
|
const finalScopeData = finalScope.getScopeData();
|
|
applyScopeDataToEvent.mergeScopeData(data, finalScopeData);
|
|
}
|
|
|
|
const attachments = [...(hint.attachments || []), ...data.attachments];
|
|
if (attachments.length) {
|
|
hint.attachments = attachments;
|
|
}
|
|
|
|
applyScopeDataToEvent.applyScopeDataToEvent(prepared, data);
|
|
|
|
const eventProcessors$1 = [
|
|
...clientEventProcessors,
|
|
// Run scope event processors _after_ all other processors
|
|
...data.eventProcessors,
|
|
];
|
|
|
|
const result = eventProcessors.notifyEventProcessors(eventProcessors$1, prepared, hint);
|
|
|
|
return result.then(evt => {
|
|
if (evt) {
|
|
// We apply the debug_meta field only after all event processors have ran, so that if any event processors modified
|
|
// file names (e.g.the RewriteFrames integration) the filename -> debug ID relationship isn't destroyed.
|
|
// This should not cause any PII issues, since we're only moving data that is already on the event and not adding
|
|
// any new data
|
|
applyDebugMeta(evt);
|
|
}
|
|
|
|
if (typeof normalizeDepth === 'number' && normalizeDepth > 0) {
|
|
return normalizeEvent(evt, normalizeDepth, normalizeMaxBreadth);
|
|
}
|
|
return evt;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Enhances event using the client configuration.
|
|
* It takes care of all "static" values like environment, release and `dist`,
|
|
* as well as truncating overly long values.
|
|
*
|
|
* Only exported for tests.
|
|
*
|
|
* @param event event instance to be enhanced
|
|
*/
|
|
function applyClientOptions(event, options) {
|
|
const { environment, release, dist, maxValueLength = 250 } = options;
|
|
|
|
// empty strings do not make sense for environment, release, and dist
|
|
// so we handle them the same as if they were not provided
|
|
event.environment = event.environment || environment || constants.DEFAULT_ENVIRONMENT;
|
|
|
|
if (!event.release && release) {
|
|
event.release = release;
|
|
}
|
|
|
|
if (!event.dist && dist) {
|
|
event.dist = dist;
|
|
}
|
|
|
|
const request = event.request;
|
|
if (request?.url) {
|
|
request.url = string.truncate(request.url, maxValueLength);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Puts debug IDs into the stack frames of an error event.
|
|
*/
|
|
function applyDebugIds(event, stackParser) {
|
|
// Build a map of filename -> debug_id
|
|
const filenameDebugIdMap = debugIds.getFilenameToDebugIdMap(stackParser);
|
|
|
|
event.exception?.values?.forEach(exception => {
|
|
exception.stacktrace?.frames?.forEach(frame => {
|
|
if (frame.filename) {
|
|
frame.debug_id = filenameDebugIdMap[frame.filename];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Moves debug IDs from the stack frames of an error event into the debug_meta field.
|
|
*/
|
|
function applyDebugMeta(event) {
|
|
// Extract debug IDs and filenames from the stack frames on the event.
|
|
const filenameDebugIdMap = {};
|
|
event.exception?.values?.forEach(exception => {
|
|
exception.stacktrace?.frames?.forEach(frame => {
|
|
if (frame.debug_id) {
|
|
if (frame.abs_path) {
|
|
filenameDebugIdMap[frame.abs_path] = frame.debug_id;
|
|
} else if (frame.filename) {
|
|
filenameDebugIdMap[frame.filename] = frame.debug_id;
|
|
}
|
|
delete frame.debug_id;
|
|
}
|
|
});
|
|
});
|
|
|
|
if (Object.keys(filenameDebugIdMap).length === 0) {
|
|
return;
|
|
}
|
|
|
|
// Fill debug_meta information
|
|
event.debug_meta = event.debug_meta || {};
|
|
event.debug_meta.images = event.debug_meta.images || [];
|
|
const images = event.debug_meta.images;
|
|
Object.entries(filenameDebugIdMap).forEach(([filename, debug_id]) => {
|
|
images.push({
|
|
type: 'sourcemap',
|
|
code_file: filename,
|
|
debug_id,
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* This function adds all used integrations to the SDK info in the event.
|
|
* @param event The event that will be filled with all integrations.
|
|
*/
|
|
function applyIntegrationsMetadata(event, integrationNames) {
|
|
if (integrationNames.length > 0) {
|
|
event.sdk = event.sdk || {};
|
|
event.sdk.integrations = [...(event.sdk.integrations || []), ...integrationNames];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Applies `normalize` function on necessary `Event` attributes to make them safe for serialization.
|
|
* Normalized keys:
|
|
* - `breadcrumbs.data`
|
|
* - `user`
|
|
* - `contexts`
|
|
* - `extra`
|
|
* @param event Event
|
|
* @returns Normalized event
|
|
*/
|
|
function normalizeEvent(event, depth, maxBreadth) {
|
|
if (!event) {
|
|
return null;
|
|
}
|
|
|
|
const normalized = {
|
|
...event,
|
|
...(event.breadcrumbs && {
|
|
breadcrumbs: event.breadcrumbs.map(b => ({
|
|
...b,
|
|
...(b.data && {
|
|
data: normalize.normalize(b.data, depth, maxBreadth),
|
|
}),
|
|
})),
|
|
}),
|
|
...(event.user && {
|
|
user: normalize.normalize(event.user, depth, maxBreadth),
|
|
}),
|
|
...(event.contexts && {
|
|
contexts: normalize.normalize(event.contexts, depth, maxBreadth),
|
|
}),
|
|
...(event.extra && {
|
|
extra: normalize.normalize(event.extra, depth, maxBreadth),
|
|
}),
|
|
};
|
|
|
|
// event.contexts.trace stores information about a Transaction. Similarly,
|
|
// event.spans[] stores information about child Spans. Given that a
|
|
// Transaction is conceptually a Span, normalization should apply to both
|
|
// Transactions and Spans consistently.
|
|
// For now the decision is to skip normalization of Transactions and Spans,
|
|
// so this block overwrites the normalized event to add back the original
|
|
// Transaction information prior to normalization.
|
|
if (event.contexts?.trace && normalized.contexts) {
|
|
normalized.contexts.trace = event.contexts.trace;
|
|
|
|
// event.contexts.trace.data may contain circular/dangerous data so we need to normalize it
|
|
if (event.contexts.trace.data) {
|
|
normalized.contexts.trace.data = normalize.normalize(event.contexts.trace.data, depth, maxBreadth);
|
|
}
|
|
}
|
|
|
|
// event.spans[].data may contain circular/dangerous data so we need to normalize it
|
|
if (event.spans) {
|
|
normalized.spans = event.spans.map(span => {
|
|
return {
|
|
...span,
|
|
...(span.data && {
|
|
data: normalize.normalize(span.data, depth, maxBreadth),
|
|
}),
|
|
};
|
|
});
|
|
}
|
|
|
|
// event.contexts.flags (FeatureFlagContext) stores context for our feature
|
|
// flag integrations. It has a greater nesting depth than our other typed
|
|
// Contexts, so we re-normalize with a fixed depth of 3 here. We do not want
|
|
// to skip this in case of conflicting, user-provided context.
|
|
if (event.contexts?.flags && normalized.contexts) {
|
|
normalized.contexts.flags = normalize.normalize(event.contexts.flags, 3, maxBreadth);
|
|
}
|
|
|
|
return normalized;
|
|
}
|
|
|
|
function getFinalScope(scope$1, captureContext) {
|
|
if (!captureContext) {
|
|
return scope$1;
|
|
}
|
|
|
|
const finalScope = scope$1 ? scope$1.clone() : new scope.Scope();
|
|
finalScope.update(captureContext);
|
|
return finalScope;
|
|
}
|
|
|
|
/**
|
|
* Parse either an `EventHint` directly, or convert a `CaptureContext` to an `EventHint`.
|
|
* This is used to allow to update method signatures that used to accept a `CaptureContext` but should now accept an `EventHint`.
|
|
*/
|
|
function parseEventHintOrCaptureContext(
|
|
hint,
|
|
) {
|
|
if (!hint) {
|
|
return undefined;
|
|
}
|
|
|
|
// If you pass a Scope or `() => Scope` as CaptureContext, we just return this as captureContext
|
|
if (hintIsScopeOrFunction(hint)) {
|
|
return { captureContext: hint };
|
|
}
|
|
|
|
if (hintIsScopeContext(hint)) {
|
|
return {
|
|
captureContext: hint,
|
|
};
|
|
}
|
|
|
|
return hint;
|
|
}
|
|
|
|
function hintIsScopeOrFunction(hint) {
|
|
return hint instanceof scope.Scope || typeof hint === 'function';
|
|
}
|
|
|
|
const captureContextKeys = [
|
|
'user',
|
|
'level',
|
|
'extra',
|
|
'contexts',
|
|
'tags',
|
|
'fingerprint',
|
|
'propagationContext',
|
|
] ;
|
|
|
|
function hintIsScopeContext(hint) {
|
|
return Object.keys(hint).some(key => captureContextKeys.includes(key ));
|
|
}
|
|
|
|
exports.applyClientOptions = applyClientOptions;
|
|
exports.applyDebugIds = applyDebugIds;
|
|
exports.applyDebugMeta = applyDebugMeta;
|
|
exports.parseEventHintOrCaptureContext = parseEventHintOrCaptureContext;
|
|
exports.prepareEvent = prepareEvent;
|
|
//# sourceMappingURL=prepareEvent.js.map
|