@sentry/node 10.0.0-alpha.1 → 10.0.0-beta.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 (56) hide show
  1. package/build/cjs/index.js +2 -0
  2. package/build/cjs/index.js.map +1 -1
  3. package/build/cjs/integrations/tracing/fastify/index.js +57 -11
  4. package/build/cjs/integrations/tracing/fastify/index.js.map +1 -1
  5. package/build/cjs/integrations/tracing/firebase/firebase.js +32 -0
  6. package/build/cjs/integrations/tracing/firebase/firebase.js.map +1 -0
  7. package/build/cjs/integrations/tracing/firebase/otel/firebaseInstrumentation.js +41 -0
  8. package/build/cjs/integrations/tracing/firebase/otel/firebaseInstrumentation.js.map +1 -0
  9. package/build/cjs/integrations/tracing/firebase/otel/patches/firestore.js +295 -0
  10. package/build/cjs/integrations/tracing/firebase/otel/patches/firestore.js.map +1 -0
  11. package/build/cjs/integrations/tracing/index.js +3 -0
  12. package/build/cjs/integrations/tracing/index.js.map +1 -1
  13. package/build/cjs/integrations/tracing/vercelai/instrumentation.js +15 -2
  14. package/build/cjs/integrations/tracing/vercelai/instrumentation.js.map +1 -1
  15. package/build/esm/index.js +1 -0
  16. package/build/esm/index.js.map +1 -1
  17. package/build/esm/integrations/tracing/fastify/index.js +57 -11
  18. package/build/esm/integrations/tracing/fastify/index.js.map +1 -1
  19. package/build/esm/integrations/tracing/firebase/firebase.js +29 -0
  20. package/build/esm/integrations/tracing/firebase/firebase.js.map +1 -0
  21. package/build/esm/integrations/tracing/firebase/otel/firebaseInstrumentation.js +39 -0
  22. package/build/esm/integrations/tracing/firebase/otel/firebaseInstrumentation.js.map +1 -0
  23. package/build/esm/integrations/tracing/firebase/otel/patches/firestore.js +292 -0
  24. package/build/esm/integrations/tracing/firebase/otel/patches/firestore.js.map +1 -0
  25. package/build/esm/integrations/tracing/index.js +3 -0
  26. package/build/esm/integrations/tracing/index.js.map +1 -1
  27. package/build/esm/integrations/tracing/vercelai/instrumentation.js +16 -3
  28. package/build/esm/integrations/tracing/vercelai/instrumentation.js.map +1 -1
  29. package/build/esm/package.json +1 -1
  30. package/build/types/index.d.ts +1 -0
  31. package/build/types/index.d.ts.map +1 -1
  32. package/build/types/integrations/tracing/fastify/index.d.ts +38 -2
  33. package/build/types/integrations/tracing/fastify/index.d.ts.map +1 -1
  34. package/build/types/integrations/tracing/firebase/firebase.d.ts +6 -0
  35. package/build/types/integrations/tracing/firebase/firebase.d.ts.map +1 -0
  36. package/build/types/integrations/tracing/firebase/index.d.ts +2 -0
  37. package/build/types/integrations/tracing/firebase/index.d.ts.map +1 -0
  38. package/build/types/integrations/tracing/firebase/otel/firebaseInstrumentation.d.ts +19 -0
  39. package/build/types/integrations/tracing/firebase/otel/firebaseInstrumentation.d.ts.map +1 -0
  40. package/build/types/integrations/tracing/firebase/otel/index.d.ts +3 -0
  41. package/build/types/integrations/tracing/firebase/otel/index.d.ts.map +1 -0
  42. package/build/types/integrations/tracing/firebase/otel/patches/firestore.d.ts +23 -0
  43. package/build/types/integrations/tracing/firebase/otel/patches/firestore.d.ts.map +1 -0
  44. package/build/types/integrations/tracing/firebase/otel/types.d.ts +86 -0
  45. package/build/types/integrations/tracing/firebase/otel/types.d.ts.map +1 -0
  46. package/build/types/integrations/tracing/index.d.ts.map +1 -1
  47. package/build/types/integrations/tracing/vercelai/instrumentation.d.ts.map +1 -1
  48. package/build/types-ts3.8/index.d.ts +1 -0
  49. package/build/types-ts3.8/integrations/tracing/fastify/index.d.ts +38 -2
  50. package/build/types-ts3.8/integrations/tracing/firebase/firebase.d.ts +6 -0
  51. package/build/types-ts3.8/integrations/tracing/firebase/index.d.ts +2 -0
  52. package/build/types-ts3.8/integrations/tracing/firebase/otel/firebaseInstrumentation.d.ts +19 -0
  53. package/build/types-ts3.8/integrations/tracing/firebase/otel/index.d.ts +3 -0
  54. package/build/types-ts3.8/integrations/tracing/firebase/otel/patches/firestore.d.ts +23 -0
  55. package/build/types-ts3.8/integrations/tracing/firebase/otel/types.d.ts +86 -0
  56. package/package.json +5 -5
@@ -30,6 +30,7 @@ const launchDarkly = require('./integrations/featureFlagShims/launchDarkly.js');
30
30
  const openFeature = require('./integrations/featureFlagShims/openFeature.js');
31
31
  const statsig = require('./integrations/featureFlagShims/statsig.js');
32
32
  const unleash = require('./integrations/featureFlagShims/unleash.js');
33
+ const firebase = require('./integrations/tracing/firebase/firebase.js');
33
34
  const index$6 = require('./sdk/index.js');
34
35
  const initOtel = require('./sdk/initOtel.js');
35
36
  const index$7 = require('./integrations/tracing/index.js');
@@ -77,6 +78,7 @@ exports.OpenFeatureIntegrationHook = openFeature.OpenFeatureIntegrationHookShim;
77
78
  exports.openFeatureIntegration = openFeature.openFeatureIntegrationShim;
78
79
  exports.statsigIntegration = statsig.statsigIntegrationShim;
79
80
  exports.unleashIntegration = unleash.unleashIntegrationShim;
81
+ exports.firebaseIntegration = firebase.firebaseIntegration;
80
82
  exports.getDefaultIntegrations = index$6.getDefaultIntegrations;
81
83
  exports.getDefaultIntegrationsWithoutPerformance = index$6.getDefaultIntegrationsWithoutPerformance;
82
84
  exports.init = index$6.init;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -7,19 +7,52 @@ const debugBuild = require('../../../debug-build.js');
7
7
  const index = require('./fastify-otel/index.js');
8
8
  const instrumentation = require('./v3/instrumentation.js');
9
9
 
10
+ /**
11
+ * Options for the Fastify integration.
12
+ *
13
+ * `shouldHandleError` - Callback method deciding whether error should be captured and sent to Sentry
14
+ * This is used on Fastify v5 where Sentry handles errors in the diagnostics channel.
15
+ * Fastify v3 and v4 use `setupFastifyErrorHandler` instead.
16
+ *
17
+ * @example
18
+ *
19
+ * ```javascript
20
+ * Sentry.init({
21
+ * integrations: [
22
+ * Sentry.fastifyIntegration({
23
+ * shouldHandleError(_error, _request, reply) {
24
+ * return reply.statusCode >= 500;
25
+ * },
26
+ * });
27
+ * },
28
+ * });
29
+ * ```
30
+ *
31
+ */
32
+
10
33
  const INTEGRATION_NAME = 'Fastify';
34
+ const INTEGRATION_NAME_V5 = 'Fastify-V5';
11
35
  const INTEGRATION_NAME_V3 = 'Fastify-V3';
12
36
 
13
37
  const instrumentFastifyV3 = nodeCore.generateInstrumentOnce(INTEGRATION_NAME_V3, () => new instrumentation.FastifyInstrumentationV3());
14
38
 
39
+ function getFastifyIntegration() {
40
+ const client = core.getClient();
41
+ if (!client) {
42
+ return undefined;
43
+ } else {
44
+ return client.getIntegrationByName(INTEGRATION_NAME) ;
45
+ }
46
+ }
47
+
15
48
  function handleFastifyError(
16
49
 
17
50
  error,
18
51
  request,
19
52
  reply,
20
- shouldHandleError,
21
53
  handlerOrigin,
22
54
  ) {
55
+ const shouldHandleError = getFastifyIntegration()?.getShouldHandleError() || defaultShouldHandleError;
23
56
  // Diagnostics channel runs before the onError hook, so we can use it to check if the handler was already registered
24
57
  if (handlerOrigin === 'diagnostics-channel') {
25
58
  this.diagnosticsChannelExists = true;
@@ -29,7 +62,7 @@ function handleFastifyError(
29
62
  debugBuild.DEBUG_BUILD &&
30
63
  core.debug.warn(
31
64
  'Fastify error handler was already registered via diagnostics channel.',
32
- 'You can safely remove `setupFastifyErrorHandler` call.',
65
+ 'You can safely remove `setupFastifyErrorHandler` call and set `shouldHandleError` on the integration options.',
33
66
  );
34
67
 
35
68
  // If the diagnostics channel already exists, we don't need to handle the error again
@@ -37,15 +70,13 @@ function handleFastifyError(
37
70
  }
38
71
 
39
72
  if (shouldHandleError(error, request, reply)) {
40
- core.captureException(error);
73
+ core.captureException(error, { mechanism: { handled: false, type: 'fastify' } });
41
74
  }
42
75
  }
43
76
 
44
- const instrumentFastify = nodeCore.generateInstrumentOnce(INTEGRATION_NAME, () => {
77
+ const instrumentFastify = nodeCore.generateInstrumentOnce(INTEGRATION_NAME_V5, () => {
45
78
  const fastifyOtelInstrumentationInstance = new index.FastifyOtelInstrumentation();
46
79
  const plugin = fastifyOtelInstrumentationInstance.plugin();
47
- const options = fastifyOtelInstrumentationInstance.getConfig();
48
- const shouldHandleError = (options )?.shouldHandleError || defaultShouldHandleError;
49
80
 
50
81
  // This message handler works for Fastify versions 3, 4 and 5
51
82
  dc.subscribe('fastify.initialization', message => {
@@ -71,20 +102,30 @@ const instrumentFastify = nodeCore.generateInstrumentOnce(INTEGRATION_NAME, () =
71
102
 
72
103
  ;
73
104
 
74
- handleFastifyError.call(handleFastifyError, error, request, reply, shouldHandleError, 'diagnostics-channel');
105
+ handleFastifyError.call(handleFastifyError, error, request, reply, 'diagnostics-channel');
75
106
  });
76
107
 
77
108
  // Returning this as unknown not to deal with the internal types of the FastifyOtelInstrumentation
78
109
  return fastifyOtelInstrumentationInstance ;
79
110
  });
80
111
 
81
- const _fastifyIntegration = (() => {
112
+ const _fastifyIntegration = (({ shouldHandleError }) => {
113
+ let _shouldHandleError;
114
+
82
115
  return {
83
116
  name: INTEGRATION_NAME,
84
117
  setupOnce() {
118
+ _shouldHandleError = shouldHandleError || defaultShouldHandleError;
119
+
85
120
  instrumentFastifyV3();
86
121
  instrumentFastify();
87
122
  },
123
+ getShouldHandleError() {
124
+ return _shouldHandleError;
125
+ },
126
+ setShouldHandleError(fn) {
127
+ _shouldHandleError = fn;
128
+ },
88
129
  };
89
130
  }) ;
90
131
 
@@ -104,7 +145,9 @@ const _fastifyIntegration = (() => {
104
145
  * })
105
146
  * ```
106
147
  */
107
- const fastifyIntegration = core.defineIntegration(_fastifyIntegration);
148
+ const fastifyIntegration = core.defineIntegration((options = {}) =>
149
+ _fastifyIntegration(options),
150
+ );
108
151
 
109
152
  /**
110
153
  * Default function to determine if an error should be sent to Sentry
@@ -138,11 +181,14 @@ function defaultShouldHandleError(_error, _request, reply) {
138
181
  * ```
139
182
  */
140
183
  function setupFastifyErrorHandler(fastify, options) {
141
- const shouldHandleError = options?.shouldHandleError || defaultShouldHandleError;
184
+ if (options?.shouldHandleError) {
185
+ getFastifyIntegration()?.setShouldHandleError(options.shouldHandleError);
186
+ }
187
+
142
188
  const plugin = Object.assign(
143
189
  function (fastify, _options, done) {
144
190
  fastify.addHook('onError', async (request, reply, error) => {
145
- handleFastifyError.call(handleFastifyError, error, request, reply, shouldHandleError, 'onError-hook');
191
+ handleFastifyError.call(handleFastifyError, error, request, reply, 'onError-hook');
146
192
  });
147
193
  done();
148
194
  },
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../../src/integrations/tracing/fastify/index.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { Instrumentation, InstrumentationConfig } from '@opentelemetry/instrumentation';\nimport type { IntegrationFn, Span } from '@sentry/core';\nimport {\n captureException,\n debug,\n defineIntegration,\n getClient,\n getIsolationScope,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n} from '@sentry/core';\nimport { generateInstrumentOnce } from '@sentry/node-core';\nimport { DEBUG_BUILD } from '../../../debug-build';\nimport { FastifyOtelInstrumentation } from './fastify-otel/index';\nimport type { FastifyInstance, FastifyReply, FastifyRequest } from './types';\nimport { FastifyInstrumentationV3 } from './v3/instrumentation';\n\ninterface FastifyHandlerOptions {\n /**\n * Callback method deciding whether error should be captured and sent to Sentry\n *\n * @param error Captured Fastify error\n * @param request Fastify request (or any object containing at least method, routeOptions.url, and routerPath)\n * @param reply Fastify reply (or any object containing at least statusCode)\n *\n * @example\n *\n * ```javascript\n * setupFastifyErrorHandler(app, {\n * shouldHandleError(_error, _request, reply) {\n * return reply.statusCode >= 400;\n * },\n * });\n * ```\n *\n * If using TypeScript, you can cast the request and reply to get full type safety.\n *\n * ```typescript\n * import type { FastifyRequest, FastifyReply } from 'fastify';\n *\n * setupFastifyErrorHandler(app, {\n * shouldHandleError(error, minimalRequest, minimalReply) {\n * const request = minimalRequest as FastifyRequest;\n * const reply = minimalReply as FastifyReply;\n * return reply.statusCode >= 500;\n * },\n * });\n * ```\n */\n shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean;\n}\n\nconst INTEGRATION_NAME = 'Fastify';\nconst INTEGRATION_NAME_V3 = 'Fastify-V3';\n\nexport const instrumentFastifyV3 = generateInstrumentOnce(INTEGRATION_NAME_V3, () => new FastifyInstrumentationV3());\n\nfunction handleFastifyError(\n this: {\n diagnosticsChannelExists?: boolean;\n },\n error: Error,\n request: FastifyRequest & { opentelemetry?: () => { span?: Span } },\n reply: FastifyReply,\n shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean,\n handlerOrigin: 'diagnostics-channel' | 'onError-hook',\n): void {\n // Diagnostics channel runs before the onError hook, so we can use it to check if the handler was already registered\n if (handlerOrigin === 'diagnostics-channel') {\n this.diagnosticsChannelExists = true;\n }\n\n if (this.diagnosticsChannelExists && handlerOrigin === 'onError-hook') {\n DEBUG_BUILD &&\n debug.warn(\n 'Fastify error handler was already registered via diagnostics channel.',\n 'You can safely remove `setupFastifyErrorHandler` call.',\n );\n\n // If the diagnostics channel already exists, we don't need to handle the error again\n return;\n }\n\n if (shouldHandleError(error, request, reply)) {\n captureException(error);\n }\n}\n\nexport const instrumentFastify = generateInstrumentOnce(INTEGRATION_NAME, () => {\n const fastifyOtelInstrumentationInstance = new FastifyOtelInstrumentation();\n const plugin = fastifyOtelInstrumentationInstance.plugin();\n const options = fastifyOtelInstrumentationInstance.getConfig();\n const shouldHandleError = (options as FastifyHandlerOptions)?.shouldHandleError || defaultShouldHandleError;\n\n // This message handler works for Fastify versions 3, 4 and 5\n diagnosticsChannel.subscribe('fastify.initialization', message => {\n const fastifyInstance = (message as { fastify?: FastifyInstance }).fastify;\n\n fastifyInstance?.register(plugin).after(err => {\n if (err) {\n DEBUG_BUILD && debug.error('Failed to setup Fastify instrumentation', err);\n } else {\n instrumentClient();\n\n if (fastifyInstance) {\n instrumentOnRequest(fastifyInstance);\n }\n }\n });\n });\n\n // This diagnostics channel only works on Fastify version 5\n // For versions 3 and 4, we use `setupFastifyErrorHandler` instead\n diagnosticsChannel.subscribe('tracing:fastify.request.handler:error', message => {\n const { error, request, reply } = message as {\n error: Error;\n request: FastifyRequest & { opentelemetry?: () => { span?: Span } };\n reply: FastifyReply;\n };\n\n handleFastifyError.call(handleFastifyError, error, request, reply, shouldHandleError, 'diagnostics-channel');\n });\n\n // Returning this as unknown not to deal with the internal types of the FastifyOtelInstrumentation\n return fastifyOtelInstrumentationInstance as Instrumentation<InstrumentationConfig & FastifyHandlerOptions>;\n});\n\nconst _fastifyIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n instrumentFastifyV3();\n instrumentFastify();\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for [Fastify](https://fastify.dev/).\n *\n * If you also want to capture errors, you need to call `setupFastifyErrorHandler(app)` after you set up your Fastify server.\n *\n * For more information, see the [fastify documentation](https://docs.sentry.io/platforms/javascript/guides/fastify/).\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n *\n * Sentry.init({\n * integrations: [Sentry.fastifyIntegration()],\n * })\n * ```\n */\nexport const fastifyIntegration = defineIntegration(_fastifyIntegration);\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: Error, _request: FastifyRequest, reply: FastifyReply): boolean {\n const statusCode = reply.statusCode;\n // 3xx and 4xx errors are not sent by default.\n return statusCode >= 500 || statusCode <= 299;\n}\n\n/**\n * Add an Fastify error handler to capture errors to Sentry.\n *\n * @param fastify The Fastify instance to which to add the error handler\n * @param options Configuration options for the handler\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n * const Fastify = require(\"fastify\");\n *\n * const app = Fastify();\n *\n * Sentry.setupFastifyErrorHandler(app);\n *\n * // Add your routes, etc.\n *\n * app.listen({ port: 3000 });\n * ```\n */\nexport function setupFastifyErrorHandler(fastify: FastifyInstance, options?: Partial<FastifyHandlerOptions>): void {\n const shouldHandleError = options?.shouldHandleError || defaultShouldHandleError;\n const plugin = Object.assign(\n function (fastify: FastifyInstance, _options: unknown, done: () => void): void {\n fastify.addHook('onError', async (request, reply, error) => {\n handleFastifyError.call(handleFastifyError, error, request, reply, shouldHandleError, 'onError-hook');\n });\n done();\n },\n {\n [Symbol.for('skip-override')]: true,\n [Symbol.for('fastify.display-name')]: 'sentry-fastify-error-handler',\n },\n );\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n fastify.register(plugin);\n}\n\nfunction addFastifySpanAttributes(span: Span): void {\n const spanJSON = spanToJSON(span);\n const spanName = spanJSON.description;\n const attributes = spanJSON.data;\n\n const type = attributes['fastify.type'];\n\n const isHook = type === 'hook';\n const isHandler = type === spanName?.startsWith('handler -');\n // In @fastify/otel `request-handler` is separated by dash, not underscore\n const isRequestHandler = spanName === 'request' || type === 'request-handler';\n\n // If this is already set, or we have no fastify span, no need to process again...\n if (attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] || (!isHandler && !isRequestHandler && !isHook)) {\n return;\n }\n\n const opPrefix = isHook ? 'hook' : isHandler ? 'middleware' : isRequestHandler ? 'request-handler' : '<unknown>';\n\n span.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.fastify',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: `${opPrefix}.fastify`,\n });\n\n const attrName = attributes['fastify.name'] || attributes['plugin.name'] || attributes['hook.name'];\n if (typeof attrName === 'string') {\n // Try removing `fastify -> ` and `@fastify/otel -> ` prefixes\n // This is a bit of a hack, and not always working for all spans\n // But it's the best we can do without a proper API\n const updatedName = attrName.replace(/^fastify -> /, '').replace(/^@fastify\\/otel -> /, '');\n\n span.updateName(updatedName);\n }\n}\n\nfunction instrumentClient(): void {\n const client = getClient();\n if (client) {\n client.on('spanStart', (span: Span) => {\n addFastifySpanAttributes(span);\n });\n }\n}\n\nfunction instrumentOnRequest(fastify: FastifyInstance): void {\n fastify.addHook('onRequest', async (request: FastifyRequest & { opentelemetry?: () => { span?: Span } }, _reply) => {\n if (request.opentelemetry) {\n const { span } = request.opentelemetry();\n\n if (span) {\n addFastifySpanAttributes(span);\n }\n }\n\n const routeName = request.routeOptions?.url;\n const method = request.method || 'GET';\n\n getIsolationScope().setTransactionName(`${method} ${routeName}`);\n });\n}\n"],"names":["generateInstrumentOnce","FastifyInstrumentationV3","DEBUG_BUILD","debug","captureException","FastifyOtelInstrumentation","diagnosticsChannel","defineIntegration","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","getClient","getIsolationScope"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../../../src/integrations/tracing/fastify/index.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { Instrumentation, InstrumentationConfig } from '@opentelemetry/instrumentation';\nimport type { IntegrationFn, Span } from '@sentry/core';\nimport {\n captureException,\n debug,\n defineIntegration,\n getClient,\n getIsolationScope,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n} from '@sentry/core';\nimport { generateInstrumentOnce } from '@sentry/node-core';\nimport { DEBUG_BUILD } from '../../../debug-build';\nimport { FastifyOtelInstrumentation } from './fastify-otel/index';\nimport type { FastifyInstance, FastifyReply, FastifyRequest } from './types';\nimport { FastifyInstrumentationV3 } from './v3/instrumentation';\n\n/**\n * Options for the Fastify integration.\n *\n * `shouldHandleError` - Callback method deciding whether error should be captured and sent to Sentry\n * This is used on Fastify v5 where Sentry handles errors in the diagnostics channel.\n * Fastify v3 and v4 use `setupFastifyErrorHandler` instead.\n *\n * @example\n *\n * ```javascript\n * Sentry.init({\n * integrations: [\n * Sentry.fastifyIntegration({\n * shouldHandleError(_error, _request, reply) {\n * return reply.statusCode >= 500;\n * },\n * });\n * },\n * });\n * ```\n *\n */\ninterface FastifyIntegrationOptions {\n /**\n * Callback method deciding whether error should be captured and sent to Sentry\n * This is used on Fastify v5 where Sentry handles errors in the diagnostics channel.\n * Fastify v3 and v4 use `setupFastifyErrorHandler` instead.\n *\n * @param error Captured Fastify error\n * @param request Fastify request (or any object containing at least method, routeOptions.url, and routerPath)\n * @param reply Fastify reply (or any object containing at least statusCode)\n */\n shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean;\n}\n\ninterface FastifyHandlerOptions {\n /**\n * Callback method deciding whether error should be captured and sent to Sentry\n *\n * @param error Captured Fastify error\n * @param request Fastify request (or any object containing at least method, routeOptions.url, and routerPath)\n * @param reply Fastify reply (or any object containing at least statusCode)\n *\n * @example\n *\n *\n * ```javascript\n * setupFastifyErrorHandler(app, {\n * shouldHandleError(_error, _request, reply) {\n * return reply.statusCode >= 400;\n * },\n * });\n * ```\n *\n *\n * If using TypeScript, you can cast the request and reply to get full type safety.\n *\n * ```typescript\n * import type { FastifyRequest, FastifyReply } from 'fastify';\n *\n * setupFastifyErrorHandler(app, {\n * shouldHandleError(error, minimalRequest, minimalReply) {\n * const request = minimalRequest as FastifyRequest;\n * const reply = minimalReply as FastifyReply;\n * return reply.statusCode >= 500;\n * },\n * });\n * ```\n */\n shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean;\n}\n\nconst INTEGRATION_NAME = 'Fastify';\nconst INTEGRATION_NAME_V5 = 'Fastify-V5';\nconst INTEGRATION_NAME_V3 = 'Fastify-V3';\n\nexport const instrumentFastifyV3 = generateInstrumentOnce(INTEGRATION_NAME_V3, () => new FastifyInstrumentationV3());\n\nfunction getFastifyIntegration(): ReturnType<typeof _fastifyIntegration> | undefined {\n const client = getClient();\n if (!client) {\n return undefined;\n } else {\n return client.getIntegrationByName(INTEGRATION_NAME) as ReturnType<typeof _fastifyIntegration> | undefined;\n }\n}\n\nfunction handleFastifyError(\n this: {\n diagnosticsChannelExists?: boolean;\n },\n error: Error,\n request: FastifyRequest & { opentelemetry?: () => { span?: Span } },\n reply: FastifyReply,\n handlerOrigin: 'diagnostics-channel' | 'onError-hook',\n): void {\n const shouldHandleError = getFastifyIntegration()?.getShouldHandleError() || defaultShouldHandleError;\n // Diagnostics channel runs before the onError hook, so we can use it to check if the handler was already registered\n if (handlerOrigin === 'diagnostics-channel') {\n this.diagnosticsChannelExists = true;\n }\n\n if (this.diagnosticsChannelExists && handlerOrigin === 'onError-hook') {\n DEBUG_BUILD &&\n debug.warn(\n 'Fastify error handler was already registered via diagnostics channel.',\n 'You can safely remove `setupFastifyErrorHandler` call and set `shouldHandleError` on the integration options.',\n );\n\n // If the diagnostics channel already exists, we don't need to handle the error again\n return;\n }\n\n if (shouldHandleError(error, request, reply)) {\n captureException(error, { mechanism: { handled: false, type: 'fastify' } });\n }\n}\n\nexport const instrumentFastify = generateInstrumentOnce(INTEGRATION_NAME_V5, () => {\n const fastifyOtelInstrumentationInstance = new FastifyOtelInstrumentation();\n const plugin = fastifyOtelInstrumentationInstance.plugin();\n\n // This message handler works for Fastify versions 3, 4 and 5\n diagnosticsChannel.subscribe('fastify.initialization', message => {\n const fastifyInstance = (message as { fastify?: FastifyInstance }).fastify;\n\n fastifyInstance?.register(plugin).after(err => {\n if (err) {\n DEBUG_BUILD && debug.error('Failed to setup Fastify instrumentation', err);\n } else {\n instrumentClient();\n\n if (fastifyInstance) {\n instrumentOnRequest(fastifyInstance);\n }\n }\n });\n });\n\n // This diagnostics channel only works on Fastify version 5\n // For versions 3 and 4, we use `setupFastifyErrorHandler` instead\n diagnosticsChannel.subscribe('tracing:fastify.request.handler:error', message => {\n const { error, request, reply } = message as {\n error: Error;\n request: FastifyRequest & { opentelemetry?: () => { span?: Span } };\n reply: FastifyReply;\n };\n\n handleFastifyError.call(handleFastifyError, error, request, reply, 'diagnostics-channel');\n });\n\n // Returning this as unknown not to deal with the internal types of the FastifyOtelInstrumentation\n return fastifyOtelInstrumentationInstance as Instrumentation<InstrumentationConfig & FastifyIntegrationOptions>;\n});\n\nconst _fastifyIntegration = (({ shouldHandleError }: Partial<FastifyIntegrationOptions>) => {\n let _shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean;\n\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n _shouldHandleError = shouldHandleError || defaultShouldHandleError;\n\n instrumentFastifyV3();\n instrumentFastify();\n },\n getShouldHandleError() {\n return _shouldHandleError;\n },\n setShouldHandleError(fn: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean): void {\n _shouldHandleError = fn;\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for [Fastify](https://fastify.dev/).\n *\n * If you also want to capture errors, you need to call `setupFastifyErrorHandler(app)` after you set up your Fastify server.\n *\n * For more information, see the [fastify documentation](https://docs.sentry.io/platforms/javascript/guides/fastify/).\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n *\n * Sentry.init({\n * integrations: [Sentry.fastifyIntegration()],\n * })\n * ```\n */\nexport const fastifyIntegration = defineIntegration((options: Partial<FastifyIntegrationOptions> = {}) =>\n _fastifyIntegration(options),\n);\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: Error, _request: FastifyRequest, reply: FastifyReply): boolean {\n const statusCode = reply.statusCode;\n // 3xx and 4xx errors are not sent by default.\n return statusCode >= 500 || statusCode <= 299;\n}\n\n/**\n * Add an Fastify error handler to capture errors to Sentry.\n *\n * @param fastify The Fastify instance to which to add the error handler\n * @param options Configuration options for the handler\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n * const Fastify = require(\"fastify\");\n *\n * const app = Fastify();\n *\n * Sentry.setupFastifyErrorHandler(app);\n *\n * // Add your routes, etc.\n *\n * app.listen({ port: 3000 });\n * ```\n */\nexport function setupFastifyErrorHandler(fastify: FastifyInstance, options?: Partial<FastifyHandlerOptions>): void {\n if (options?.shouldHandleError) {\n getFastifyIntegration()?.setShouldHandleError(options.shouldHandleError);\n }\n\n const plugin = Object.assign(\n function (fastify: FastifyInstance, _options: unknown, done: () => void): void {\n fastify.addHook('onError', async (request, reply, error) => {\n handleFastifyError.call(handleFastifyError, error, request, reply, 'onError-hook');\n });\n done();\n },\n {\n [Symbol.for('skip-override')]: true,\n [Symbol.for('fastify.display-name')]: 'sentry-fastify-error-handler',\n },\n );\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n fastify.register(plugin);\n}\n\nfunction addFastifySpanAttributes(span: Span): void {\n const spanJSON = spanToJSON(span);\n const spanName = spanJSON.description;\n const attributes = spanJSON.data;\n\n const type = attributes['fastify.type'];\n\n const isHook = type === 'hook';\n const isHandler = type === spanName?.startsWith('handler -');\n // In @fastify/otel `request-handler` is separated by dash, not underscore\n const isRequestHandler = spanName === 'request' || type === 'request-handler';\n\n // If this is already set, or we have no fastify span, no need to process again...\n if (attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] || (!isHandler && !isRequestHandler && !isHook)) {\n return;\n }\n\n const opPrefix = isHook ? 'hook' : isHandler ? 'middleware' : isRequestHandler ? 'request-handler' : '<unknown>';\n\n span.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.fastify',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: `${opPrefix}.fastify`,\n });\n\n const attrName = attributes['fastify.name'] || attributes['plugin.name'] || attributes['hook.name'];\n if (typeof attrName === 'string') {\n // Try removing `fastify -> ` and `@fastify/otel -> ` prefixes\n // This is a bit of a hack, and not always working for all spans\n // But it's the best we can do without a proper API\n const updatedName = attrName.replace(/^fastify -> /, '').replace(/^@fastify\\/otel -> /, '');\n\n span.updateName(updatedName);\n }\n}\n\nfunction instrumentClient(): void {\n const client = getClient();\n if (client) {\n client.on('spanStart', (span: Span) => {\n addFastifySpanAttributes(span);\n });\n }\n}\n\nfunction instrumentOnRequest(fastify: FastifyInstance): void {\n fastify.addHook('onRequest', async (request: FastifyRequest & { opentelemetry?: () => { span?: Span } }, _reply) => {\n if (request.opentelemetry) {\n const { span } = request.opentelemetry();\n\n if (span) {\n addFastifySpanAttributes(span);\n }\n }\n\n const routeName = request.routeOptions?.url;\n const method = request.method || 'GET';\n\n getIsolationScope().setTransactionName(`${method} ${routeName}`);\n });\n}\n"],"names":["generateInstrumentOnce","FastifyInstrumentationV3","getClient","DEBUG_BUILD","debug","captureException","FastifyOtelInstrumentation","diagnosticsChannel","defineIntegration","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","getIsolationScope"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ const core = require('@sentry/core');
4
+ const nodeCore = require('@sentry/node-core');
5
+ const firebaseInstrumentation = require('./otel/firebaseInstrumentation.js');
6
+
7
+ const INTEGRATION_NAME = 'Firebase';
8
+
9
+ const config = {
10
+ firestoreSpanCreationHook: span => {
11
+ nodeCore.addOriginToSpan(span , 'auto.firebase.otel.firestore');
12
+
13
+ span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'db.query');
14
+ },
15
+ };
16
+
17
+ const instrumentFirebase = nodeCore.generateInstrumentOnce(INTEGRATION_NAME, () => new firebaseInstrumentation.FirebaseInstrumentation(config));
18
+
19
+ const _firebaseIntegration = (() => {
20
+ return {
21
+ name: INTEGRATION_NAME,
22
+ setupOnce() {
23
+ instrumentFirebase();
24
+ },
25
+ };
26
+ }) ;
27
+
28
+ const firebaseIntegration = core.defineIntegration(_firebaseIntegration);
29
+
30
+ exports.firebaseIntegration = firebaseIntegration;
31
+ exports.instrumentFirebase = instrumentFirebase;
32
+ //# sourceMappingURL=firebase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firebase.js","sources":["../../../../../src/integrations/tracing/firebase/firebase.ts"],"sourcesContent":["import type { Span } from '@opentelemetry/api';\nimport type { IntegrationFn } from '@sentry/core';\nimport { defineIntegration, SEMANTIC_ATTRIBUTE_SENTRY_OP } from '@sentry/core';\nimport { addOriginToSpan, generateInstrumentOnce } from '@sentry/node-core';\nimport { type FirebaseInstrumentationConfig, FirebaseInstrumentation } from './otel';\n\nconst INTEGRATION_NAME = 'Firebase';\n\nconst config: FirebaseInstrumentationConfig = {\n firestoreSpanCreationHook: span => {\n addOriginToSpan(span as Span, 'auto.firebase.otel.firestore');\n\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'db.query');\n },\n};\n\nexport const instrumentFirebase = generateInstrumentOnce(INTEGRATION_NAME, () => new FirebaseInstrumentation(config));\n\nconst _firebaseIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n instrumentFirebase();\n },\n };\n}) satisfies IntegrationFn;\n\nexport const firebaseIntegration = defineIntegration(_firebaseIntegration);\n"],"names":["addOriginToSpan","SEMANTIC_ATTRIBUTE_SENTRY_OP","generateInstrumentOnce","FirebaseInstrumentation","defineIntegration"],"mappings":";;;;;;AAMA,MAAM,gBAAA,GAAmB,UAAU;;AAEnC,MAAM,MAAM,GAAkC;AAC9C,EAAE,yBAAyB,EAAE,IAAA,IAAQ;AACrC,IAAIA,wBAAe,CAAC,IAAA,GAAc,8BAA8B,CAAC;;AAEjE,IAAI,IAAI,CAAC,YAAY,CAACC,iCAA4B,EAAE,UAAU,CAAC;AAC/D,GAAG;AACH,CAAC;;AAEM,MAAM,kBAAA,GAAqBC,+BAAsB,CAAC,gBAAgB,EAAE,MAAM,IAAIC,+CAAuB,CAAC,MAAM,CAAC;;AAEpH,MAAM,oBAAA,IAAwB,MAAM;AACpC,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,SAAS,GAAG;AAChB,MAAM,kBAAkB,EAAE;AAC1B,KAAK;AACL,GAAG;AACH,CAAC,CAAA;;MAEY,mBAAA,GAAsBC,sBAAiB,CAAC,oBAAoB;;;;;"}
@@ -0,0 +1,41 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ const instrumentation = require('@opentelemetry/instrumentation');
4
+ const core = require('@sentry/core');
5
+ const firestore = require('./patches/firestore.js');
6
+
7
+ const DefaultFirebaseInstrumentationConfig = {};
8
+ const firestoreSupportedVersions = ['>=3.0.0 <5']; // firebase 9+
9
+
10
+ /**
11
+ * Instrumentation for Firebase services, specifically Firestore.
12
+ */
13
+ class FirebaseInstrumentation extends instrumentation.InstrumentationBase {
14
+ constructor(config = DefaultFirebaseInstrumentationConfig) {
15
+ super('@sentry/instrumentation-firebase', core.SDK_VERSION, config);
16
+ }
17
+
18
+ /**
19
+ * sets config
20
+ * @param config
21
+ */
22
+ setConfig(config = {}) {
23
+ super.setConfig({ ...DefaultFirebaseInstrumentationConfig, ...config });
24
+ }
25
+
26
+ /**
27
+ *
28
+ * @protected
29
+ */
30
+ // eslint-disable-next-line @typescript-eslint/naming-convention
31
+ init() {
32
+ const modules = [];
33
+
34
+ modules.push(firestore.patchFirestore(this.tracer, firestoreSupportedVersions, this._wrap, this._unwrap, this.getConfig()));
35
+
36
+ return modules;
37
+ }
38
+ }
39
+
40
+ exports.FirebaseInstrumentation = FirebaseInstrumentation;
41
+ //# sourceMappingURL=firebaseInstrumentation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firebaseInstrumentation.js","sources":["../../../../../../src/integrations/tracing/firebase/otel/firebaseInstrumentation.ts"],"sourcesContent":["import { type InstrumentationNodeModuleDefinition, InstrumentationBase } from '@opentelemetry/instrumentation';\nimport { SDK_VERSION } from '@sentry/core';\nimport { patchFirestore } from './patches/firestore';\nimport type { FirebaseInstrumentationConfig } from './types';\n\nconst DefaultFirebaseInstrumentationConfig: FirebaseInstrumentationConfig = {};\nconst firestoreSupportedVersions = ['>=3.0.0 <5']; // firebase 9+\n\n/**\n * Instrumentation for Firebase services, specifically Firestore.\n */\nexport class FirebaseInstrumentation extends InstrumentationBase<FirebaseInstrumentationConfig> {\n public constructor(config: FirebaseInstrumentationConfig = DefaultFirebaseInstrumentationConfig) {\n super('@sentry/instrumentation-firebase', SDK_VERSION, config);\n }\n\n /**\n * sets config\n * @param config\n */\n public override setConfig(config: FirebaseInstrumentationConfig = {}): void {\n super.setConfig({ ...DefaultFirebaseInstrumentationConfig, ...config });\n }\n\n /**\n *\n * @protected\n */\n // eslint-disable-next-line @typescript-eslint/naming-convention\n protected init(): InstrumentationNodeModuleDefinition | InstrumentationNodeModuleDefinition[] | void {\n const modules: InstrumentationNodeModuleDefinition[] = [];\n\n modules.push(patchFirestore(this.tracer, firestoreSupportedVersions, this._wrap, this._unwrap, this.getConfig()));\n\n return modules;\n }\n}\n"],"names":["InstrumentationBase","SDK_VERSION","patchFirestore"],"mappings":";;;;;;AAKA,MAAM,oCAAoC,GAAkC,EAAE;AAC9E,MAAM,0BAAA,GAA6B,CAAC,YAAY,CAAC,CAAA;;AAEjD;AACA;AACA;AACO,MAAM,uBAAA,SAAgCA,mCAAmB,CAAgC;AAChG,GAAS,WAAW,CAAC,MAAM,GAAkC,oCAAoC,EAAE;AACnG,IAAI,KAAK,CAAC,kCAAkC,EAAEC,gBAAW,EAAE,MAAM,CAAC;AAClE;;AAEA;AACA;AACA;AACA;AACA,IAAkB,SAAS,CAAC,MAAM,GAAkC,EAAE,EAAQ;AAC9E,IAAI,KAAK,CAAC,SAAS,CAAC,EAAE,GAAG,oCAAoC,EAAE,GAAG,MAAA,EAAQ,CAAC;AAC3E;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAY,IAAI,GAAuF;AACvG,IAAI,MAAM,OAAO,GAA0C,EAAE;;AAE7D,IAAI,OAAO,CAAC,IAAI,CAACC,wBAAc,CAAC,IAAI,CAAC,MAAM,EAAE,0BAA0B,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;;AAErH,IAAI,OAAO,OAAO;AAClB;AACA;;;;"}
@@ -0,0 +1,295 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ const net = require('node:net');
4
+ const api = require('@opentelemetry/api');
5
+ const instrumentation = require('@opentelemetry/instrumentation');
6
+ const semanticConventions = require('@opentelemetry/semantic-conventions');
7
+
8
+ /**
9
+ *
10
+ * @param tracer - Opentelemetry Tracer
11
+ * @param firestoreSupportedVersions - supported version of firebase/firestore
12
+ * @param wrap - reference to native instrumentation wrap function
13
+ * @param unwrap - reference to native instrumentation wrap function
14
+ */
15
+ function patchFirestore(
16
+ tracer,
17
+ firestoreSupportedVersions,
18
+ wrap,
19
+ unwrap,
20
+ config,
21
+ ) {
22
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
23
+ const defaultFirestoreSpanCreationHook = () => {};
24
+
25
+ let firestoreSpanCreationHook = defaultFirestoreSpanCreationHook;
26
+ const configFirestoreSpanCreationHook = config.firestoreSpanCreationHook;
27
+
28
+ if (typeof configFirestoreSpanCreationHook === 'function') {
29
+ firestoreSpanCreationHook = (span) => {
30
+ instrumentation.safeExecuteInTheMiddle(
31
+ () => configFirestoreSpanCreationHook(span),
32
+ error => {
33
+ if (!error) {
34
+ return;
35
+ }
36
+ api.diag.error(error?.message);
37
+ },
38
+ true,
39
+ );
40
+ };
41
+ }
42
+
43
+ const moduleFirestoreCJS = new instrumentation.InstrumentationNodeModuleDefinition(
44
+ '@firebase/firestore',
45
+ firestoreSupportedVersions,
46
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
+ (moduleExports) => wrapMethods(moduleExports, wrap, unwrap, tracer, firestoreSpanCreationHook),
48
+ );
49
+ const files = [
50
+ '@firebase/firestore/dist/lite/index.node.cjs.js',
51
+ '@firebase/firestore/dist/lite/index.node.mjs.js',
52
+ '@firebase/firestore/dist/lite/index.rn.esm2017.js',
53
+ '@firebase/firestore/dist/lite/index.cjs.js',
54
+ ];
55
+
56
+ for (const file of files) {
57
+ moduleFirestoreCJS.files.push(
58
+ new instrumentation.InstrumentationNodeModuleFile(
59
+ file,
60
+ firestoreSupportedVersions,
61
+ moduleExports => wrapMethods(moduleExports, wrap, unwrap, tracer, firestoreSpanCreationHook),
62
+ moduleExports => unwrapMethods(moduleExports, unwrap),
63
+ ),
64
+ );
65
+ }
66
+
67
+ return moduleFirestoreCJS;
68
+ }
69
+
70
+ function wrapMethods(
71
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
72
+ moduleExports,
73
+ wrap,
74
+ unwrap,
75
+ tracer,
76
+ firestoreSpanCreationHook,
77
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
78
+ ) {
79
+ unwrapMethods(moduleExports, unwrap);
80
+
81
+ wrap(moduleExports, 'addDoc', patchAddDoc(tracer, firestoreSpanCreationHook));
82
+ wrap(moduleExports, 'getDocs', patchGetDocs(tracer, firestoreSpanCreationHook));
83
+ wrap(moduleExports, 'setDoc', patchSetDoc(tracer, firestoreSpanCreationHook));
84
+ wrap(moduleExports, 'deleteDoc', patchDeleteDoc(tracer, firestoreSpanCreationHook));
85
+
86
+ return moduleExports;
87
+ }
88
+
89
+ function unwrapMethods(
90
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
91
+ moduleExports,
92
+ unwrap,
93
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
+ ) {
95
+ for (const method of ['addDoc', 'getDocs', 'setDoc', 'deleteDoc']) {
96
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
97
+ if (instrumentation.isWrapped(moduleExports[method])) {
98
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
99
+ unwrap(moduleExports, method);
100
+ }
101
+ }
102
+ return moduleExports;
103
+ }
104
+
105
+ function patchAddDoc(
106
+ tracer,
107
+ firestoreSpanCreationHook,
108
+ )
109
+
110
+ {
111
+ return function addDoc(original) {
112
+ return function (
113
+ reference,
114
+ data,
115
+ ) {
116
+ const span = startDBSpan(tracer, 'addDoc', reference);
117
+ firestoreSpanCreationHook(span);
118
+ return executeContextWithSpan(span, () => {
119
+ return original(reference, data);
120
+ });
121
+ };
122
+ };
123
+ }
124
+
125
+ function patchDeleteDoc(
126
+ tracer,
127
+ firestoreSpanCreationHook,
128
+ )
129
+
130
+ {
131
+ return function deleteDoc(original) {
132
+ return function (reference) {
133
+ const span = startDBSpan(tracer, 'deleteDoc', reference.parent || reference);
134
+ firestoreSpanCreationHook(span);
135
+ return executeContextWithSpan(span, () => {
136
+ return original(reference);
137
+ });
138
+ };
139
+ };
140
+ }
141
+
142
+ function patchGetDocs(
143
+ tracer,
144
+ firestoreSpanCreationHook,
145
+ )
146
+
147
+ {
148
+ return function getDocs(original) {
149
+ return function (
150
+ reference,
151
+ ) {
152
+ const span = startDBSpan(tracer, 'getDocs', reference);
153
+ firestoreSpanCreationHook(span);
154
+ return executeContextWithSpan(span, () => {
155
+ return original(reference);
156
+ });
157
+ };
158
+ };
159
+ }
160
+
161
+ function patchSetDoc(
162
+ tracer,
163
+ firestoreSpanCreationHook,
164
+ )
165
+
166
+ {
167
+ return function setDoc(original) {
168
+ return function (
169
+ reference,
170
+ data,
171
+ options,
172
+ ) {
173
+ const span = startDBSpan(tracer, 'setDoc', reference.parent || reference);
174
+ firestoreSpanCreationHook(span);
175
+
176
+ return executeContextWithSpan(span, () => {
177
+ return typeof options !== 'undefined' ? original(reference, data, options) : original(reference, data);
178
+ });
179
+ };
180
+ };
181
+ }
182
+
183
+ function executeContextWithSpan(span, callback) {
184
+ return api.context.with(api.trace.setSpan(api.context.active(), span), () => {
185
+ return instrumentation.safeExecuteInTheMiddle(
186
+ () => {
187
+ return callback();
188
+ },
189
+ err => {
190
+ if (err) {
191
+ span.recordException(err);
192
+ }
193
+ span.end();
194
+ },
195
+ true,
196
+ );
197
+ });
198
+ }
199
+
200
+ function startDBSpan(
201
+ tracer,
202
+ spanName,
203
+ reference,
204
+ ) {
205
+ const span = tracer.startSpan(`${spanName} ${reference.path}`, { kind: api.SpanKind.CLIENT });
206
+ addAttributes(span, reference);
207
+ span.setAttribute(semanticConventions.ATTR_DB_OPERATION_NAME, spanName);
208
+ return span;
209
+ }
210
+
211
+ /**
212
+ * Gets the server address and port attributes from the Firestore settings.
213
+ * It's best effort to extract the address and port from the settings, especially for IPv6.
214
+ * @param span - The span to set attributes on.
215
+ * @param settings - The Firestore settings containing host information.
216
+ */
217
+ function getPortAndAddress(settings)
218
+
219
+ {
220
+ let address;
221
+ let port;
222
+
223
+ if (typeof settings.host === 'string') {
224
+ if (settings.host.startsWith('[')) {
225
+ // IPv6 addresses can be enclosed in square brackets, e.g., [2001:db8::1]:8080
226
+ if (settings.host.endsWith(']')) {
227
+ // IPv6 with square brackets without port
228
+ address = settings.host.replace(/^\[|\]$/g, '');
229
+ } else if (settings.host.includes(']:')) {
230
+ // IPv6 with square brackets with port
231
+ const lastColonIndex = settings.host.lastIndexOf(':');
232
+ if (lastColonIndex !== -1) {
233
+ address = settings.host.slice(1, lastColonIndex).replace(/^\[|\]$/g, '');
234
+ port = settings.host.slice(lastColonIndex + 1);
235
+ }
236
+ }
237
+ } else {
238
+ // IPv4 or IPv6 without square brackets
239
+ // If it's an IPv6 address without square brackets, we assume it does not have a port.
240
+ if (net.isIPv6(settings.host)) {
241
+ address = settings.host;
242
+ }
243
+ // If it's an IPv4 address, we can extract the port if it exists.
244
+ else {
245
+ const lastColonIndex = settings.host.lastIndexOf(':');
246
+ if (lastColonIndex !== -1) {
247
+ address = settings.host.slice(0, lastColonIndex);
248
+ port = settings.host.slice(lastColonIndex + 1);
249
+ } else {
250
+ address = settings.host;
251
+ }
252
+ }
253
+ }
254
+ }
255
+ return {
256
+ address: address,
257
+ port: port ? parseInt(port, 10) : undefined,
258
+ };
259
+ }
260
+
261
+ function addAttributes(
262
+ span,
263
+ reference,
264
+ ) {
265
+ const firestoreApp = reference.firestore.app;
266
+ const firestoreOptions = firestoreApp.options;
267
+ const json = reference.firestore.toJSON() || {};
268
+ const settings = json.settings || {};
269
+
270
+ const attributes = {
271
+ [semanticConventions.ATTR_DB_COLLECTION_NAME]: reference.path,
272
+ [semanticConventions.ATTR_DB_NAMESPACE]: firestoreApp.name,
273
+ [semanticConventions.ATTR_DB_SYSTEM_NAME]: 'firebase.firestore',
274
+ 'firebase.firestore.type': reference.type,
275
+ 'firebase.firestore.options.projectId': firestoreOptions.projectId,
276
+ 'firebase.firestore.options.appId': firestoreOptions.appId,
277
+ 'firebase.firestore.options.messagingSenderId': firestoreOptions.messagingSenderId,
278
+ 'firebase.firestore.options.storageBucket': firestoreOptions.storageBucket,
279
+ };
280
+
281
+ const { address, port } = getPortAndAddress(settings);
282
+
283
+ if (address) {
284
+ attributes[semanticConventions.ATTR_SERVER_ADDRESS] = address;
285
+ }
286
+ if (port) {
287
+ attributes[semanticConventions.ATTR_SERVER_PORT] = port;
288
+ }
289
+
290
+ span.setAttributes(attributes);
291
+ }
292
+
293
+ exports.getPortAndAddress = getPortAndAddress;
294
+ exports.patchFirestore = patchFirestore;
295
+ //# sourceMappingURL=firestore.js.map