@reactionary/source 0.0.48 → 0.0.52

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 (175) hide show
  1. package/core/package.json +4 -3
  2. package/core/src/cache/cache.interface.ts +1 -1
  3. package/core/src/cache/memory-cache.ts +2 -2
  4. package/core/src/cache/noop-cache.ts +1 -1
  5. package/core/src/cache/redis-cache.ts +1 -1
  6. package/core/src/client/client-builder.ts +4 -4
  7. package/core/src/client/client.ts +12 -12
  8. package/core/src/decorators/reactionary.decorator.ts +22 -2
  9. package/core/src/index.ts +14 -14
  10. package/core/src/initialization.ts +1 -1
  11. package/core/src/providers/analytics.provider.ts +2 -2
  12. package/core/src/providers/base.provider.ts +5 -5
  13. package/core/src/providers/cart.provider.ts +6 -6
  14. package/core/src/providers/category.provider.ts +4 -9
  15. package/core/src/providers/checkout.provider.ts +156 -0
  16. package/core/src/providers/identity.provider.ts +5 -5
  17. package/core/src/providers/index.ts +13 -12
  18. package/core/src/providers/inventory.provider.ts +4 -4
  19. package/core/src/providers/order.provider.ts +31 -0
  20. package/core/src/providers/price.provider.ts +5 -5
  21. package/core/src/providers/product.provider.ts +5 -5
  22. package/core/src/providers/profile.provider.ts +5 -5
  23. package/core/src/providers/search.provider.ts +4 -4
  24. package/core/src/providers/store.provider.ts +4 -4
  25. package/core/src/schemas/capabilities.schema.ts +2 -1
  26. package/core/src/schemas/models/analytics.model.ts +1 -1
  27. package/core/src/schemas/models/cart.model.ts +3 -28
  28. package/core/src/schemas/models/category.model.ts +2 -2
  29. package/core/src/schemas/models/checkout.model.ts +66 -0
  30. package/core/src/schemas/models/cost.model.ts +21 -0
  31. package/core/src/schemas/models/identifiers.model.ts +23 -2
  32. package/core/src/schemas/models/identity.model.ts +8 -5
  33. package/core/src/schemas/models/index.ts +19 -15
  34. package/core/src/schemas/models/inventory.model.ts +2 -2
  35. package/core/src/schemas/models/order.model.ts +46 -0
  36. package/core/src/schemas/models/payment.model.ts +5 -12
  37. package/core/src/schemas/models/price.model.ts +3 -3
  38. package/core/src/schemas/models/product.model.ts +6 -3
  39. package/core/src/schemas/models/profile.model.ts +2 -2
  40. package/core/src/schemas/models/search.model.ts +2 -3
  41. package/core/src/schemas/models/shipping-method.model.ts +34 -3
  42. package/core/src/schemas/models/store.model.ts +2 -2
  43. package/core/src/schemas/mutations/analytics.mutation.ts +2 -2
  44. package/core/src/schemas/mutations/cart.mutation.ts +5 -5
  45. package/core/src/schemas/mutations/checkout.mutation.ts +50 -0
  46. package/core/src/schemas/mutations/identity.mutation.ts +1 -1
  47. package/core/src/schemas/mutations/index.ts +10 -10
  48. package/core/src/schemas/mutations/profile.mutation.ts +1 -1
  49. package/core/src/schemas/queries/cart.query.ts +2 -2
  50. package/core/src/schemas/queries/category.query.ts +3 -3
  51. package/core/src/schemas/queries/checkout.query.ts +22 -0
  52. package/core/src/schemas/queries/identity.query.ts +1 -1
  53. package/core/src/schemas/queries/index.ts +13 -12
  54. package/core/src/schemas/queries/inventory.query.ts +2 -2
  55. package/core/src/schemas/queries/order.query.ts +9 -0
  56. package/core/src/schemas/queries/price.query.ts +2 -2
  57. package/core/src/schemas/queries/product.query.ts +9 -2
  58. package/core/src/schemas/queries/profile.query.ts +1 -1
  59. package/core/src/schemas/queries/search.query.ts +2 -2
  60. package/core/src/schemas/queries/store.query.ts +1 -1
  61. package/core/src/schemas/session.schema.ts +3 -3
  62. package/core/tsconfig.json +3 -2
  63. package/examples/next/next.config.js +17 -6
  64. package/examples/next/src/app/page.tsx +1 -2
  65. package/examples/node/package.json +2 -1
  66. package/examples/node/src/basic/basic-node-setup.spec.ts +1 -1
  67. package/examples/node/tsconfig.json +2 -1
  68. package/examples/node/tsconfig.spec.json +3 -2
  69. package/package.json +3 -1
  70. package/providers/algolia/package.json +2 -1
  71. package/providers/algolia/src/core/initialize.ts +5 -5
  72. package/providers/algolia/src/index.ts +5 -5
  73. package/providers/algolia/src/providers/product.provider.ts +8 -2
  74. package/providers/algolia/src/providers/search.provider.ts +1 -1
  75. package/providers/algolia/src/test/search.provider.spec.ts +1 -1
  76. package/providers/algolia/tsconfig.json +2 -1
  77. package/providers/algolia/tsconfig.spec.json +3 -2
  78. package/providers/commercetools/{jest.config.ts → jest.config.cjs} +1 -1
  79. package/providers/commercetools/package.json +3 -2
  80. package/providers/commercetools/src/core/client.ts +63 -32
  81. package/providers/commercetools/src/core/initialize.ts +20 -16
  82. package/providers/commercetools/src/index.ts +10 -10
  83. package/providers/commercetools/src/providers/cart.provider.ts +14 -19
  84. package/providers/commercetools/src/providers/category.provider.ts +3 -12
  85. package/providers/commercetools/src/providers/checkout.provider.ts +644 -0
  86. package/providers/commercetools/src/providers/identity.provider.ts +8 -8
  87. package/providers/commercetools/src/providers/index.ts +12 -9
  88. package/providers/commercetools/src/providers/inventory.provider.ts +2 -4
  89. package/providers/commercetools/src/providers/order.provider.ts +163 -0
  90. package/providers/commercetools/src/providers/price.provider.ts +3 -3
  91. package/providers/commercetools/src/providers/product.provider.ts +24 -6
  92. package/providers/commercetools/src/providers/profile.provider.ts +2 -2
  93. package/providers/commercetools/src/providers/search.provider.ts +3 -5
  94. package/providers/commercetools/src/providers/store.provider.ts +3 -3
  95. package/providers/commercetools/src/schema/capabilities.schema.ts +2 -1
  96. package/providers/commercetools/src/schema/commercetools.schema.ts +7 -5
  97. package/providers/commercetools/src/schema/configuration.schema.ts +2 -0
  98. package/providers/commercetools/src/test/cart.provider.spec.ts +24 -4
  99. package/providers/commercetools/src/test/category.provider.spec.ts +3 -3
  100. package/providers/commercetools/src/test/checkout.provider.spec.ts +312 -0
  101. package/providers/commercetools/src/test/identity.provider.spec.ts +3 -3
  102. package/providers/commercetools/src/test/inventory.provider.spec.ts +2 -2
  103. package/providers/commercetools/src/test/price.provider.spec.ts +4 -4
  104. package/providers/commercetools/src/test/product.provider.spec.ts +22 -5
  105. package/providers/commercetools/src/test/profile.provider.spec.ts +3 -3
  106. package/providers/commercetools/src/test/search.provider.spec.ts +2 -2
  107. package/providers/commercetools/src/test/store.provider.spec.ts +2 -2
  108. package/providers/commercetools/src/test/test-utils.ts +14 -0
  109. package/providers/commercetools/tsconfig.json +2 -1
  110. package/providers/commercetools/tsconfig.spec.json +4 -3
  111. package/providers/fake/{jest.config.ts → jest.config.cjs} +1 -1
  112. package/providers/fake/package.json +2 -2
  113. package/providers/fake/src/core/initialize.ts +6 -6
  114. package/providers/fake/src/index.ts +4 -4
  115. package/providers/fake/src/providers/analytics.provider.ts +1 -1
  116. package/providers/fake/src/providers/cart.provider.ts +2 -2
  117. package/providers/fake/src/providers/category.provider.ts +7 -3
  118. package/providers/fake/src/providers/identity.provider.ts +1 -1
  119. package/providers/fake/src/providers/index.ts +9 -9
  120. package/providers/fake/src/providers/inventory.provider.ts +1 -1
  121. package/providers/fake/src/providers/price.provider.ts +1 -1
  122. package/providers/fake/src/providers/product.provider.ts +10 -4
  123. package/providers/fake/src/providers/search.provider.ts +2 -5
  124. package/providers/fake/src/providers/store.provider.ts +2 -3
  125. package/providers/fake/src/test/cart.provider.spec.ts +3 -3
  126. package/providers/fake/src/test/category.provider.spec.ts +2 -2
  127. package/providers/fake/src/test/price.provider.spec.ts +2 -2
  128. package/providers/fake/src/test/product.provider.spec.ts +8 -8
  129. package/providers/fake/src/test/test-utils.ts +1 -1
  130. package/providers/fake/tsconfig.json +2 -1
  131. package/providers/fake/tsconfig.spec.json +1 -3
  132. package/providers/posthog/package.json +4 -4
  133. package/providers/posthog/project.json +2 -2
  134. package/providers/posthog/src/core/initialize.ts +2 -2
  135. package/providers/posthog/src/index.ts +3 -3
  136. package/providers/posthog/tsconfig.json +2 -1
  137. package/tsconfig.base.json +3 -4
  138. package/.claude/settings.local.json +0 -28
  139. package/core/src/providers/cart-payment.provider.ts +0 -57
  140. package/core/src/schemas/mutations/cart-payment.mutation.ts +0 -21
  141. package/core/src/schemas/queries/cart-payment.query.ts +0 -12
  142. package/otel/README.md +0 -227
  143. package/otel/eslint.config.mjs +0 -23
  144. package/otel/package.json +0 -11
  145. package/otel/pnpm-lock.yaml +0 -805
  146. package/otel/project.json +0 -33
  147. package/otel/src/index.ts +0 -22
  148. package/otel/src/metrics.ts +0 -76
  149. package/otel/src/provider-instrumentation.ts +0 -108
  150. package/otel/src/test/otel.spec.ts +0 -8
  151. package/otel/src/trace-decorator.ts +0 -226
  152. package/otel/src/tracer.ts +0 -83
  153. package/otel/src/trpc-middleware.ts +0 -128
  154. package/otel/tsconfig.json +0 -23
  155. package/otel/tsconfig.lib.json +0 -23
  156. package/otel/tsconfig.spec.json +0 -28
  157. package/otel/vite.config.ts +0 -24
  158. package/providers/commercetools/src/providers/cart-payment.provider.ts +0 -193
  159. package/providers/commercetools/src/test/cart-payment.provider.spec.ts +0 -145
  160. package/trpc/README.md +0 -7
  161. package/trpc/__mocks__/superjson.js +0 -25
  162. package/trpc/eslint.config.mjs +0 -19
  163. package/trpc/jest.config.ts +0 -14
  164. package/trpc/package.json +0 -14
  165. package/trpc/project.json +0 -31
  166. package/trpc/src/client.ts +0 -175
  167. package/trpc/src/index.ts +0 -44
  168. package/trpc/src/integration.spec.ts +0 -223
  169. package/trpc/src/server.ts +0 -125
  170. package/trpc/src/test-utils.ts +0 -31
  171. package/trpc/src/transparent-client.spec.ts +0 -162
  172. package/trpc/src/types.ts +0 -144
  173. package/trpc/tsconfig.json +0 -16
  174. package/trpc/tsconfig.lib.json +0 -10
  175. package/trpc/tsconfig.spec.json +0 -15
package/otel/project.json DELETED
@@ -1,33 +0,0 @@
1
- {
2
- "name": "otel",
3
- "$schema": "../node_modules/nx/schemas/project-schema.json",
4
- "sourceRoot": "otel/src",
5
- "projectType": "library",
6
- "release": {
7
- "version": {
8
- "manifestRootsToUpdate": ["dist/{projectRoot}"],
9
- "currentVersionResolver": "git-tag",
10
- "fallbackCurrentVersionResolver": "disk"
11
- }
12
- },
13
- "tags": [],
14
- "targets": {
15
- "build": {
16
- "executor": "@nx/esbuild:esbuild",
17
- "outputs": ["{options.outputPath}"],
18
- "options": {
19
- "outputPath": "dist/otel",
20
- "main": "otel/src/index.ts",
21
- "tsConfig": "otel/tsconfig.lib.json",
22
- "assets": ["otel/*.md"],
23
- "format": ["cjs"],
24
- "generatePackageJson": true
25
- }
26
- },
27
- "nx-release-publish": {
28
- "options": {
29
- "packageRoot": "dist/{projectRoot}"
30
- }
31
- }
32
- }
33
- }
package/otel/src/index.ts DELETED
@@ -1,22 +0,0 @@
1
- // OpenTelemetry instrumentation library
2
- // This library provides instrumentation only - the host application
3
- // is responsible for initializing the OpenTelemetry SDK
4
-
5
- // Framework integration exports (internal use only)
6
- export { createTRPCTracing } from './trpc-middleware';
7
- export { createProviderInstrumentation } from './provider-instrumentation';
8
-
9
- // Decorator for tracing functions
10
- export { traced } from './trace-decorator';
11
- export type { TracedOptions } from './trace-decorator';
12
-
13
- // Utility functions for manual instrumentation
14
- export {
15
- getTracer,
16
- startSpan,
17
- withSpan,
18
- setSpanAttributes,
19
- createChildSpan,
20
- SpanKind,
21
- SpanStatusCode
22
- } from './tracer';
@@ -1,76 +0,0 @@
1
- import type { Meter, Counter, Histogram, UpDownCounter } from '@opentelemetry/api';
2
- import { metrics } from '@opentelemetry/api';
3
-
4
- const METER_NAME = '@reactionary/otel';
5
- const METER_VERSION = '0.0.1';
6
-
7
- let globalMeter: Meter | null = null;
8
-
9
- export function getMeter(): Meter {
10
- if (!globalMeter) {
11
- // Simply get the meter from the API
12
- // If the SDK is not initialized by the host application,
13
- // this will return a NoopMeter
14
- globalMeter = metrics.getMeter(METER_NAME, METER_VERSION);
15
- }
16
- return globalMeter;
17
- }
18
-
19
- export interface ReactMetrics {
20
- requestCounter: Counter;
21
- requestDuration: Histogram;
22
- activeRequests: UpDownCounter;
23
- errorCounter: Counter;
24
- providerCallCounter: Counter;
25
- providerCallDuration: Histogram;
26
- cacheHitCounter: Counter;
27
- cacheMissCounter: Counter;
28
- }
29
-
30
- let metricsInstance: ReactMetrics | null = null;
31
-
32
- export function initializeMetrics(): ReactMetrics {
33
- if (metricsInstance) {
34
- return metricsInstance;
35
- }
36
-
37
- const meter = getMeter();
38
-
39
- metricsInstance = {
40
- requestCounter: meter.createCounter('reactionary.requests', {
41
- description: 'Total number of requests',
42
- }),
43
- requestDuration: meter.createHistogram('reactionary.request.duration', {
44
- description: 'Request duration in milliseconds',
45
- unit: 'ms',
46
- }),
47
- activeRequests: meter.createUpDownCounter('reactionary.requests.active', {
48
- description: 'Number of active requests',
49
- }),
50
- errorCounter: meter.createCounter('reactionary.errors', {
51
- description: 'Total number of errors',
52
- }),
53
- providerCallCounter: meter.createCounter('reactionary.provider.calls', {
54
- description: 'Total number of provider calls',
55
- }),
56
- providerCallDuration: meter.createHistogram('reactionary.provider.duration', {
57
- description: 'Provider call duration in milliseconds',
58
- unit: 'ms',
59
- }),
60
- cacheHitCounter: meter.createCounter('reactionary.cache.hits', {
61
- description: 'Total number of cache hits',
62
- }),
63
- cacheMissCounter: meter.createCounter('reactionary.cache.misses', {
64
- description: 'Total number of cache misses',
65
- }),
66
- };
67
-
68
- return metricsInstance;
69
- }
70
-
71
- export function getMetrics(): ReactMetrics {
72
- if (!metricsInstance) {
73
- return initializeMetrics();
74
- }
75
- return metricsInstance;
76
- }
@@ -1,108 +0,0 @@
1
- import type { Span} from '@opentelemetry/api';
2
- import { SpanKind } from '@opentelemetry/api';
3
- import { withSpan, setSpanAttributes } from './tracer';
4
- import { getMetrics } from './metrics';
5
-
6
- export interface ProviderSpanOptions {
7
- providerName: string;
8
- operationType: 'query' | 'mutation';
9
- operationName?: string;
10
- attributes?: Record<string, unknown>;
11
- }
12
-
13
- export async function withProviderSpan<T>(
14
- options: ProviderSpanOptions,
15
- fn: (span: Span) => Promise<T>
16
- ): Promise<T> {
17
- const { providerName, operationType, operationName, attributes = {} } = options;
18
- const metrics = getMetrics();
19
- const spanName = `provider.${providerName}.${operationType}${operationName ? `.${operationName}` : ''}`;
20
-
21
- const startTime = Date.now();
22
- metrics.providerCallCounter.add(1, {
23
- 'provider.name': providerName,
24
- 'provider.operation.type': operationType,
25
- 'provider.operation.name': operationName || 'unknown',
26
- });
27
-
28
- return withSpan(
29
- spanName,
30
- async (span) => {
31
- setSpanAttributes(span, {
32
- 'provider.name': providerName,
33
- 'provider.operation.type': operationType,
34
- 'provider.operation.name': operationName,
35
- ...attributes,
36
- });
37
-
38
- // Span kind is set via options in withSpan
39
-
40
- try {
41
- const result = await fn(span);
42
-
43
- const duration = Date.now() - startTime;
44
- metrics.providerCallDuration.record(duration, {
45
- 'provider.name': providerName,
46
- 'provider.operation.type': operationType,
47
- 'provider.operation.name': operationName || 'unknown',
48
- 'status': 'success',
49
- });
50
-
51
- return result;
52
- } catch (error) {
53
- const duration = Date.now() - startTime;
54
- metrics.providerCallDuration.record(duration, {
55
- 'provider.name': providerName,
56
- 'provider.operation.type': operationType,
57
- 'provider.operation.name': operationName || 'unknown',
58
- 'status': 'error',
59
- });
60
-
61
- metrics.errorCounter.add(1, {
62
- 'provider.name': providerName,
63
- 'provider.operation.type': operationType,
64
- 'provider.operation.name': operationName || 'unknown',
65
- });
66
-
67
- throw error;
68
- }
69
- },
70
- { kind: SpanKind.CLIENT }
71
- );
72
- }
73
-
74
- export function createProviderInstrumentation(providerName: string) {
75
- return {
76
- traceQuery: <T>(
77
- operationName: string,
78
- fn: (span: Span) => Promise<T>,
79
- attributes?: Record<string, unknown>
80
- ) => {
81
- return withProviderSpan(
82
- {
83
- providerName,
84
- operationType: 'query',
85
- operationName,
86
- attributes,
87
- },
88
- fn
89
- );
90
- },
91
-
92
- traceMutation: <T>(
93
- operationName: string,
94
- fn: (span: Span) => Promise<T>,
95
- attributes?: Record<string, unknown>
96
- ) => {
97
- return withProviderSpan(
98
- {
99
- providerName,
100
- operationType: 'mutation',
101
- operationName,
102
- attributes,
103
- },
104
- fn
105
- );
106
- },
107
- };
108
- }
@@ -1,8 +0,0 @@
1
- import { getTracer } from '../tracer';
2
- describe('Otel Integration', () => {
3
- it('should initialize OpenTelemetry without errors', async () => {
4
- const tracer = getTracer();
5
-
6
- expect(tracer).toBeDefined();
7
- });
8
- });
@@ -1,226 +0,0 @@
1
- import { SpanKind, SpanStatusCode } from '@opentelemetry/api';
2
- import { getTracer } from './tracer';
3
-
4
- /**
5
- * Options for the @traced decorator
6
- */
7
- export interface TracedOptions {
8
- /** Whether to capture function arguments as span attributes (default: true) */
9
- captureArgs?: boolean;
10
- /** Whether to capture the return value as a span attribute (default: true) */
11
- captureResult?: boolean;
12
- /** Custom span name to use instead of the function name */
13
- spanName?: string;
14
- /** OpenTelemetry SpanKind (default: INTERNAL) */
15
- spanKind?: SpanKind;
16
- }
17
-
18
- /**
19
- * Safely serializes a value for use as a span attribute
20
- * Handles circular references and large objects
21
- */
22
- function safeSerialize(value: unknown, maxDepth = 3, currentDepth = 0): string {
23
- if (currentDepth >= maxDepth) {
24
- return '[Max depth reached]';
25
- }
26
-
27
- if (value === null) return 'null';
28
- if (value === undefined) return 'undefined';
29
-
30
- const type = typeof value;
31
-
32
- if (type === 'string' || type === 'number' || type === 'boolean') {
33
- return String(value);
34
- }
35
-
36
- if (type === 'function') {
37
- return `[Function: ${(value as { name?: string }).name || 'anonymous'}]`;
38
- }
39
-
40
- if (value instanceof Date) {
41
- return value.toISOString();
42
- }
43
-
44
- if (value instanceof Error) {
45
- return `[Error: ${value.message}]`;
46
- }
47
-
48
- if (Array.isArray(value)) {
49
- if (value.length > 10) {
50
- return `[Array(${value.length})]`;
51
- }
52
- try {
53
- return JSON.stringify(value.map(item =>
54
- safeSerialize(item, maxDepth, currentDepth + 1)
55
- ));
56
- } catch {
57
- return '[Array - circular reference]';
58
- }
59
- }
60
-
61
- if (type === 'object') {
62
- try {
63
- const keys = Object.keys(value as object);
64
- if (keys.length > 20) {
65
- return `[Object with ${keys.length} keys]`;
66
- }
67
- const simplified: Record<string, unknown> = {};
68
- for (const key of keys.slice(0, 10)) {
69
- simplified[key] = safeSerialize(
70
- (value as Record<string, unknown>)[key],
71
- maxDepth,
72
- currentDepth + 1
73
- );
74
- }
75
- return JSON.stringify(simplified);
76
- } catch {
77
- return '[Object - circular reference]';
78
- }
79
- }
80
-
81
- return String(value);
82
- }
83
-
84
- /**
85
- * TypeScript decorator for tracing function execution
86
- * Automatically creates OpenTelemetry spans for decorated methods
87
- * Uses Stage 2 (legacy) decorator syntax
88
- *
89
- * @example
90
- * ```typescript
91
- * class MyService {
92
- * @traced()
93
- * async fetchData(id: string): Promise<Data> {
94
- * // method implementation
95
- * }
96
- *
97
- * @traced({ spanName: 'custom-operation', captureResult: false })
98
- * processData(data: Data): void {
99
- * // method implementation
100
- * }
101
- * }
102
- * ```
103
- */
104
- export function traced(options: TracedOptions = {}): MethodDecorator {
105
- const {
106
- captureArgs = false,
107
- captureResult = false,
108
- spanName,
109
- spanKind = SpanKind.INTERNAL
110
- } = options;
111
-
112
- return function (
113
- target: any,
114
- propertyKey: string | symbol,
115
- descriptor: PropertyDescriptor
116
- ): PropertyDescriptor {
117
- const originalMethod = descriptor.value;
118
- const methodName = String(propertyKey);
119
-
120
- descriptor.value = createTracedMethod(originalMethod, methodName, {
121
- captureArgs,
122
- captureResult,
123
- spanName,
124
- spanKind
125
- });
126
-
127
- return descriptor;
128
- };
129
- }
130
-
131
- function createTracedMethod(
132
- originalMethod: (...args: any[]) => any,
133
- methodName: string,
134
- options: {
135
- captureArgs: boolean;
136
- captureResult: boolean;
137
- spanName?: string;
138
- spanKind: SpanKind;
139
- }
140
- ): any {
141
- const { captureArgs, captureResult, spanName, spanKind } = options;
142
-
143
- function tracedMethod(this: any, ...args: any[]): any {
144
- const tracer = getTracer();
145
- const className = this?.constructor?.name || 'Unknown';
146
- const effectiveSpanName = spanName || `${className}.${methodName}`;
147
-
148
- // Use startActiveSpan to ensure proper context propagation
149
- return tracer.startActiveSpan(effectiveSpanName, {
150
- kind: spanKind,
151
- attributes: {
152
- 'function.name': methodName,
153
- 'function.class': className,
154
- }
155
- }, (span) => {
156
- // Capture arguments if enabled
157
- if (captureArgs && args.length > 0) {
158
- args.forEach((arg, index) => {
159
- try {
160
- span.setAttribute(`function.args.${index}`, safeSerialize(arg));
161
- } catch {
162
- span.setAttribute(`function.args.${index}`, '[Serialization error]');
163
- }
164
- });
165
- span.setAttribute('function.args.count', args.length);
166
- }
167
-
168
- // Helper function to set span attributes and status
169
- const setSpanResult = (result: unknown, isError = false) => {
170
- if (!isError && captureResult && result !== undefined) {
171
- try {
172
- span.setAttribute('function.result', safeSerialize(result));
173
- } catch {
174
- span.setAttribute('function.result', '[Serialization error]');
175
- }
176
- }
177
-
178
- if (isError) {
179
- span.setStatus({
180
- code: SpanStatusCode.ERROR,
181
- message: result instanceof Error ? result.message : String(result)
182
- });
183
- if (result instanceof Error) {
184
- span.recordException(result);
185
- }
186
- } else {
187
- span.setStatus({ code: SpanStatusCode.OK });
188
- }
189
-
190
- span.end();
191
- };
192
-
193
- try {
194
- const result = originalMethod.apply(this, args);
195
-
196
- // Handle async functions - await them to keep span open
197
- if (result instanceof Promise) {
198
- try {
199
- return result.then(value => {
200
- setSpanResult(value);
201
- return value;
202
- });
203
- } catch (error) {
204
- setSpanResult(error, true);
205
- throw error;
206
- }
207
- }
208
-
209
- // Handle sync functions
210
- setSpanResult(result);
211
- return result;
212
- } catch (error) {
213
- setSpanResult(error, true);
214
- throw error;
215
- }
216
- });
217
- }
218
-
219
- // Preserve the original function's name and properties
220
- Object.defineProperty(tracedMethod, 'name', {
221
- value: methodName,
222
- configurable: true
223
- });
224
-
225
- return tracedMethod;
226
- }
@@ -1,83 +0,0 @@
1
- import type {
2
- Tracer,
3
- Span,
4
- Context,
5
- SpanOptions,
6
- Attributes} from '@opentelemetry/api';
7
- import {
8
- trace,
9
- SpanStatusCode,
10
- context as otelContext
11
- } from '@opentelemetry/api';
12
-
13
- const TRACER_NAME = '@reactionary/otel';
14
- const TRACER_VERSION = '0.0.1';
15
-
16
- let globalTracer: Tracer | null = null;
17
-
18
- export function getTracer(): Tracer {
19
- if (!globalTracer) {
20
- // Simply get the tracer from the API
21
- // If the SDK is not initialized by the host application,
22
- // this will return a ProxyTracer that produces NonRecordingSpans
23
- globalTracer = trace.getTracer(TRACER_NAME, TRACER_VERSION);
24
- }
25
- return globalTracer;
26
- }
27
-
28
- export function startSpan(
29
- name: string,
30
- options?: SpanOptions,
31
- context?: Context
32
- ): Span {
33
- const tracer = getTracer();
34
- if (context) {
35
- return tracer.startActiveSpan(name, options || {}, context, (span) => span);
36
- }
37
- return tracer.startSpan(name, options);
38
- }
39
-
40
- export function withSpan<T>(
41
- name: string,
42
- fn: (span: Span) => T | Promise<T>,
43
- options?: SpanOptions
44
- ): Promise<T> {
45
- const tracer = getTracer();
46
- return tracer.startActiveSpan(name, options || {}, async (span) => {
47
- try {
48
- const result = await fn(span);
49
- span.setStatus({ code: SpanStatusCode.OK });
50
- return result;
51
- } catch (error) {
52
- span.setStatus({
53
- code: SpanStatusCode.ERROR,
54
- message: error instanceof Error ? error.message : String(error),
55
- });
56
- if (error instanceof Error) {
57
- span.recordException(error);
58
- }
59
- throw error;
60
- } finally {
61
- span.end();
62
- }
63
- });
64
- }
65
-
66
- export function setSpanAttributes(span: Span, attributes: Attributes): void {
67
- Object.entries(attributes).forEach(([key, value]) => {
68
- if (value !== undefined && value !== null) {
69
- span.setAttribute(key, value);
70
- }
71
- });
72
- }
73
-
74
- export function createChildSpan(
75
- parentSpan: Span,
76
- name: string,
77
- options?: SpanOptions
78
- ): Span {
79
- const ctx = trace.setSpan(otelContext.active(), parentSpan);
80
- return getTracer().startSpan(name, options, ctx);
81
- }
82
-
83
- export { SpanKind, SpanStatusCode } from '@opentelemetry/api';
@@ -1,128 +0,0 @@
1
- import { TRPCError } from '@trpc/server';
2
- import type {
3
- Span} from '@opentelemetry/api';
4
- import {
5
- SpanKind,
6
- SpanStatusCode,
7
- } from '@opentelemetry/api';
8
- import { getTracer } from './tracer';
9
- import { getMetrics } from './metrics';
10
-
11
- export interface TRPCMiddlewareOptions {
12
- /** Whether to include input data in span attributes */
13
- includeInput?: boolean;
14
- /** Whether to include output data in span attributes */
15
- includeOutput?: boolean;
16
- /** Maximum string length for attributes */
17
- maxAttributeLength?: number;
18
- }
19
-
20
- const defaultOptions: TRPCMiddlewareOptions = {
21
- includeInput: true,
22
- includeOutput: false,
23
- maxAttributeLength: 1000,
24
- };
25
-
26
- export function createTRPCTracing(options: TRPCMiddlewareOptions = {}) {
27
- const opts = { ...defaultOptions, ...options };
28
- const metrics = getMetrics();
29
-
30
- return ({ path, type, next, input, rawInput }: any) => {
31
- const pathStr = path || 'unknown';
32
- const tracer = getTracer();
33
- const spanName = `trpc.${type}.${pathStr}`;
34
-
35
- const startTime = Date.now();
36
- metrics.requestCounter.add(1, {
37
- 'rpc.method': pathStr,
38
- 'rpc.system': 'trpc',
39
- 'rpc.service': type,
40
- });
41
- metrics.activeRequests.add(1);
42
-
43
- return tracer.startActiveSpan(
44
- spanName,
45
- {
46
- kind: type === 'mutation' ? SpanKind.CLIENT : SpanKind.SERVER,
47
- attributes: {
48
- 'rpc.system': 'trpc',
49
- 'rpc.method': pathStr,
50
- 'rpc.service': type,
51
- 'trpc.type': type,
52
- 'trpc.path': pathStr,
53
- },
54
- },
55
- async (span: Span) => {
56
- try {
57
- if (opts.includeInput && (rawInput !== undefined || input !== undefined)) {
58
- const inputData = rawInput || input;
59
- const inputStr = truncateString(JSON.stringify(inputData), opts.maxAttributeLength || 1000);
60
- span.setAttribute('trpc.input', inputStr);
61
- }
62
-
63
- const result = await next();
64
-
65
- if (opts.includeOutput && result !== undefined) {
66
- const outputStr = truncateString(JSON.stringify(result), opts.maxAttributeLength || 1000);
67
- span.setAttribute('trpc.output', outputStr);
68
- }
69
-
70
- span.setStatus({ code: SpanStatusCode.OK });
71
-
72
- const duration = Date.now() - startTime;
73
- metrics.requestDuration.record(duration, {
74
- 'rpc.method': pathStr,
75
- 'rpc.system': 'trpc',
76
- 'rpc.service': type,
77
- 'status': 'success',
78
- });
79
-
80
- return result;
81
- } catch (error) {
82
- const errorMessage = error instanceof Error ? error.message : String(error);
83
- const errorCode = error instanceof TRPCError ? error.code : 'INTERNAL_SERVER_ERROR';
84
-
85
- span.setStatus({
86
- code: SpanStatusCode.ERROR,
87
- message: errorMessage,
88
- });
89
-
90
- span.setAttribute('trpc.error.code', errorCode);
91
- span.setAttribute('trpc.error.message', errorMessage);
92
-
93
- if (error instanceof Error) {
94
- span.recordException(error);
95
- }
96
-
97
- const duration = Date.now() - startTime;
98
- metrics.requestDuration.record(duration, {
99
- 'rpc.method': pathStr,
100
- 'rpc.system': 'trpc',
101
- 'rpc.service': type,
102
- 'status': 'error',
103
- 'error.code': errorCode,
104
- });
105
-
106
- metrics.errorCounter.add(1, {
107
- 'rpc.method': pathStr,
108
- 'rpc.system': 'trpc',
109
- 'rpc.service': type,
110
- 'error.code': errorCode,
111
- });
112
-
113
- throw error;
114
- } finally {
115
- span.end();
116
- metrics.activeRequests.add(-1);
117
- }
118
- }
119
- );
120
- };
121
- };
122
-
123
- function truncateString(str: string, maxLength: number): string {
124
- if (str.length <= maxLength) {
125
- return str;
126
- }
127
- return str.substring(0, maxLength) + '...';
128
- }