@sentry/node 10.50.0 → 10.52.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 (81) hide show
  1. package/build/cjs/index.js +4 -4
  2. package/build/cjs/integrations/http.js +18 -145
  3. package/build/cjs/integrations/http.js.map +1 -1
  4. package/build/cjs/integrations/tracing/index.js +21 -22
  5. package/build/cjs/integrations/tracing/index.js.map +1 -1
  6. package/build/cjs/integrations/tracing/langgraph/instrumentation.js +70 -25
  7. package/build/cjs/integrations/tracing/langgraph/instrumentation.js.map +1 -1
  8. package/build/cjs/integrations/tracing/prisma.js +6 -2
  9. package/build/cjs/integrations/tracing/prisma.js.map +1 -1
  10. package/build/cjs/integrations/tracing/{redis.js → redis/index.js} +18 -10
  11. package/build/cjs/integrations/tracing/redis/index.js.map +1 -0
  12. package/build/cjs/integrations/tracing/redis/redis-dc-subscriber.js +186 -0
  13. package/build/cjs/integrations/tracing/redis/redis-dc-subscriber.js.map +1 -0
  14. package/build/cjs/integrations/tracing/redis/vendored/ioredis-instrumentation.js +255 -0
  15. package/build/cjs/integrations/tracing/redis/vendored/ioredis-instrumentation.js.map +1 -0
  16. package/build/cjs/integrations/tracing/redis/vendored/redis-common.js +74 -0
  17. package/build/cjs/integrations/tracing/redis/vendored/redis-common.js.map +1 -0
  18. package/build/cjs/integrations/tracing/redis/vendored/redis-instrumentation.js +685 -0
  19. package/build/cjs/integrations/tracing/redis/vendored/redis-instrumentation.js.map +1 -0
  20. package/build/cjs/integrations/tracing/redis/vendored/semconv.js +47 -0
  21. package/build/cjs/integrations/tracing/redis/vendored/semconv.js.map +1 -0
  22. package/build/cjs/utils/redisCache.js.map +1 -1
  23. package/build/esm/index.js +1 -1
  24. package/build/esm/integrations/http.js +21 -146
  25. package/build/esm/integrations/http.js.map +1 -1
  26. package/build/esm/integrations/tracing/index.js +2 -3
  27. package/build/esm/integrations/tracing/index.js.map +1 -1
  28. package/build/esm/integrations/tracing/langgraph/instrumentation.js +71 -26
  29. package/build/esm/integrations/tracing/langgraph/instrumentation.js.map +1 -1
  30. package/build/esm/integrations/tracing/prisma.js +6 -2
  31. package/build/esm/integrations/tracing/prisma.js.map +1 -1
  32. package/build/esm/integrations/tracing/{redis.js → redis/index.js} +17 -9
  33. package/build/esm/integrations/tracing/redis/index.js.map +1 -0
  34. package/build/esm/integrations/tracing/redis/redis-dc-subscriber.js +184 -0
  35. package/build/esm/integrations/tracing/redis/redis-dc-subscriber.js.map +1 -0
  36. package/build/esm/integrations/tracing/redis/vendored/ioredis-instrumentation.js +253 -0
  37. package/build/esm/integrations/tracing/redis/vendored/ioredis-instrumentation.js.map +1 -0
  38. package/build/esm/integrations/tracing/redis/vendored/redis-common.js +72 -0
  39. package/build/esm/integrations/tracing/redis/vendored/redis-common.js.map +1 -0
  40. package/build/esm/integrations/tracing/redis/vendored/redis-instrumentation.js +683 -0
  41. package/build/esm/integrations/tracing/redis/vendored/redis-instrumentation.js.map +1 -0
  42. package/build/esm/integrations/tracing/redis/vendored/semconv.js +39 -0
  43. package/build/esm/integrations/tracing/redis/vendored/semconv.js.map +1 -0
  44. package/build/esm/package.json +1 -1
  45. package/build/esm/utils/redisCache.js.map +1 -1
  46. package/build/types/integrations/http.d.ts +8 -15
  47. package/build/types/integrations/http.d.ts.map +1 -1
  48. package/build/types/integrations/tracing/index.d.ts.map +1 -1
  49. package/build/types/integrations/tracing/langgraph/instrumentation.d.ts +1 -1
  50. package/build/types/integrations/tracing/langgraph/instrumentation.d.ts.map +1 -1
  51. package/build/types/integrations/tracing/prisma.d.ts.map +1 -1
  52. package/build/types/integrations/tracing/{redis.d.ts → redis/index.d.ts} +3 -3
  53. package/build/types/integrations/tracing/redis/index.d.ts.map +1 -0
  54. package/build/types/integrations/tracing/redis/redis-dc-subscriber.d.ts +17 -0
  55. package/build/types/integrations/tracing/redis/redis-dc-subscriber.d.ts.map +1 -0
  56. package/build/types/integrations/tracing/redis/vendored/ioredis-instrumentation.d.ts +15 -0
  57. package/build/types/integrations/tracing/redis/vendored/ioredis-instrumentation.d.ts.map +1 -0
  58. package/build/types/integrations/tracing/redis/vendored/redis-common.d.ts +6 -0
  59. package/build/types/integrations/tracing/redis/vendored/redis-common.d.ts.map +1 -0
  60. package/build/types/integrations/tracing/redis/vendored/redis-instrumentation.d.ts +16 -0
  61. package/build/types/integrations/tracing/redis/vendored/redis-instrumentation.d.ts.map +1 -0
  62. package/build/types/integrations/tracing/redis/vendored/semconv.d.ts +8 -0
  63. package/build/types/integrations/tracing/redis/vendored/semconv.d.ts.map +1 -0
  64. package/build/types/integrations/tracing/redis/vendored/types.d.ts +58 -0
  65. package/build/types/integrations/tracing/redis/vendored/types.d.ts.map +1 -0
  66. package/build/types/utils/redisCache.d.ts +1 -1
  67. package/build/types/utils/redisCache.d.ts.map +1 -1
  68. package/build/types-ts3.8/integrations/http.d.ts +8 -15
  69. package/build/types-ts3.8/integrations/tracing/langgraph/instrumentation.d.ts +1 -1
  70. package/build/types-ts3.8/integrations/tracing/{redis.d.ts → redis/index.d.ts} +3 -3
  71. package/build/types-ts3.8/integrations/tracing/redis/redis-dc-subscriber.d.ts +17 -0
  72. package/build/types-ts3.8/integrations/tracing/redis/vendored/ioredis-instrumentation.d.ts +15 -0
  73. package/build/types-ts3.8/integrations/tracing/redis/vendored/redis-common.d.ts +6 -0
  74. package/build/types-ts3.8/integrations/tracing/redis/vendored/redis-instrumentation.d.ts +16 -0
  75. package/build/types-ts3.8/integrations/tracing/redis/vendored/semconv.d.ts +8 -0
  76. package/build/types-ts3.8/integrations/tracing/redis/vendored/types.d.ts +58 -0
  77. package/build/types-ts3.8/utils/redisCache.d.ts +1 -1
  78. package/package.json +4 -6
  79. package/build/cjs/integrations/tracing/redis.js.map +0 -1
  80. package/build/esm/integrations/tracing/redis.js.map +0 -1
  81. package/build/types/integrations/tracing/redis.d.ts.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { InstrumentationBase, InstrumentationNodeModuleDefinition, InstrumentationNodeModuleFile } from '@opentelemetry/instrumentation';
2
- import { SDK_VERSION, instrumentLangGraph } from '@sentry/core';
2
+ import { SDK_VERSION, getClient, instrumentLangGraph, instrumentCreateReactAgent } from '@sentry/core';
3
3
 
4
4
  const supportedVersions = ['>=0.0.0 <2.0.0'];
5
5
 
@@ -15,39 +15,84 @@ class SentryLangGraphInstrumentation extends InstrumentationBase {
15
15
  * Initializes the instrumentation by defining the modules to be patched.
16
16
  */
17
17
  init() {
18
- const module = new InstrumentationNodeModuleDefinition(
19
- '@langchain/langgraph',
20
- supportedVersions,
21
- this._patch.bind(this),
22
- exports$1 => exports$1,
23
- [
24
- new InstrumentationNodeModuleFile(
25
- /**
26
- * In CJS, LangGraph packages re-export from dist/index.cjs files.
27
- * Patching only the root module sometimes misses the real implementation or
28
- * gets overwritten when that file is loaded. We add a file-level patch so that
29
- * _patch runs again on the concrete implementation
30
- */
31
- '@langchain/langgraph/dist/index.cjs',
32
- supportedVersions,
33
- this._patch.bind(this),
34
- exports$1 => exports$1,
35
- ),
36
- ],
37
- );
38
- return module;
18
+ return [
19
+ new InstrumentationNodeModuleDefinition(
20
+ '@langchain/langgraph',
21
+ supportedVersions,
22
+ this._patch.bind(this),
23
+ exports$1 => exports$1,
24
+ [
25
+ new InstrumentationNodeModuleFile(
26
+ /**
27
+ * In CJS, LangGraph packages re-export from dist/index.cjs files.
28
+ * Patching only the root module sometimes misses the real implementation or
29
+ * gets overwritten when that file is loaded. We add a file-level patch so that
30
+ * _patch runs again on the concrete implementation
31
+ */
32
+ '@langchain/langgraph/dist/index.cjs',
33
+ supportedVersions,
34
+ this._patch.bind(this),
35
+ exports$1 => exports$1,
36
+ ),
37
+ new InstrumentationNodeModuleFile(
38
+ /**
39
+ * In CJS, the prebuilt submodule re-exports from dist/prebuilt/index.cjs.
40
+ * We add a file-level patch under the main module so that CJS require()
41
+ * of @langchain/langgraph/prebuilt gets patched.
42
+ */
43
+ '@langchain/langgraph/dist/prebuilt/index.cjs',
44
+ supportedVersions,
45
+ this._patch.bind(this),
46
+ exports$1 => exports$1,
47
+ ),
48
+ ],
49
+ ),
50
+ new InstrumentationNodeModuleDefinition(
51
+ '@langchain/langgraph/prebuilt',
52
+ supportedVersions,
53
+ this._patch.bind(this),
54
+ exports$1 => exports$1,
55
+ [
56
+ new InstrumentationNodeModuleFile(
57
+ /**
58
+ * In CJS, the prebuilt submodule re-exports from dist/prebuilt/index.cjs.
59
+ * We add file-level patches so _patch runs on the concrete implementation.
60
+ */
61
+ '@langchain/langgraph/dist/prebuilt/index.cjs',
62
+ supportedVersions,
63
+ this._patch.bind(this),
64
+ exports$1 => exports$1,
65
+ ),
66
+ ],
67
+ ),
68
+ ];
39
69
  }
40
70
 
41
71
  /**
42
72
  * Core patch logic applying instrumentation to the LangGraph module.
43
73
  */
44
74
  _patch(exports$1) {
75
+ const client = getClient();
76
+ const options = {
77
+ ...this.getConfig(),
78
+ recordInputs: this.getConfig().recordInputs ?? client?.getOptions().sendDefaultPii,
79
+ recordOutputs: this.getConfig().recordOutputs ?? client?.getOptions().sendDefaultPii,
80
+ };
81
+
45
82
  // Patch StateGraph.compile to instrument both compile() and invoke()
46
83
  if (exports$1.StateGraph && typeof exports$1.StateGraph === 'function') {
47
- instrumentLangGraph(
48
- exports$1.StateGraph.prototype ,
49
- this.getConfig(),
50
- );
84
+ instrumentLangGraph(exports$1.StateGraph.prototype , options);
85
+ }
86
+
87
+ // Patch createReactAgent to instrument agent creation and invocation
88
+ if (exports$1.createReactAgent && typeof exports$1.createReactAgent === 'function') {
89
+ const originalCreateReactAgent = exports$1.createReactAgent;
90
+ Object.defineProperty(exports$1, 'createReactAgent', {
91
+ value: instrumentCreateReactAgent(originalCreateReactAgent , options),
92
+ writable: true,
93
+ enumerable: true,
94
+ configurable: true,
95
+ });
51
96
  }
52
97
 
53
98
  return exports$1;
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentation.js","sources":["../../../../../src/integrations/tracing/langgraph/instrumentation.ts"],"sourcesContent":["import {\n InstrumentationBase,\n type InstrumentationConfig,\n type InstrumentationModuleDefinition,\n InstrumentationNodeModuleDefinition,\n InstrumentationNodeModuleFile,\n} from '@opentelemetry/instrumentation';\nimport type { LangGraphOptions } from '@sentry/core';\nimport { instrumentLangGraph, SDK_VERSION } from '@sentry/core';\n\nconst supportedVersions = ['>=0.0.0 <2.0.0'];\n\ntype LangGraphInstrumentationOptions = InstrumentationConfig & LangGraphOptions;\n\n/**\n * Represents the patched shape of the LangGraph module export.\n */\ninterface PatchedModuleExports {\n [key: string]: unknown;\n StateGraph?: abstract new (...args: unknown[]) => unknown;\n}\n\n/**\n * Sentry LangGraph instrumentation using OpenTelemetry.\n */\nexport class SentryLangGraphInstrumentation extends InstrumentationBase<LangGraphInstrumentationOptions> {\n public constructor(config: LangGraphInstrumentationOptions = {}) {\n super('@sentry/instrumentation-langgraph', SDK_VERSION, config);\n }\n\n /**\n * Initializes the instrumentation by defining the modules to be patched.\n */\n public init(): InstrumentationModuleDefinition {\n const module = new InstrumentationNodeModuleDefinition(\n '@langchain/langgraph',\n supportedVersions,\n this._patch.bind(this),\n exports => exports,\n [\n new InstrumentationNodeModuleFile(\n /**\n * In CJS, LangGraph packages re-export from dist/index.cjs files.\n * Patching only the root module sometimes misses the real implementation or\n * gets overwritten when that file is loaded. We add a file-level patch so that\n * _patch runs again on the concrete implementation\n */\n '@langchain/langgraph/dist/index.cjs',\n supportedVersions,\n this._patch.bind(this),\n exports => exports,\n ),\n ],\n );\n return module;\n }\n\n /**\n * Core patch logic applying instrumentation to the LangGraph module.\n */\n private _patch(exports: PatchedModuleExports): PatchedModuleExports | void {\n // Patch StateGraph.compile to instrument both compile() and invoke()\n if (exports.StateGraph && typeof exports.StateGraph === 'function') {\n instrumentLangGraph(\n exports.StateGraph.prototype as { compile: (...args: unknown[]) => unknown },\n this.getConfig(),\n );\n }\n\n return exports;\n }\n}\n"],"names":["exports"],"mappings":";;;AAUA,MAAM,iBAAA,GAAoB,CAAC,gBAAgB,CAAC;;AAY5C;AACA;AACA;AACO,MAAM,8BAAA,SAAuC,mBAAmB,CAAkC;AACzG,GAAS,WAAW,CAAC,MAAM,GAAoC,EAAE,EAAE;AACnE,IAAI,KAAK,CAAC,mCAAmC,EAAE,WAAW,EAAE,MAAM,CAAC;AACnE,EAAE;;AAEF;AACA;AACA;AACA,GAAS,IAAI,GAAoC;AACjD,IAAI,MAAM,MAAA,GAAS,IAAI,mCAAmC;AAC1D,MAAM,sBAAsB;AAC5B,MAAM,iBAAiB;AACvB,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AAC5B,MAAMA,SAAA,IAAWA,SAAO;AACxB,MAAM;AACN,QAAQ,IAAI,6BAA6B;AACzC;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,qCAAqC;AAC/C,UAAU,iBAAiB;AAC3B,UAAU,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AAChC,UAAUA,SAAA,IAAWA,SAAO;AAC5B,SAAS;AACT,OAAO;AACP,KAAK;AACL,IAAI,OAAO,MAAM;AACjB,EAAE;;AAEF;AACA;AACA;AACA,GAAU,MAAM,CAACA,SAAO,EAAqD;AAC7E;AACA,IAAI,IAAIA,SAAO,CAAC,UAAA,IAAc,OAAOA,SAAO,CAAC,UAAA,KAAe,UAAU,EAAE;AACxE,MAAM,mBAAmB;AACzB,QAAQA,SAAO,CAAC,UAAU,CAAC,SAAA;AAC3B,QAAQ,IAAI,CAAC,SAAS,EAAE;AACxB,OAAO;AACP,IAAI;;AAEJ,IAAI,OAAOA,SAAO;AAClB,EAAE;AACF;;;;"}
1
+ {"version":3,"file":"instrumentation.js","sources":["../../../../../src/integrations/tracing/langgraph/instrumentation.ts"],"sourcesContent":["import {\n InstrumentationBase,\n type InstrumentationConfig,\n type InstrumentationModuleDefinition,\n InstrumentationNodeModuleDefinition,\n InstrumentationNodeModuleFile,\n} from '@opentelemetry/instrumentation';\nimport type { CompiledGraph, LangGraphOptions } from '@sentry/core';\nimport { getClient, instrumentCreateReactAgent, instrumentLangGraph, SDK_VERSION } from '@sentry/core';\n\nconst supportedVersions = ['>=0.0.0 <2.0.0'];\n\ntype LangGraphInstrumentationOptions = InstrumentationConfig & LangGraphOptions;\n\n/**\n * Represents the patched shape of the LangGraph module export.\n */\ninterface PatchedModuleExports {\n [key: string]: unknown;\n StateGraph?: abstract new (...args: unknown[]) => unknown;\n createReactAgent?: (...args: unknown[]) => CompiledGraph;\n}\n\n/**\n * Sentry LangGraph instrumentation using OpenTelemetry.\n */\nexport class SentryLangGraphInstrumentation extends InstrumentationBase<LangGraphInstrumentationOptions> {\n public constructor(config: LangGraphInstrumentationOptions = {}) {\n super('@sentry/instrumentation-langgraph', SDK_VERSION, config);\n }\n\n /**\n * Initializes the instrumentation by defining the modules to be patched.\n */\n public init(): InstrumentationModuleDefinition[] {\n return [\n new InstrumentationNodeModuleDefinition(\n '@langchain/langgraph',\n supportedVersions,\n this._patch.bind(this),\n exports => exports,\n [\n new InstrumentationNodeModuleFile(\n /**\n * In CJS, LangGraph packages re-export from dist/index.cjs files.\n * Patching only the root module sometimes misses the real implementation or\n * gets overwritten when that file is loaded. We add a file-level patch so that\n * _patch runs again on the concrete implementation\n */\n '@langchain/langgraph/dist/index.cjs',\n supportedVersions,\n this._patch.bind(this),\n exports => exports,\n ),\n new InstrumentationNodeModuleFile(\n /**\n * In CJS, the prebuilt submodule re-exports from dist/prebuilt/index.cjs.\n * We add a file-level patch under the main module so that CJS require()\n * of @langchain/langgraph/prebuilt gets patched.\n */\n '@langchain/langgraph/dist/prebuilt/index.cjs',\n supportedVersions,\n this._patch.bind(this),\n exports => exports,\n ),\n ],\n ),\n new InstrumentationNodeModuleDefinition(\n '@langchain/langgraph/prebuilt',\n supportedVersions,\n this._patch.bind(this),\n exports => exports,\n [\n new InstrumentationNodeModuleFile(\n /**\n * In CJS, the prebuilt submodule re-exports from dist/prebuilt/index.cjs.\n * We add file-level patches so _patch runs on the concrete implementation.\n */\n '@langchain/langgraph/dist/prebuilt/index.cjs',\n supportedVersions,\n this._patch.bind(this),\n exports => exports,\n ),\n ],\n ),\n ];\n }\n\n /**\n * Core patch logic applying instrumentation to the LangGraph module.\n */\n private _patch(exports: PatchedModuleExports): PatchedModuleExports | void {\n const client = getClient();\n const options = {\n ...this.getConfig(),\n recordInputs: this.getConfig().recordInputs ?? client?.getOptions().sendDefaultPii,\n recordOutputs: this.getConfig().recordOutputs ?? client?.getOptions().sendDefaultPii,\n };\n\n // Patch StateGraph.compile to instrument both compile() and invoke()\n if (exports.StateGraph && typeof exports.StateGraph === 'function') {\n instrumentLangGraph(exports.StateGraph.prototype as { compile: (...args: unknown[]) => unknown }, options);\n }\n\n // Patch createReactAgent to instrument agent creation and invocation\n if (exports.createReactAgent && typeof exports.createReactAgent === 'function') {\n const originalCreateReactAgent = exports.createReactAgent;\n Object.defineProperty(exports, 'createReactAgent', {\n value: instrumentCreateReactAgent(originalCreateReactAgent as (...args: unknown[]) => CompiledGraph, options),\n writable: true,\n enumerable: true,\n configurable: true,\n });\n }\n\n return exports;\n }\n}\n"],"names":["exports"],"mappings":";;;AAUA,MAAM,iBAAA,GAAoB,CAAC,gBAAgB,CAAC;;AAa5C;AACA;AACA;AACO,MAAM,8BAAA,SAAuC,mBAAmB,CAAkC;AACzG,GAAS,WAAW,CAAC,MAAM,GAAoC,EAAE,EAAE;AACnE,IAAI,KAAK,CAAC,mCAAmC,EAAE,WAAW,EAAE,MAAM,CAAC;AACnE,EAAE;;AAEF;AACA;AACA;AACA,GAAS,IAAI,GAAsC;AACnD,IAAI,OAAO;AACX,MAAM,IAAI,mCAAmC;AAC7C,QAAQ,sBAAsB;AAC9B,QAAQ,iBAAiB;AACzB,QAAQ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AAC9B,QAAQA,SAAA,IAAWA,SAAO;AAC1B,QAAQ;AACR,UAAU,IAAI,6BAA6B;AAC3C;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,qCAAqC;AACjD,YAAY,iBAAiB;AAC7B,YAAY,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AAClC,YAAYA,SAAA,IAAWA,SAAO;AAC9B,WAAW;AACX,UAAU,IAAI,6BAA6B;AAC3C;AACA;AACA;AACA;AACA;AACA,YAAY,8CAA8C;AAC1D,YAAY,iBAAiB;AAC7B,YAAY,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AAClC,YAAYA,SAAA,IAAWA,SAAO;AAC9B,WAAW;AACX,SAAS;AACT,OAAO;AACP,MAAM,IAAI,mCAAmC;AAC7C,QAAQ,+BAA+B;AACvC,QAAQ,iBAAiB;AACzB,QAAQ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AAC9B,QAAQA,SAAA,IAAWA,SAAO;AAC1B,QAAQ;AACR,UAAU,IAAI,6BAA6B;AAC3C;AACA;AACA;AACA;AACA,YAAY,8CAA8C;AAC1D,YAAY,iBAAiB;AAC7B,YAAY,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;AAClC,YAAYA,SAAA,IAAWA,SAAO;AAC9B,WAAW;AACX,SAAS;AACT,OAAO;AACP,KAAK;AACL,EAAE;;AAEF;AACA;AACA;AACA,GAAU,MAAM,CAACA,SAAO,EAAqD;AAC7E,IAAI,MAAM,MAAA,GAAS,SAAS,EAAE;AAC9B,IAAI,MAAM,UAAU;AACpB,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE;AACzB,MAAM,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,YAAA,IAAgB,MAAM,EAAE,UAAU,EAAE,CAAC,cAAc;AACxF,MAAM,aAAa,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,aAAA,IAAiB,MAAM,EAAE,UAAU,EAAE,CAAC,cAAc;AAC1F,KAAK;;AAEL;AACA,IAAI,IAAIA,SAAO,CAAC,UAAA,IAAc,OAAOA,SAAO,CAAC,UAAA,KAAe,UAAU,EAAE;AACxE,MAAM,mBAAmB,CAACA,SAAO,CAAC,UAAU,CAAC,SAAA,GAA2D,OAAO,CAAC;AAChH,IAAI;;AAEJ;AACA,IAAI,IAAIA,SAAO,CAAC,gBAAA,IAAoB,OAAOA,SAAO,CAAC,gBAAA,KAAqB,UAAU,EAAE;AACpF,MAAM,MAAM,wBAAA,GAA2BA,SAAO,CAAC,gBAAgB;AAC/D,MAAM,MAAM,CAAC,cAAc,CAACA,SAAO,EAAE,kBAAkB,EAAE;AACzD,QAAQ,KAAK,EAAE,0BAA0B,CAAC,wBAAA,GAAmE,OAAO,CAAC;AACrH,QAAQ,QAAQ,EAAE,IAAI;AACtB,QAAQ,UAAU,EAAE,IAAI;AACxB,QAAQ,YAAY,EAAE,IAAI;AAC1B,OAAO,CAAC;AACR,IAAI;;AAEJ,IAAI,OAAOA,SAAO;AAClB,EAAE;AACF;;;;"}
@@ -181,8 +181,12 @@ const prismaIntegration = defineIntegration((options) => {
181
181
  span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.prisma');
182
182
  }
183
183
 
184
- // Make sure we use the query text as the span name, for ex. SELECT * FROM "User" WHERE "id" = $1
185
- if (spanJSON.description === 'prisma:engine:db_query' && spanJSON.data['db.query.text']) {
184
+ // Make sure we use the query text as the span name, for ex. SELECT * FROM "User" WHERE "id" = $1.
185
+ // v5/v6 emit `prisma:engine:db_query`; v7 inlined the engine and emits `prisma:client:db_query`.
186
+ if (
187
+ (spanJSON.description === 'prisma:engine:db_query' || spanJSON.description === 'prisma:client:db_query') &&
188
+ spanJSON.data['db.query.text']
189
+ ) {
186
190
  span.updateName(spanJSON.data['db.query.text'] );
187
191
  }
188
192
 
@@ -1 +1 @@
1
- {"version":3,"file":"prisma.js","sources":["../../../../src/integrations/tracing/prisma.ts"],"sourcesContent":["import type { Link, Tracer } from '@opentelemetry/api';\nimport { context, SpanKind, trace, TraceFlags } from '@opentelemetry/api';\nimport type { Instrumentation } from '@opentelemetry/instrumentation';\nimport type { IdGenerator } from '@opentelemetry/sdk-trace-base';\nimport { PrismaInstrumentation } from '@prisma/instrumentation';\nimport { consoleSandbox, defineIntegration, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, spanToJSON } from '@sentry/core';\nimport { generateInstrumentOnce } from '@sentry/node-core';\nimport type { PrismaV5TracingHelper } from './prisma/vendor/v5-tracing-helper';\nimport type { PrismaV6TracingHelper } from './prisma/vendor/v6-tracing-helper';\n\nconst INTEGRATION_NAME = 'Prisma';\n\ntype CompatibilityLayerTraceHelper = PrismaV5TracingHelper & PrismaV6TracingHelper;\n\n// Vendored in from @prisma/instrumentation v5:\ntype V5EngineSpanEvent = {\n span: boolean;\n spans: V5EngineSpan[];\n};\n\ntype V5EngineSpanKind = 'client' | 'internal';\n\ntype V5EngineSpan = {\n span: boolean;\n name: string;\n trace_id: string;\n span_id: string;\n parent_span_id: string;\n start_time: [number, number];\n end_time: [number, number];\n attributes?: Record<string, string>;\n links?: { trace_id: string; span_id: string }[];\n kind: V5EngineSpanKind;\n};\n\nfunction isPrismaV6TracingHelper(helper: unknown): helper is PrismaV6TracingHelper {\n return !!helper && typeof helper === 'object' && 'dispatchEngineSpans' in helper;\n}\n\nfunction getPrismaTracingHelper(): unknown | undefined {\n const prismaInstrumentationObject = (globalThis as Record<string, unknown>).PRISMA_INSTRUMENTATION;\n const prismaTracingHelper =\n prismaInstrumentationObject &&\n typeof prismaInstrumentationObject === 'object' &&\n 'helper' in prismaInstrumentationObject\n ? prismaInstrumentationObject.helper\n : undefined;\n\n return prismaTracingHelper;\n}\n\ntype TracerWithIdGenerator = Tracer & {\n _idGenerator?: IdGenerator;\n};\n\ninterface PrismaOptions {\n /**\n * @deprecated This is no longer used, v5 works out of the box.\n */\n prismaInstrumentation?: Instrumentation;\n /**\n * Configuration passed through to the {@link PrismaInstrumentation} constructor.\n */\n instrumentationConfig?: ConstructorParameters<typeof PrismaInstrumentation>[0];\n}\n\nclass SentryPrismaInteropInstrumentation extends PrismaInstrumentation {\n public constructor(options?: PrismaOptions) {\n super(options?.instrumentationConfig);\n }\n\n public enable(): void {\n super.enable();\n\n // The PrismaIntegration (super class) defines a global variable `global[\"PRISMA_INSTRUMENTATION\"]` when `enable()` is called. This global variable holds a \"TracingHelper\" which Prisma uses internally to create tracing data. It's their way of not depending on OTEL with their main package. The sucky thing is, prisma broke the interface of the tracing helper with the v6 major update. This means that if you use Prisma 5 with the v6 instrumentation (or vice versa) Prisma just blows up, because tries to call methods on the helper that no longer exist.\n // Because we actually want to use the v6 instrumentation and not blow up in Prisma 5 user's faces, what we're doing here is backfilling the v5 method (`createEngineSpan`) with a noop so that no longer crashes when it attempts to call that function.\n const prismaTracingHelper = getPrismaTracingHelper();\n\n if (isPrismaV6TracingHelper(prismaTracingHelper)) {\n // Inspired & adjusted from https://github.com/prisma/prisma/tree/5.22.0/packages/instrumentation\n (prismaTracingHelper as CompatibilityLayerTraceHelper).createEngineSpan = (\n engineSpanEvent: V5EngineSpanEvent,\n ) => {\n const tracer = trace.getTracer('prismaV5Compatibility') as TracerWithIdGenerator;\n\n // Prisma v5 relies on being able to create spans with a specific span & trace ID\n // this is no longer possible in OTEL v2, there is no public API to do this anymore\n // So in order to kind of hack this possibility, we rely on the internal `_idGenerator` property\n // This is used to generate the random IDs, and we overwrite this temporarily to generate static IDs\n // This is flawed and may not work, e.g. if the code is bundled and the private property is renamed\n // in such cases, these spans will not be captured and some Prisma spans will be missing\n const initialIdGenerator = tracer._idGenerator;\n\n if (!initialIdGenerator) {\n consoleSandbox(() => {\n // eslint-disable-next-line no-console\n console.warn(\n '[Sentry] Could not find _idGenerator on tracer, skipping Prisma v5 compatibility - some Prisma spans may be missing!',\n );\n });\n\n return;\n }\n\n try {\n engineSpanEvent.spans.forEach(engineSpan => {\n const kind = engineSpanKindToOTELSpanKind(engineSpan.kind);\n\n const parentSpanId = engineSpan.parent_span_id;\n const spanId = engineSpan.span_id;\n const traceId = engineSpan.trace_id;\n\n const links: Link[] | undefined = engineSpan.links?.map(link => {\n return {\n context: {\n traceId: link.trace_id,\n spanId: link.span_id,\n traceFlags: TraceFlags.SAMPLED,\n },\n };\n });\n\n const ctx = trace.setSpanContext(context.active(), {\n traceId,\n spanId: parentSpanId,\n traceFlags: TraceFlags.SAMPLED,\n });\n\n context.with(ctx, () => {\n const temporaryIdGenerator: IdGenerator = {\n generateTraceId: () => {\n return traceId;\n },\n generateSpanId: () => {\n return spanId;\n },\n };\n\n tracer._idGenerator = temporaryIdGenerator;\n\n const span = tracer.startSpan(engineSpan.name, {\n kind,\n links,\n startTime: engineSpan.start_time,\n attributes: engineSpan.attributes,\n });\n\n span.end(engineSpan.end_time);\n\n tracer._idGenerator = initialIdGenerator;\n });\n });\n } finally {\n // Ensure we always restore this at the end, even if something errors\n tracer._idGenerator = initialIdGenerator;\n }\n };\n }\n }\n}\n\nfunction engineSpanKindToOTELSpanKind(engineSpanKind: V5EngineSpanKind): SpanKind {\n switch (engineSpanKind) {\n case 'client':\n return SpanKind.CLIENT;\n case 'internal':\n default: // Other span kinds aren't currently supported\n return SpanKind.INTERNAL;\n }\n}\n\nexport const instrumentPrisma = generateInstrumentOnce<PrismaOptions>(INTEGRATION_NAME, options => {\n return new SentryPrismaInteropInstrumentation(options);\n});\n\n/**\n * Adds Sentry tracing instrumentation for the [prisma](https://www.npmjs.com/package/prisma) library.\n * For more information, see the [`prismaIntegration` documentation](https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/prisma/).\n *\n * NOTE: By default, this integration works with Prisma version 6.\n * To get performance instrumentation for other Prisma versions,\n * 1. Install the `@prisma/instrumentation` package with the desired version.\n * 1. Pass a `new PrismaInstrumentation()` instance as exported from `@prisma/instrumentation` to the `prismaInstrumentation` option of this integration:\n *\n * ```js\n * import { PrismaInstrumentation } from '@prisma/instrumentation'\n *\n * Sentry.init({\n * integrations: [\n * prismaIntegration({\n * // Override the default instrumentation that Sentry uses\n * prismaInstrumentation: new PrismaInstrumentation()\n * })\n * ]\n * })\n * ```\n *\n * The passed instrumentation instance will override the default instrumentation instance the integration would use, while the `prismaIntegration` will still ensure data compatibility for the various Prisma versions.\n * 1. Depending on your Prisma version (prior to version 6), add `previewFeatures = [\"tracing\"]` to the client generator block of your Prisma schema:\n *\n * ```\n * generator client {\n * provider = \"prisma-client-js\"\n * previewFeatures = [\"tracing\"]\n * }\n * ```\n */\nexport const prismaIntegration = defineIntegration((options?: PrismaOptions) => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n instrumentPrisma(options);\n },\n setup(client) {\n // If no tracing helper exists, we skip any work here\n // this means that prisma is not being used\n if (!getPrismaTracingHelper()) {\n return;\n }\n\n client.on('spanStart', span => {\n const spanJSON = spanToJSON(span);\n if (spanJSON.description?.startsWith('prisma:')) {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.prisma');\n }\n\n // Make sure we use the query text as the span name, for ex. SELECT * FROM \"User\" WHERE \"id\" = $1\n if (spanJSON.description === 'prisma:engine:db_query' && spanJSON.data['db.query.text']) {\n span.updateName(spanJSON.data['db.query.text'] as string);\n }\n\n // In Prisma v5.22+, the `db.system` attribute is automatically set\n // On older versions, this is missing, so we add it here\n if (spanJSON.description === 'prisma:engine:db_query' && !spanJSON.data['db.system']) {\n span.setAttribute('db.system', 'prisma');\n }\n });\n },\n };\n});\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prisma.js","sources":["../../../../src/integrations/tracing/prisma.ts"],"sourcesContent":["import type { Link, Tracer } from '@opentelemetry/api';\nimport { context, SpanKind, trace, TraceFlags } from '@opentelemetry/api';\nimport type { Instrumentation } from '@opentelemetry/instrumentation';\nimport type { IdGenerator } from '@opentelemetry/sdk-trace-base';\nimport { PrismaInstrumentation } from '@prisma/instrumentation';\nimport { consoleSandbox, defineIntegration, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, spanToJSON } from '@sentry/core';\nimport { generateInstrumentOnce } from '@sentry/node-core';\nimport type { PrismaV5TracingHelper } from './prisma/vendor/v5-tracing-helper';\nimport type { PrismaV6TracingHelper } from './prisma/vendor/v6-tracing-helper';\n\nconst INTEGRATION_NAME = 'Prisma';\n\ntype CompatibilityLayerTraceHelper = PrismaV5TracingHelper & PrismaV6TracingHelper;\n\n// Vendored in from @prisma/instrumentation v5:\ntype V5EngineSpanEvent = {\n span: boolean;\n spans: V5EngineSpan[];\n};\n\ntype V5EngineSpanKind = 'client' | 'internal';\n\ntype V5EngineSpan = {\n span: boolean;\n name: string;\n trace_id: string;\n span_id: string;\n parent_span_id: string;\n start_time: [number, number];\n end_time: [number, number];\n attributes?: Record<string, string>;\n links?: { trace_id: string; span_id: string }[];\n kind: V5EngineSpanKind;\n};\n\nfunction isPrismaV6TracingHelper(helper: unknown): helper is PrismaV6TracingHelper {\n return !!helper && typeof helper === 'object' && 'dispatchEngineSpans' in helper;\n}\n\nfunction getPrismaTracingHelper(): unknown | undefined {\n const prismaInstrumentationObject = (globalThis as Record<string, unknown>).PRISMA_INSTRUMENTATION;\n const prismaTracingHelper =\n prismaInstrumentationObject &&\n typeof prismaInstrumentationObject === 'object' &&\n 'helper' in prismaInstrumentationObject\n ? prismaInstrumentationObject.helper\n : undefined;\n\n return prismaTracingHelper;\n}\n\ntype TracerWithIdGenerator = Tracer & {\n _idGenerator?: IdGenerator;\n};\n\ninterface PrismaOptions {\n /**\n * @deprecated This is no longer used, v5 works out of the box.\n */\n prismaInstrumentation?: Instrumentation;\n /**\n * Configuration passed through to the {@link PrismaInstrumentation} constructor.\n */\n instrumentationConfig?: ConstructorParameters<typeof PrismaInstrumentation>[0];\n}\n\nclass SentryPrismaInteropInstrumentation extends PrismaInstrumentation {\n public constructor(options?: PrismaOptions) {\n super(options?.instrumentationConfig);\n }\n\n public enable(): void {\n super.enable();\n\n // The PrismaIntegration (super class) defines a global variable `global[\"PRISMA_INSTRUMENTATION\"]` when `enable()` is called. This global variable holds a \"TracingHelper\" which Prisma uses internally to create tracing data. It's their way of not depending on OTEL with their main package. The sucky thing is, prisma broke the interface of the tracing helper with the v6 major update. This means that if you use Prisma 5 with the v6 instrumentation (or vice versa) Prisma just blows up, because tries to call methods on the helper that no longer exist.\n // Because we actually want to use the v6 instrumentation and not blow up in Prisma 5 user's faces, what we're doing here is backfilling the v5 method (`createEngineSpan`) with a noop so that no longer crashes when it attempts to call that function.\n const prismaTracingHelper = getPrismaTracingHelper();\n\n if (isPrismaV6TracingHelper(prismaTracingHelper)) {\n // Inspired & adjusted from https://github.com/prisma/prisma/tree/5.22.0/packages/instrumentation\n (prismaTracingHelper as CompatibilityLayerTraceHelper).createEngineSpan = (\n engineSpanEvent: V5EngineSpanEvent,\n ) => {\n const tracer = trace.getTracer('prismaV5Compatibility') as TracerWithIdGenerator;\n\n // Prisma v5 relies on being able to create spans with a specific span & trace ID\n // this is no longer possible in OTEL v2, there is no public API to do this anymore\n // So in order to kind of hack this possibility, we rely on the internal `_idGenerator` property\n // This is used to generate the random IDs, and we overwrite this temporarily to generate static IDs\n // This is flawed and may not work, e.g. if the code is bundled and the private property is renamed\n // in such cases, these spans will not be captured and some Prisma spans will be missing\n const initialIdGenerator = tracer._idGenerator;\n\n if (!initialIdGenerator) {\n consoleSandbox(() => {\n // eslint-disable-next-line no-console\n console.warn(\n '[Sentry] Could not find _idGenerator on tracer, skipping Prisma v5 compatibility - some Prisma spans may be missing!',\n );\n });\n\n return;\n }\n\n try {\n engineSpanEvent.spans.forEach(engineSpan => {\n const kind = engineSpanKindToOTELSpanKind(engineSpan.kind);\n\n const parentSpanId = engineSpan.parent_span_id;\n const spanId = engineSpan.span_id;\n const traceId = engineSpan.trace_id;\n\n const links: Link[] | undefined = engineSpan.links?.map(link => {\n return {\n context: {\n traceId: link.trace_id,\n spanId: link.span_id,\n traceFlags: TraceFlags.SAMPLED,\n },\n };\n });\n\n const ctx = trace.setSpanContext(context.active(), {\n traceId,\n spanId: parentSpanId,\n traceFlags: TraceFlags.SAMPLED,\n });\n\n context.with(ctx, () => {\n const temporaryIdGenerator: IdGenerator = {\n generateTraceId: () => {\n return traceId;\n },\n generateSpanId: () => {\n return spanId;\n },\n };\n\n tracer._idGenerator = temporaryIdGenerator;\n\n const span = tracer.startSpan(engineSpan.name, {\n kind,\n links,\n startTime: engineSpan.start_time,\n attributes: engineSpan.attributes,\n });\n\n span.end(engineSpan.end_time);\n\n tracer._idGenerator = initialIdGenerator;\n });\n });\n } finally {\n // Ensure we always restore this at the end, even if something errors\n tracer._idGenerator = initialIdGenerator;\n }\n };\n }\n }\n}\n\nfunction engineSpanKindToOTELSpanKind(engineSpanKind: V5EngineSpanKind): SpanKind {\n switch (engineSpanKind) {\n case 'client':\n return SpanKind.CLIENT;\n case 'internal':\n default: // Other span kinds aren't currently supported\n return SpanKind.INTERNAL;\n }\n}\n\nexport const instrumentPrisma = generateInstrumentOnce<PrismaOptions>(INTEGRATION_NAME, options => {\n return new SentryPrismaInteropInstrumentation(options);\n});\n\n/**\n * Adds Sentry tracing instrumentation for the [prisma](https://www.npmjs.com/package/prisma) library.\n * For more information, see the [`prismaIntegration` documentation](https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/prisma/).\n *\n * NOTE: By default, this integration works with Prisma version 6.\n * To get performance instrumentation for other Prisma versions,\n * 1. Install the `@prisma/instrumentation` package with the desired version.\n * 1. Pass a `new PrismaInstrumentation()` instance as exported from `@prisma/instrumentation` to the `prismaInstrumentation` option of this integration:\n *\n * ```js\n * import { PrismaInstrumentation } from '@prisma/instrumentation'\n *\n * Sentry.init({\n * integrations: [\n * prismaIntegration({\n * // Override the default instrumentation that Sentry uses\n * prismaInstrumentation: new PrismaInstrumentation()\n * })\n * ]\n * })\n * ```\n *\n * The passed instrumentation instance will override the default instrumentation instance the integration would use, while the `prismaIntegration` will still ensure data compatibility for the various Prisma versions.\n * 1. Depending on your Prisma version (prior to version 6), add `previewFeatures = [\"tracing\"]` to the client generator block of your Prisma schema:\n *\n * ```\n * generator client {\n * provider = \"prisma-client-js\"\n * previewFeatures = [\"tracing\"]\n * }\n * ```\n */\nexport const prismaIntegration = defineIntegration((options?: PrismaOptions) => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n instrumentPrisma(options);\n },\n setup(client) {\n // If no tracing helper exists, we skip any work here\n // this means that prisma is not being used\n if (!getPrismaTracingHelper()) {\n return;\n }\n\n client.on('spanStart', span => {\n const spanJSON = spanToJSON(span);\n if (spanJSON.description?.startsWith('prisma:')) {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.prisma');\n }\n\n // Make sure we use the query text as the span name, for ex. SELECT * FROM \"User\" WHERE \"id\" = $1.\n // v5/v6 emit `prisma:engine:db_query`; v7 inlined the engine and emits `prisma:client:db_query`.\n if (\n (spanJSON.description === 'prisma:engine:db_query' || spanJSON.description === 'prisma:client:db_query') &&\n spanJSON.data['db.query.text']\n ) {\n span.updateName(spanJSON.data['db.query.text'] as string);\n }\n\n // In Prisma v5.22+, the `db.system` attribute is automatically set\n // On older versions, this is missing, so we add it here\n if (spanJSON.description === 'prisma:engine:db_query' && !spanJSON.data['db.system']) {\n span.setAttribute('db.system', 'prisma');\n }\n });\n },\n };\n});\n"],"names":[],"mappings":"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"}
@@ -1,8 +1,9 @@
1
- import { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis';
2
- import { RedisInstrumentation } from '@opentelemetry/instrumentation-redis';
3
- import { defineIntegration, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, spanToJSON, SEMANTIC_ATTRIBUTE_CACHE_ITEM_SIZE, SEMANTIC_ATTRIBUTE_CACHE_HIT, SEMANTIC_ATTRIBUTE_CACHE_KEY, SEMANTIC_ATTRIBUTE_SENTRY_OP, truncate } from '@sentry/core';
1
+ import { defineIntegration, spanToJSON, SEMANTIC_ATTRIBUTE_CACHE_ITEM_SIZE, SEMANTIC_ATTRIBUTE_CACHE_HIT, SEMANTIC_ATTRIBUTE_CACHE_KEY, SEMANTIC_ATTRIBUTE_SENTRY_OP, truncate } from '@sentry/core';
4
2
  import { generateInstrumentOnce } from '@sentry/node-core';
5
- import { getCacheKeySafely, getCacheOperation, shouldConsiderForCache, calculateCacheItemSize, isInCommands, GET_COMMANDS } from '../../utils/redisCache.js';
3
+ import { getCacheKeySafely, getCacheOperation, shouldConsiderForCache, calculateCacheItemSize, isInCommands, GET_COMMANDS } from '../../../utils/redisCache.js';
4
+ import { IORedisInstrumentation } from './vendored/ioredis-instrumentation.js';
5
+ import { RedisInstrumentation } from './vendored/redis-instrumentation.js';
6
+ import { subscribeRedisDiagnosticChannels } from './redis-dc-subscriber.js';
6
7
 
7
8
  const INTEGRATION_NAME = 'Redis';
8
9
 
@@ -16,8 +17,6 @@ const cacheResponseHook = (
16
17
  cmdArgs,
17
18
  response,
18
19
  ) => {
19
- span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.redis');
20
-
21
20
  const safeKey = getCacheKeySafely(redisCommand, cmdArgs);
22
21
  const cacheOperation = getCacheOperation(redisCommand);
23
22
 
@@ -33,8 +32,12 @@ const cacheResponseHook = (
33
32
 
34
33
  // otel/ioredis seems to be using the old standard, as there was a change to those params: https://github.com/open-telemetry/opentelemetry-specification/issues/3199
35
34
  // We are using params based on the docs: https://opentelemetry.io/docs/specs/semconv/attributes-registry/network/
36
- const networkPeerAddress = spanToJSON(span).data['net.peer.name'];
37
- const networkPeerPort = spanToJSON(span).data['net.peer.port'];
35
+ // Fall back to stable semconv attributes (server.address/server.port) when
36
+ // old-semconv ones are absent, eg OTEL_SEMCONV_STABILITY_OPT_IN=database
37
+ // set for node-redis v4/v5.
38
+ const spanData = spanToJSON(span).data;
39
+ const networkPeerAddress = spanData['net.peer.name'] ?? spanData['server.address'];
40
+ const networkPeerPort = spanData['net.peer.port'] ?? spanData['server.port'];
38
41
  if (networkPeerPort && networkPeerAddress) {
39
42
  span.setAttributes({ 'network.peer.address': networkPeerAddress, 'network.peer.port': networkPeerPort });
40
43
  }
@@ -79,6 +82,11 @@ const instrumentRedis = Object.assign(
79
82
  () => {
80
83
  instrumentIORedis();
81
84
  instrumentRedisModule();
85
+ // node-redis >= 5.12.0 publishes via diagnostics_channel. The subscriber uses
86
+ // `@sentry/opentelemetry/tracing-channel`, which needs the Sentry OTel context manager
87
+ // to be registered before it can `bindStore`. `initOpenTelemetry()` runs after integration
88
+ // `setupOnce`, so defer to the next tick.
89
+ void Promise.resolve().then(() => subscribeRedisDiagnosticChannels(cacheResponseHook));
82
90
 
83
91
  // todo: implement them gradually
84
92
  // new LegacyRedisInstrumentation({}),
@@ -114,4 +122,4 @@ const _redisIntegration = ((options = {}) => {
114
122
  const redisIntegration = defineIntegration(_redisIntegration);
115
123
 
116
124
  export { _redisOptions, cacheResponseHook, instrumentRedis, redisIntegration };
117
- //# sourceMappingURL=redis.js.map
125
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../../../src/integrations/tracing/redis/index.ts"],"sourcesContent":["import type { Span } from '@opentelemetry/api';\nimport type { IntegrationFn } from '@sentry/core';\nimport {\n defineIntegration,\n SEMANTIC_ATTRIBUTE_CACHE_HIT,\n SEMANTIC_ATTRIBUTE_CACHE_ITEM_SIZE,\n SEMANTIC_ATTRIBUTE_CACHE_KEY,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n spanToJSON,\n truncate,\n} from '@sentry/core';\nimport { generateInstrumentOnce } from '@sentry/node-core';\nimport type { IORedisCommandArgs } from '../../../utils/redisCache';\nimport {\n calculateCacheItemSize,\n GET_COMMANDS,\n getCacheKeySafely,\n getCacheOperation,\n isInCommands,\n shouldConsiderForCache,\n} from '../../../utils/redisCache';\nimport type { IORedisResponseCustomAttributeFunction } from './vendored/types';\nimport { IORedisInstrumentation } from './vendored/ioredis-instrumentation';\nimport { RedisInstrumentation } from './vendored/redis-instrumentation';\nimport { subscribeRedisDiagnosticChannels } from './redis-dc-subscriber';\n\ninterface RedisOptions {\n /**\n * Define cache prefixes for cache keys that should be captured as a cache span.\n *\n * Setting this to, for example, `['user:']` will capture cache keys that start with `user:`.\n */\n cachePrefixes?: string[];\n /**\n * Maximum length of the cache key added to the span description. If the key exceeds this length, it will be truncated.\n *\n * Passing `0` will use the full cache key without truncation.\n *\n * By default, the full cache key is used.\n */\n maxCacheKeyLength?: number;\n}\n\nconst INTEGRATION_NAME = 'Redis';\n\n/* Only exported for testing purposes */\nexport let _redisOptions: RedisOptions = {};\n\n/* Only exported for testing purposes */\nexport const cacheResponseHook: IORedisResponseCustomAttributeFunction = (\n span: Span,\n redisCommand: string,\n cmdArgs: IORedisCommandArgs,\n response: unknown,\n) => {\n const safeKey = getCacheKeySafely(redisCommand, cmdArgs);\n const cacheOperation = getCacheOperation(redisCommand);\n\n if (\n !safeKey ||\n !cacheOperation ||\n !_redisOptions.cachePrefixes ||\n !shouldConsiderForCache(redisCommand, safeKey, _redisOptions.cachePrefixes)\n ) {\n // not relevant for cache\n return;\n }\n\n // otel/ioredis seems to be using the old standard, as there was a change to those params: https://github.com/open-telemetry/opentelemetry-specification/issues/3199\n // We are using params based on the docs: https://opentelemetry.io/docs/specs/semconv/attributes-registry/network/\n // Fall back to stable semconv attributes (server.address/server.port) when\n // old-semconv ones are absent, eg OTEL_SEMCONV_STABILITY_OPT_IN=database\n // set for node-redis v4/v5.\n const spanData = spanToJSON(span).data;\n const networkPeerAddress = spanData['net.peer.name'] ?? spanData['server.address'];\n const networkPeerPort = spanData['net.peer.port'] ?? spanData['server.port'];\n if (networkPeerPort && networkPeerAddress) {\n span.setAttributes({ 'network.peer.address': networkPeerAddress, 'network.peer.port': networkPeerPort });\n }\n\n const cacheItemSize = calculateCacheItemSize(response);\n\n if (cacheItemSize) {\n span.setAttribute(SEMANTIC_ATTRIBUTE_CACHE_ITEM_SIZE, cacheItemSize);\n }\n\n if (isInCommands(GET_COMMANDS, redisCommand) && cacheItemSize !== undefined) {\n span.setAttribute(SEMANTIC_ATTRIBUTE_CACHE_HIT, cacheItemSize > 0);\n }\n\n span.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: cacheOperation,\n [SEMANTIC_ATTRIBUTE_CACHE_KEY]: safeKey,\n });\n\n // todo: change to string[] once EAP supports it\n const spanDescription = safeKey.join(', ');\n\n span.updateName(\n _redisOptions.maxCacheKeyLength ? truncate(spanDescription, _redisOptions.maxCacheKeyLength) : spanDescription,\n );\n};\n\nconst instrumentIORedis = generateInstrumentOnce(`${INTEGRATION_NAME}.IORedis`, () => {\n return new IORedisInstrumentation({\n responseHook: cacheResponseHook,\n });\n});\n\nconst instrumentRedisModule = generateInstrumentOnce(`${INTEGRATION_NAME}.Redis`, () => {\n return new RedisInstrumentation({\n responseHook: cacheResponseHook,\n });\n});\n\n/** To be able to preload all Redis OTel instrumentations with just one ID (\"Redis\"), all the instrumentations are generated in this one function */\nexport const instrumentRedis = Object.assign(\n (): void => {\n instrumentIORedis();\n instrumentRedisModule();\n // node-redis >= 5.12.0 publishes via diagnostics_channel. The subscriber uses\n // `@sentry/opentelemetry/tracing-channel`, which needs the Sentry OTel context manager\n // to be registered before it can `bindStore`. `initOpenTelemetry()` runs after integration\n // `setupOnce`, so defer to the next tick.\n void Promise.resolve().then(() => subscribeRedisDiagnosticChannels(cacheResponseHook));\n\n // todo: implement them gradually\n // new LegacyRedisInstrumentation({}),\n },\n { id: INTEGRATION_NAME },\n);\n\nconst _redisIntegration = ((options: RedisOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n _redisOptions = options;\n instrumentRedis();\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for the [redis](https://www.npmjs.com/package/redis) and\n * [ioredis](https://www.npmjs.com/package/ioredis) libraries.\n *\n * For more information, see the [`redisIntegration` documentation](https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/redis/).\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n *\n * Sentry.init({\n * integrations: [Sentry.redisIntegration()],\n * });\n * ```\n */\nexport const redisIntegration = defineIntegration(_redisIntegration);\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,184 @@
1
+ import { startSpanManual, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_STATUS_ERROR } from '@sentry/core';
2
+ import { tracingChannel } from '@sentry/opentelemetry/tracing-channel';
3
+ import { defaultDbStatementSerializer } from './vendored/redis-common.js';
4
+ import { DB_SYSTEM_VALUE_REDIS, ATTR_NET_PEER_PORT, ATTR_NET_PEER_NAME, ATTR_DB_STATEMENT, ATTR_DB_SYSTEM } from './vendored/semconv.js';
5
+
6
+ // Channel names as published by node-redis >= 5.12.0.
7
+ // Hardcoded so we don't import `redis` at module-load time.
8
+ const CHANNEL_COMMAND = 'node-redis:command';
9
+ const CHANNEL_BATCH = 'node-redis:batch';
10
+ const CHANNEL_CONNECT = 'node-redis:connect';
11
+
12
+ const ORIGIN = 'auto.db.redis.diagnostic_channel';
13
+
14
+ const NOOP = () => {};
15
+
16
+ let subscribed = false;
17
+ let currentResponseHook;
18
+
19
+ /**
20
+ * Subscribe Sentry handlers to node-redis diagnostics_channel events (>= 5.12.0).
21
+ *
22
+ * Uses `@sentry/opentelemetry/tracing-channel` so OTel AsyncLocalStorage context propagates
23
+ * automatically via `bindStore` — without it, spans created in `start` would not become
24
+ * the active context for subsequent operations.
25
+ *
26
+ * Safe on every runtime that exposes `node:diagnostics_channel` (Node, Bun, Deno, Workers).
27
+ * In node-redis < 5.12.0 the channels are never published to, so subscribers are inert and
28
+ * there is no double-instrumentation against the IITM-based patcher (gated to < 5.12.0).
29
+ */
30
+ function subscribeRedisDiagnosticChannels(responseHook) {
31
+ currentResponseHook = responseHook;
32
+ if (subscribed) return;
33
+
34
+ try {
35
+ setupCommandChannel();
36
+ setupBatchChannel();
37
+ setupConnectChannel();
38
+ subscribed = true;
39
+ } catch {
40
+ // tracingChannel from @sentry/opentelemetry requires `node:diagnostics_channel`.
41
+ // On runtimes where it isn't available, fail closed.
42
+ }
43
+ }
44
+
45
+ function setupCommandChannel() {
46
+ const channel = tracingChannel(CHANNEL_COMMAND, data => {
47
+ // node-redis >= 5.12.0 includes the command name as args[0] in the DC payload.
48
+ // Strip it so serialization and cache key extraction see only the actual arguments.
49
+ const actualArgs = data.args.slice(1);
50
+ const statement = safeSerialize(data.command, actualArgs);
51
+ return startSpanManual(
52
+ {
53
+ name: `redis-${data.command}`,
54
+ attributes: {
55
+ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,
56
+ [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db.redis',
57
+ [ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_REDIS,
58
+ ...(statement != null ? { [ATTR_DB_STATEMENT]: statement } : {}),
59
+ ...(data.serverAddress != null ? { [ATTR_NET_PEER_NAME]: data.serverAddress } : {}),
60
+ ...(data.serverPort != null ? { [ATTR_NET_PEER_PORT]: data.serverPort } : {}),
61
+ },
62
+ },
63
+ span => span,
64
+ ) ;
65
+ });
66
+
67
+ channel.subscribe({
68
+ start: NOOP,
69
+ asyncStart: NOOP,
70
+ end: NOOP,
71
+ asyncEnd: data => {
72
+ const span = data._sentrySpan;
73
+ // only end if error handler isn't going to
74
+ if (!span || data.error) return;
75
+ // Same slice: strip command name from args before passing to the response hook.
76
+ runResponseHook(span, data.command, data.args.slice(1), data.result);
77
+ span.end();
78
+ },
79
+ error: data => {
80
+ const span = data._sentrySpan;
81
+ if (!span) return;
82
+ if (data.error) {
83
+ span.setStatus({ code: SPAN_STATUS_ERROR, message: data.error.message });
84
+ }
85
+ span.end();
86
+ },
87
+ });
88
+ }
89
+
90
+ function setupBatchChannel() {
91
+ const channel = tracingChannel(CHANNEL_BATCH, data => {
92
+ const operationName = data.batchMode === 'PIPELINE' ? 'PIPELINE' : 'MULTI';
93
+
94
+ return startSpanManual(
95
+ {
96
+ name: operationName,
97
+ attributes: {
98
+ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,
99
+ [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db.redis',
100
+ [ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_REDIS,
101
+ ...(data.batchSize != null ? { 'db.redis.batch_size': data.batchSize } : {}),
102
+ ...(data.serverAddress != null ? { [ATTR_NET_PEER_NAME]: data.serverAddress } : {}),
103
+ ...(data.serverPort != null ? { [ATTR_NET_PEER_PORT]: data.serverPort } : {}),
104
+ },
105
+ },
106
+ span => span,
107
+ ) ;
108
+ });
109
+
110
+ channel.subscribe({
111
+ start: NOOP,
112
+ asyncStart: NOOP,
113
+ end: NOOP,
114
+ asyncEnd: data => {
115
+ // only end if the error handler isn't going to
116
+ if (!data.error) data._sentrySpan?.end();
117
+ },
118
+ error: data => {
119
+ const span = data._sentrySpan;
120
+ if (!span) return;
121
+ if (data.error) {
122
+ span.setStatus({ code: SPAN_STATUS_ERROR, message: data.error.message });
123
+ }
124
+ span.end();
125
+ },
126
+ });
127
+ }
128
+
129
+ function setupConnectChannel() {
130
+ const channel = tracingChannel(CHANNEL_CONNECT, data => {
131
+ return startSpanManual(
132
+ {
133
+ name: 'redis-connect',
134
+ attributes: {
135
+ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,
136
+ [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db.redis.connect',
137
+ [ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_REDIS,
138
+ ...(data.serverAddress != null ? { [ATTR_NET_PEER_NAME]: data.serverAddress } : {}),
139
+ ...(data.serverPort != null ? { [ATTR_NET_PEER_PORT]: data.serverPort } : {}),
140
+ },
141
+ },
142
+ span => span,
143
+ ) ;
144
+ });
145
+
146
+ channel.subscribe({
147
+ start: NOOP,
148
+ asyncStart: NOOP,
149
+ end: NOOP,
150
+ asyncEnd: data => {
151
+ // only end if the error handler isn't going to
152
+ if (!data.error) data._sentrySpan?.end();
153
+ },
154
+ error: data => {
155
+ const span = data._sentrySpan;
156
+ if (!span) return;
157
+ if (data.error) {
158
+ span.setStatus({ code: SPAN_STATUS_ERROR, message: data.error.message });
159
+ }
160
+ span.end();
161
+ },
162
+ });
163
+ }
164
+
165
+ function runResponseHook(span, command, args, result) {
166
+ const hook = currentResponseHook;
167
+ if (!hook) return;
168
+ try {
169
+ hook(span, command, args , result);
170
+ } catch {
171
+ // never let user hooks break instrumentation
172
+ }
173
+ }
174
+
175
+ function safeSerialize(command, args) {
176
+ try {
177
+ return defaultDbStatementSerializer(command, args);
178
+ } catch {
179
+ return undefined;
180
+ }
181
+ }
182
+
183
+ export { subscribeRedisDiagnosticChannels };
184
+ //# sourceMappingURL=redis-dc-subscriber.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis-dc-subscriber.js","sources":["../../../../../src/integrations/tracing/redis/redis-dc-subscriber.ts"],"sourcesContent":["import type { Span } from '@opentelemetry/api';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n startSpanManual,\n} from '@sentry/core';\nimport { tracingChannel, type TracingChannelContextWithSpan } from '@sentry/opentelemetry/tracing-channel';\nimport { defaultDbStatementSerializer } from './vendored/redis-common';\nimport {\n ATTR_DB_STATEMENT,\n ATTR_DB_SYSTEM,\n ATTR_NET_PEER_NAME,\n ATTR_NET_PEER_PORT,\n DB_SYSTEM_VALUE_REDIS,\n} from './vendored/semconv';\nimport type { IORedisInstrumentationConfig } from './vendored/types';\n\n// Channel names as published by node-redis >= 5.12.0.\n// Hardcoded so we don't import `redis` at module-load time.\nconst CHANNEL_COMMAND = 'node-redis:command';\nconst CHANNEL_BATCH = 'node-redis:batch';\nconst CHANNEL_CONNECT = 'node-redis:connect';\n\nconst ORIGIN = 'auto.db.redis.diagnostic_channel';\n\ninterface CommandData {\n command: string;\n args: Array<string | Buffer>;\n database?: number;\n serverAddress?: string;\n serverPort?: number;\n result?: unknown;\n error?: Error;\n}\n\ninterface BatchData {\n batchMode?: 'MULTI' | 'PIPELINE';\n batchSize?: number;\n database?: number;\n clientId?: string | number;\n serverAddress?: string;\n serverPort?: number;\n result?: unknown[];\n error?: Error;\n}\n\ninterface ConnectData {\n serverAddress?: string;\n serverPort?: number;\n url?: string;\n error?: Error;\n}\n\nconst NOOP = (): void => {};\n\nlet subscribed = false;\nlet currentResponseHook: IORedisInstrumentationConfig['responseHook'] | undefined;\n\n/**\n * Subscribe Sentry handlers to node-redis diagnostics_channel events (>= 5.12.0).\n *\n * Uses `@sentry/opentelemetry/tracing-channel` so OTel AsyncLocalStorage context propagates\n * automatically via `bindStore` — without it, spans created in `start` would not become\n * the active context for subsequent operations.\n *\n * Safe on every runtime that exposes `node:diagnostics_channel` (Node, Bun, Deno, Workers).\n * In node-redis < 5.12.0 the channels are never published to, so subscribers are inert and\n * there is no double-instrumentation against the IITM-based patcher (gated to < 5.12.0).\n */\nexport function subscribeRedisDiagnosticChannels(responseHook?: IORedisInstrumentationConfig['responseHook']): void {\n currentResponseHook = responseHook;\n if (subscribed) return;\n\n try {\n setupCommandChannel();\n setupBatchChannel();\n setupConnectChannel();\n subscribed = true;\n } catch {\n // tracingChannel from @sentry/opentelemetry requires `node:diagnostics_channel`.\n // On runtimes where it isn't available, fail closed.\n }\n}\n\nfunction setupCommandChannel(): void {\n const channel = tracingChannel<CommandData>(CHANNEL_COMMAND, data => {\n // node-redis >= 5.12.0 includes the command name as args[0] in the DC payload.\n // Strip it so serialization and cache key extraction see only the actual arguments.\n const actualArgs = data.args.slice(1);\n const statement = safeSerialize(data.command, actualArgs);\n return startSpanManual(\n {\n name: `redis-${data.command}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db.redis',\n [ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_REDIS,\n ...(statement != null ? { [ATTR_DB_STATEMENT]: statement } : {}),\n ...(data.serverAddress != null ? { [ATTR_NET_PEER_NAME]: data.serverAddress } : {}),\n ...(data.serverPort != null ? { [ATTR_NET_PEER_PORT]: data.serverPort } : {}),\n },\n },\n span => span,\n ) as Span;\n });\n\n channel.subscribe({\n start: NOOP,\n asyncStart: NOOP,\n end: NOOP,\n asyncEnd: data => {\n const span = data._sentrySpan;\n // only end if error handler isn't going to\n if (!span || data.error) return;\n // Same slice: strip command name from args before passing to the response hook.\n runResponseHook(span, data.command, data.args.slice(1), data.result);\n span.end();\n },\n error: data => {\n const span = data._sentrySpan;\n if (!span) return;\n if (data.error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: data.error.message });\n }\n span.end();\n },\n });\n}\n\nfunction setupBatchChannel(): void {\n const channel = tracingChannel<BatchData>(CHANNEL_BATCH, data => {\n const operationName = data.batchMode === 'PIPELINE' ? 'PIPELINE' : 'MULTI';\n\n return startSpanManual(\n {\n name: operationName,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db.redis',\n [ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_REDIS,\n ...(data.batchSize != null ? { 'db.redis.batch_size': data.batchSize } : {}),\n ...(data.serverAddress != null ? { [ATTR_NET_PEER_NAME]: data.serverAddress } : {}),\n ...(data.serverPort != null ? { [ATTR_NET_PEER_PORT]: data.serverPort } : {}),\n },\n },\n span => span,\n ) as Span;\n });\n\n channel.subscribe({\n start: NOOP,\n asyncStart: NOOP,\n end: NOOP,\n asyncEnd: data => {\n // only end if the error handler isn't going to\n if (!data.error) data._sentrySpan?.end();\n },\n error: data => {\n const span = data._sentrySpan;\n if (!span) return;\n if (data.error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: data.error.message });\n }\n span.end();\n },\n });\n}\n\nfunction setupConnectChannel(): void {\n const channel = tracingChannel<ConnectData>(CHANNEL_CONNECT, data => {\n return startSpanManual(\n {\n name: 'redis-connect',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db.redis.connect',\n [ATTR_DB_SYSTEM]: DB_SYSTEM_VALUE_REDIS,\n ...(data.serverAddress != null ? { [ATTR_NET_PEER_NAME]: data.serverAddress } : {}),\n ...(data.serverPort != null ? { [ATTR_NET_PEER_PORT]: data.serverPort } : {}),\n },\n },\n span => span,\n ) as Span;\n });\n\n channel.subscribe({\n start: NOOP,\n asyncStart: NOOP,\n end: NOOP,\n asyncEnd: data => {\n // only end if the error handler isn't going to\n if (!data.error) data._sentrySpan?.end();\n },\n error: data => {\n const span = data._sentrySpan;\n if (!span) return;\n if (data.error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: data.error.message });\n }\n span.end();\n },\n });\n}\n\nfunction runResponseHook(span: Span, command: string, args: Array<string | Buffer>, result: unknown): void {\n const hook = currentResponseHook;\n if (!hook) return;\n try {\n hook(span, command, args as unknown as Parameters<typeof hook>[2], result);\n } catch {\n // never let user hooks break instrumentation\n }\n}\n\nfunction safeSerialize(command: string, args: Array<string | Buffer>): string | undefined {\n try {\n return defaultDbStatementSerializer(command, args);\n } catch {\n return undefined;\n }\n}\n\n// Test-only helper.\nexport function _resetRedisDiagnosticChannelsForTesting(): void {\n subscribed = false;\n currentResponseHook = undefined;\n}\n\n// Suppress unused-import lint when only used in types.\nexport type { TracingChannelContextWithSpan };\n"],"names":[],"mappings":";;;;;AAkBA;AACA;AACA,MAAM,eAAA,GAAkB,oBAAoB;AAC5C,MAAM,aAAA,GAAgB,kBAAkB;AACxC,MAAM,eAAA,GAAkB,oBAAoB;;AAE5C,MAAM,MAAA,GAAS,kCAAkC;;AA8BjD,MAAM,IAAA,GAAO,MAAY,CAAC,CAAC;;AAE3B,IAAI,UAAA,GAAa,KAAK;AACtB,IAAI,mBAAmB;;AAEvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,gCAAgC,CAAC,YAAY,EAAuD;AACpH,EAAE,mBAAA,GAAsB,YAAY;AACpC,EAAE,IAAI,UAAU,EAAE;;AAElB,EAAE,IAAI;AACN,IAAI,mBAAmB,EAAE;AACzB,IAAI,iBAAiB,EAAE;AACvB,IAAI,mBAAmB,EAAE;AACzB,IAAI,UAAA,GAAa,IAAI;AACrB,EAAE,EAAE,MAAM;AACV;AACA;AACA,EAAE;AACF;;AAEA,SAAS,mBAAmB,GAAS;AACrC,EAAE,MAAM,UAAU,cAAc,CAAc,eAAe,EAAE,QAAQ;AACvE;AACA;AACA,IAAI,MAAM,UAAA,GAAa,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACzC,IAAI,MAAM,SAAA,GAAY,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,CAAC;AAC7D,IAAI,OAAO,eAAe;AAC1B,MAAM;AACN,QAAQ,IAAI,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;AACA,QAAA,UAAA,EAAA;AACA,UAAA,CAAA,gCAAA,GAAA,MAAA;AACA,UAAA,CAAA,4BAAA,GAAA,UAAA;AACA,UAAA,CAAA,cAAA,GAAA,qBAAA;AACA,UAAA,IAAA,SAAA,IAAA,IAAA,GAAA,EAAA,CAAA,iBAAA,GAAA,SAAA,EAAA,GAAA,EAAA,CAAA;AACA,UAAA,IAAA,IAAA,CAAA,aAAA,IAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,GAAA,IAAA,CAAA,aAAA,EAAA,GAAA,EAAA,CAAA;AACA,UAAA,IAAA,IAAA,CAAA,UAAA,IAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,GAAA,IAAA,CAAA,UAAA,EAAA,GAAA,EAAA,CAAA;AACA,SAAA;AACA,OAAA;AACA,MAAA,IAAA,IAAA,IAAA;AACA,KAAA;AACA,EAAA,CAAA,CAAA;;AAEA,EAAA,OAAA,CAAA,SAAA,CAAA;AACA,IAAA,KAAA,EAAA,IAAA;AACA,IAAA,UAAA,EAAA,IAAA;AACA,IAAA,GAAA,EAAA,IAAA;AACA,IAAA,QAAA,EAAA,IAAA,IAAA;AACA,MAAA,MAAA,IAAA,GAAA,IAAA,CAAA,WAAA;AACA;AACA,MAAA,IAAA,CAAA,IAAA,IAAA,IAAA,CAAA,KAAA,EAAA;AACA;AACA,MAAA,eAAA,CAAA,IAAA,EAAA,IAAA,CAAA,OAAA,EAAA,IAAA,CAAA,IAAA,CAAA,KAAA,CAAA,CAAA,CAAA,EAAA,IAAA,CAAA,MAAA,CAAA;AACA,MAAA,IAAA,CAAA,GAAA,EAAA;AACA,IAAA,CAAA;AACA,IAAA,KAAA,EAAA,IAAA,IAAA;AACA,MAAA,MAAA,IAAA,GAAA,IAAA,CAAA,WAAA;AACA,MAAA,IAAA,CAAA,IAAA,EAAA;AACA,MAAA,IAAA,IAAA,CAAA,KAAA,EAAA;AACA,QAAA,IAAA,CAAA,SAAA,CAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,IAAA,CAAA,KAAA,CAAA,OAAA,EAAA,CAAA;AACA,MAAA;AACA,MAAA,IAAA,CAAA,GAAA,EAAA;AACA,IAAA,CAAA;AACA,GAAA,CAAA;AACA;;AAEA,SAAA,iBAAA,GAAA;AACA,EAAA,MAAA,OAAA,GAAA,cAAA,CAAA,aAAA,EAAA,IAAA,IAAA;AACA,IAAA,MAAA,aAAA,GAAA,IAAA,CAAA,SAAA,KAAA,UAAA,GAAA,UAAA,GAAA,OAAA;;AAEA,IAAA,OAAA,eAAA;AACA,MAAA;AACA,QAAA,IAAA,EAAA,aAAA;AACA,QAAA,UAAA,EAAA;AACA,UAAA,CAAA,gCAAA,GAAA,MAAA;AACA,UAAA,CAAA,4BAAA,GAAA,UAAA;AACA,UAAA,CAAA,cAAA,GAAA,qBAAA;AACA,UAAA,IAAA,IAAA,CAAA,SAAA,IAAA,IAAA,GAAA,EAAA,qBAAA,EAAA,IAAA,CAAA,SAAA,EAAA,GAAA,EAAA,CAAA;AACA,UAAA,IAAA,IAAA,CAAA,aAAA,IAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,GAAA,IAAA,CAAA,aAAA,EAAA,GAAA,EAAA,CAAA;AACA,UAAA,IAAA,IAAA,CAAA,UAAA,IAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,GAAA,IAAA,CAAA,UAAA,EAAA,GAAA,EAAA,CAAA;AACA,SAAA;AACA,OAAA;AACA,MAAA,IAAA,IAAA,IAAA;AACA,KAAA;AACA,EAAA,CAAA,CAAA;;AAEA,EAAA,OAAA,CAAA,SAAA,CAAA;AACA,IAAA,KAAA,EAAA,IAAA;AACA,IAAA,UAAA,EAAA,IAAA;AACA,IAAA,GAAA,EAAA,IAAA;AACA,IAAA,QAAA,EAAA,IAAA,IAAA;AACA;AACA,MAAA,IAAA,CAAA,IAAA,CAAA,KAAA,EAAA,IAAA,CAAA,WAAA,EAAA,GAAA,EAAA;AACA,IAAA,CAAA;AACA,IAAA,KAAA,EAAA,IAAA,IAAA;AACA,MAAA,MAAA,IAAA,GAAA,IAAA,CAAA,WAAA;AACA,MAAA,IAAA,CAAA,IAAA,EAAA;AACA,MAAA,IAAA,IAAA,CAAA,KAAA,EAAA;AACA,QAAA,IAAA,CAAA,SAAA,CAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,IAAA,CAAA,KAAA,CAAA,OAAA,EAAA,CAAA;AACA,MAAA;AACA,MAAA,IAAA,CAAA,GAAA,EAAA;AACA,IAAA,CAAA;AACA,GAAA,CAAA;AACA;;AAEA,SAAA,mBAAA,GAAA;AACA,EAAA,MAAA,OAAA,GAAA,cAAA,CAAA,eAAA,EAAA,IAAA,IAAA;AACA,IAAA,OAAA,eAAA;AACA,MAAA;AACA,QAAA,IAAA,EAAA,eAAA;AACA,QAAA,UAAA,EAAA;AACA,UAAA,CAAA,gCAAA,GAAA,MAAA;AACA,UAAA,CAAA,4BAAA,GAAA,kBAAA;AACA,UAAA,CAAA,cAAA,GAAA,qBAAA;AACA,UAAA,IAAA,IAAA,CAAA,aAAA,IAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,GAAA,IAAA,CAAA,aAAA,EAAA,GAAA,EAAA,CAAA;AACA,UAAA,IAAA,IAAA,CAAA,UAAA,IAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,GAAA,IAAA,CAAA,UAAA,EAAA,GAAA,EAAA,CAAA;AACA,SAAA;AACA,OAAA;AACA,MAAA,IAAA,IAAA,IAAA;AACA,KAAA;AACA,EAAA,CAAA,CAAA;;AAEA,EAAA,OAAA,CAAA,SAAA,CAAA;AACA,IAAA,KAAA,EAAA,IAAA;AACA,IAAA,UAAA,EAAA,IAAA;AACA,IAAA,GAAA,EAAA,IAAA;AACA,IAAA,QAAA,EAAA,IAAA,IAAA;AACA;AACA,MAAA,IAAA,CAAA,IAAA,CAAA,KAAA,EAAA,IAAA,CAAA,WAAA,EAAA,GAAA,EAAA;AACA,IAAA,CAAA;AACA,IAAA,KAAA,EAAA,IAAA,IAAA;AACA,MAAA,MAAA,IAAA,GAAA,IAAA,CAAA,WAAA;AACA,MAAA,IAAA,CAAA,IAAA,EAAA;AACA,MAAA,IAAA,IAAA,CAAA,KAAA,EAAA;AACA,QAAA,IAAA,CAAA,SAAA,CAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,IAAA,CAAA,KAAA,CAAA,OAAA,EAAA,CAAA;AACA,MAAA;AACA,MAAA,IAAA,CAAA,GAAA,EAAA;AACA,IAAA,CAAA;AACA,GAAA,CAAA;AACA;;AAEA,SAAA,eAAA,CAAA,IAAA,EAAA,OAAA,EAAA,IAAA,EAAA,MAAA,EAAA;AACA,EAAA,MAAA,IAAA,GAAA,mBAAA;AACA,EAAA,IAAA,CAAA,IAAA,EAAA;AACA,EAAA,IAAA;AACA,IAAA,IAAA,CAAA,IAAA,EAAA,OAAA,EAAA,IAAA,GAAA,MAAA,CAAA;AACA,EAAA,CAAA,CAAA,MAAA;AACA;AACA,EAAA;AACA;;AAEA,SAAA,aAAA,CAAA,OAAA,EAAA,IAAA,EAAA;AACA,EAAA,IAAA;AACA,IAAA,OAAA,4BAAA,CAAA,OAAA,EAAA,IAAA,CAAA;AACA,EAAA,CAAA,CAAA,MAAA;AACA,IAAA,OAAA,SAAA;AACA,EAAA;AACA;;;;"}