@sentry/utils
Advanced tools
Comparing version
@@ -69,2 +69,3 @@ Object.defineProperty(exports, '__esModule', { value: true }); | ||
exports.addConsoleInstrumentationHandler = console.addConsoleInstrumentationHandler; | ||
exports.addFetchEndInstrumentationHandler = fetch.addFetchEndInstrumentationHandler; | ||
exports.addFetchInstrumentationHandler = fetch.addFetchInstrumentationHandler; | ||
@@ -71,0 +72,0 @@ exports.addGlobalErrorInstrumentationHandler = globalError.addGlobalErrorInstrumentationHandler; |
@@ -18,10 +18,27 @@ Object.defineProperty(exports, '__esModule', { value: true }); | ||
*/ | ||
function addFetchInstrumentationHandler(handler) { | ||
function addFetchInstrumentationHandler( | ||
handler, | ||
skipNativeFetchCheck, | ||
) { | ||
const type = 'fetch'; | ||
handlers.addHandler(type, handler); | ||
handlers.maybeInstrument(type, instrumentFetch); | ||
handlers.maybeInstrument(type, () => instrumentFetch(undefined, skipNativeFetchCheck)); | ||
} | ||
function instrumentFetch() { | ||
if (!supports.supportsNativeFetch()) { | ||
/** | ||
* Add an instrumentation handler for long-lived fetch requests, like consuming server-sent events (SSE) via fetch. | ||
* The handler will resolve the request body and emit the actual `endTimestamp`, so that the | ||
* span can be updated accordingly. | ||
* | ||
* Only used internally | ||
* @hidden | ||
*/ | ||
function addFetchEndInstrumentationHandler(handler) { | ||
const type = 'fetch-body-resolved'; | ||
handlers.addHandler(type, handler); | ||
handlers.maybeInstrument(type, () => instrumentFetch(streamHandler)); | ||
} | ||
function instrumentFetch(onFetchResolved, skipNativeFetchCheck = false) { | ||
if (skipNativeFetchCheck && !supports.supportsNativeFetch()) { | ||
return; | ||
@@ -33,3 +50,2 @@ } | ||
const { method, url } = parseFetchArgs(args); | ||
const handlerData = { | ||
@@ -44,5 +60,8 @@ args, | ||
handlers.triggerHandlers('fetch', { | ||
...handlerData, | ||
}); | ||
// if there is no callback, fetch is instrumented directly | ||
if (!onFetchResolved) { | ||
handlers.triggerHandlers('fetch', { | ||
...handlerData, | ||
}); | ||
} | ||
@@ -60,34 +79,40 @@ // We capture the stack right here and not in the Promise error callback because Safari (and probably other | ||
return originalFetch.apply(worldwide.GLOBAL_OBJ, args).then( | ||
(response) => { | ||
const finishedHandlerData = { | ||
...handlerData, | ||
endTimestamp: time.timestampInSeconds() * 1000, | ||
response, | ||
}; | ||
async (response) => { | ||
if (onFetchResolved) { | ||
onFetchResolved(response); | ||
} else { | ||
const finishedHandlerData = { | ||
...handlerData, | ||
endTimestamp: time.timestampInSeconds() * 1000, | ||
response, | ||
}; | ||
handlers.triggerHandlers('fetch', finishedHandlerData); | ||
} | ||
handlers.triggerHandlers('fetch', finishedHandlerData); | ||
return response; | ||
}, | ||
(error) => { | ||
const erroredHandlerData = { | ||
...handlerData, | ||
endTimestamp: time.timestampInSeconds() * 1000, | ||
error, | ||
}; | ||
if (!onFetchResolved) { | ||
const erroredHandlerData = { | ||
...handlerData, | ||
endTimestamp: time.timestampInSeconds() * 1000, | ||
error, | ||
}; | ||
handlers.triggerHandlers('fetch', erroredHandlerData); | ||
handlers.triggerHandlers('fetch', erroredHandlerData); | ||
if (is.isError(error) && error.stack === undefined) { | ||
if (is.isError(error) && error.stack === undefined) { | ||
// NOTE: If you are a Sentry user, and you are seeing this stack frame, | ||
// it means the error, that was caused by your fetch call did not | ||
// have a stack trace, so the SDK backfilled the stack trace so | ||
// you can see which fetch call failed. | ||
error.stack = virtualStackTrace; | ||
object.addNonEnumerableProperty(error, 'framesToPop', 1); | ||
} | ||
// NOTE: If you are a Sentry user, and you are seeing this stack frame, | ||
// it means the error, that was caused by your fetch call did not | ||
// have a stack trace, so the SDK backfilled the stack trace so | ||
// you can see which fetch call failed. | ||
error.stack = virtualStackTrace; | ||
object.addNonEnumerableProperty(error, 'framesToPop', 1); | ||
// it means the sentry.javascript SDK caught an error invoking your application code. | ||
// This is expected behavior and NOT indicative of a bug with sentry.javascript. | ||
throw error; | ||
} | ||
// NOTE: If you are a Sentry user, and you are seeing this stack frame, | ||
// it means the sentry.javascript SDK caught an error invoking your application code. | ||
// This is expected behavior and NOT indicative of a bug with sentry.javascript. | ||
throw error; | ||
}, | ||
@@ -99,2 +124,57 @@ ); | ||
function resolveResponse(res, onFinishedResolving) { | ||
if (res && res.body) { | ||
const responseReader = res.body.getReader(); | ||
// eslint-disable-next-line no-inner-declarations | ||
async function consumeChunks({ done }) { | ||
if (!done) { | ||
try { | ||
// abort reading if read op takes more than 5s | ||
const result = await Promise.race([ | ||
responseReader.read(), | ||
new Promise(res => { | ||
setTimeout(() => { | ||
res({ done: true }); | ||
}, 5000); | ||
}), | ||
]); | ||
await consumeChunks(result); | ||
} catch (error) { | ||
// handle error if needed | ||
} | ||
} else { | ||
return Promise.resolve(); | ||
} | ||
} | ||
responseReader | ||
.read() | ||
.then(consumeChunks) | ||
.then(() => { | ||
onFinishedResolving(); | ||
}) | ||
.catch(() => { | ||
// noop | ||
}); | ||
} | ||
} | ||
async function streamHandler(response) { | ||
// clone response for awaiting stream | ||
let clonedResponseForResolving; | ||
try { | ||
clonedResponseForResolving = response.clone(); | ||
} catch (e) { | ||
// noop | ||
} | ||
await resolveResponse(clonedResponseForResolving, () => { | ||
handlers.triggerHandlers('fetch-body-resolved', { | ||
endTimestamp: time.timestampInSeconds() * 1000, | ||
response, | ||
}); | ||
}); | ||
} | ||
function hasProp(obj, prop) { | ||
@@ -149,4 +229,5 @@ return !!obj && typeof obj === 'object' && !!(obj )[prop]; | ||
exports.addFetchEndInstrumentationHandler = addFetchEndInstrumentationHandler; | ||
exports.addFetchInstrumentationHandler = addFetchInstrumentationHandler; | ||
exports.parseFetchArgs = parseFetchArgs; | ||
//# sourceMappingURL=fetch.js.map |
Object.defineProperty(exports, '__esModule', { value: true }); | ||
const SDK_VERSION = '8.20.0'; | ||
const SDK_VERSION = '8.21.0'; | ||
exports.SDK_VERSION = SDK_VERSION; | ||
//# sourceMappingURL=version.js.map |
@@ -8,3 +8,3 @@ export { applyAggregateErrorsToEvent } from './aggregate-errors.js'; | ||
export { addConsoleInstrumentationHandler } from './instrument/console.js'; | ||
export { addFetchInstrumentationHandler } from './instrument/fetch.js'; | ||
export { addFetchEndInstrumentationHandler, addFetchInstrumentationHandler } from './instrument/fetch.js'; | ||
export { addGlobalErrorInstrumentationHandler } from './instrument/globalError.js'; | ||
@@ -11,0 +11,0 @@ export { addGlobalUnhandledRejectionInstrumentationHandler } from './instrument/globalUnhandledRejection.js'; |
@@ -16,10 +16,27 @@ import { isError } from '../is.js'; | ||
*/ | ||
function addFetchInstrumentationHandler(handler) { | ||
function addFetchInstrumentationHandler( | ||
handler, | ||
skipNativeFetchCheck, | ||
) { | ||
const type = 'fetch'; | ||
addHandler(type, handler); | ||
maybeInstrument(type, instrumentFetch); | ||
maybeInstrument(type, () => instrumentFetch(undefined, skipNativeFetchCheck)); | ||
} | ||
function instrumentFetch() { | ||
if (!supportsNativeFetch()) { | ||
/** | ||
* Add an instrumentation handler for long-lived fetch requests, like consuming server-sent events (SSE) via fetch. | ||
* The handler will resolve the request body and emit the actual `endTimestamp`, so that the | ||
* span can be updated accordingly. | ||
* | ||
* Only used internally | ||
* @hidden | ||
*/ | ||
function addFetchEndInstrumentationHandler(handler) { | ||
const type = 'fetch-body-resolved'; | ||
addHandler(type, handler); | ||
maybeInstrument(type, () => instrumentFetch(streamHandler)); | ||
} | ||
function instrumentFetch(onFetchResolved, skipNativeFetchCheck = false) { | ||
if (skipNativeFetchCheck && !supportsNativeFetch()) { | ||
return; | ||
@@ -31,3 +48,2 @@ } | ||
const { method, url } = parseFetchArgs(args); | ||
const handlerData = { | ||
@@ -42,5 +58,8 @@ args, | ||
triggerHandlers('fetch', { | ||
...handlerData, | ||
}); | ||
// if there is no callback, fetch is instrumented directly | ||
if (!onFetchResolved) { | ||
triggerHandlers('fetch', { | ||
...handlerData, | ||
}); | ||
} | ||
@@ -58,34 +77,40 @@ // We capture the stack right here and not in the Promise error callback because Safari (and probably other | ||
return originalFetch.apply(GLOBAL_OBJ, args).then( | ||
(response) => { | ||
const finishedHandlerData = { | ||
...handlerData, | ||
endTimestamp: timestampInSeconds() * 1000, | ||
response, | ||
}; | ||
async (response) => { | ||
if (onFetchResolved) { | ||
onFetchResolved(response); | ||
} else { | ||
const finishedHandlerData = { | ||
...handlerData, | ||
endTimestamp: timestampInSeconds() * 1000, | ||
response, | ||
}; | ||
triggerHandlers('fetch', finishedHandlerData); | ||
} | ||
triggerHandlers('fetch', finishedHandlerData); | ||
return response; | ||
}, | ||
(error) => { | ||
const erroredHandlerData = { | ||
...handlerData, | ||
endTimestamp: timestampInSeconds() * 1000, | ||
error, | ||
}; | ||
if (!onFetchResolved) { | ||
const erroredHandlerData = { | ||
...handlerData, | ||
endTimestamp: timestampInSeconds() * 1000, | ||
error, | ||
}; | ||
triggerHandlers('fetch', erroredHandlerData); | ||
triggerHandlers('fetch', erroredHandlerData); | ||
if (isError(error) && error.stack === undefined) { | ||
if (isError(error) && error.stack === undefined) { | ||
// NOTE: If you are a Sentry user, and you are seeing this stack frame, | ||
// it means the error, that was caused by your fetch call did not | ||
// have a stack trace, so the SDK backfilled the stack trace so | ||
// you can see which fetch call failed. | ||
error.stack = virtualStackTrace; | ||
addNonEnumerableProperty(error, 'framesToPop', 1); | ||
} | ||
// NOTE: If you are a Sentry user, and you are seeing this stack frame, | ||
// it means the error, that was caused by your fetch call did not | ||
// have a stack trace, so the SDK backfilled the stack trace so | ||
// you can see which fetch call failed. | ||
error.stack = virtualStackTrace; | ||
addNonEnumerableProperty(error, 'framesToPop', 1); | ||
// it means the sentry.javascript SDK caught an error invoking your application code. | ||
// This is expected behavior and NOT indicative of a bug with sentry.javascript. | ||
throw error; | ||
} | ||
// NOTE: If you are a Sentry user, and you are seeing this stack frame, | ||
// it means the sentry.javascript SDK caught an error invoking your application code. | ||
// This is expected behavior and NOT indicative of a bug with sentry.javascript. | ||
throw error; | ||
}, | ||
@@ -97,2 +122,57 @@ ); | ||
function resolveResponse(res, onFinishedResolving) { | ||
if (res && res.body) { | ||
const responseReader = res.body.getReader(); | ||
// eslint-disable-next-line no-inner-declarations | ||
async function consumeChunks({ done }) { | ||
if (!done) { | ||
try { | ||
// abort reading if read op takes more than 5s | ||
const result = await Promise.race([ | ||
responseReader.read(), | ||
new Promise(res => { | ||
setTimeout(() => { | ||
res({ done: true }); | ||
}, 5000); | ||
}), | ||
]); | ||
await consumeChunks(result); | ||
} catch (error) { | ||
// handle error if needed | ||
} | ||
} else { | ||
return Promise.resolve(); | ||
} | ||
} | ||
responseReader | ||
.read() | ||
.then(consumeChunks) | ||
.then(() => { | ||
onFinishedResolving(); | ||
}) | ||
.catch(() => { | ||
// noop | ||
}); | ||
} | ||
} | ||
async function streamHandler(response) { | ||
// clone response for awaiting stream | ||
let clonedResponseForResolving; | ||
try { | ||
clonedResponseForResolving = response.clone(); | ||
} catch (e) { | ||
// noop | ||
} | ||
await resolveResponse(clonedResponseForResolving, () => { | ||
triggerHandlers('fetch-body-resolved', { | ||
endTimestamp: timestampInSeconds() * 1000, | ||
response, | ||
}); | ||
}); | ||
} | ||
function hasProp(obj, prop) { | ||
@@ -147,3 +227,3 @@ return !!obj && typeof obj === 'object' && !!(obj )[prop]; | ||
export { addFetchInstrumentationHandler, parseFetchArgs }; | ||
export { addFetchEndInstrumentationHandler, addFetchInstrumentationHandler, parseFetchArgs }; | ||
//# sourceMappingURL=fetch.js.map |
@@ -1,4 +0,4 @@ | ||
const SDK_VERSION = '8.20.0'; | ||
const SDK_VERSION = '8.21.0'; | ||
export { SDK_VERSION }; | ||
//# sourceMappingURL=version.js.map |
@@ -10,4 +10,13 @@ import { HandlerDataFetch } from '@sentry/types'; | ||
*/ | ||
export declare function addFetchInstrumentationHandler(handler: (data: HandlerDataFetch) => void): void; | ||
export declare function addFetchInstrumentationHandler(handler: (data: HandlerDataFetch) => void, skipNativeFetchCheck?: boolean): void; | ||
/** | ||
* Add an instrumentation handler for long-lived fetch requests, like consuming server-sent events (SSE) via fetch. | ||
* The handler will resolve the request body and emit the actual `endTimestamp`, so that the | ||
* span can be updated accordingly. | ||
* | ||
* Only used internally | ||
* @hidden | ||
*/ | ||
export declare function addFetchEndInstrumentationHandler(handler: (data: HandlerDataFetch) => void): void; | ||
/** | ||
* Parses the fetch arguments to find the used Http method and the url of the request. | ||
@@ -14,0 +23,0 @@ * Exported for tests only. |
@@ -1,2 +0,2 @@ | ||
export type InstrumentHandlerType = 'console' | 'dom' | 'fetch' | 'history' | 'xhr' | 'error' | 'unhandledrejection'; | ||
export type InstrumentHandlerType = 'console' | 'dom' | 'fetch' | 'fetch-body-resolved' | 'history' | 'xhr' | 'error' | 'unhandledrejection'; | ||
export type InstrumentHandlerCallback = (data: any) => void; | ||
@@ -3,0 +3,0 @@ /** Add a handler function. */ |
import { addConsoleInstrumentationHandler } from './console'; | ||
import { addFetchInstrumentationHandler } from './fetch'; | ||
import { addFetchEndInstrumentationHandler, addFetchInstrumentationHandler } from './fetch'; | ||
import { addGlobalErrorInstrumentationHandler } from './globalError'; | ||
import { addGlobalUnhandledRejectionInstrumentationHandler } from './globalUnhandledRejection'; | ||
import { addHandler, maybeInstrument, resetInstrumentationHandlers, triggerHandlers } from './handlers'; | ||
export { addConsoleInstrumentationHandler, addFetchInstrumentationHandler, addGlobalErrorInstrumentationHandler, addGlobalUnhandledRejectionInstrumentationHandler, addHandler, maybeInstrument, triggerHandlers, resetInstrumentationHandlers, }; | ||
export { addConsoleInstrumentationHandler, addFetchInstrumentationHandler, addGlobalErrorInstrumentationHandler, addGlobalUnhandledRejectionInstrumentationHandler, addHandler, maybeInstrument, triggerHandlers, resetInstrumentationHandlers, addFetchEndInstrumentationHandler, }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -1,2 +0,2 @@ | ||
export declare const SDK_VERSION = "8.20.0"; | ||
export declare const SDK_VERSION = "8.21.0"; | ||
//# sourceMappingURL=version.d.ts.map |
@@ -10,4 +10,13 @@ import type { HandlerDataFetch } from '@sentry/types'; | ||
*/ | ||
export declare function addFetchInstrumentationHandler(handler: (data: HandlerDataFetch) => void): void; | ||
export declare function addFetchInstrumentationHandler(handler: (data: HandlerDataFetch) => void, skipNativeFetchCheck?: boolean): void; | ||
/** | ||
* Add an instrumentation handler for long-lived fetch requests, like consuming server-sent events (SSE) via fetch. | ||
* The handler will resolve the request body and emit the actual `endTimestamp`, so that the | ||
* span can be updated accordingly. | ||
* | ||
* Only used internally | ||
* @hidden | ||
*/ | ||
export declare function addFetchEndInstrumentationHandler(handler: (data: HandlerDataFetch) => void): void; | ||
/** | ||
* Parses the fetch arguments to find the used Http method and the url of the request. | ||
@@ -14,0 +23,0 @@ * Exported for tests only. |
@@ -1,2 +0,2 @@ | ||
export type InstrumentHandlerType = 'console' | 'dom' | 'fetch' | 'history' | 'xhr' | 'error' | 'unhandledrejection'; | ||
export type InstrumentHandlerType = 'console' | 'dom' | 'fetch' | 'fetch-body-resolved' | 'history' | 'xhr' | 'error' | 'unhandledrejection'; | ||
export type InstrumentHandlerCallback = (data: any) => void; | ||
@@ -3,0 +3,0 @@ /** Add a handler function. */ |
import { addConsoleInstrumentationHandler } from './console'; | ||
import { addFetchInstrumentationHandler } from './fetch'; | ||
import { addFetchEndInstrumentationHandler, addFetchInstrumentationHandler } from './fetch'; | ||
import { addGlobalErrorInstrumentationHandler } from './globalError'; | ||
import { addGlobalUnhandledRejectionInstrumentationHandler } from './globalUnhandledRejection'; | ||
import { addHandler, maybeInstrument, resetInstrumentationHandlers, triggerHandlers } from './handlers'; | ||
export { addConsoleInstrumentationHandler, addFetchInstrumentationHandler, addGlobalErrorInstrumentationHandler, addGlobalUnhandledRejectionInstrumentationHandler, addHandler, maybeInstrument, triggerHandlers, resetInstrumentationHandlers, }; | ||
export { addConsoleInstrumentationHandler, addFetchInstrumentationHandler, addGlobalErrorInstrumentationHandler, addGlobalUnhandledRejectionInstrumentationHandler, addHandler, maybeInstrument, triggerHandlers, resetInstrumentationHandlers, addFetchEndInstrumentationHandler, }; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -1,2 +0,2 @@ | ||
export declare const SDK_VERSION = "8.20.0"; | ||
export declare const SDK_VERSION = "8.21.0"; | ||
//# sourceMappingURL=version.d.ts.map |
{ | ||
"name": "@sentry/utils", | ||
"version": "8.20.0", | ||
"version": "8.21.0", | ||
"description": "Utilities for all Sentry JavaScript SDKs", | ||
@@ -42,3 +42,3 @@ "repository": "git://github.com/getsentry/sentry-javascript.git", | ||
"dependencies": { | ||
"@sentry/types": "8.20.0" | ||
"@sentry/types": "8.21.0" | ||
}, | ||
@@ -45,0 +45,0 @@ "devDependencies": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
1157502
1.28%12743
1.37%+ Added
- Removed
Updated