@sentry/cloudflare 10.53.1 → 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.
Files changed (172) hide show
  1. package/build/cjs/async.js +4 -30
  2. package/build/cjs/async.js.map +1 -1
  3. package/build/cjs/client.js +31 -58
  4. package/build/cjs/client.js.map +1 -1
  5. package/build/cjs/d1.js +26 -80
  6. package/build/cjs/d1.js.map +1 -1
  7. package/build/cjs/debug-build.js +0 -5
  8. package/build/cjs/debug-build.js.map +1 -1
  9. package/build/cjs/durableobject.js +44 -131
  10. package/build/cjs/durableobject.js.map +1 -1
  11. package/build/cjs/flush.js +53 -34
  12. package/build/cjs/flush.js.map +1 -1
  13. package/build/cjs/instrument.js +7 -48
  14. package/build/cjs/instrument.js.map +1 -1
  15. package/build/cjs/instrumentations/instrumentDurableObjectNamespace.js +9 -34
  16. package/build/cjs/instrumentations/instrumentDurableObjectNamespace.js.map +1 -1
  17. package/build/cjs/instrumentations/instrumentDurableObjectStorage.js +20 -54
  18. package/build/cjs/instrumentations/instrumentDurableObjectStorage.js.map +1 -1
  19. package/build/cjs/instrumentations/instrumentWorkerEntrypoint.js +12 -66
  20. package/build/cjs/instrumentations/instrumentWorkerEntrypoint.js.map +1 -1
  21. package/build/cjs/instrumentations/worker/instrumentEmail.js +21 -43
  22. package/build/cjs/instrumentations/worker/instrumentEmail.js.map +1 -1
  23. package/build/cjs/instrumentations/worker/instrumentEnv.js +12 -42
  24. package/build/cjs/instrumentations/worker/instrumentEnv.js.map +1 -1
  25. package/build/cjs/instrumentations/worker/instrumentFetch.js +20 -34
  26. package/build/cjs/instrumentations/worker/instrumentFetch.js.map +1 -1
  27. package/build/cjs/instrumentations/worker/instrumentFetcher.js +5 -19
  28. package/build/cjs/instrumentations/worker/instrumentFetcher.js.map +1 -1
  29. package/build/cjs/instrumentations/worker/instrumentQueue.js +30 -62
  30. package/build/cjs/instrumentations/worker/instrumentQueue.js.map +1 -1
  31. package/build/cjs/instrumentations/worker/instrumentQueueProducer.js +31 -57
  32. package/build/cjs/instrumentations/worker/instrumentQueueProducer.js.map +1 -1
  33. package/build/cjs/instrumentations/worker/instrumentScheduled.js +25 -54
  34. package/build/cjs/instrumentations/worker/instrumentScheduled.js.map +1 -1
  35. package/build/cjs/instrumentations/worker/instrumentTail.js +16 -43
  36. package/build/cjs/instrumentations/worker/instrumentTail.js.map +1 -1
  37. package/build/cjs/integrations/fetch.js +24 -56
  38. package/build/cjs/integrations/fetch.js.map +1 -1
  39. package/build/cjs/integrations/hono.js +7 -38
  40. package/build/cjs/integrations/hono.js.map +1 -1
  41. package/build/cjs/integrations/httpServer.js +6 -39
  42. package/build/cjs/integrations/httpServer.js.map +1 -1
  43. package/build/cjs/integrations/tracing/vercelai.js +3 -31
  44. package/build/cjs/integrations/tracing/vercelai.js.map +1 -1
  45. package/build/cjs/opentelemetry/tracer.js +17 -45
  46. package/build/cjs/opentelemetry/tracer.js.map +1 -1
  47. package/build/cjs/options.js +10 -46
  48. package/build/cjs/options.js.map +1 -1
  49. package/build/cjs/pages-plugin.js +9 -42
  50. package/build/cjs/pages-plugin.js.map +1 -1
  51. package/build/cjs/request.js +22 -68
  52. package/build/cjs/request.js.map +1 -1
  53. package/build/cjs/scope-utils.js +4 -15
  54. package/build/cjs/scope-utils.js.map +1 -1
  55. package/build/cjs/sdk.js +8 -25
  56. package/build/cjs/sdk.js.map +1 -1
  57. package/build/cjs/transport.js +14 -48
  58. package/build/cjs/transport.js.map +1 -1
  59. package/build/cjs/utils/instrumentContext.js +16 -52
  60. package/build/cjs/utils/instrumentContext.js.map +1 -1
  61. package/build/cjs/utils/isBinding.js +3 -23
  62. package/build/cjs/utils/isBinding.js.map +1 -1
  63. package/build/cjs/utils/isCloudflareClass.js +2 -8
  64. package/build/cjs/utils/isCloudflareClass.js.map +1 -1
  65. package/build/cjs/utils/rpcMeta.js +8 -32
  66. package/build/cjs/utils/rpcMeta.js.map +1 -1
  67. package/build/cjs/utils/rpcOptions.js +9 -32
  68. package/build/cjs/utils/rpcOptions.js.map +1 -1
  69. package/build/cjs/utils/streaming.js +3 -29
  70. package/build/cjs/utils/streaming.js.map +1 -1
  71. package/build/cjs/utils/traceLinks.js +8 -33
  72. package/build/cjs/utils/traceLinks.js.map +1 -1
  73. package/build/cjs/vendor/stacktrace.js +6 -27
  74. package/build/cjs/vendor/stacktrace.js.map +1 -1
  75. package/build/cjs/withSentry.js +16 -47
  76. package/build/cjs/withSentry.js.map +1 -1
  77. package/build/cjs/workflows.js +40 -100
  78. package/build/cjs/workflows.js.map +1 -1
  79. package/build/cjs/wrapMethodWithSentry.js +110 -167
  80. package/build/cjs/wrapMethodWithSentry.js.map +1 -1
  81. package/build/esm/async.js +4 -30
  82. package/build/esm/async.js.map +1 -1
  83. package/build/esm/client.js +31 -58
  84. package/build/esm/client.js.map +1 -1
  85. package/build/esm/d1.js +26 -80
  86. package/build/esm/d1.js.map +1 -1
  87. package/build/esm/debug-build.js +0 -5
  88. package/build/esm/debug-build.js.map +1 -1
  89. package/build/esm/durableobject.js +44 -131
  90. package/build/esm/durableobject.js.map +1 -1
  91. package/build/esm/flush.js +53 -35
  92. package/build/esm/flush.js.map +1 -1
  93. package/build/esm/instrument.js +7 -48
  94. package/build/esm/instrument.js.map +1 -1
  95. package/build/esm/instrumentations/instrumentDurableObjectNamespace.js +9 -34
  96. package/build/esm/instrumentations/instrumentDurableObjectNamespace.js.map +1 -1
  97. package/build/esm/instrumentations/instrumentDurableObjectStorage.js +20 -54
  98. package/build/esm/instrumentations/instrumentDurableObjectStorage.js.map +1 -1
  99. package/build/esm/instrumentations/instrumentWorkerEntrypoint.js +12 -66
  100. package/build/esm/instrumentations/instrumentWorkerEntrypoint.js.map +1 -1
  101. package/build/esm/instrumentations/worker/instrumentEmail.js +21 -43
  102. package/build/esm/instrumentations/worker/instrumentEmail.js.map +1 -1
  103. package/build/esm/instrumentations/worker/instrumentEnv.js +12 -42
  104. package/build/esm/instrumentations/worker/instrumentEnv.js.map +1 -1
  105. package/build/esm/instrumentations/worker/instrumentFetch.js +20 -34
  106. package/build/esm/instrumentations/worker/instrumentFetch.js.map +1 -1
  107. package/build/esm/instrumentations/worker/instrumentFetcher.js +5 -19
  108. package/build/esm/instrumentations/worker/instrumentFetcher.js.map +1 -1
  109. package/build/esm/instrumentations/worker/instrumentQueue.js +30 -62
  110. package/build/esm/instrumentations/worker/instrumentQueue.js.map +1 -1
  111. package/build/esm/instrumentations/worker/instrumentQueueProducer.js +31 -57
  112. package/build/esm/instrumentations/worker/instrumentQueueProducer.js.map +1 -1
  113. package/build/esm/instrumentations/worker/instrumentScheduled.js +25 -54
  114. package/build/esm/instrumentations/worker/instrumentScheduled.js.map +1 -1
  115. package/build/esm/instrumentations/worker/instrumentTail.js +16 -43
  116. package/build/esm/instrumentations/worker/instrumentTail.js.map +1 -1
  117. package/build/esm/integrations/fetch.js +24 -56
  118. package/build/esm/integrations/fetch.js.map +1 -1
  119. package/build/esm/integrations/hono.js +7 -38
  120. package/build/esm/integrations/hono.js.map +1 -1
  121. package/build/esm/integrations/httpServer.js +6 -39
  122. package/build/esm/integrations/httpServer.js.map +1 -1
  123. package/build/esm/integrations/tracing/vercelai.js +3 -31
  124. package/build/esm/integrations/tracing/vercelai.js.map +1 -1
  125. package/build/esm/opentelemetry/tracer.js +17 -45
  126. package/build/esm/opentelemetry/tracer.js.map +1 -1
  127. package/build/esm/options.js +10 -46
  128. package/build/esm/options.js.map +1 -1
  129. package/build/esm/package.json +1 -1
  130. package/build/esm/pages-plugin.js +9 -42
  131. package/build/esm/pages-plugin.js.map +1 -1
  132. package/build/esm/request.js +23 -69
  133. package/build/esm/request.js.map +1 -1
  134. package/build/esm/scope-utils.js +4 -15
  135. package/build/esm/scope-utils.js.map +1 -1
  136. package/build/esm/sdk.js +8 -25
  137. package/build/esm/sdk.js.map +1 -1
  138. package/build/esm/transport.js +14 -48
  139. package/build/esm/transport.js.map +1 -1
  140. package/build/esm/utils/instrumentContext.js +16 -52
  141. package/build/esm/utils/instrumentContext.js.map +1 -1
  142. package/build/esm/utils/isBinding.js +3 -23
  143. package/build/esm/utils/isBinding.js.map +1 -1
  144. package/build/esm/utils/isCloudflareClass.js +2 -8
  145. package/build/esm/utils/isCloudflareClass.js.map +1 -1
  146. package/build/esm/utils/rpcMeta.js +8 -32
  147. package/build/esm/utils/rpcMeta.js.map +1 -1
  148. package/build/esm/utils/rpcOptions.js +9 -32
  149. package/build/esm/utils/rpcOptions.js.map +1 -1
  150. package/build/esm/utils/streaming.js +3 -29
  151. package/build/esm/utils/streaming.js.map +1 -1
  152. package/build/esm/utils/traceLinks.js +8 -33
  153. package/build/esm/utils/traceLinks.js.map +1 -1
  154. package/build/esm/vendor/stacktrace.js +6 -27
  155. package/build/esm/vendor/stacktrace.js.map +1 -1
  156. package/build/esm/withSentry.js +16 -47
  157. package/build/esm/withSentry.js.map +1 -1
  158. package/build/esm/workflows.js +40 -100
  159. package/build/esm/workflows.js.map +1 -1
  160. package/build/esm/wrapMethodWithSentry.js +110 -167
  161. package/build/esm/wrapMethodWithSentry.js.map +1 -1
  162. package/build/types/client.d.ts.map +1 -1
  163. package/build/types/flush.d.ts +15 -0
  164. package/build/types/flush.d.ts.map +1 -1
  165. package/build/types/instrumentations/worker/instrumentFetch.d.ts.map +1 -1
  166. package/build/types/integrations/hono.d.ts +3 -0
  167. package/build/types/integrations/hono.d.ts.map +1 -1
  168. package/build/types/pages-plugin.d.ts.map +1 -1
  169. package/build/types/request.d.ts.map +1 -1
  170. package/build/types-ts3.8/flush.d.ts +15 -0
  171. package/build/types-ts3.8/integrations/hono.d.ts +3 -0
  172. package/package.json +2 -2
@@ -1,136 +1,96 @@
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';
7
7
 
8
- /**
9
- * Wraps a cloudflare request handler in Sentry instrumentation
10
- */
11
- function wrapRequestHandler(
12
- wrapperOptions,
13
- handler,
14
- ) {
15
- return withIsolationScope(async isolationScope => {
8
+ function wrapRequestHandler(wrapperOptions, handler) {
9
+ return withIsolationScope(async (isolationScope) => {
16
10
  const { options, request, captureErrors = true } = wrapperOptions;
17
11
  const context = wrapperOptions.context;
18
-
19
- const waitUntil = context?.waitUntil?.bind?.(context);
20
-
12
+ const waitUntil = context ? getOriginalWaitUntil(context)?.bind(context) : void 0;
21
13
  const client = init({ ...options, ctx: context });
22
14
  isolationScope.setClient(client);
23
-
24
15
  const urlObject = parseStringToURLObject(request.url);
25
- const [name, attributes] = getHttpSpanDetailsFromUrlObject(urlObject, 'server', 'auto.http.cloudflare', request);
26
-
27
- const contentLength = request.headers.get('content-length');
16
+ const [name, attributes] = getHttpSpanDetailsFromUrlObject(urlObject, "server", "auto.http.cloudflare", request);
17
+ const contentLength = request.headers.get("content-length");
28
18
  if (contentLength) {
29
- attributes['http.request.body.size'] = parseInt(contentLength, 10);
19
+ attributes["http.request.body.size"] = parseInt(contentLength, 10);
30
20
  }
31
-
32
- const userAgentHeader = request.headers.get('user-agent');
21
+ const userAgentHeader = request.headers.get("user-agent");
33
22
  if (userAgentHeader) {
34
- attributes['user_agent.original'] = userAgentHeader;
23
+ attributes["user_agent.original"] = userAgentHeader;
35
24
  }
36
-
37
25
  Object.assign(
38
26
  attributes,
39
27
  httpHeadersToSpanAttributes(
40
28
  winterCGHeadersToDict(request.headers),
41
- getClient()?.getOptions().sendDefaultPii ?? false,
42
- ),
29
+ getClient()?.getOptions().sendDefaultPii ?? false
30
+ )
43
31
  );
44
-
45
- attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] = 'http.server';
46
-
32
+ attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] = "http.server";
47
33
  addCloudResourceContext(isolationScope);
48
34
  addRequest(isolationScope, request);
49
35
  if (request.cf) {
50
36
  addCultureContext(isolationScope, request.cf);
51
-
52
- if (typeof request.cf.httpProtocol === 'string') {
53
- attributes['network.protocol.name'] = request.cf.httpProtocol;
37
+ if (typeof request.cf.httpProtocol === "string") {
38
+ attributes["network.protocol.name"] = request.cf.httpProtocol;
54
39
  }
55
40
  }
56
-
57
- // Do not capture spans for OPTIONS and HEAD requests
58
- if (request.method === 'OPTIONS' || request.method === 'HEAD') {
41
+ if (request.method === "OPTIONS" || request.method === "HEAD") {
59
42
  try {
60
43
  return await handler();
61
44
  } catch (e) {
62
45
  if (captureErrors) {
63
- captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });
46
+ captureException(e, { mechanism: { handled: false, type: "auto.http.cloudflare" } });
64
47
  }
65
48
  throw e;
66
49
  } finally {
67
50
  waitUntil?.(flushAndDispose(client));
68
51
  }
69
52
  }
70
-
71
53
  if (client) {
72
54
  await captureIncomingRequestBody(client, request);
73
55
  }
74
-
75
56
  return continueTrace(
76
- { sentryTrace: request.headers.get('sentry-trace') || '', baggage: request.headers.get('baggage') },
57
+ { sentryTrace: request.headers.get("sentry-trace") || "", baggage: request.headers.get("baggage") },
77
58
  () => {
78
- // Note: This span will not have a duration unless I/O happens in the handler. This is
79
- // because of how the cloudflare workers runtime works.
80
- // See: https://developers.cloudflare.com/workers/runtime-apis/performance/
81
-
82
- // Use startSpanManual to control when span ends (needed for streaming responses)
83
- return startSpanManual({ name, attributes }, async span => {
59
+ return startSpanManual({ name, attributes }, async (span) => {
84
60
  let res;
85
-
86
61
  try {
87
62
  res = await handler();
88
63
  setHttpStatus(span, res.status);
89
-
90
- // After the handler runs, the span name might have been updated by nested instrumentation
91
- // (e.g., Remix parameterizing routes). The span should already have the correct name
92
- // from that instrumentation, so we don't need to do anything here.
93
64
  } catch (e) {
94
65
  span.end();
95
66
  if (captureErrors) {
96
- captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });
67
+ captureException(e, { mechanism: { handled: false, type: "auto.http.cloudflare" } });
97
68
  }
98
69
  waitUntil?.(flushAndDispose(client));
99
70
  throw e;
100
71
  }
101
-
102
- // Classify response to detect actual streaming
103
72
  const classification = classifyResponseStreaming(res);
104
-
105
73
  if (classification.isStreaming && res.body) {
106
74
  try {
107
75
  let ended = false;
108
-
109
76
  const endSpanOnce = () => {
110
77
  if (ended) return;
111
-
112
78
  ended = true;
113
79
  span.end();
114
80
  waitUntil?.(flushAndDispose(client));
115
81
  };
116
-
117
82
  const transform = new TransformStream({
118
83
  flush() {
119
- // Source stream completed normally.
120
84
  endSpanOnce();
121
85
  },
122
86
  cancel() {
123
- // Client disconnected (or downstream cancelled). The `cancel`
124
- // is being called while the response is still considered
125
- // active, so this is a safe place to end the span.
126
87
  endSpanOnce();
127
- },
88
+ }
128
89
  });
129
-
130
90
  return new Response(res.body.pipeThrough(transform), {
131
91
  status: res.status,
132
92
  statusText: res.statusText,
133
- headers: res.headers,
93
+ headers: res.headers
134
94
  });
135
95
  } catch {
136
96
  span.end();
@@ -138,21 +98,15 @@ function wrapRequestHandler(
138
98
  return res;
139
99
  }
140
100
  }
141
-
142
- // Non-streaming response - end span immediately and return original
143
101
  span.end();
144
-
145
- // Don't dispose for protocol upgrades (101 Switching Protocols) - the connection stays alive.
146
- // This includes WebSocket upgrades where webSocketMessage/webSocketClose handlers
147
- // will still be called and may need the client to capture errors.
148
102
  if (res.status === 101) {
149
- waitUntil?.(client?.flush(2000));
103
+ waitUntil?.(client?.flush(2e3));
150
104
  } else {
151
105
  waitUntil?.(flushAndDispose(client));
152
106
  }
153
107
  return res;
154
108
  });
155
- },
109
+ }
156
110
  );
157
111
  });
158
112
  }
@@ -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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"}
@@ -1,26 +1,15 @@
1
1
  import { winterCGRequestToRequestData } from '@sentry/core';
2
2
 
3
- /**
4
- * Set cloud resource context on scope.
5
- */
6
3
  function addCloudResourceContext(scope) {
7
- scope.setContext('cloud_resource', {
8
- 'cloud.provider': 'cloudflare',
4
+ scope.setContext("cloud_resource", {
5
+ "cloud.provider": "cloudflare"
9
6
  });
10
7
  }
11
-
12
- /**
13
- * Set culture context on scope
14
- */
15
8
  function addCultureContext(scope, cf) {
16
- scope.setContext('culture', {
17
- timezone: cf.timezone,
9
+ scope.setContext("culture", {
10
+ timezone: cf.timezone
18
11
  });
19
12
  }
20
-
21
- /**
22
- * Set request data on scope
23
- */
24
13
  function addRequest(scope, request) {
25
14
  scope.setSDKProcessingMetadata({ normalizedRequest: winterCGRequestToRequestData(request) });
26
15
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scope-utils.js","sources":["../../src/scope-utils.ts"],"sourcesContent":["import type { CfProperties, IncomingRequestCfProperties } from '@cloudflare/workers-types';\nimport type { Scope } from '@sentry/core';\nimport { winterCGRequestToRequestData } from '@sentry/core';\n\n/**\n * Set cloud resource context on scope.\n */\nexport function addCloudResourceContext(scope: Scope): void {\n scope.setContext('cloud_resource', {\n 'cloud.provider': 'cloudflare',\n });\n}\n\n/**\n * Set culture context on scope\n */\nexport function addCultureContext(scope: Scope, cf: IncomingRequestCfProperties | CfProperties): void {\n scope.setContext('culture', {\n timezone: cf.timezone,\n });\n}\n\n/**\n * Set request data on scope\n */\nexport function addRequest(scope: Scope, request: Request): void {\n scope.setSDKProcessingMetadata({ normalizedRequest: winterCGRequestToRequestData(request) });\n}\n"],"names":[],"mappings":";;AAIA;AACA;AACA;AACO,SAAS,uBAAuB,CAAC,KAAK,EAAe;AAC5D,EAAE,KAAK,CAAC,UAAU,CAAC,gBAAgB,EAAE;AACrC,IAAI,gBAAgB,EAAE,YAAY;AAClC,GAAG,CAAC;AACJ;;AAEA;AACA;AACA;AACO,SAAS,iBAAiB,CAAC,KAAK,EAAS,EAAE,EAAoD;AACtG,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,EAAE;AAC9B,IAAI,QAAQ,EAAE,EAAE,CAAC,QAAQ;AACzB,GAAG,CAAC;AACJ;;AAEA;AACA;AACA;AACO,SAAS,UAAU,CAAC,KAAK,EAAS,OAAO,EAAiB;AACjE,EAAE,KAAK,CAAC,wBAAwB,CAAC,EAAE,iBAAiB,EAAE,4BAA4B,CAAC,OAAO,CAAA,EAAG,CAAC;AAC9F;;;;"}
1
+ {"version":3,"file":"scope-utils.js","sources":["../../src/scope-utils.ts"],"sourcesContent":["import type { CfProperties, IncomingRequestCfProperties } from '@cloudflare/workers-types';\nimport type { Scope } from '@sentry/core';\nimport { winterCGRequestToRequestData } from '@sentry/core';\n\n/**\n * Set cloud resource context on scope.\n */\nexport function addCloudResourceContext(scope: Scope): void {\n scope.setContext('cloud_resource', {\n 'cloud.provider': 'cloudflare',\n });\n}\n\n/**\n * Set culture context on scope\n */\nexport function addCultureContext(scope: Scope, cf: IncomingRequestCfProperties | CfProperties): void {\n scope.setContext('culture', {\n timezone: cf.timezone,\n });\n}\n\n/**\n * Set request data on scope\n */\nexport function addRequest(scope: Scope, request: Request): void {\n scope.setSDKProcessingMetadata({ normalizedRequest: winterCGRequestToRequestData(request) });\n}\n"],"names":[],"mappings":";;AAOO,SAAS,wBAAwB,KAAA,EAAoB;AAC1D,EAAA,KAAA,CAAM,WAAW,gBAAA,EAAkB;AAAA,IACjC,gBAAA,EAAkB;AAAA,GACnB,CAAA;AACH;AAKO,SAAS,iBAAA,CAAkB,OAAc,EAAA,EAAsD;AACpG,EAAA,KAAA,CAAM,WAAW,SAAA,EAAW;AAAA,IAC1B,UAAU,EAAA,CAAG;AAAA,GACd,CAAA;AACH;AAKO,SAAS,UAAA,CAAW,OAAc,OAAA,EAAwB;AAC/D,EAAA,KAAA,CAAM,yBAAyB,EAAE,iBAAA,EAAmB,4BAAA,CAA6B,OAAO,GAAG,CAAA;AAC7F;;;;"}
package/build/esm/sdk.js CHANGED
@@ -8,13 +8,12 @@ import { setupOpenTelemetryTracer } from './opentelemetry/tracer.js';
8
8
  import { makeCloudflareTransport } from './transport.js';
9
9
  import { defaultStackParser } from './vendor/stacktrace.js';
10
10
 
11
- /** Get the default integrations for the Cloudflare SDK. */
12
11
  function getDefaultIntegrations(options) {
13
12
  const sendDefaultPii = options.sendDefaultPii ?? false;
14
13
  return [
15
14
  // The Dedupe integration should not be used in workflows because we want to
16
15
  // capture all step failures, even if they are the same error.
17
- ...(options.enableDedupe === false ? [] : [dedupeIntegration()]),
16
+ ...options.enableDedupe === false ? [] : [dedupeIntegration()],
18
17
  // TODO(v11): Replace with `eventFiltersIntegration` once we remove the deprecated `inboundFiltersIntegration`
19
18
  // eslint-disable-next-line deprecation/deprecation
20
19
  inboundFiltersIntegration(),
@@ -25,47 +24,31 @@ function getDefaultIntegrations(options) {
25
24
  honoIntegration(),
26
25
  httpServerIntegration(),
27
26
  // TODO(v11): the `include` object should be defined directly in the integration based on `sendDefaultPii`
28
- requestDataIntegration(sendDefaultPii ? undefined : { include: { cookies: false } }),
29
- consoleIntegration(),
27
+ requestDataIntegration(sendDefaultPii ? void 0 : { include: { cookies: false } }),
28
+ consoleIntegration()
30
29
  ];
31
30
  }
32
-
33
- /**
34
- * Initializes the cloudflare SDK.
35
- */
36
31
  function init(options) {
37
- if (options.defaultIntegrations === undefined) {
32
+ if (options.defaultIntegrations === void 0) {
38
33
  options.defaultIntegrations = getDefaultIntegrations(options);
39
34
  }
40
-
41
- const flushLock = options.ctx ? makeFlushLock(options.ctx) : undefined;
35
+ const flushLock = options.ctx ? makeFlushLock(options.ctx) : void 0;
42
36
  delete options.ctx;
43
-
44
37
  const resolvedIntegrations = getIntegrationsToSetup(options);
45
- if (options.traceLifecycle === 'stream' && !resolvedIntegrations.some(i => i.name === 'SpanStreaming')) {
38
+ if (options.traceLifecycle === "stream" && !resolvedIntegrations.some((i) => i.name === "SpanStreaming")) {
46
39
  resolvedIntegrations.push(spanStreamingIntegration());
47
40
  }
48
-
49
41
  const clientOptions = {
50
42
  ...options,
51
43
  stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),
52
44
  integrations: resolvedIntegrations,
53
45
  transport: options.transport || makeCloudflareTransport,
54
- flushLock,
46
+ flushLock
55
47
  };
56
-
57
- /**
58
- * The Cloudflare SDK is not OpenTelemetry native, however, we set up some OpenTelemetry compatibility
59
- * via a custom trace provider.
60
- * This ensures that any spans emitted via `@opentelemetry/api` will be captured by Sentry.
61
- * HOWEVER, big caveat: This does not handle custom context handling, it will always work off the current scope.
62
- * This should be good enough for many, but not all integrations.
63
- */
64
48
  if (!options.skipOpenTelemetrySetup) {
65
49
  setupOpenTelemetryTracer();
66
50
  }
67
-
68
- return initAndBind(CloudflareClient, clientOptions) ;
51
+ return initAndBind(CloudflareClient, clientOptions);
69
52
  }
70
53
 
71
54
  export { getDefaultIntegrations, init };
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.js","sources":["../../src/sdk.ts"],"sourcesContent":["import type { Integration } from '@sentry/core';\nimport {\n consoleIntegration,\n conversationIdIntegration,\n dedupeIntegration,\n functionToStringIntegration,\n getIntegrationsToSetup,\n inboundFiltersIntegration,\n initAndBind,\n linkedErrorsIntegration,\n requestDataIntegration,\n spanStreamingIntegration,\n stackParserFromStackParserOptions,\n} from '@sentry/core';\nimport type { CloudflareClientOptions, CloudflareOptions } from './client';\nimport { CloudflareClient } from './client';\nimport { makeFlushLock } from './flush';\nimport { httpServerIntegration } from './integrations/httpServer';\nimport { fetchIntegration } from './integrations/fetch';\nimport { honoIntegration } from './integrations/hono';\nimport { setupOpenTelemetryTracer } from './opentelemetry/tracer';\nimport { makeCloudflareTransport } from './transport';\nimport { defaultStackParser } from './vendor/stacktrace';\n\n/** Get the default integrations for the Cloudflare SDK. */\nexport function getDefaultIntegrations(options: CloudflareOptions): Integration[] {\n const sendDefaultPii = options.sendDefaultPii ?? false;\n return [\n // The Dedupe integration should not be used in workflows because we want to\n // capture all step failures, even if they are the same error.\n ...(options.enableDedupe === false ? [] : [dedupeIntegration()]),\n // TODO(v11): Replace with `eventFiltersIntegration` once we remove the deprecated `inboundFiltersIntegration`\n // eslint-disable-next-line deprecation/deprecation\n inboundFiltersIntegration(),\n functionToStringIntegration(),\n conversationIdIntegration(),\n linkedErrorsIntegration(),\n fetchIntegration(),\n honoIntegration(),\n httpServerIntegration(),\n // TODO(v11): the `include` object should be defined directly in the integration based on `sendDefaultPii`\n requestDataIntegration(sendDefaultPii ? undefined : { include: { cookies: false } }),\n consoleIntegration(),\n ];\n}\n\n/**\n * Initializes the cloudflare SDK.\n */\nexport function init(options: CloudflareOptions): CloudflareClient | undefined {\n if (options.defaultIntegrations === undefined) {\n options.defaultIntegrations = getDefaultIntegrations(options);\n }\n\n const flushLock = options.ctx ? makeFlushLock(options.ctx) : undefined;\n delete options.ctx;\n\n const resolvedIntegrations = getIntegrationsToSetup(options);\n if (options.traceLifecycle === 'stream' && !resolvedIntegrations.some(i => i.name === 'SpanStreaming')) {\n resolvedIntegrations.push(spanStreamingIntegration());\n }\n\n const clientOptions: CloudflareClientOptions = {\n ...options,\n stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),\n integrations: resolvedIntegrations,\n transport: options.transport || makeCloudflareTransport,\n flushLock,\n };\n\n /**\n * The Cloudflare SDK is not OpenTelemetry native, however, we set up some OpenTelemetry compatibility\n * via a custom trace provider.\n * This ensures that any spans emitted via `@opentelemetry/api` will be captured by Sentry.\n * HOWEVER, big caveat: This does not handle custom context handling, it will always work off the current scope.\n * This should be good enough for many, but not all integrations.\n */\n if (!options.skipOpenTelemetrySetup) {\n setupOpenTelemetryTracer();\n }\n\n return initAndBind(CloudflareClient, clientOptions) as CloudflareClient;\n}\n"],"names":[],"mappings":";;;;;;;;;;AAwBA;AACO,SAAS,sBAAsB,CAAC,OAAO,EAAoC;AAClF,EAAE,MAAM,cAAA,GAAiB,OAAO,CAAC,cAAA,IAAkB,KAAK;AACxD,EAAE,OAAO;AACT;AACA;AACA,IAAI,IAAI,OAAO,CAAC,YAAA,KAAiB,KAAA,GAAQ,EAAC,GAAI,CAAC,iBAAiB,EAAE,CAAC,CAAC;AACpE;AACA;AACA,IAAI,yBAAyB,EAAE;AAC/B,IAAI,2BAA2B,EAAE;AACjC,IAAI,yBAAyB,EAAE;AAC/B,IAAI,uBAAuB,EAAE;AAC7B,IAAI,gBAAgB,EAAE;AACtB,IAAI,eAAe,EAAE;AACrB,IAAI,qBAAqB,EAAE;AAC3B;AACA,IAAI,sBAAsB,CAAC,cAAA,GAAiB,YAAY,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,KAAA,EAAM,EAAG,CAAC;AACxF,IAAI,kBAAkB,EAAE;AACxB,GAAG;AACH;;AAEA;AACA;AACA;AACO,SAAS,IAAI,CAAC,OAAO,EAAmD;AAC/E,EAAE,IAAI,OAAO,CAAC,mBAAA,KAAwB,SAAS,EAAE;AACjD,IAAI,OAAO,CAAC,mBAAA,GAAsB,sBAAsB,CAAC,OAAO,CAAC;AACjE,EAAE;;AAEF,EAAE,MAAM,SAAA,GAAY,OAAO,CAAC,GAAA,GAAM,aAAa,CAAC,OAAO,CAAC,GAAG,CAAA,GAAI,SAAS;AACxE,EAAE,OAAO,OAAO,CAAC,GAAG;;AAEpB,EAAE,MAAM,oBAAA,GAAuB,sBAAsB,CAAC,OAAO,CAAC;AAC9D,EAAE,IAAI,OAAO,CAAC,mBAAmB,QAAA,IAAY,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAA,KAAS,eAAe,CAAC,EAAE;AAC1G,IAAI,oBAAoB,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC;AACzD,EAAE;;AAEF,EAAE,MAAM,aAAa,GAA4B;AACjD,IAAI,GAAG,OAAO;AACd,IAAI,WAAW,EAAE,iCAAiC,CAAC,OAAO,CAAC,WAAA,IAAe,kBAAkB,CAAC;AAC7F,IAAI,YAAY,EAAE,oBAAoB;AACtC,IAAI,SAAS,EAAE,OAAO,CAAC,SAAA,IAAa,uBAAuB;AAC3D,IAAI,SAAS;AACb,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE;AACvC,IAAI,wBAAwB,EAAE;AAC9B,EAAE;;AAEF,EAAE,OAAO,WAAW,CAAC,gBAAgB,EAAE,aAAa,CAAA;AACpD;;;;"}
1
+ {"version":3,"file":"sdk.js","sources":["../../src/sdk.ts"],"sourcesContent":["import type { Integration } from '@sentry/core';\nimport {\n consoleIntegration,\n conversationIdIntegration,\n dedupeIntegration,\n functionToStringIntegration,\n getIntegrationsToSetup,\n inboundFiltersIntegration,\n initAndBind,\n linkedErrorsIntegration,\n requestDataIntegration,\n spanStreamingIntegration,\n stackParserFromStackParserOptions,\n} from '@sentry/core';\nimport type { CloudflareClientOptions, CloudflareOptions } from './client';\nimport { CloudflareClient } from './client';\nimport { makeFlushLock } from './flush';\nimport { httpServerIntegration } from './integrations/httpServer';\nimport { fetchIntegration } from './integrations/fetch';\nimport { honoIntegration } from './integrations/hono';\nimport { setupOpenTelemetryTracer } from './opentelemetry/tracer';\nimport { makeCloudflareTransport } from './transport';\nimport { defaultStackParser } from './vendor/stacktrace';\n\n/** Get the default integrations for the Cloudflare SDK. */\nexport function getDefaultIntegrations(options: CloudflareOptions): Integration[] {\n const sendDefaultPii = options.sendDefaultPii ?? false;\n return [\n // The Dedupe integration should not be used in workflows because we want to\n // capture all step failures, even if they are the same error.\n ...(options.enableDedupe === false ? [] : [dedupeIntegration()]),\n // TODO(v11): Replace with `eventFiltersIntegration` once we remove the deprecated `inboundFiltersIntegration`\n // eslint-disable-next-line deprecation/deprecation\n inboundFiltersIntegration(),\n functionToStringIntegration(),\n conversationIdIntegration(),\n linkedErrorsIntegration(),\n fetchIntegration(),\n honoIntegration(),\n httpServerIntegration(),\n // TODO(v11): the `include` object should be defined directly in the integration based on `sendDefaultPii`\n requestDataIntegration(sendDefaultPii ? undefined : { include: { cookies: false } }),\n consoleIntegration(),\n ];\n}\n\n/**\n * Initializes the cloudflare SDK.\n */\nexport function init(options: CloudflareOptions): CloudflareClient | undefined {\n if (options.defaultIntegrations === undefined) {\n options.defaultIntegrations = getDefaultIntegrations(options);\n }\n\n const flushLock = options.ctx ? makeFlushLock(options.ctx) : undefined;\n delete options.ctx;\n\n const resolvedIntegrations = getIntegrationsToSetup(options);\n if (options.traceLifecycle === 'stream' && !resolvedIntegrations.some(i => i.name === 'SpanStreaming')) {\n resolvedIntegrations.push(spanStreamingIntegration());\n }\n\n const clientOptions: CloudflareClientOptions = {\n ...options,\n stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),\n integrations: resolvedIntegrations,\n transport: options.transport || makeCloudflareTransport,\n flushLock,\n };\n\n /**\n * The Cloudflare SDK is not OpenTelemetry native, however, we set up some OpenTelemetry compatibility\n * via a custom trace provider.\n * This ensures that any spans emitted via `@opentelemetry/api` will be captured by Sentry.\n * HOWEVER, big caveat: This does not handle custom context handling, it will always work off the current scope.\n * This should be good enough for many, but not all integrations.\n */\n if (!options.skipOpenTelemetrySetup) {\n setupOpenTelemetryTracer();\n }\n\n return initAndBind(CloudflareClient, clientOptions) as CloudflareClient;\n}\n"],"names":[],"mappings":";;;;;;;;;;AAyBO,SAAS,uBAAuB,OAAA,EAA2C;AAChF,EAAA,MAAM,cAAA,GAAiB,QAAQ,cAAA,IAAkB,KAAA;AACjD,EAAA,OAAO;AAAA;AAAA;AAAA,IAGL,GAAI,QAAQ,YAAA,KAAiB,KAAA,GAAQ,EAAC,GAAI,CAAC,mBAAmB,CAAA;AAAA;AAAA;AAAA,IAG9D,yBAAA,EAA0B;AAAA,IAC1B,2BAAA,EAA4B;AAAA,IAC5B,yBAAA,EAA0B;AAAA,IAC1B,uBAAA,EAAwB;AAAA,IACxB,gBAAA,EAAiB;AAAA,IACjB,eAAA,EAAgB;AAAA,IAChB,qBAAA,EAAsB;AAAA;AAAA,IAEtB,sBAAA,CAAuB,iBAAiB,MAAA,GAAY,EAAE,SAAS,EAAE,OAAA,EAAS,KAAA,EAAM,EAAG,CAAA;AAAA,IACnF,kBAAA;AAAmB,GACrB;AACF;AAKO,SAAS,KAAK,OAAA,EAA0D;AAC7E,EAAA,IAAI,OAAA,CAAQ,wBAAwB,MAAA,EAAW;AAC7C,IAAA,OAAA,CAAQ,mBAAA,GAAsB,uBAAuB,OAAO,CAAA;AAAA,EAC9D;AAEA,EAAA,MAAM,YAAY,OAAA,CAAQ,GAAA,GAAM,aAAA,CAAc,OAAA,CAAQ,GAAG,CAAA,GAAI,MAAA;AAC7D,EAAA,OAAO,OAAA,CAAQ,GAAA;AAEf,EAAA,MAAM,oBAAA,GAAuB,uBAAuB,OAAO,CAAA;AAC3D,EAAA,IAAI,OAAA,CAAQ,cAAA,KAAmB,QAAA,IAAY,CAAC,oBAAA,CAAqB,KAAK,CAAA,CAAA,KAAK,CAAA,CAAE,IAAA,KAAS,eAAe,CAAA,EAAG;AACtG,IAAA,oBAAA,CAAqB,IAAA,CAAK,0BAA0B,CAAA;AAAA,EACtD;AAEA,EAAA,MAAM,aAAA,GAAyC;AAAA,IAC7C,GAAG,OAAA;AAAA,IACH,WAAA,EAAa,iCAAA,CAAkC,OAAA,CAAQ,WAAA,IAAe,kBAAkB,CAAA;AAAA,IACxF,YAAA,EAAc,oBAAA;AAAA,IACd,SAAA,EAAW,QAAQ,SAAA,IAAa,uBAAA;AAAA,IAChC;AAAA,GACF;AASA,EAAA,IAAI,CAAC,QAAQ,sBAAA,EAAwB;AACnC,IAAA,wBAAA,EAAyB;AAAA,EAC3B;AAEA,EAAA,OAAO,WAAA,CAAY,kBAAkB,aAAa,CAAA;AACpD;;;;"}
@@ -1,104 +1,70 @@
1
1
  import { createTransport, suppressTracing, SENTRY_BUFFER_FULL_ERROR } from '@sentry/core';
2
2
 
3
3
  const DEFAULT_TRANSPORT_BUFFER_SIZE = 30;
4
-
5
- /**
6
- * This is a modified promise buffer that collects tasks until drain is called.
7
- * We need this in the edge runtime because edge function invocations may not share I/O objects, like fetch requests
8
- * and responses, and the normal PromiseBuffer inherently buffers stuff inbetween incoming requests.
9
- *
10
- * A limitation we need to be aware of is that DEFAULT_TRANSPORT_BUFFER_SIZE is the maximum amount of payloads the
11
- * SDK can send for a given edge function invocation.
12
- */
13
4
  class IsolatedPromiseBuffer {
14
- // We just have this field because the promise buffer interface requires it.
15
- // If we ever remove it from the interface we should also remove it here.
16
-
17
- constructor(_bufferSize = DEFAULT_TRANSPORT_BUFFER_SIZE) {
5
+ constructor(_bufferSize = DEFAULT_TRANSPORT_BUFFER_SIZE) {
18
6
  this.$ = [];
19
7
  this._taskProducers = [];
20
8
  this._bufferSize = _bufferSize;
21
9
  }
22
-
23
10
  /**
24
11
  * @inheritdoc
25
12
  */
26
- add(taskProducer) {
13
+ add(taskProducer) {
27
14
  if (this._taskProducers.length >= this._bufferSize) {
28
15
  return Promise.reject(SENTRY_BUFFER_FULL_ERROR);
29
16
  }
30
-
31
17
  this._taskProducers.push(taskProducer);
32
18
  return Promise.resolve({});
33
19
  }
34
-
35
20
  /**
36
21
  * @inheritdoc
37
22
  */
38
- drain(timeout) {
23
+ drain(timeout) {
39
24
  const oldTaskProducers = [...this._taskProducers];
40
25
  this._taskProducers = [];
41
-
42
- return new Promise(resolve => {
26
+ return new Promise((resolve) => {
43
27
  const timer = setTimeout(() => {
44
28
  if (timeout && timeout > 0) {
45
29
  resolve(false);
46
30
  }
47
31
  }, timeout);
48
-
49
- // This cannot reject
50
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
51
32
  Promise.all(
52
- oldTaskProducers.map(taskProducer =>
53
- taskProducer().then(null, () => {
54
- // catch all failed requests
55
- }),
56
- ),
33
+ oldTaskProducers.map(
34
+ (taskProducer) => taskProducer().then(null, () => {
35
+ })
36
+ )
57
37
  ).then(() => {
58
- // resolve to true if all fetch requests settled
59
38
  clearTimeout(timer);
60
39
  resolve(true);
61
40
  });
62
41
  });
63
42
  }
64
43
  }
65
-
66
- /**
67
- * Creates a Transport that uses the native fetch API to send events to Sentry.
68
- */
69
44
  function makeCloudflareTransport(options) {
70
45
  function makeRequest(request) {
71
46
  const requestOptions = {
72
47
  body: request.body,
73
- method: 'POST',
48
+ method: "POST",
74
49
  headers: options.headers,
75
- ...options.fetchOptions,
50
+ ...options.fetchOptions
76
51
  };
77
-
78
52
  return suppressTracing(() => {
79
- return (options.fetch ?? fetch)(options.url, requestOptions).then(async response => {
80
- // Consume the response body to satisfy Cloudflare Workers' fetch requirements.
81
- // The runtime requires all fetch response bodies to be read or explicitly canceled
82
- // to prevent connection stalls and potential deadlocks. We read the body as text
83
- // even though we don't use the content, as Sentry's response information is in the headers.
84
- // See: https://github.com/getsentry/sentry-javascript/issues/18534
53
+ return (options.fetch ?? fetch)(options.url, requestOptions).then(async (response) => {
85
54
  try {
86
55
  await response.text();
87
56
  } catch {
88
- // no-op
89
57
  }
90
-
91
58
  return {
92
59
  statusCode: response.status,
93
60
  headers: {
94
- 'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'),
95
- 'retry-after': response.headers.get('Retry-After'),
96
- },
61
+ "x-sentry-rate-limits": response.headers.get("X-Sentry-Rate-Limits"),
62
+ "retry-after": response.headers.get("Retry-After")
63
+ }
97
64
  };
98
65
  });
99
66
  });
100
67
  }
101
-
102
68
  return createTransport(options, makeRequest, new IsolatedPromiseBuffer(options.bufferSize));
103
69
  }
104
70
 
@@ -1 +1 @@
1
- {"version":3,"file":"transport.js","sources":["../../src/transport.ts"],"sourcesContent":["import type { BaseTransportOptions, Transport, TransportMakeRequestResponse, TransportRequest } from '@sentry/core';\nimport { createTransport, SENTRY_BUFFER_FULL_ERROR, suppressTracing } from '@sentry/core';\n\nexport interface CloudflareTransportOptions extends BaseTransportOptions {\n /** Custom fetch function to use. This allows usage of things like Workers VPC */\n fetch?: typeof fetch;\n /** Fetch API init parameters. */\n fetchOptions?: RequestInit;\n}\n\nconst DEFAULT_TRANSPORT_BUFFER_SIZE = 30;\n\n/**\n * This is a modified promise buffer that collects tasks until drain is called.\n * We need this in the edge runtime because edge function invocations may not share I/O objects, like fetch requests\n * and responses, and the normal PromiseBuffer inherently buffers stuff inbetween incoming requests.\n *\n * A limitation we need to be aware of is that DEFAULT_TRANSPORT_BUFFER_SIZE is the maximum amount of payloads the\n * SDK can send for a given edge function invocation.\n */\nexport class IsolatedPromiseBuffer {\n // We just have this field because the promise buffer interface requires it.\n // If we ever remove it from the interface we should also remove it here.\n public $: Array<PromiseLike<TransportMakeRequestResponse>>;\n\n private _taskProducers: (() => PromiseLike<TransportMakeRequestResponse>)[];\n\n private readonly _bufferSize: number;\n\n public constructor(_bufferSize = DEFAULT_TRANSPORT_BUFFER_SIZE) {\n this.$ = [];\n this._taskProducers = [];\n this._bufferSize = _bufferSize;\n }\n\n /**\n * @inheritdoc\n */\n public add(taskProducer: () => PromiseLike<TransportMakeRequestResponse>): PromiseLike<TransportMakeRequestResponse> {\n if (this._taskProducers.length >= this._bufferSize) {\n return Promise.reject(SENTRY_BUFFER_FULL_ERROR);\n }\n\n this._taskProducers.push(taskProducer);\n return Promise.resolve({});\n }\n\n /**\n * @inheritdoc\n */\n public drain(timeout?: number): PromiseLike<boolean> {\n const oldTaskProducers = [...this._taskProducers];\n this._taskProducers = [];\n\n return new Promise(resolve => {\n const timer = setTimeout(() => {\n if (timeout && timeout > 0) {\n resolve(false);\n }\n }, timeout);\n\n // This cannot reject\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n Promise.all(\n oldTaskProducers.map(taskProducer =>\n taskProducer().then(null, () => {\n // catch all failed requests\n }),\n ),\n ).then(() => {\n // resolve to true if all fetch requests settled\n clearTimeout(timer);\n resolve(true);\n });\n });\n }\n}\n\n/**\n * Creates a Transport that uses the native fetch API to send events to Sentry.\n */\nexport function makeCloudflareTransport(options: CloudflareTransportOptions): Transport {\n function makeRequest(request: TransportRequest): PromiseLike<TransportMakeRequestResponse> {\n const requestOptions: RequestInit = {\n body: request.body,\n method: 'POST',\n headers: options.headers,\n ...options.fetchOptions,\n };\n\n return suppressTracing(() => {\n return (options.fetch ?? fetch)(options.url, requestOptions).then(async response => {\n // Consume the response body to satisfy Cloudflare Workers' fetch requirements.\n // The runtime requires all fetch response bodies to be read or explicitly canceled\n // to prevent connection stalls and potential deadlocks. We read the body as text\n // even though we don't use the content, as Sentry's response information is in the headers.\n // See: https://github.com/getsentry/sentry-javascript/issues/18534\n try {\n await response.text();\n } catch {\n // no-op\n }\n\n return {\n statusCode: response.status,\n headers: {\n 'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'),\n 'retry-after': response.headers.get('Retry-After'),\n },\n };\n });\n });\n }\n\n return createTransport(options, makeRequest, new IsolatedPromiseBuffer(options.bufferSize));\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transport.js","sources":["../../src/transport.ts"],"sourcesContent":["import type { BaseTransportOptions, Transport, TransportMakeRequestResponse, TransportRequest } from '@sentry/core';\nimport { createTransport, SENTRY_BUFFER_FULL_ERROR, suppressTracing } from '@sentry/core';\n\nexport interface CloudflareTransportOptions extends BaseTransportOptions {\n /** Custom fetch function to use. This allows usage of things like Workers VPC */\n fetch?: typeof fetch;\n /** Fetch API init parameters. */\n fetchOptions?: RequestInit;\n}\n\nconst DEFAULT_TRANSPORT_BUFFER_SIZE = 30;\n\n/**\n * This is a modified promise buffer that collects tasks until drain is called.\n * We need this in the edge runtime because edge function invocations may not share I/O objects, like fetch requests\n * and responses, and the normal PromiseBuffer inherently buffers stuff inbetween incoming requests.\n *\n * A limitation we need to be aware of is that DEFAULT_TRANSPORT_BUFFER_SIZE is the maximum amount of payloads the\n * SDK can send for a given edge function invocation.\n */\nexport class IsolatedPromiseBuffer {\n // We just have this field because the promise buffer interface requires it.\n // If we ever remove it from the interface we should also remove it here.\n public $: Array<PromiseLike<TransportMakeRequestResponse>>;\n\n private _taskProducers: (() => PromiseLike<TransportMakeRequestResponse>)[];\n\n private readonly _bufferSize: number;\n\n public constructor(_bufferSize = DEFAULT_TRANSPORT_BUFFER_SIZE) {\n this.$ = [];\n this._taskProducers = [];\n this._bufferSize = _bufferSize;\n }\n\n /**\n * @inheritdoc\n */\n public add(taskProducer: () => PromiseLike<TransportMakeRequestResponse>): PromiseLike<TransportMakeRequestResponse> {\n if (this._taskProducers.length >= this._bufferSize) {\n return Promise.reject(SENTRY_BUFFER_FULL_ERROR);\n }\n\n this._taskProducers.push(taskProducer);\n return Promise.resolve({});\n }\n\n /**\n * @inheritdoc\n */\n public drain(timeout?: number): PromiseLike<boolean> {\n const oldTaskProducers = [...this._taskProducers];\n this._taskProducers = [];\n\n return new Promise(resolve => {\n const timer = setTimeout(() => {\n if (timeout && timeout > 0) {\n resolve(false);\n }\n }, timeout);\n\n // This cannot reject\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n Promise.all(\n oldTaskProducers.map(taskProducer =>\n taskProducer().then(null, () => {\n // catch all failed requests\n }),\n ),\n ).then(() => {\n // resolve to true if all fetch requests settled\n clearTimeout(timer);\n resolve(true);\n });\n });\n }\n}\n\n/**\n * Creates a Transport that uses the native fetch API to send events to Sentry.\n */\nexport function makeCloudflareTransport(options: CloudflareTransportOptions): Transport {\n function makeRequest(request: TransportRequest): PromiseLike<TransportMakeRequestResponse> {\n const requestOptions: RequestInit = {\n body: request.body,\n method: 'POST',\n headers: options.headers,\n ...options.fetchOptions,\n };\n\n return suppressTracing(() => {\n return (options.fetch ?? fetch)(options.url, requestOptions).then(async response => {\n // Consume the response body to satisfy Cloudflare Workers' fetch requirements.\n // The runtime requires all fetch response bodies to be read or explicitly canceled\n // to prevent connection stalls and potential deadlocks. We read the body as text\n // even though we don't use the content, as Sentry's response information is in the headers.\n // See: https://github.com/getsentry/sentry-javascript/issues/18534\n try {\n await response.text();\n } catch {\n // no-op\n }\n\n return {\n statusCode: response.status,\n headers: {\n 'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'),\n 'retry-after': response.headers.get('Retry-After'),\n },\n };\n });\n });\n }\n\n return createTransport(options, makeRequest, new IsolatedPromiseBuffer(options.bufferSize));\n}\n"],"names":[],"mappings":";;AAUA,MAAM,6BAAA,GAAgC,EAAA;AAU/B,MAAM,qBAAA,CAAsB;AAAA,EAS1B,WAAA,CAAY,cAAc,6BAAA,EAA+B;AAC9D,IAAA,IAAA,CAAK,IAAI,EAAC;AACV,IAAA,IAAA,CAAK,iBAAiB,EAAC;AACvB,IAAA,IAAA,CAAK,WAAA,GAAc,WAAA;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKO,IAAI,YAAA,EAA0G;AACnH,IAAA,IAAI,IAAA,CAAK,cAAA,CAAe,MAAA,IAAU,IAAA,CAAK,WAAA,EAAa;AAClD,MAAA,OAAO,OAAA,CAAQ,OAAO,wBAAwB,CAAA;AAAA,IAChD;AAEA,IAAA,IAAA,CAAK,cAAA,CAAe,KAAK,YAAY,CAAA;AACrC,IAAA,OAAO,OAAA,CAAQ,OAAA,CAAQ,EAAE,CAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKO,MAAM,OAAA,EAAwC;AACnD,IAAA,MAAM,gBAAA,GAAmB,CAAC,GAAG,IAAA,CAAK,cAAc,CAAA;AAChD,IAAA,IAAA,CAAK,iBAAiB,EAAC;AAEvB,IAAA,OAAO,IAAI,QAAQ,CAAA,OAAA,KAAW;AAC5B,MAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,QAAA,IAAI,OAAA,IAAW,UAAU,CAAA,EAAG;AAC1B,UAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,QACf;AAAA,MACF,GAAG,OAAO,CAAA;AAIV,MAAA,OAAA,CAAQ,GAAA;AAAA,QACN,gBAAA,CAAiB,GAAA;AAAA,UAAI,CAAA,YAAA,KACnB,YAAA,EAAa,CAAE,IAAA,CAAK,MAAM,MAAM;AAAA,UAEhC,CAAC;AAAA;AACH,OACF,CAAE,KAAK,MAAM;AAEX,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,MACd,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AACF;AAKO,SAAS,wBAAwB,OAAA,EAAgD;AACtF,EAAA,SAAS,YAAY,OAAA,EAAsE;AACzF,IAAA,MAAM,cAAA,GAA8B;AAAA,MAClC,MAAM,OAAA,CAAQ,IAAA;AAAA,MACd,MAAA,EAAQ,MAAA;AAAA,MACR,SAAS,OAAA,CAAQ,OAAA;AAAA,MACjB,GAAG,OAAA,CAAQ;AAAA,KACb;AAEA,IAAA,OAAO,gBAAgB,MAAM;AAC3B,MAAA,OAAA,CAAQ,OAAA,CAAQ,SAAS,KAAA,EAAO,OAAA,CAAQ,KAAK,cAAc,CAAA,CAAE,IAAA,CAAK,OAAM,QAAA,KAAY;AAMlF,QAAA,IAAI;AACF,UAAA,MAAM,SAAS,IAAA,EAAK;AAAA,QACtB,CAAA,CAAA,MAAQ;AAAA,QAER;AAEA,QAAA,OAAO;AAAA,UACL,YAAY,QAAA,CAAS,MAAA;AAAA,UACrB,OAAA,EAAS;AAAA,YACP,sBAAA,EAAwB,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,sBAAsB,CAAA;AAAA,YACnE,aAAA,EAAe,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,aAAa;AAAA;AACnD,SACF;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,gBAAgB,OAAA,EAAS,WAAA,EAAa,IAAI,qBAAA,CAAsB,OAAA,CAAQ,UAAU,CAAC,CAAA;AAC5F;;;;"}