@sentry/cloudflare 10.54.0 → 10.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/flush.js +7 -1
- package/build/cjs/flush.js.map +1 -1
- package/build/cjs/integrations/hono.js.map +1 -1
- package/build/cjs/request.js +1 -1
- package/build/cjs/request.js.map +1 -1
- package/build/esm/flush.js +7 -2
- package/build/esm/flush.js.map +1 -1
- package/build/esm/integrations/hono.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/request.js +2 -2
- package/build/esm/request.js.map +1 -1
- package/build/types/flush.d.ts +15 -0
- package/build/types/flush.d.ts.map +1 -1
- package/build/types/integrations/hono.d.ts +3 -0
- package/build/types/integrations/hono.d.ts.map +1 -1
- package/build/types/request.d.ts.map +1 -1
- package/build/types-ts3.8/flush.d.ts +15 -0
- package/build/types-ts3.8/integrations/hono.d.ts +3 -0
- package/package.json +2 -2
package/build/cjs/flush.js
CHANGED
|
@@ -3,6 +3,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
3
3
|
const core = require('@sentry/core');
|
|
4
4
|
|
|
5
5
|
const flushLockRegistries = /* @__PURE__ */ new WeakMap();
|
|
6
|
+
function getOriginalWaitUntil(context) {
|
|
7
|
+
const currentWaitUntil = context.waitUntil;
|
|
8
|
+
const original = flushLockRegistries.get(currentWaitUntil)?.originalWaitUntil;
|
|
9
|
+
return original ?? currentWaitUntil;
|
|
10
|
+
}
|
|
6
11
|
function makeFlushLock(context) {
|
|
7
12
|
const registry = getOrCreateFlushLockRegistry(context);
|
|
8
13
|
let resolveAllDone = () => void 0;
|
|
@@ -38,8 +43,8 @@ function getOrCreateFlushLockRegistry(context) {
|
|
|
38
43
|
if (existingRegistry) {
|
|
39
44
|
return existingRegistry;
|
|
40
45
|
}
|
|
41
|
-
const registry = { locks: /* @__PURE__ */ new Set() };
|
|
42
46
|
const originalWaitUntil = context.waitUntil.bind(context);
|
|
47
|
+
const registry = { locks: /* @__PURE__ */ new Set(), originalWaitUntil };
|
|
43
48
|
const instrumentedWaitUntil = (promise) => {
|
|
44
49
|
const locks = [...registry.locks];
|
|
45
50
|
for (const lock of locks) {
|
|
@@ -67,5 +72,6 @@ async function flushAndDispose(client, timeout = 2e3) {
|
|
|
67
72
|
}
|
|
68
73
|
|
|
69
74
|
exports.flushAndDispose = flushAndDispose;
|
|
75
|
+
exports.getOriginalWaitUntil = getOriginalWaitUntil;
|
|
70
76
|
exports.makeFlushLock = makeFlushLock;
|
|
71
77
|
//# sourceMappingURL=flush.js.map
|
package/build/cjs/flush.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flush.js","sources":["../../src/flush.ts"],"sourcesContent":["import type { ExecutionContext } from '@cloudflare/workers-types';\nimport type { Client } from '@sentry/core';\nimport { flush } from '@sentry/core';\n\ntype FlushLock = {\n readonly ready: Promise<void>;\n readonly finalize: () => Promise<void>;\n};\n\ntype FlushLockRegistry = {\n readonly locks: Set<FlushLockInternal>;\n};\n\ntype FlushLockInternal = FlushLock & {\n readonly acquire: () => void;\n readonly release: () => void;\n};\n\nconst flushLockRegistries = new WeakMap<ExecutionContext['waitUntil'], FlushLockRegistry>();\n\n/**\n * Enhances the given execution context by wrapping its `waitUntil` method with a proxy\n * to monitor pending tasks, and provides a flusher function to ensure all tasks\n * have been completed before executing any subsequent logic.\n *\n * @param {ExecutionContext} context - The execution context to be enhanced. If no context is provided, the function returns undefined.\n * @return {FlushLock} Returns a flusher function if a valid context is provided, otherwise undefined.\n */\nexport function makeFlushLock(context: ExecutionContext): FlushLock {\n const registry = getOrCreateFlushLockRegistry(context);\n let resolveAllDone: () => void = () => undefined;\n const allDone = new Promise<void>(res => {\n resolveAllDone = res;\n });\n let pending = 0;\n\n const lock: FlushLockInternal = {\n ready: allDone,\n acquire: () => {\n pending++;\n },\n release: () => {\n if (--pending === 0) {\n registry.locks.delete(lock);\n resolveAllDone();\n }\n },\n finalize: () => {\n if (pending === 0) {\n registry.locks.delete(lock);\n resolveAllDone();\n }\n return allDone;\n },\n };\n\n registry.locks.add(lock);\n return Object.freeze(lock);\n}\n\nfunction getOrCreateFlushLockRegistry(context: ExecutionContext): FlushLockRegistry {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const waitUntil = context.waitUntil;\n const existingRegistry = flushLockRegistries.get(waitUntil);\n\n if (existingRegistry) {\n return existingRegistry;\n }\n\n const
|
|
1
|
+
{"version":3,"file":"flush.js","sources":["../../src/flush.ts"],"sourcesContent":["import type { ExecutionContext } from '@cloudflare/workers-types';\nimport type { Client } from '@sentry/core';\nimport { flush } from '@sentry/core';\n\ntype FlushLock = {\n readonly ready: Promise<void>;\n readonly finalize: () => Promise<void>;\n};\n\ntype FlushLockRegistry = {\n readonly locks: Set<FlushLockInternal>;\n readonly originalWaitUntil: ExecutionContext['waitUntil'];\n};\n\ntype FlushLockInternal = FlushLock & {\n readonly acquire: () => void;\n readonly release: () => void;\n};\n\nconst flushLockRegistries = new WeakMap<ExecutionContext['waitUntil'], FlushLockRegistry>();\n\n/**\n * Returns the original (un-instrumented) waitUntil function for a context.\n * This should be used when calling waitUntil with flushAndDispose to avoid deadlock.\n *\n * The flush lock mechanism wraps context.waitUntil to track pending tasks.\n * If we call waitUntil(flushAndDispose(client)) through the instrumented version,\n * it creates a deadlock because:\n * 1. The instrumented waitUntil acquires the flush lock\n * 2. flushAndDispose calls client.flush() which waits for the lock to be released\n * 3. The lock won't be released until the waitUntil promise completes\n * 4. The waitUntil promise won't complete until flush() returns\n *\n * By using the original waitUntil for flush operations, we bypass this issue.\n */\nexport function getOriginalWaitUntil(context: ExecutionContext): ExecutionContext['waitUntil'] | undefined {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const currentWaitUntil = context.waitUntil;\n const original = flushLockRegistries.get(currentWaitUntil)?.originalWaitUntil;\n return original ?? currentWaitUntil;\n}\n\n/**\n * Enhances the given execution context by wrapping its `waitUntil` method with a proxy\n * to monitor pending tasks, and provides a flusher function to ensure all tasks\n * have been completed before executing any subsequent logic.\n *\n * @param {ExecutionContext} context - The execution context to be enhanced. If no context is provided, the function returns undefined.\n * @return {FlushLock} Returns a flusher function if a valid context is provided, otherwise undefined.\n */\nexport function makeFlushLock(context: ExecutionContext): FlushLock {\n const registry = getOrCreateFlushLockRegistry(context);\n let resolveAllDone: () => void = () => undefined;\n const allDone = new Promise<void>(res => {\n resolveAllDone = res;\n });\n let pending = 0;\n\n const lock: FlushLockInternal = {\n ready: allDone,\n acquire: () => {\n pending++;\n },\n release: () => {\n if (--pending === 0) {\n registry.locks.delete(lock);\n resolveAllDone();\n }\n },\n finalize: () => {\n if (pending === 0) {\n registry.locks.delete(lock);\n resolveAllDone();\n }\n return allDone;\n },\n };\n\n registry.locks.add(lock);\n return Object.freeze(lock);\n}\n\nfunction getOrCreateFlushLockRegistry(context: ExecutionContext): FlushLockRegistry {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const waitUntil = context.waitUntil;\n const existingRegistry = flushLockRegistries.get(waitUntil);\n\n if (existingRegistry) {\n return existingRegistry;\n }\n\n const originalWaitUntil = context.waitUntil.bind(context) as typeof context.waitUntil;\n const registry: FlushLockRegistry = { locks: new Set(), originalWaitUntil };\n const instrumentedWaitUntil: typeof context.waitUntil = promise => {\n // Snapshot active locks so locks created after this call do not wait for earlier waitUntil work.\n const locks = [...registry.locks];\n\n for (const lock of locks) {\n lock.acquire();\n }\n\n return originalWaitUntil(\n promise.finally(() => {\n for (const lock of locks) {\n lock.release();\n }\n }),\n );\n };\n\n flushLockRegistries.set(instrumentedWaitUntil, registry);\n context.waitUntil = instrumentedWaitUntil;\n\n return registry;\n}\n\n/**\n * Flushes the client and then disposes of it to allow garbage collection.\n * This should be called at the end of each request to prevent memory leaks.\n *\n * @param client - The CloudflareClient instance to flush and dispose\n * @param timeout - Timeout in milliseconds for the flush operation\n * @returns A promise that resolves when flush and dispose are complete\n */\nexport async function flushAndDispose(client: Client | undefined, timeout = 2000): Promise<void> {\n if (!client) {\n await flush(timeout);\n\n return;\n }\n\n await client.flush(timeout);\n client.dispose();\n}\n"],"names":["flush"],"mappings":";;;;AAmBA,MAAM,mBAAA,uBAA0B,OAAA,EAA0D;AAgBnF,SAAS,qBAAqB,OAAA,EAAsE;AAEzG,EAAA,MAAM,mBAAmB,OAAA,CAAQ,SAAA;AACjC,EAAA,MAAM,QAAA,GAAW,mBAAA,CAAoB,GAAA,CAAI,gBAAgB,CAAA,EAAG,iBAAA;AAC5D,EAAA,OAAO,QAAA,IAAY,gBAAA;AACrB;AAUO,SAAS,cAAc,OAAA,EAAsC;AAClE,EAAA,MAAM,QAAA,GAAW,6BAA6B,OAAO,CAAA;AACrD,EAAA,IAAI,iBAA6B,MAAM,MAAA;AACvC,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAc,CAAA,GAAA,KAAO;AACvC,IAAA,cAAA,GAAiB,GAAA;AAAA,EACnB,CAAC,CAAA;AACD,EAAA,IAAI,OAAA,GAAU,CAAA;AAEd,EAAA,MAAM,IAAA,GAA0B;AAAA,IAC9B,KAAA,EAAO,OAAA;AAAA,IACP,SAAS,MAAM;AACb,MAAA,OAAA,EAAA;AAAA,IACF,CAAA;AAAA,IACA,SAAS,MAAM;AACb,MAAA,IAAI,EAAE,YAAY,CAAA,EAAG;AACnB,QAAA,QAAA,CAAS,KAAA,CAAM,OAAO,IAAI,CAAA;AAC1B,QAAA,cAAA,EAAe;AAAA,MACjB;AAAA,IACF,CAAA;AAAA,IACA,UAAU,MAAM;AACd,MAAA,IAAI,YAAY,CAAA,EAAG;AACjB,QAAA,QAAA,CAAS,KAAA,CAAM,OAAO,IAAI,CAAA;AAC1B,QAAA,cAAA,EAAe;AAAA,MACjB;AACA,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,GACF;AAEA,EAAA,QAAA,CAAS,KAAA,CAAM,IAAI,IAAI,CAAA;AACvB,EAAA,OAAO,MAAA,CAAO,OAAO,IAAI,CAAA;AAC3B;AAEA,SAAS,6BAA6B,OAAA,EAA8C;AAElF,EAAA,MAAM,YAAY,OAAA,CAAQ,SAAA;AAC1B,EAAA,MAAM,gBAAA,GAAmB,mBAAA,CAAoB,GAAA,CAAI,SAAS,CAAA;AAE1D,EAAA,IAAI,gBAAA,EAAkB;AACpB,IAAA,OAAO,gBAAA;AAAA,EACT;AAEA,EAAA,MAAM,iBAAA,GAAoB,OAAA,CAAQ,SAAA,CAAU,IAAA,CAAK,OAAO,CAAA;AACxD,EAAA,MAAM,WAA8B,EAAE,KAAA,kBAAO,IAAI,GAAA,IAAO,iBAAA,EAAkB;AAC1E,EAAA,MAAM,wBAAkD,CAAA,OAAA,KAAW;AAEjE,IAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,QAAA,CAAS,KAAK,CAAA;AAEhC,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,MAAA,IAAA,CAAK,OAAA,EAAQ;AAAA,IACf;AAEA,IAAA,OAAO,iBAAA;AAAA,MACL,OAAA,CAAQ,QAAQ,MAAM;AACpB,QAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,UAAA,IAAA,CAAK,OAAA,EAAQ;AAAA,QACf;AAAA,MACF,CAAC;AAAA,KACH;AAAA,EACF,CAAA;AAEA,EAAA,mBAAA,CAAoB,GAAA,CAAI,uBAAuB,QAAQ,CAAA;AACvD,EAAA,OAAA,CAAQ,SAAA,GAAY,qBAAA;AAEpB,EAAA,OAAO,QAAA;AACT;AAUA,eAAsB,eAAA,CAAgB,MAAA,EAA4B,OAAA,GAAU,GAAA,EAAqB;AAC/F,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAMA,WAAM,OAAO,CAAA;AAEnB,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,MAAA,CAAO,MAAM,OAAO,CAAA;AAC1B,EAAA,MAAA,CAAO,OAAA,EAAQ;AACjB;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono.js","sources":["../../../src/integrations/hono.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport {\n captureException,\n debug,\n defineIntegration,\n getActiveSpan,\n getClient,\n getIsolationScope,\n getRootSpan,\n updateSpanName,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\n\nconst INTEGRATION_NAME = 'Hono';\n\ninterface HonoError extends Error {\n status?: number;\n}\n\n// Minimal type - only exported for tests\nexport interface HonoContext {\n req: { method: string; path?: string };\n}\n\nexport interface Options {\n /**\n * Callback method deciding whether error should be captured and sent to Sentry\n * @param error Captured middleware error\n */\n shouldHandleError?(this: void, error: HonoError): boolean;\n}\n\n/** Only exported for internal use */\nexport function getHonoIntegration(): ReturnType<typeof _honoIntegration> | undefined {\n return getClient()?.getIntegrationByName(INTEGRATION_NAME);\n}\n\nfunction isHonoError(err: unknown): err is HonoError {\n if (err instanceof Error) {\n return true;\n }\n return typeof err === 'object' && err !== null && 'status' in (err as Record<string, unknown>);\n}\n\n// Vendored from https://github.com/honojs/hono/blob/d3abeb1f801aaa1b334285c73da5f5f022dbcadb/src/helper/route/index.ts#L58-L59\nconst routePath = (c: HonoContext): string => c.req?.path ?? '';\n\nconst _honoIntegration = ((options: Partial<Options> = {}) => {\n return {\n name: INTEGRATION_NAME,\n // Hono error handler: https://github.com/honojs/hono/blob/d3abeb1f801aaa1b334285c73da5f5f022dbcadb/src/hono-base.ts#L35\n handleHonoException(err: HonoError, context: HonoContext): void {\n const shouldHandleError = options.shouldHandleError || defaultShouldHandleError;\n\n if (!isHonoError(err)) {\n DEBUG_BUILD && debug.log(\"[Hono] Won't capture exception in `onError` because it's not a Hono error.\", err);\n return;\n }\n\n if (shouldHandleError(err)) {\n if (context) {\n const activeSpan = getActiveSpan();\n const spanName = `${context.req.method} ${routePath(context)}`;\n\n if (activeSpan) {\n activeSpan.updateName(spanName);\n updateSpanName(getRootSpan(activeSpan), spanName);\n }\n\n getIsolationScope().setTransactionName(spanName);\n }\n\n captureException(err, { mechanism: { handled: false, type: 'auto.faas.hono.error_handler' } });\n } else {\n DEBUG_BUILD && debug.log('[Hono] Not capturing exception because `shouldHandleError` returned `false`.', err);\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Automatically captures exceptions caught with the `onError` handler in Hono.\n *\n * The integration is enabled by default.\n *\n * @example\n * integrations: [\n * honoIntegration({\n * shouldHandleError: (err) => true; // always capture exceptions in onError\n * })\n * ]\n */\nexport const honoIntegration = defineIntegration(_honoIntegration);\n\n/**\n * Default function to determine if an error should be sent to Sentry\n *\n * 3xx and 4xx errors are not sent by default.\n */\nfunction defaultShouldHandleError(error: HonoError): boolean {\n const statusCode = error?.status;\n // 3xx and 4xx errors are not sent by default.\n return statusCode ? statusCode >= 500 || statusCode <= 299 : true;\n}\n"],"names":["getClient","DEBUG_BUILD","debug","getActiveSpan","updateSpanName","getRootSpan","getIsolationScope","captureException","defineIntegration"],"mappings":";;;;;AAaA,MAAM,gBAAA,GAAmB,MAAA;AAoBlB,SAAS,kBAAA,GAAsE;AACpF,EAAA,OAAOA,cAAA,EAAU,EAAG,oBAAA,CAAqB,gBAAgB,CAAA;AAC3D;AAEA,SAAS,YAAY,GAAA,EAAgC;AACnD,EAAA,IAAI,eAAe,KAAA,EAAO;AACxB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,KAAQ,QAAQ,QAAA,IAAa,GAAA;AACjE;AAGA,MAAM,SAAA,GAAY,CAAC,CAAA,KAA2B,CAAA,CAAE,KAAK,IAAA,IAAQ,EAAA;AAE7D,MAAM,gBAAA,IAAoB,CAAC,OAAA,GAA4B,EAAC,KAAM;AAC5D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA;AAAA,IAEN,mBAAA,CAAoB,KAAgB,OAAA,EAA4B;AAC9D,MAAA,MAAM,iBAAA,GAAoB,QAAQ,iBAAA,IAAqB,wBAAA;AAEvD,MAAA,IAAI,CAAC,WAAA,CAAY,GAAG,CAAA,EAAG;AACrB,QAAAC,sBAAA,IAAeC,UAAA,CAAM,GAAA,CAAI,4EAAA,EAA8E,GAAG,CAAA;AAC1G,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,iBAAA,CAAkB,GAAG,CAAA,EAAG;AAC1B,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,MAAM,aAAaC,kBAAA,EAAc;AACjC,UAAA,MAAM,QAAA,GAAW,GAAG,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA,CAAA,EAAI,SAAA,CAAU,OAAO,CAAC,CAAA,CAAA;AAE5D,UAAA,IAAI,UAAA,EAAY;AACd,YAAA,UAAA,CAAW,WAAW,QAAQ,CAAA;AAC9B,YAAAC,mBAAA,CAAeC,gBAAA,CAAY,UAAU,CAAA,EAAG,QAAQ,CAAA;AAAA,UAClD;AAEA,UAAAC,sBAAA,EAAkB,CAAE,mBAAmB,QAAQ,CAAA;AAAA,QACjD;AAEA,QAAAC,qBAAA,CAAiB,GAAA,EAAK,EAAE,SAAA,EAAW,EAAE,SAAS,KAAA,EAAO,IAAA,EAAM,8BAAA,EAA+B,EAAG,CAAA;AAAA,MAC/F,CAAA,MAAO;AACL,QAAAN,sBAAA,IAAeC,UAAA,CAAM,GAAA,CAAI,8EAAA,EAAgF,GAAG,CAAA;AAAA,MAC9G;AAAA,IACF;AAAA,GACF;AACF,CAAA,CAAA;
|
|
1
|
+
{"version":3,"file":"hono.js","sources":["../../../src/integrations/hono.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport {\n captureException,\n debug,\n defineIntegration,\n getActiveSpan,\n getClient,\n getIsolationScope,\n getRootSpan,\n updateSpanName,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\n\nconst INTEGRATION_NAME = 'Hono';\n\ninterface HonoError extends Error {\n status?: number;\n}\n\n// Minimal type - only exported for tests\nexport interface HonoContext {\n req: { method: string; path?: string };\n}\n\nexport interface Options {\n /**\n * Callback method deciding whether error should be captured and sent to Sentry\n * @param error Captured middleware error\n */\n shouldHandleError?(this: void, error: HonoError): boolean;\n}\n\n/** Only exported for internal use */\nexport function getHonoIntegration(): ReturnType<typeof _honoIntegration> | undefined {\n return getClient()?.getIntegrationByName(INTEGRATION_NAME);\n}\n\nfunction isHonoError(err: unknown): err is HonoError {\n if (err instanceof Error) {\n return true;\n }\n return typeof err === 'object' && err !== null && 'status' in (err as Record<string, unknown>);\n}\n\n// Vendored from https://github.com/honojs/hono/blob/d3abeb1f801aaa1b334285c73da5f5f022dbcadb/src/helper/route/index.ts#L58-L59\nconst routePath = (c: HonoContext): string => c.req?.path ?? '';\n\nconst _honoIntegration = ((options: Partial<Options> = {}) => {\n return {\n name: INTEGRATION_NAME,\n // Hono error handler: https://github.com/honojs/hono/blob/d3abeb1f801aaa1b334285c73da5f5f022dbcadb/src/hono-base.ts#L35\n handleHonoException(err: HonoError, context: HonoContext): void {\n const shouldHandleError = options.shouldHandleError || defaultShouldHandleError;\n\n if (!isHonoError(err)) {\n DEBUG_BUILD && debug.log(\"[Hono] Won't capture exception in `onError` because it's not a Hono error.\", err);\n return;\n }\n\n if (shouldHandleError(err)) {\n if (context) {\n const activeSpan = getActiveSpan();\n const spanName = `${context.req.method} ${routePath(context)}`;\n\n if (activeSpan) {\n activeSpan.updateName(spanName);\n updateSpanName(getRootSpan(activeSpan), spanName);\n }\n\n getIsolationScope().setTransactionName(spanName);\n }\n\n captureException(err, { mechanism: { handled: false, type: 'auto.faas.hono.error_handler' } });\n } else {\n DEBUG_BUILD && debug.log('[Hono] Not capturing exception because `shouldHandleError` returned `false`.', err);\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Automatically captures exceptions caught with the `onError` handler in Hono.\n *\n * The integration is enabled by default.\n *\n * @deprecated Use the `@sentry/hono` package instead. The `sentry()` middleware from `@sentry/hono/cloudflare`\n * handles error capturing automatically without needing this integration.\n *\n * @example\n * integrations: [\n * honoIntegration({\n * shouldHandleError: (err) => true; // always capture exceptions in onError\n * })\n * ]\n */\nexport const honoIntegration = defineIntegration(_honoIntegration);\n\n/**\n * Default function to determine if an error should be sent to Sentry\n *\n * 3xx and 4xx errors are not sent by default.\n */\nfunction defaultShouldHandleError(error: HonoError): boolean {\n const statusCode = error?.status;\n // 3xx and 4xx errors are not sent by default.\n return statusCode ? statusCode >= 500 || statusCode <= 299 : true;\n}\n"],"names":["getClient","DEBUG_BUILD","debug","getActiveSpan","updateSpanName","getRootSpan","getIsolationScope","captureException","defineIntegration"],"mappings":";;;;;AAaA,MAAM,gBAAA,GAAmB,MAAA;AAoBlB,SAAS,kBAAA,GAAsE;AACpF,EAAA,OAAOA,cAAA,EAAU,EAAG,oBAAA,CAAqB,gBAAgB,CAAA;AAC3D;AAEA,SAAS,YAAY,GAAA,EAAgC;AACnD,EAAA,IAAI,eAAe,KAAA,EAAO;AACxB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,KAAQ,QAAQ,QAAA,IAAa,GAAA;AACjE;AAGA,MAAM,SAAA,GAAY,CAAC,CAAA,KAA2B,CAAA,CAAE,KAAK,IAAA,IAAQ,EAAA;AAE7D,MAAM,gBAAA,IAAoB,CAAC,OAAA,GAA4B,EAAC,KAAM;AAC5D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA;AAAA,IAEN,mBAAA,CAAoB,KAAgB,OAAA,EAA4B;AAC9D,MAAA,MAAM,iBAAA,GAAoB,QAAQ,iBAAA,IAAqB,wBAAA;AAEvD,MAAA,IAAI,CAAC,WAAA,CAAY,GAAG,CAAA,EAAG;AACrB,QAAAC,sBAAA,IAAeC,UAAA,CAAM,GAAA,CAAI,4EAAA,EAA8E,GAAG,CAAA;AAC1G,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,iBAAA,CAAkB,GAAG,CAAA,EAAG;AAC1B,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,MAAM,aAAaC,kBAAA,EAAc;AACjC,UAAA,MAAM,QAAA,GAAW,GAAG,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA,CAAA,EAAI,SAAA,CAAU,OAAO,CAAC,CAAA,CAAA;AAE5D,UAAA,IAAI,UAAA,EAAY;AACd,YAAA,UAAA,CAAW,WAAW,QAAQ,CAAA;AAC9B,YAAAC,mBAAA,CAAeC,gBAAA,CAAY,UAAU,CAAA,EAAG,QAAQ,CAAA;AAAA,UAClD;AAEA,UAAAC,sBAAA,EAAkB,CAAE,mBAAmB,QAAQ,CAAA;AAAA,QACjD;AAEA,QAAAC,qBAAA,CAAiB,GAAA,EAAK,EAAE,SAAA,EAAW,EAAE,SAAS,KAAA,EAAO,IAAA,EAAM,8BAAA,EAA+B,EAAG,CAAA;AAAA,MAC/F,CAAA,MAAO;AACL,QAAAN,sBAAA,IAAeC,UAAA,CAAM,GAAA,CAAI,8EAAA,EAAgF,GAAG,CAAA;AAAA,MAC9G;AAAA,IACF;AAAA,GACF;AACF,CAAA,CAAA;AAiBO,MAAM,eAAA,GAAkBM,uBAAkB,gBAAgB;AAOjE,SAAS,yBAAyB,KAAA,EAA2B;AAC3D,EAAA,MAAM,aAAa,KAAA,EAAO,MAAA;AAE1B,EAAA,OAAO,UAAA,GAAa,UAAA,IAAc,GAAA,IAAO,UAAA,IAAc,GAAA,GAAM,IAAA;AAC/D;;;;;"}
|
package/build/cjs/request.js
CHANGED
|
@@ -11,7 +11,7 @@ function wrapRequestHandler(wrapperOptions, handler) {
|
|
|
11
11
|
return core.withIsolationScope(async (isolationScope) => {
|
|
12
12
|
const { options, request, captureErrors = true } = wrapperOptions;
|
|
13
13
|
const context = wrapperOptions.context;
|
|
14
|
-
const waitUntil = context?.
|
|
14
|
+
const waitUntil = context ? flush.getOriginalWaitUntil(context)?.bind(context) : void 0;
|
|
15
15
|
const client = sdk.init({ ...options, ctx: context });
|
|
16
16
|
isolationScope.setClient(client);
|
|
17
17
|
const urlObject = core.parseStringToURLObject(request.url);
|
package/build/cjs/request.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.js","sources":["../../src/request.ts"],"sourcesContent":["import type { CfProperties, ExecutionContext, IncomingRequestCfProperties } from '@cloudflare/workers-types';\nimport {\n captureException,\n continueTrace,\n getClient,\n getHttpSpanDetailsFromUrlObject,\n httpHeadersToSpanAttributes,\n parseStringToURLObject,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n setHttpStatus,\n startSpanManual,\n winterCGHeadersToDict,\n withIsolationScope,\n} from '@sentry/core';\nimport { captureIncomingRequestBody } from './integrations/httpServer';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose } from './flush';\nimport { addCloudResourceContext, addCultureContext, addRequest } from './scope-utils';\nimport { init } from './sdk';\nimport { classifyResponseStreaming } from './utils/streaming';\n\ninterface RequestHandlerWrapperOptions {\n options: CloudflareOptions;\n request: Request<unknown, IncomingRequestCfProperties<unknown> | CfProperties<unknown>>;\n context: ExecutionContext | undefined;\n /**\n * If true, errors will be captured, rethrown and sent to Sentry.\n * Otherwise, errors are rethrown but not captured.\n *\n * You most likely don't want to set this to `false`, if you use `wrapRequestHandler` directly.\n * This is primarily meant as an escape hatch for higher-level SDKs relying on additional error\n * capturing mechanisms where this wrapper captures errors too early or too generally.\n *\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Wraps a cloudflare request handler in Sentry instrumentation\n */\nexport function wrapRequestHandler(\n wrapperOptions: RequestHandlerWrapperOptions,\n handler: (...args: unknown[]) => Response | Promise<Response>,\n): Promise<Response> {\n return withIsolationScope(async isolationScope => {\n const { options, request, captureErrors = true } = wrapperOptions;\n const context = wrapperOptions.context;\n\n const waitUntil = context?.waitUntil?.bind?.(context);\n\n const client = init({ ...options, ctx: context });\n isolationScope.setClient(client);\n\n const urlObject = parseStringToURLObject(request.url);\n const [name, attributes] = getHttpSpanDetailsFromUrlObject(urlObject, 'server', 'auto.http.cloudflare', request);\n\n const contentLength = request.headers.get('content-length');\n if (contentLength) {\n attributes['http.request.body.size'] = parseInt(contentLength, 10);\n }\n\n const userAgentHeader = request.headers.get('user-agent');\n if (userAgentHeader) {\n attributes['user_agent.original'] = userAgentHeader;\n }\n\n Object.assign(\n attributes,\n httpHeadersToSpanAttributes(\n winterCGHeadersToDict(request.headers),\n getClient()?.getOptions().sendDefaultPii ?? false,\n ),\n );\n\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] = 'http.server';\n\n addCloudResourceContext(isolationScope);\n addRequest(isolationScope, request);\n if (request.cf) {\n addCultureContext(isolationScope, request.cf);\n\n if (typeof request.cf.httpProtocol === 'string') {\n attributes['network.protocol.name'] = request.cf.httpProtocol;\n }\n }\n\n // Do not capture spans for OPTIONS and HEAD requests\n if (request.method === 'OPTIONS' || request.method === 'HEAD') {\n try {\n return await handler();\n } catch (e) {\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n throw e;\n } finally {\n waitUntil?.(flushAndDispose(client));\n }\n }\n\n if (client) {\n await captureIncomingRequestBody(client, request);\n }\n\n return continueTrace(\n { sentryTrace: request.headers.get('sentry-trace') || '', baggage: request.headers.get('baggage') },\n () => {\n // Note: This span will not have a duration unless I/O happens in the handler. This is\n // because of how the cloudflare workers runtime works.\n // See: https://developers.cloudflare.com/workers/runtime-apis/performance/\n\n // Use startSpanManual to control when span ends (needed for streaming responses)\n return startSpanManual({ name, attributes }, async span => {\n let res: Response;\n\n try {\n res = await handler();\n setHttpStatus(span, res.status);\n\n // After the handler runs, the span name might have been updated by nested instrumentation\n // (e.g., Remix parameterizing routes). The span should already have the correct name\n // from that instrumentation, so we don't need to do anything here.\n } catch (e) {\n span.end();\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n waitUntil?.(flushAndDispose(client));\n throw e;\n }\n\n // Classify response to detect actual streaming\n const classification = classifyResponseStreaming(res);\n\n if (classification.isStreaming && res.body) {\n try {\n let ended = false;\n\n const endSpanOnce = (): void => {\n if (ended) return;\n\n ended = true;\n span.end();\n waitUntil?.(flushAndDispose(client));\n };\n\n const transform = new TransformStream({\n flush() {\n // Source stream completed normally.\n endSpanOnce();\n },\n cancel() {\n // Client disconnected (or downstream cancelled). The `cancel`\n // is being called while the response is still considered\n // active, so this is a safe place to end the span.\n endSpanOnce();\n },\n });\n\n return new Response(res.body.pipeThrough(transform), {\n status: res.status,\n statusText: res.statusText,\n headers: res.headers,\n });\n } catch {\n span.end();\n waitUntil?.(flushAndDispose(client));\n return res;\n }\n }\n\n // Non-streaming response - end span immediately and return original\n span.end();\n\n // Don't dispose for protocol upgrades (101 Switching Protocols) - the connection stays alive.\n // This includes WebSocket upgrades where webSocketMessage/webSocketClose handlers\n // will still be called and may need the client to capture errors.\n if (res.status === 101) {\n waitUntil?.(client?.flush(2000));\n } else {\n waitUntil?.(flushAndDispose(client));\n }\n return res;\n });\n },\n );\n });\n}\n"],"names":["withIsolationScope","init","parseStringToURLObject","getHttpSpanDetailsFromUrlObject","httpHeadersToSpanAttributes","winterCGHeadersToDict","getClient","SEMANTIC_ATTRIBUTE_SENTRY_OP","addCloudResourceContext","addRequest","addCultureContext","captureException","flushAndDispose","captureIncomingRequestBody","continueTrace","startSpanManual","setHttpStatus","classifyResponseStreaming"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"request.js","sources":["../../src/request.ts"],"sourcesContent":["import type { CfProperties, ExecutionContext, IncomingRequestCfProperties } from '@cloudflare/workers-types';\nimport {\n captureException,\n continueTrace,\n getClient,\n getHttpSpanDetailsFromUrlObject,\n httpHeadersToSpanAttributes,\n parseStringToURLObject,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n setHttpStatus,\n startSpanManual,\n winterCGHeadersToDict,\n withIsolationScope,\n} from '@sentry/core';\nimport { captureIncomingRequestBody } from './integrations/httpServer';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose, getOriginalWaitUntil } from './flush';\nimport { addCloudResourceContext, addCultureContext, addRequest } from './scope-utils';\nimport { init } from './sdk';\nimport { classifyResponseStreaming } from './utils/streaming';\n\ninterface RequestHandlerWrapperOptions {\n options: CloudflareOptions;\n request: Request<unknown, IncomingRequestCfProperties<unknown> | CfProperties<unknown>>;\n context: ExecutionContext | undefined;\n /**\n * If true, errors will be captured, rethrown and sent to Sentry.\n * Otherwise, errors are rethrown but not captured.\n *\n * You most likely don't want to set this to `false`, if you use `wrapRequestHandler` directly.\n * This is primarily meant as an escape hatch for higher-level SDKs relying on additional error\n * capturing mechanisms where this wrapper captures errors too early or too generally.\n *\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Wraps a cloudflare request handler in Sentry instrumentation\n */\nexport function wrapRequestHandler(\n wrapperOptions: RequestHandlerWrapperOptions,\n handler: (...args: unknown[]) => Response | Promise<Response>,\n): Promise<Response> {\n return withIsolationScope(async isolationScope => {\n const { options, request, captureErrors = true } = wrapperOptions;\n const context = wrapperOptions.context;\n\n // Use getOriginalWaitUntil to get the un-instrumented waitUntil function.\n // This is crucial to avoid deadlock: the flush lock mechanism wraps waitUntil\n // to track pending tasks. If we use the instrumented version for flushAndDispose,\n // it acquires the lock, then flushAndDispose tries to wait for the same lock,\n // creating a deadlock.\n const waitUntil = context ? getOriginalWaitUntil(context)?.bind(context) : undefined;\n\n const client = init({ ...options, ctx: context });\n isolationScope.setClient(client);\n\n const urlObject = parseStringToURLObject(request.url);\n const [name, attributes] = getHttpSpanDetailsFromUrlObject(urlObject, 'server', 'auto.http.cloudflare', request);\n\n const contentLength = request.headers.get('content-length');\n if (contentLength) {\n attributes['http.request.body.size'] = parseInt(contentLength, 10);\n }\n\n const userAgentHeader = request.headers.get('user-agent');\n if (userAgentHeader) {\n attributes['user_agent.original'] = userAgentHeader;\n }\n\n Object.assign(\n attributes,\n httpHeadersToSpanAttributes(\n winterCGHeadersToDict(request.headers),\n getClient()?.getOptions().sendDefaultPii ?? false,\n ),\n );\n\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] = 'http.server';\n\n addCloudResourceContext(isolationScope);\n addRequest(isolationScope, request);\n if (request.cf) {\n addCultureContext(isolationScope, request.cf);\n\n if (typeof request.cf.httpProtocol === 'string') {\n attributes['network.protocol.name'] = request.cf.httpProtocol;\n }\n }\n\n // Do not capture spans for OPTIONS and HEAD requests\n if (request.method === 'OPTIONS' || request.method === 'HEAD') {\n try {\n return await handler();\n } catch (e) {\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n throw e;\n } finally {\n waitUntil?.(flushAndDispose(client));\n }\n }\n\n if (client) {\n await captureIncomingRequestBody(client, request);\n }\n\n return continueTrace(\n { sentryTrace: request.headers.get('sentry-trace') || '', baggage: request.headers.get('baggage') },\n () => {\n // Note: This span will not have a duration unless I/O happens in the handler. This is\n // because of how the cloudflare workers runtime works.\n // See: https://developers.cloudflare.com/workers/runtime-apis/performance/\n\n // Use startSpanManual to control when span ends (needed for streaming responses)\n return startSpanManual({ name, attributes }, async span => {\n let res: Response;\n\n try {\n res = await handler();\n setHttpStatus(span, res.status);\n\n // After the handler runs, the span name might have been updated by nested instrumentation\n // (e.g., Remix parameterizing routes). The span should already have the correct name\n // from that instrumentation, so we don't need to do anything here.\n } catch (e) {\n span.end();\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n waitUntil?.(flushAndDispose(client));\n throw e;\n }\n\n // Classify response to detect actual streaming\n const classification = classifyResponseStreaming(res);\n\n if (classification.isStreaming && res.body) {\n try {\n let ended = false;\n\n const endSpanOnce = (): void => {\n if (ended) return;\n\n ended = true;\n span.end();\n waitUntil?.(flushAndDispose(client));\n };\n\n const transform = new TransformStream({\n flush() {\n // Source stream completed normally.\n endSpanOnce();\n },\n cancel() {\n // Client disconnected (or downstream cancelled). The `cancel`\n // is being called while the response is still considered\n // active, so this is a safe place to end the span.\n endSpanOnce();\n },\n });\n\n return new Response(res.body.pipeThrough(transform), {\n status: res.status,\n statusText: res.statusText,\n headers: res.headers,\n });\n } catch {\n span.end();\n waitUntil?.(flushAndDispose(client));\n return res;\n }\n }\n\n // Non-streaming response - end span immediately and return original\n span.end();\n\n // Don't dispose for protocol upgrades (101 Switching Protocols) - the connection stays alive.\n // This includes WebSocket upgrades where webSocketMessage/webSocketClose handlers\n // will still be called and may need the client to capture errors.\n if (res.status === 101) {\n waitUntil?.(client?.flush(2000));\n } else {\n waitUntil?.(flushAndDispose(client));\n }\n return res;\n });\n },\n );\n });\n}\n"],"names":["withIsolationScope","getOriginalWaitUntil","init","parseStringToURLObject","getHttpSpanDetailsFromUrlObject","httpHeadersToSpanAttributes","winterCGHeadersToDict","getClient","SEMANTIC_ATTRIBUTE_SENTRY_OP","addCloudResourceContext","addRequest","addCultureContext","captureException","flushAndDispose","captureIncomingRequestBody","continueTrace","startSpanManual","setHttpStatus","classifyResponseStreaming"],"mappings":"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"}
|
package/build/esm/flush.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { flush } from '@sentry/core';
|
|
2
2
|
|
|
3
3
|
const flushLockRegistries = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
function getOriginalWaitUntil(context) {
|
|
5
|
+
const currentWaitUntil = context.waitUntil;
|
|
6
|
+
const original = flushLockRegistries.get(currentWaitUntil)?.originalWaitUntil;
|
|
7
|
+
return original ?? currentWaitUntil;
|
|
8
|
+
}
|
|
4
9
|
function makeFlushLock(context) {
|
|
5
10
|
const registry = getOrCreateFlushLockRegistry(context);
|
|
6
11
|
let resolveAllDone = () => void 0;
|
|
@@ -36,8 +41,8 @@ function getOrCreateFlushLockRegistry(context) {
|
|
|
36
41
|
if (existingRegistry) {
|
|
37
42
|
return existingRegistry;
|
|
38
43
|
}
|
|
39
|
-
const registry = { locks: /* @__PURE__ */ new Set() };
|
|
40
44
|
const originalWaitUntil = context.waitUntil.bind(context);
|
|
45
|
+
const registry = { locks: /* @__PURE__ */ new Set(), originalWaitUntil };
|
|
41
46
|
const instrumentedWaitUntil = (promise) => {
|
|
42
47
|
const locks = [...registry.locks];
|
|
43
48
|
for (const lock of locks) {
|
|
@@ -64,5 +69,5 @@ async function flushAndDispose(client, timeout = 2e3) {
|
|
|
64
69
|
client.dispose();
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
export { flushAndDispose, makeFlushLock };
|
|
72
|
+
export { flushAndDispose, getOriginalWaitUntil, makeFlushLock };
|
|
68
73
|
//# sourceMappingURL=flush.js.map
|
package/build/esm/flush.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flush.js","sources":["../../src/flush.ts"],"sourcesContent":["import type { ExecutionContext } from '@cloudflare/workers-types';\nimport type { Client } from '@sentry/core';\nimport { flush } from '@sentry/core';\n\ntype FlushLock = {\n readonly ready: Promise<void>;\n readonly finalize: () => Promise<void>;\n};\n\ntype FlushLockRegistry = {\n readonly locks: Set<FlushLockInternal>;\n};\n\ntype FlushLockInternal = FlushLock & {\n readonly acquire: () => void;\n readonly release: () => void;\n};\n\nconst flushLockRegistries = new WeakMap<ExecutionContext['waitUntil'], FlushLockRegistry>();\n\n/**\n * Enhances the given execution context by wrapping its `waitUntil` method with a proxy\n * to monitor pending tasks, and provides a flusher function to ensure all tasks\n * have been completed before executing any subsequent logic.\n *\n * @param {ExecutionContext} context - The execution context to be enhanced. If no context is provided, the function returns undefined.\n * @return {FlushLock} Returns a flusher function if a valid context is provided, otherwise undefined.\n */\nexport function makeFlushLock(context: ExecutionContext): FlushLock {\n const registry = getOrCreateFlushLockRegistry(context);\n let resolveAllDone: () => void = () => undefined;\n const allDone = new Promise<void>(res => {\n resolveAllDone = res;\n });\n let pending = 0;\n\n const lock: FlushLockInternal = {\n ready: allDone,\n acquire: () => {\n pending++;\n },\n release: () => {\n if (--pending === 0) {\n registry.locks.delete(lock);\n resolveAllDone();\n }\n },\n finalize: () => {\n if (pending === 0) {\n registry.locks.delete(lock);\n resolveAllDone();\n }\n return allDone;\n },\n };\n\n registry.locks.add(lock);\n return Object.freeze(lock);\n}\n\nfunction getOrCreateFlushLockRegistry(context: ExecutionContext): FlushLockRegistry {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const waitUntil = context.waitUntil;\n const existingRegistry = flushLockRegistries.get(waitUntil);\n\n if (existingRegistry) {\n return existingRegistry;\n }\n\n const
|
|
1
|
+
{"version":3,"file":"flush.js","sources":["../../src/flush.ts"],"sourcesContent":["import type { ExecutionContext } from '@cloudflare/workers-types';\nimport type { Client } from '@sentry/core';\nimport { flush } from '@sentry/core';\n\ntype FlushLock = {\n readonly ready: Promise<void>;\n readonly finalize: () => Promise<void>;\n};\n\ntype FlushLockRegistry = {\n readonly locks: Set<FlushLockInternal>;\n readonly originalWaitUntil: ExecutionContext['waitUntil'];\n};\n\ntype FlushLockInternal = FlushLock & {\n readonly acquire: () => void;\n readonly release: () => void;\n};\n\nconst flushLockRegistries = new WeakMap<ExecutionContext['waitUntil'], FlushLockRegistry>();\n\n/**\n * Returns the original (un-instrumented) waitUntil function for a context.\n * This should be used when calling waitUntil with flushAndDispose to avoid deadlock.\n *\n * The flush lock mechanism wraps context.waitUntil to track pending tasks.\n * If we call waitUntil(flushAndDispose(client)) through the instrumented version,\n * it creates a deadlock because:\n * 1. The instrumented waitUntil acquires the flush lock\n * 2. flushAndDispose calls client.flush() which waits for the lock to be released\n * 3. The lock won't be released until the waitUntil promise completes\n * 4. The waitUntil promise won't complete until flush() returns\n *\n * By using the original waitUntil for flush operations, we bypass this issue.\n */\nexport function getOriginalWaitUntil(context: ExecutionContext): ExecutionContext['waitUntil'] | undefined {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const currentWaitUntil = context.waitUntil;\n const original = flushLockRegistries.get(currentWaitUntil)?.originalWaitUntil;\n return original ?? currentWaitUntil;\n}\n\n/**\n * Enhances the given execution context by wrapping its `waitUntil` method with a proxy\n * to monitor pending tasks, and provides a flusher function to ensure all tasks\n * have been completed before executing any subsequent logic.\n *\n * @param {ExecutionContext} context - The execution context to be enhanced. If no context is provided, the function returns undefined.\n * @return {FlushLock} Returns a flusher function if a valid context is provided, otherwise undefined.\n */\nexport function makeFlushLock(context: ExecutionContext): FlushLock {\n const registry = getOrCreateFlushLockRegistry(context);\n let resolveAllDone: () => void = () => undefined;\n const allDone = new Promise<void>(res => {\n resolveAllDone = res;\n });\n let pending = 0;\n\n const lock: FlushLockInternal = {\n ready: allDone,\n acquire: () => {\n pending++;\n },\n release: () => {\n if (--pending === 0) {\n registry.locks.delete(lock);\n resolveAllDone();\n }\n },\n finalize: () => {\n if (pending === 0) {\n registry.locks.delete(lock);\n resolveAllDone();\n }\n return allDone;\n },\n };\n\n registry.locks.add(lock);\n return Object.freeze(lock);\n}\n\nfunction getOrCreateFlushLockRegistry(context: ExecutionContext): FlushLockRegistry {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const waitUntil = context.waitUntil;\n const existingRegistry = flushLockRegistries.get(waitUntil);\n\n if (existingRegistry) {\n return existingRegistry;\n }\n\n const originalWaitUntil = context.waitUntil.bind(context) as typeof context.waitUntil;\n const registry: FlushLockRegistry = { locks: new Set(), originalWaitUntil };\n const instrumentedWaitUntil: typeof context.waitUntil = promise => {\n // Snapshot active locks so locks created after this call do not wait for earlier waitUntil work.\n const locks = [...registry.locks];\n\n for (const lock of locks) {\n lock.acquire();\n }\n\n return originalWaitUntil(\n promise.finally(() => {\n for (const lock of locks) {\n lock.release();\n }\n }),\n );\n };\n\n flushLockRegistries.set(instrumentedWaitUntil, registry);\n context.waitUntil = instrumentedWaitUntil;\n\n return registry;\n}\n\n/**\n * Flushes the client and then disposes of it to allow garbage collection.\n * This should be called at the end of each request to prevent memory leaks.\n *\n * @param client - The CloudflareClient instance to flush and dispose\n * @param timeout - Timeout in milliseconds for the flush operation\n * @returns A promise that resolves when flush and dispose are complete\n */\nexport async function flushAndDispose(client: Client | undefined, timeout = 2000): Promise<void> {\n if (!client) {\n await flush(timeout);\n\n return;\n }\n\n await client.flush(timeout);\n client.dispose();\n}\n"],"names":[],"mappings":";;AAmBA,MAAM,mBAAA,uBAA0B,OAAA,EAA0D;AAgBnF,SAAS,qBAAqB,OAAA,EAAsE;AAEzG,EAAA,MAAM,mBAAmB,OAAA,CAAQ,SAAA;AACjC,EAAA,MAAM,QAAA,GAAW,mBAAA,CAAoB,GAAA,CAAI,gBAAgB,CAAA,EAAG,iBAAA;AAC5D,EAAA,OAAO,QAAA,IAAY,gBAAA;AACrB;AAUO,SAAS,cAAc,OAAA,EAAsC;AAClE,EAAA,MAAM,QAAA,GAAW,6BAA6B,OAAO,CAAA;AACrD,EAAA,IAAI,iBAA6B,MAAM,MAAA;AACvC,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAc,CAAA,GAAA,KAAO;AACvC,IAAA,cAAA,GAAiB,GAAA;AAAA,EACnB,CAAC,CAAA;AACD,EAAA,IAAI,OAAA,GAAU,CAAA;AAEd,EAAA,MAAM,IAAA,GAA0B;AAAA,IAC9B,KAAA,EAAO,OAAA;AAAA,IACP,SAAS,MAAM;AACb,MAAA,OAAA,EAAA;AAAA,IACF,CAAA;AAAA,IACA,SAAS,MAAM;AACb,MAAA,IAAI,EAAE,YAAY,CAAA,EAAG;AACnB,QAAA,QAAA,CAAS,KAAA,CAAM,OAAO,IAAI,CAAA;AAC1B,QAAA,cAAA,EAAe;AAAA,MACjB;AAAA,IACF,CAAA;AAAA,IACA,UAAU,MAAM;AACd,MAAA,IAAI,YAAY,CAAA,EAAG;AACjB,QAAA,QAAA,CAAS,KAAA,CAAM,OAAO,IAAI,CAAA;AAC1B,QAAA,cAAA,EAAe;AAAA,MACjB;AACA,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,GACF;AAEA,EAAA,QAAA,CAAS,KAAA,CAAM,IAAI,IAAI,CAAA;AACvB,EAAA,OAAO,MAAA,CAAO,OAAO,IAAI,CAAA;AAC3B;AAEA,SAAS,6BAA6B,OAAA,EAA8C;AAElF,EAAA,MAAM,YAAY,OAAA,CAAQ,SAAA;AAC1B,EAAA,MAAM,gBAAA,GAAmB,mBAAA,CAAoB,GAAA,CAAI,SAAS,CAAA;AAE1D,EAAA,IAAI,gBAAA,EAAkB;AACpB,IAAA,OAAO,gBAAA;AAAA,EACT;AAEA,EAAA,MAAM,iBAAA,GAAoB,OAAA,CAAQ,SAAA,CAAU,IAAA,CAAK,OAAO,CAAA;AACxD,EAAA,MAAM,WAA8B,EAAE,KAAA,kBAAO,IAAI,GAAA,IAAO,iBAAA,EAAkB;AAC1E,EAAA,MAAM,wBAAkD,CAAA,OAAA,KAAW;AAEjE,IAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,QAAA,CAAS,KAAK,CAAA;AAEhC,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,MAAA,IAAA,CAAK,OAAA,EAAQ;AAAA,IACf;AAEA,IAAA,OAAO,iBAAA;AAAA,MACL,OAAA,CAAQ,QAAQ,MAAM;AACpB,QAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,UAAA,IAAA,CAAK,OAAA,EAAQ;AAAA,QACf;AAAA,MACF,CAAC;AAAA,KACH;AAAA,EACF,CAAA;AAEA,EAAA,mBAAA,CAAoB,GAAA,CAAI,uBAAuB,QAAQ,CAAA;AACvD,EAAA,OAAA,CAAQ,SAAA,GAAY,qBAAA;AAEpB,EAAA,OAAO,QAAA;AACT;AAUA,eAAsB,eAAA,CAAgB,MAAA,EAA4B,OAAA,GAAU,GAAA,EAAqB;AAC/F,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,MAAM,OAAO,CAAA;AAEnB,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,MAAA,CAAO,MAAM,OAAO,CAAA;AAC1B,EAAA,MAAA,CAAO,OAAA,EAAQ;AACjB;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono.js","sources":["../../../src/integrations/hono.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport {\n captureException,\n debug,\n defineIntegration,\n getActiveSpan,\n getClient,\n getIsolationScope,\n getRootSpan,\n updateSpanName,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\n\nconst INTEGRATION_NAME = 'Hono';\n\ninterface HonoError extends Error {\n status?: number;\n}\n\n// Minimal type - only exported for tests\nexport interface HonoContext {\n req: { method: string; path?: string };\n}\n\nexport interface Options {\n /**\n * Callback method deciding whether error should be captured and sent to Sentry\n * @param error Captured middleware error\n */\n shouldHandleError?(this: void, error: HonoError): boolean;\n}\n\n/** Only exported for internal use */\nexport function getHonoIntegration(): ReturnType<typeof _honoIntegration> | undefined {\n return getClient()?.getIntegrationByName(INTEGRATION_NAME);\n}\n\nfunction isHonoError(err: unknown): err is HonoError {\n if (err instanceof Error) {\n return true;\n }\n return typeof err === 'object' && err !== null && 'status' in (err as Record<string, unknown>);\n}\n\n// Vendored from https://github.com/honojs/hono/blob/d3abeb1f801aaa1b334285c73da5f5f022dbcadb/src/helper/route/index.ts#L58-L59\nconst routePath = (c: HonoContext): string => c.req?.path ?? '';\n\nconst _honoIntegration = ((options: Partial<Options> = {}) => {\n return {\n name: INTEGRATION_NAME,\n // Hono error handler: https://github.com/honojs/hono/blob/d3abeb1f801aaa1b334285c73da5f5f022dbcadb/src/hono-base.ts#L35\n handleHonoException(err: HonoError, context: HonoContext): void {\n const shouldHandleError = options.shouldHandleError || defaultShouldHandleError;\n\n if (!isHonoError(err)) {\n DEBUG_BUILD && debug.log(\"[Hono] Won't capture exception in `onError` because it's not a Hono error.\", err);\n return;\n }\n\n if (shouldHandleError(err)) {\n if (context) {\n const activeSpan = getActiveSpan();\n const spanName = `${context.req.method} ${routePath(context)}`;\n\n if (activeSpan) {\n activeSpan.updateName(spanName);\n updateSpanName(getRootSpan(activeSpan), spanName);\n }\n\n getIsolationScope().setTransactionName(spanName);\n }\n\n captureException(err, { mechanism: { handled: false, type: 'auto.faas.hono.error_handler' } });\n } else {\n DEBUG_BUILD && debug.log('[Hono] Not capturing exception because `shouldHandleError` returned `false`.', err);\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Automatically captures exceptions caught with the `onError` handler in Hono.\n *\n * The integration is enabled by default.\n *\n * @example\n * integrations: [\n * honoIntegration({\n * shouldHandleError: (err) => true; // always capture exceptions in onError\n * })\n * ]\n */\nexport const honoIntegration = defineIntegration(_honoIntegration);\n\n/**\n * Default function to determine if an error should be sent to Sentry\n *\n * 3xx and 4xx errors are not sent by default.\n */\nfunction defaultShouldHandleError(error: HonoError): boolean {\n const statusCode = error?.status;\n // 3xx and 4xx errors are not sent by default.\n return statusCode ? statusCode >= 500 || statusCode <= 299 : true;\n}\n"],"names":[],"mappings":";;;AAaA,MAAM,gBAAA,GAAmB,MAAA;AAoBlB,SAAS,kBAAA,GAAsE;AACpF,EAAA,OAAO,SAAA,EAAU,EAAG,oBAAA,CAAqB,gBAAgB,CAAA;AAC3D;AAEA,SAAS,YAAY,GAAA,EAAgC;AACnD,EAAA,IAAI,eAAe,KAAA,EAAO;AACxB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,KAAQ,QAAQ,QAAA,IAAa,GAAA;AACjE;AAGA,MAAM,SAAA,GAAY,CAAC,CAAA,KAA2B,CAAA,CAAE,KAAK,IAAA,IAAQ,EAAA;AAE7D,MAAM,gBAAA,IAAoB,CAAC,OAAA,GAA4B,EAAC,KAAM;AAC5D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA;AAAA,IAEN,mBAAA,CAAoB,KAAgB,OAAA,EAA4B;AAC9D,MAAA,MAAM,iBAAA,GAAoB,QAAQ,iBAAA,IAAqB,wBAAA;AAEvD,MAAA,IAAI,CAAC,WAAA,CAAY,GAAG,CAAA,EAAG;AACrB,QAAA,WAAA,IAAe,KAAA,CAAM,GAAA,CAAI,4EAAA,EAA8E,GAAG,CAAA;AAC1G,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,iBAAA,CAAkB,GAAG,CAAA,EAAG;AAC1B,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,MAAM,aAAa,aAAA,EAAc;AACjC,UAAA,MAAM,QAAA,GAAW,GAAG,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA,CAAA,EAAI,SAAA,CAAU,OAAO,CAAC,CAAA,CAAA;AAE5D,UAAA,IAAI,UAAA,EAAY;AACd,YAAA,UAAA,CAAW,WAAW,QAAQ,CAAA;AAC9B,YAAA,cAAA,CAAe,WAAA,CAAY,UAAU,CAAA,EAAG,QAAQ,CAAA;AAAA,UAClD;AAEA,UAAA,iBAAA,EAAkB,CAAE,mBAAmB,QAAQ,CAAA;AAAA,QACjD;AAEA,QAAA,gBAAA,CAAiB,GAAA,EAAK,EAAE,SAAA,EAAW,EAAE,SAAS,KAAA,EAAO,IAAA,EAAM,8BAAA,EAA+B,EAAG,CAAA;AAAA,MAC/F,CAAA,MAAO;AACL,QAAA,WAAA,IAAe,KAAA,CAAM,GAAA,CAAI,8EAAA,EAAgF,GAAG,CAAA;AAAA,MAC9G;AAAA,IACF;AAAA,GACF;AACF,CAAA,CAAA;
|
|
1
|
+
{"version":3,"file":"hono.js","sources":["../../../src/integrations/hono.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport {\n captureException,\n debug,\n defineIntegration,\n getActiveSpan,\n getClient,\n getIsolationScope,\n getRootSpan,\n updateSpanName,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\n\nconst INTEGRATION_NAME = 'Hono';\n\ninterface HonoError extends Error {\n status?: number;\n}\n\n// Minimal type - only exported for tests\nexport interface HonoContext {\n req: { method: string; path?: string };\n}\n\nexport interface Options {\n /**\n * Callback method deciding whether error should be captured and sent to Sentry\n * @param error Captured middleware error\n */\n shouldHandleError?(this: void, error: HonoError): boolean;\n}\n\n/** Only exported for internal use */\nexport function getHonoIntegration(): ReturnType<typeof _honoIntegration> | undefined {\n return getClient()?.getIntegrationByName(INTEGRATION_NAME);\n}\n\nfunction isHonoError(err: unknown): err is HonoError {\n if (err instanceof Error) {\n return true;\n }\n return typeof err === 'object' && err !== null && 'status' in (err as Record<string, unknown>);\n}\n\n// Vendored from https://github.com/honojs/hono/blob/d3abeb1f801aaa1b334285c73da5f5f022dbcadb/src/helper/route/index.ts#L58-L59\nconst routePath = (c: HonoContext): string => c.req?.path ?? '';\n\nconst _honoIntegration = ((options: Partial<Options> = {}) => {\n return {\n name: INTEGRATION_NAME,\n // Hono error handler: https://github.com/honojs/hono/blob/d3abeb1f801aaa1b334285c73da5f5f022dbcadb/src/hono-base.ts#L35\n handleHonoException(err: HonoError, context: HonoContext): void {\n const shouldHandleError = options.shouldHandleError || defaultShouldHandleError;\n\n if (!isHonoError(err)) {\n DEBUG_BUILD && debug.log(\"[Hono] Won't capture exception in `onError` because it's not a Hono error.\", err);\n return;\n }\n\n if (shouldHandleError(err)) {\n if (context) {\n const activeSpan = getActiveSpan();\n const spanName = `${context.req.method} ${routePath(context)}`;\n\n if (activeSpan) {\n activeSpan.updateName(spanName);\n updateSpanName(getRootSpan(activeSpan), spanName);\n }\n\n getIsolationScope().setTransactionName(spanName);\n }\n\n captureException(err, { mechanism: { handled: false, type: 'auto.faas.hono.error_handler' } });\n } else {\n DEBUG_BUILD && debug.log('[Hono] Not capturing exception because `shouldHandleError` returned `false`.', err);\n }\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Automatically captures exceptions caught with the `onError` handler in Hono.\n *\n * The integration is enabled by default.\n *\n * @deprecated Use the `@sentry/hono` package instead. The `sentry()` middleware from `@sentry/hono/cloudflare`\n * handles error capturing automatically without needing this integration.\n *\n * @example\n * integrations: [\n * honoIntegration({\n * shouldHandleError: (err) => true; // always capture exceptions in onError\n * })\n * ]\n */\nexport const honoIntegration = defineIntegration(_honoIntegration);\n\n/**\n * Default function to determine if an error should be sent to Sentry\n *\n * 3xx and 4xx errors are not sent by default.\n */\nfunction defaultShouldHandleError(error: HonoError): boolean {\n const statusCode = error?.status;\n // 3xx and 4xx errors are not sent by default.\n return statusCode ? statusCode >= 500 || statusCode <= 299 : true;\n}\n"],"names":[],"mappings":";;;AAaA,MAAM,gBAAA,GAAmB,MAAA;AAoBlB,SAAS,kBAAA,GAAsE;AACpF,EAAA,OAAO,SAAA,EAAU,EAAG,oBAAA,CAAqB,gBAAgB,CAAA;AAC3D;AAEA,SAAS,YAAY,GAAA,EAAgC;AACnD,EAAA,IAAI,eAAe,KAAA,EAAO;AACxB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,KAAQ,QAAQ,QAAA,IAAa,GAAA;AACjE;AAGA,MAAM,SAAA,GAAY,CAAC,CAAA,KAA2B,CAAA,CAAE,KAAK,IAAA,IAAQ,EAAA;AAE7D,MAAM,gBAAA,IAAoB,CAAC,OAAA,GAA4B,EAAC,KAAM;AAC5D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA;AAAA,IAEN,mBAAA,CAAoB,KAAgB,OAAA,EAA4B;AAC9D,MAAA,MAAM,iBAAA,GAAoB,QAAQ,iBAAA,IAAqB,wBAAA;AAEvD,MAAA,IAAI,CAAC,WAAA,CAAY,GAAG,CAAA,EAAG;AACrB,QAAA,WAAA,IAAe,KAAA,CAAM,GAAA,CAAI,4EAAA,EAA8E,GAAG,CAAA;AAC1G,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,iBAAA,CAAkB,GAAG,CAAA,EAAG;AAC1B,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,MAAM,aAAa,aAAA,EAAc;AACjC,UAAA,MAAM,QAAA,GAAW,GAAG,OAAA,CAAQ,GAAA,CAAI,MAAM,CAAA,CAAA,EAAI,SAAA,CAAU,OAAO,CAAC,CAAA,CAAA;AAE5D,UAAA,IAAI,UAAA,EAAY;AACd,YAAA,UAAA,CAAW,WAAW,QAAQ,CAAA;AAC9B,YAAA,cAAA,CAAe,WAAA,CAAY,UAAU,CAAA,EAAG,QAAQ,CAAA;AAAA,UAClD;AAEA,UAAA,iBAAA,EAAkB,CAAE,mBAAmB,QAAQ,CAAA;AAAA,QACjD;AAEA,QAAA,gBAAA,CAAiB,GAAA,EAAK,EAAE,SAAA,EAAW,EAAE,SAAS,KAAA,EAAO,IAAA,EAAM,8BAAA,EAA+B,EAAG,CAAA;AAAA,MAC/F,CAAA,MAAO;AACL,QAAA,WAAA,IAAe,KAAA,CAAM,GAAA,CAAI,8EAAA,EAAgF,GAAG,CAAA;AAAA,MAC9G;AAAA,IACF;AAAA,GACF;AACF,CAAA,CAAA;AAiBO,MAAM,eAAA,GAAkB,kBAAkB,gBAAgB;AAOjE,SAAS,yBAAyB,KAAA,EAA2B;AAC3D,EAAA,MAAM,aAAa,KAAA,EAAO,MAAA;AAE1B,EAAA,OAAO,UAAA,GAAa,UAAA,IAAc,GAAA,IAAO,UAAA,IAAc,GAAA,GAAM,IAAA;AAC/D;;;;"}
|
package/build/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"10.
|
|
1
|
+
{"type":"module","version":"10.55.0","sideEffects":false}
|
package/build/esm/request.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { withIsolationScope, parseStringToURLObject, getHttpSpanDetailsFromUrlObject, httpHeadersToSpanAttributes, winterCGHeadersToDict, getClient, SEMANTIC_ATTRIBUTE_SENTRY_OP, captureException, continueTrace, startSpanManual, setHttpStatus } from '@sentry/core';
|
|
2
2
|
import { captureIncomingRequestBody } from './integrations/httpServer.js';
|
|
3
|
-
import { flushAndDispose } from './flush.js';
|
|
3
|
+
import { getOriginalWaitUntil, flushAndDispose } from './flush.js';
|
|
4
4
|
import { addCloudResourceContext, addRequest, addCultureContext } from './scope-utils.js';
|
|
5
5
|
import { init } from './sdk.js';
|
|
6
6
|
import { classifyResponseStreaming } from './utils/streaming.js';
|
|
@@ -9,7 +9,7 @@ function wrapRequestHandler(wrapperOptions, handler) {
|
|
|
9
9
|
return withIsolationScope(async (isolationScope) => {
|
|
10
10
|
const { options, request, captureErrors = true } = wrapperOptions;
|
|
11
11
|
const context = wrapperOptions.context;
|
|
12
|
-
const waitUntil = context?.
|
|
12
|
+
const waitUntil = context ? getOriginalWaitUntil(context)?.bind(context) : void 0;
|
|
13
13
|
const client = init({ ...options, ctx: context });
|
|
14
14
|
isolationScope.setClient(client);
|
|
15
15
|
const urlObject = parseStringToURLObject(request.url);
|
package/build/esm/request.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.js","sources":["../../src/request.ts"],"sourcesContent":["import type { CfProperties, ExecutionContext, IncomingRequestCfProperties } from '@cloudflare/workers-types';\nimport {\n captureException,\n continueTrace,\n getClient,\n getHttpSpanDetailsFromUrlObject,\n httpHeadersToSpanAttributes,\n parseStringToURLObject,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n setHttpStatus,\n startSpanManual,\n winterCGHeadersToDict,\n withIsolationScope,\n} from '@sentry/core';\nimport { captureIncomingRequestBody } from './integrations/httpServer';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose } from './flush';\nimport { addCloudResourceContext, addCultureContext, addRequest } from './scope-utils';\nimport { init } from './sdk';\nimport { classifyResponseStreaming } from './utils/streaming';\n\ninterface RequestHandlerWrapperOptions {\n options: CloudflareOptions;\n request: Request<unknown, IncomingRequestCfProperties<unknown> | CfProperties<unknown>>;\n context: ExecutionContext | undefined;\n /**\n * If true, errors will be captured, rethrown and sent to Sentry.\n * Otherwise, errors are rethrown but not captured.\n *\n * You most likely don't want to set this to `false`, if you use `wrapRequestHandler` directly.\n * This is primarily meant as an escape hatch for higher-level SDKs relying on additional error\n * capturing mechanisms where this wrapper captures errors too early or too generally.\n *\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Wraps a cloudflare request handler in Sentry instrumentation\n */\nexport function wrapRequestHandler(\n wrapperOptions: RequestHandlerWrapperOptions,\n handler: (...args: unknown[]) => Response | Promise<Response>,\n): Promise<Response> {\n return withIsolationScope(async isolationScope => {\n const { options, request, captureErrors = true } = wrapperOptions;\n const context = wrapperOptions.context;\n\n const waitUntil = context?.waitUntil?.bind?.(context);\n\n const client = init({ ...options, ctx: context });\n isolationScope.setClient(client);\n\n const urlObject = parseStringToURLObject(request.url);\n const [name, attributes] = getHttpSpanDetailsFromUrlObject(urlObject, 'server', 'auto.http.cloudflare', request);\n\n const contentLength = request.headers.get('content-length');\n if (contentLength) {\n attributes['http.request.body.size'] = parseInt(contentLength, 10);\n }\n\n const userAgentHeader = request.headers.get('user-agent');\n if (userAgentHeader) {\n attributes['user_agent.original'] = userAgentHeader;\n }\n\n Object.assign(\n attributes,\n httpHeadersToSpanAttributes(\n winterCGHeadersToDict(request.headers),\n getClient()?.getOptions().sendDefaultPii ?? false,\n ),\n );\n\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] = 'http.server';\n\n addCloudResourceContext(isolationScope);\n addRequest(isolationScope, request);\n if (request.cf) {\n addCultureContext(isolationScope, request.cf);\n\n if (typeof request.cf.httpProtocol === 'string') {\n attributes['network.protocol.name'] = request.cf.httpProtocol;\n }\n }\n\n // Do not capture spans for OPTIONS and HEAD requests\n if (request.method === 'OPTIONS' || request.method === 'HEAD') {\n try {\n return await handler();\n } catch (e) {\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n throw e;\n } finally {\n waitUntil?.(flushAndDispose(client));\n }\n }\n\n if (client) {\n await captureIncomingRequestBody(client, request);\n }\n\n return continueTrace(\n { sentryTrace: request.headers.get('sentry-trace') || '', baggage: request.headers.get('baggage') },\n () => {\n // Note: This span will not have a duration unless I/O happens in the handler. This is\n // because of how the cloudflare workers runtime works.\n // See: https://developers.cloudflare.com/workers/runtime-apis/performance/\n\n // Use startSpanManual to control when span ends (needed for streaming responses)\n return startSpanManual({ name, attributes }, async span => {\n let res: Response;\n\n try {\n res = await handler();\n setHttpStatus(span, res.status);\n\n // After the handler runs, the span name might have been updated by nested instrumentation\n // (e.g., Remix parameterizing routes). The span should already have the correct name\n // from that instrumentation, so we don't need to do anything here.\n } catch (e) {\n span.end();\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n waitUntil?.(flushAndDispose(client));\n throw e;\n }\n\n // Classify response to detect actual streaming\n const classification = classifyResponseStreaming(res);\n\n if (classification.isStreaming && res.body) {\n try {\n let ended = false;\n\n const endSpanOnce = (): void => {\n if (ended) return;\n\n ended = true;\n span.end();\n waitUntil?.(flushAndDispose(client));\n };\n\n const transform = new TransformStream({\n flush() {\n // Source stream completed normally.\n endSpanOnce();\n },\n cancel() {\n // Client disconnected (or downstream cancelled). The `cancel`\n // is being called while the response is still considered\n // active, so this is a safe place to end the span.\n endSpanOnce();\n },\n });\n\n return new Response(res.body.pipeThrough(transform), {\n status: res.status,\n statusText: res.statusText,\n headers: res.headers,\n });\n } catch {\n span.end();\n waitUntil?.(flushAndDispose(client));\n return res;\n }\n }\n\n // Non-streaming response - end span immediately and return original\n span.end();\n\n // Don't dispose for protocol upgrades (101 Switching Protocols) - the connection stays alive.\n // This includes WebSocket upgrades where webSocketMessage/webSocketClose handlers\n // will still be called and may need the client to capture errors.\n if (res.status === 101) {\n waitUntil?.(client?.flush(2000));\n } else {\n waitUntil?.(flushAndDispose(client));\n }\n return res;\n });\n },\n );\n });\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"request.js","sources":["../../src/request.ts"],"sourcesContent":["import type { CfProperties, ExecutionContext, IncomingRequestCfProperties } from '@cloudflare/workers-types';\nimport {\n captureException,\n continueTrace,\n getClient,\n getHttpSpanDetailsFromUrlObject,\n httpHeadersToSpanAttributes,\n parseStringToURLObject,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n setHttpStatus,\n startSpanManual,\n winterCGHeadersToDict,\n withIsolationScope,\n} from '@sentry/core';\nimport { captureIncomingRequestBody } from './integrations/httpServer';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose, getOriginalWaitUntil } from './flush';\nimport { addCloudResourceContext, addCultureContext, addRequest } from './scope-utils';\nimport { init } from './sdk';\nimport { classifyResponseStreaming } from './utils/streaming';\n\ninterface RequestHandlerWrapperOptions {\n options: CloudflareOptions;\n request: Request<unknown, IncomingRequestCfProperties<unknown> | CfProperties<unknown>>;\n context: ExecutionContext | undefined;\n /**\n * If true, errors will be captured, rethrown and sent to Sentry.\n * Otherwise, errors are rethrown but not captured.\n *\n * You most likely don't want to set this to `false`, if you use `wrapRequestHandler` directly.\n * This is primarily meant as an escape hatch for higher-level SDKs relying on additional error\n * capturing mechanisms where this wrapper captures errors too early or too generally.\n *\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Wraps a cloudflare request handler in Sentry instrumentation\n */\nexport function wrapRequestHandler(\n wrapperOptions: RequestHandlerWrapperOptions,\n handler: (...args: unknown[]) => Response | Promise<Response>,\n): Promise<Response> {\n return withIsolationScope(async isolationScope => {\n const { options, request, captureErrors = true } = wrapperOptions;\n const context = wrapperOptions.context;\n\n // Use getOriginalWaitUntil to get the un-instrumented waitUntil function.\n // This is crucial to avoid deadlock: the flush lock mechanism wraps waitUntil\n // to track pending tasks. If we use the instrumented version for flushAndDispose,\n // it acquires the lock, then flushAndDispose tries to wait for the same lock,\n // creating a deadlock.\n const waitUntil = context ? getOriginalWaitUntil(context)?.bind(context) : undefined;\n\n const client = init({ ...options, ctx: context });\n isolationScope.setClient(client);\n\n const urlObject = parseStringToURLObject(request.url);\n const [name, attributes] = getHttpSpanDetailsFromUrlObject(urlObject, 'server', 'auto.http.cloudflare', request);\n\n const contentLength = request.headers.get('content-length');\n if (contentLength) {\n attributes['http.request.body.size'] = parseInt(contentLength, 10);\n }\n\n const userAgentHeader = request.headers.get('user-agent');\n if (userAgentHeader) {\n attributes['user_agent.original'] = userAgentHeader;\n }\n\n Object.assign(\n attributes,\n httpHeadersToSpanAttributes(\n winterCGHeadersToDict(request.headers),\n getClient()?.getOptions().sendDefaultPii ?? false,\n ),\n );\n\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] = 'http.server';\n\n addCloudResourceContext(isolationScope);\n addRequest(isolationScope, request);\n if (request.cf) {\n addCultureContext(isolationScope, request.cf);\n\n if (typeof request.cf.httpProtocol === 'string') {\n attributes['network.protocol.name'] = request.cf.httpProtocol;\n }\n }\n\n // Do not capture spans for OPTIONS and HEAD requests\n if (request.method === 'OPTIONS' || request.method === 'HEAD') {\n try {\n return await handler();\n } catch (e) {\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n throw e;\n } finally {\n waitUntil?.(flushAndDispose(client));\n }\n }\n\n if (client) {\n await captureIncomingRequestBody(client, request);\n }\n\n return continueTrace(\n { sentryTrace: request.headers.get('sentry-trace') || '', baggage: request.headers.get('baggage') },\n () => {\n // Note: This span will not have a duration unless I/O happens in the handler. This is\n // because of how the cloudflare workers runtime works.\n // See: https://developers.cloudflare.com/workers/runtime-apis/performance/\n\n // Use startSpanManual to control when span ends (needed for streaming responses)\n return startSpanManual({ name, attributes }, async span => {\n let res: Response;\n\n try {\n res = await handler();\n setHttpStatus(span, res.status);\n\n // After the handler runs, the span name might have been updated by nested instrumentation\n // (e.g., Remix parameterizing routes). The span should already have the correct name\n // from that instrumentation, so we don't need to do anything here.\n } catch (e) {\n span.end();\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n waitUntil?.(flushAndDispose(client));\n throw e;\n }\n\n // Classify response to detect actual streaming\n const classification = classifyResponseStreaming(res);\n\n if (classification.isStreaming && res.body) {\n try {\n let ended = false;\n\n const endSpanOnce = (): void => {\n if (ended) return;\n\n ended = true;\n span.end();\n waitUntil?.(flushAndDispose(client));\n };\n\n const transform = new TransformStream({\n flush() {\n // Source stream completed normally.\n endSpanOnce();\n },\n cancel() {\n // Client disconnected (or downstream cancelled). The `cancel`\n // is being called while the response is still considered\n // active, so this is a safe place to end the span.\n endSpanOnce();\n },\n });\n\n return new Response(res.body.pipeThrough(transform), {\n status: res.status,\n statusText: res.statusText,\n headers: res.headers,\n });\n } catch {\n span.end();\n waitUntil?.(flushAndDispose(client));\n return res;\n }\n }\n\n // Non-streaming response - end span immediately and return original\n span.end();\n\n // Don't dispose for protocol upgrades (101 Switching Protocols) - the connection stays alive.\n // This includes WebSocket upgrades where webSocketMessage/webSocketClose handlers\n // will still be called and may need the client to capture errors.\n if (res.status === 101) {\n waitUntil?.(client?.flush(2000));\n } else {\n waitUntil?.(flushAndDispose(client));\n }\n return res;\n });\n },\n );\n });\n}\n"],"names":[],"mappings":"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"}
|
package/build/types/flush.d.ts
CHANGED
|
@@ -4,6 +4,21 @@ type FlushLock = {
|
|
|
4
4
|
readonly ready: Promise<void>;
|
|
5
5
|
readonly finalize: () => Promise<void>;
|
|
6
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* Returns the original (un-instrumented) waitUntil function for a context.
|
|
9
|
+
* This should be used when calling waitUntil with flushAndDispose to avoid deadlock.
|
|
10
|
+
*
|
|
11
|
+
* The flush lock mechanism wraps context.waitUntil to track pending tasks.
|
|
12
|
+
* If we call waitUntil(flushAndDispose(client)) through the instrumented version,
|
|
13
|
+
* it creates a deadlock because:
|
|
14
|
+
* 1. The instrumented waitUntil acquires the flush lock
|
|
15
|
+
* 2. flushAndDispose calls client.flush() which waits for the lock to be released
|
|
16
|
+
* 3. The lock won't be released until the waitUntil promise completes
|
|
17
|
+
* 4. The waitUntil promise won't complete until flush() returns
|
|
18
|
+
*
|
|
19
|
+
* By using the original waitUntil for flush operations, we bypass this issue.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getOriginalWaitUntil(context: ExecutionContext): ExecutionContext['waitUntil'] | undefined;
|
|
7
22
|
/**
|
|
8
23
|
* Enhances the given execution context by wrapping its `waitUntil` method with a proxy
|
|
9
24
|
* to monitor pending tasks, and provides a flusher function to ensure all tasks
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flush.d.ts","sourceRoot":"","sources":["../../src/flush.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,KAAK,SAAS,GAAG;IACf,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;
|
|
1
|
+
{"version":3,"file":"flush.d.ts","sourceRoot":"","sources":["../../src/flush.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,KAAK,SAAS,GAAG;IACf,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC,CAAC;AAcF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,gBAAgB,GAAG,gBAAgB,CAAC,WAAW,CAAC,GAAG,SAAS,CAKzG;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CA8BlE;AAoCD;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAS/F"}
|
|
@@ -25,6 +25,9 @@ declare const _honoIntegration: (options?: Partial<Options>) => {
|
|
|
25
25
|
*
|
|
26
26
|
* The integration is enabled by default.
|
|
27
27
|
*
|
|
28
|
+
* @deprecated Use the `@sentry/hono` package instead. The `sentry()` middleware from `@sentry/hono/cloudflare`
|
|
29
|
+
* handles error capturing automatically without needing this integration.
|
|
30
|
+
*
|
|
28
31
|
* @example
|
|
29
32
|
* integrations: [
|
|
30
33
|
* honoIntegration({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../../../src/integrations/hono.ts"],"names":[],"mappings":"AAeA,UAAU,SAAU,SAAQ,KAAK;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAGD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACxC;AAED,MAAM,WAAW,OAAO;IACtB;;;OAGG;IACH,iBAAiB,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC;CAC3D;AAED,qCAAqC;AACrC,wBAAgB,kBAAkB,IAAI,UAAU,CAAC,OAAO,gBAAgB,CAAC,GAAG,SAAS,CAEpF;AAYD,QAAA,MAAM,gBAAgB,aAAc,OAAO,CAAC,OAAO,CAAC;;6BAIvB,SAAS,WAAW,WAAW,GAAG,IAAI;CA2BzC,CAAC;AAE3B
|
|
1
|
+
{"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../../../src/integrations/hono.ts"],"names":[],"mappings":"AAeA,UAAU,SAAU,SAAQ,KAAK;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAGD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACxC;AAED,MAAM,WAAW,OAAO;IACtB;;;OAGG;IACH,iBAAiB,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC;CAC3D;AAED,qCAAqC;AACrC,wBAAgB,kBAAkB,IAAI,UAAU,CAAC,OAAO,gBAAgB,CAAC,GAAG,SAAS,CAEpF;AAYD,QAAA,MAAM,gBAAgB,aAAc,OAAO,CAAC,OAAO,CAAC;;6BAIvB,SAAS,WAAW,WAAW,GAAG,IAAI;CA2BzC,CAAC;AAE3B;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,eAAe,gFAAsC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAe7G,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAMlD,UAAU,4BAA4B;IACpC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,2BAA2B,CAAC,OAAO,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IACxF,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACtC;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,cAAc,EAAE,4BAA4B,EAC5C,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAC5D,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAe7G,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAMlD,UAAU,4BAA4B;IACpC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,2BAA2B,CAAC,OAAO,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IACxF,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACtC;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,cAAc,EAAE,4BAA4B,EAC5C,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAC5D,OAAO,CAAC,QAAQ,CAAC,CAqJnB"}
|
|
@@ -4,6 +4,21 @@ type FlushLock = {
|
|
|
4
4
|
readonly ready: Promise<void>;
|
|
5
5
|
readonly finalize: () => Promise<void>;
|
|
6
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* Returns the original (un-instrumented) waitUntil function for a context.
|
|
9
|
+
* This should be used when calling waitUntil with flushAndDispose to avoid deadlock.
|
|
10
|
+
*
|
|
11
|
+
* The flush lock mechanism wraps context.waitUntil to track pending tasks.
|
|
12
|
+
* If we call waitUntil(flushAndDispose(client)) through the instrumented version,
|
|
13
|
+
* it creates a deadlock because:
|
|
14
|
+
* 1. The instrumented waitUntil acquires the flush lock
|
|
15
|
+
* 2. flushAndDispose calls client.flush() which waits for the lock to be released
|
|
16
|
+
* 3. The lock won't be released until the waitUntil promise completes
|
|
17
|
+
* 4. The waitUntil promise won't complete until flush() returns
|
|
18
|
+
*
|
|
19
|
+
* By using the original waitUntil for flush operations, we bypass this issue.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getOriginalWaitUntil(context: ExecutionContext): ExecutionContext['waitUntil'] | undefined;
|
|
7
22
|
/**
|
|
8
23
|
* Enhances the given execution context by wrapping its `waitUntil` method with a proxy
|
|
9
24
|
* to monitor pending tasks, and provides a flusher function to ensure all tasks
|
|
@@ -25,6 +25,9 @@ declare const _honoIntegration: (options?: Partial<Options>) => {
|
|
|
25
25
|
*
|
|
26
26
|
* The integration is enabled by default.
|
|
27
27
|
*
|
|
28
|
+
* @deprecated Use the `@sentry/hono` package instead. The `sentry()` middleware from `@sentry/hono/cloudflare`
|
|
29
|
+
* handles error capturing automatically without needing this integration.
|
|
30
|
+
*
|
|
28
31
|
* @example
|
|
29
32
|
* integrations: [
|
|
30
33
|
* honoIntegration({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/cloudflare",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.55.0",
|
|
4
4
|
"description": "Official Sentry SDK for Cloudflare Workers and Pages",
|
|
5
5
|
"repository": "git://github.com/getsentry/sentry-javascript.git",
|
|
6
6
|
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/cloudflare",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@opentelemetry/api": "^1.9.1",
|
|
53
|
-
"@sentry/core": "10.
|
|
53
|
+
"@sentry/core": "10.55.0"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"@cloudflare/workers-types": "^4.x"
|