@ciq-dev/neoiq-foundation-node 1.1.2-beta.2 → 1.1.2-beta.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"tracing-m0aaBMdF.mjs","names":["input: FoundationConfigInput","sdk: NodeSDK | null","options: TracingOptions","config: AutoInstrumentationConfig","mapping: Record<string, string>","result: Record<string, { enabled: boolean }>","name: string"],"sources":["../src/config.ts","../src/features/tracing.ts"],"sourcesContent":["/**\n * Foundation Configuration with Zod Validation\n */\n\nimport { z } from 'zod';\n\n// Auto-Instrumentation Config\nexport const AutoInstrumentationConfigSchema = z\n .object({\n http: z.boolean().default(true),\n fastify: z.boolean().default(true),\n express: z.boolean().default(true),\n mongodb: z.boolean().default(true),\n pg: z.boolean().default(true),\n mysql: z.boolean().default(true),\n redis: z.boolean().default(true),\n ioredis: z.boolean().default(true),\n grpc: z.boolean().default(true),\n fs: z.boolean().default(false),\n dns: z.boolean().default(false),\n })\n .partial();\n\nexport type AutoInstrumentationConfig = z.infer<typeof AutoInstrumentationConfigSchema>;\n\n// Features Config\nexport const FeaturesConfigSchema = z\n .object({\n tracing: z.boolean().default(true),\n metrics: z.boolean().default(true),\n logging: z.boolean().default(true),\n autoInstrumentation: AutoInstrumentationConfigSchema.default({}),\n })\n .partial();\n\nexport type FeaturesConfig = z.infer<typeof FeaturesConfigSchema>;\n\n// OTEL Config\nconst DEFAULT_OTEL_ENDPOINT =\n 'http://otel-stack-deployment-collector.observability.svc.cluster.local:4317';\n\nexport const OtelConfigSchema = z.object({\n endpoint: z\n .string()\n .default(() => process.env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_OTEL_ENDPOINT),\n metricsIntervalMs: z.number().min(1000).default(5000),\n // Level at which OpenTelemetry SDK internal logs are routed to the foundation\n // logger. This is the ONLY way OTLP export failures (e.g. the collector being\n // unreachable or rejecting telemetry) surface — they are emitted asynchronously\n // on the export interval via the diag channel, not through setup try/catch.\n // 'none' disables the bridge. Overridable at deploy time via OTEL_DIAG_LOG_LEVEL.\n diagLogLevel: z.enum(['none', 'error', 'warn', 'info', 'debug', 'verbose']).default('warn'),\n});\n\nexport type OtelConfig = z.infer<typeof OtelConfigSchema>;\n\n// Logging Config\nexport const LoggingConfigSchema = z\n .object({\n level: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n prettyPrint: z.boolean().optional(),\n })\n .partial();\n\nexport type LoggingConfig = z.infer<typeof LoggingConfigSchema>;\n\n// Request Logging Config\nexport const RequestLoggingConfigSchema = z\n .object({\n logHeaders: z.boolean().default(true),\n logBody: z.boolean().default(false),\n logResponseBody: z.boolean().default(false),\n maxBodySize: z.number().default(10 * 1024),\n redactHeaders: z.array(z.string()).optional(),\n })\n .partial();\n\nexport type RequestLoggingConfig = z.infer<typeof RequestLoggingConfigSchema>;\n\n// Redaction Config\nexport const RedactionConfigSchema = z\n .object({\n additionalPaths: z.array(z.string()).default([]),\n })\n .partial();\n\nexport type RedactionConfig = z.infer<typeof RedactionConfigSchema>;\n\n// Shutdown Config\nexport const ShutdownConfigSchema = z\n .object({\n /** Flush telemetry on uncaughtException / unhandledRejection before process exits */\n flushOnCrash: z.boolean().default(false),\n /** Grace period (ms) for flushing before forcing exit */\n flushTimeoutMs: z.number().min(100).default(5000),\n })\n .partial();\n\nexport type ShutdownConfig = z.infer<typeof ShutdownConfigSchema>;\n\n// Vault Config\nexport const VaultConfigSchema = z.object({\n enabled: z.boolean().default(false),\n address: z.string().default('https://vault.beta.commerceiq.ai'),\n authMethod: z.enum(['kubernetes', 'token']).default('kubernetes'),\n role: z.string().optional(),\n mountPoint: z.string().default('secret'),\n tokenPath: z.string().default('/var/run/secrets/kubernetes.io/serviceaccount/token'),\n k8sAuthMount: z.string().default('kubernetes'),\n namespace: z.string().optional(),\n});\n\nexport type VaultConfig = z.infer<typeof VaultConfigSchema>;\n\n// Main Foundation Config\nexport const FoundationConfigSchema = z.object({\n serviceName: z.string().min(1, 'serviceName is required'),\n serviceVersion: z.string().default(process.env.SERVICE_VERSION || '1.0.0'),\n environment: z\n .enum(['development', 'staging', 'qa', 'production'])\n .default(\n ['development', 'staging', 'qa', 'production'].includes(process.env.NODE_ENV ?? '')\n ? (process.env.NODE_ENV as 'development' | 'staging' | 'qa' | 'production')\n : 'development'\n ),\n features: FeaturesConfigSchema.default({}),\n otel: OtelConfigSchema.default({}),\n logging: LoggingConfigSchema.default({}),\n requestLogging: RequestLoggingConfigSchema.default({}),\n redaction: RedactionConfigSchema.default({}),\n shutdown: ShutdownConfigSchema.default({}),\n vault: VaultConfigSchema.default({}),\n});\n\nexport type FoundationConfig = z.infer<typeof FoundationConfigSchema>;\n\nexport type FoundationConfigInput = z.input<typeof FoundationConfigSchema> & {\n serviceName: string;\n};\n\n/** Parse and validate configuration */\nexport function parseConfig(input: FoundationConfigInput): FoundationConfig {\n const result = FoundationConfigSchema.safeParse(input);\n\n if (!result.success) {\n const errors = result.error.errors\n .map((e) => ` - ${e.path.join('.')}: ${e.message}`)\n .join('\\n');\n throw new Error(`Invalid foundation configuration:\\n${errors}`);\n }\n\n return result.data;\n}\n\n/** Get default OTEL endpoint */\nexport function getDefaultOtelEndpoint(): string {\n return process.env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_OTEL_ENDPOINT;\n}\n","/**\n * OpenTelemetry Tracing Setup\n */\n\nimport { NodeSDK } from '@opentelemetry/sdk-node';\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';\nimport { resourceFromAttributes } from '@opentelemetry/resources';\nimport { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';\nimport { trace, context, propagation, SpanStatusCode, type Tracer } from '@opentelemetry/api';\nimport { type IMetricReader } from '@opentelemetry/sdk-metrics';\nimport { type AutoInstrumentationConfig, getDefaultOtelEndpoint } from '../config';\n\nexport interface TracingOptions {\n serviceName: string;\n serviceVersion: string;\n environment: string;\n endpoint?: string;\n autoInstrumentation?: AutoInstrumentationConfig;\n /**\n * Metric reader to attach to the NodeSDK so a single SDK owns both traces and\n * metrics (one global MeterProvider, same gRPC collector). When provided, NodeSDK\n * is the sole owner of metrics; when omitted, NodeSDK is opted out of metrics\n * entirely (see below) so it never registers a stray default MeterProvider.\n */\n metricReader?: IMetricReader;\n}\n\nlet sdk: NodeSDK | null = null;\nlet isInitialized = false;\n\nconst MONITORED_MODULES = ['pg', 'mongodb', 'ioredis', 'mysql2', 'express', '@grpc/grpc-js'];\n\nfunction warnPreloadedModules(): void {\n // require.resolve / require.cache are only available in CJS contexts\n if (typeof require === 'undefined' || typeof require.cache === 'undefined') return;\n\n for (const mod of MONITORED_MODULES) {\n try {\n const resolved = require.resolve(mod);\n if (require.cache[resolved]) {\n console.warn(\n `[neoiq-foundation] \"${mod}\" was imported before tracing init. ` +\n 'Auto-instrumentation may not work for this module. ' +\n 'Use node -r @ciq-dev/neoiq-foundation-node/bootstrap or call createFoundation() first.'\n );\n }\n } catch {\n // Module not installed — no warning needed\n }\n }\n}\n\n/** Initialize OpenTelemetry tracing */\nexport function setupTracing(options: TracingOptions): void {\n if (isInitialized) {\n console.warn('[neoiq-foundation] Tracing already initialized');\n return;\n }\n\n warnPreloadedModules();\n\n const {\n serviceName,\n serviceVersion,\n environment,\n endpoint = getDefaultOtelEndpoint(),\n autoInstrumentation = {},\n metricReader,\n } = options;\n\n const resource = resourceFromAttributes({\n [ATTR_SERVICE_NAME]: serviceName,\n [ATTR_SERVICE_VERSION]: serviceVersion,\n 'deployment.environment': environment,\n });\n\n const traceExporter = new OTLPTraceExporter({ url: endpoint });\n const instrumentationConfig = buildInstrumentationConfig(autoInstrumentation);\n\n // Left to its own devices, NodeSDK auto-configures a MeterProvider from\n // OTEL_METRICS_EXPORTER (default 'otlp' over HTTP -> localhost:4318) and registers\n // it as the GLOBAL meter provider on start(). When the caller manages metrics\n // separately, that produces a duplicate global registration and ships metrics to\n // localhost:4318 (ECONNREFUSED). So:\n // - reader provided -> NodeSDK owns metrics via this gRPC reader (single SDK,\n // single global MeterProvider, same collector as traces).\n // - reader omitted -> opt NodeSDK out of metrics entirely (unless the deployer\n // explicitly set OTEL_METRICS_EXPORTER) so it registers no\n // stray provider.\n if (!metricReader && !process.env.OTEL_METRICS_EXPORTER) {\n process.env.OTEL_METRICS_EXPORTER = 'none';\n }\n\n sdk = new NodeSDK({\n resource,\n traceExporter,\n ...(metricReader ? { metricReaders: [metricReader] } : {}),\n instrumentations: [getNodeAutoInstrumentations(instrumentationConfig)],\n });\n\n sdk.start();\n isInitialized = true;\n}\n\nfunction buildInstrumentationConfig(\n config: AutoInstrumentationConfig\n): Record<string, { enabled: boolean }> {\n const mapping: Record<string, string> = {\n http: '@opentelemetry/instrumentation-http',\n fastify: '@opentelemetry/instrumentation-fastify',\n express: '@opentelemetry/instrumentation-express',\n mongodb: '@opentelemetry/instrumentation-mongodb',\n pg: '@opentelemetry/instrumentation-pg',\n mysql: '@opentelemetry/instrumentation-mysql',\n redis: '@opentelemetry/instrumentation-redis',\n ioredis: '@opentelemetry/instrumentation-ioredis',\n grpc: '@opentelemetry/instrumentation-grpc',\n fs: '@opentelemetry/instrumentation-fs',\n dns: '@opentelemetry/instrumentation-dns',\n };\n\n const result: Record<string, { enabled: boolean }> = {};\n for (const [key, instrumentationName] of Object.entries(mapping)) {\n const userSetting = config[key as keyof AutoInstrumentationConfig];\n const defaultValue = key !== 'fs' && key !== 'dns';\n result[instrumentationName] = { enabled: userSetting ?? defaultValue };\n }\n return result;\n}\n\n/** Shutdown tracing gracefully */\nexport async function shutdownTracing(): Promise<void> {\n if (!sdk) return;\n try {\n await sdk.shutdown();\n isInitialized = false;\n sdk = null;\n } catch (error) {\n console.error('[neoiq-foundation] Error shutting down tracing:', error);\n throw error;\n }\n}\n\nexport function getTracer(name: string): Tracer {\n return trace.getTracer(name);\n}\n\nexport function getActiveSpan(): ReturnType<typeof trace.getActiveSpan> {\n return trace.getActiveSpan();\n}\n\nexport function getTraceContext(): { traceId?: string; spanId?: string } {\n const span = trace.getActiveSpan();\n if (!span) return {};\n const ctx = span.spanContext();\n return { traceId: ctx.traceId, spanId: ctx.spanId };\n}\n\nexport function isTracingEnabled(): boolean {\n return isInitialized;\n}\n\nexport { trace, context, propagation, SpanStatusCode };\nexport type { Tracer };\n"],"mappings":"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"}
1
+ {"version":3,"file":"tracing-BdAbHWu1.mjs","names":["input: FoundationConfigInput","sdk: NodeSDK | null","options: TracingOptions","config: AutoInstrumentationConfig","mapping: Record<string, string>","result: Record<string, { enabled: boolean }>","name: string"],"sources":["../src/config.ts","../src/features/tracing.ts"],"sourcesContent":["/**\n * Foundation Configuration with Zod Validation\n */\n\nimport { z } from 'zod';\n\n// Auto-Instrumentation Config\nexport const AutoInstrumentationConfigSchema = z\n .object({\n http: z.boolean().default(true),\n fastify: z.boolean().default(true),\n express: z.boolean().default(true),\n mongodb: z.boolean().default(true),\n pg: z.boolean().default(true),\n mysql: z.boolean().default(true),\n redis: z.boolean().default(true),\n ioredis: z.boolean().default(true),\n grpc: z.boolean().default(true),\n fs: z.boolean().default(false),\n dns: z.boolean().default(false),\n })\n .partial();\n\nexport type AutoInstrumentationConfig = z.infer<typeof AutoInstrumentationConfigSchema>;\n\n// Features Config\nexport const FeaturesConfigSchema = z\n .object({\n tracing: z.boolean().default(true),\n metrics: z.boolean().default(true),\n logging: z.boolean().default(true),\n autoInstrumentation: AutoInstrumentationConfigSchema.default({}),\n })\n .partial();\n\nexport type FeaturesConfig = z.infer<typeof FeaturesConfigSchema>;\n\n// OTEL Config\nconst DEFAULT_OTEL_ENDPOINT =\n 'http://otel-stack-deployment-collector.observability.svc.cluster.local:4317';\n\nexport const OtelConfigSchema = z.object({\n endpoint: z\n .string()\n .default(() => process.env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_OTEL_ENDPOINT),\n metricsIntervalMs: z.number().min(1000).default(5000),\n});\n\nexport type OtelConfig = z.infer<typeof OtelConfigSchema>;\n\n// Logging Config\nexport const LoggingConfigSchema = z\n .object({\n level: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n prettyPrint: z.boolean().optional(),\n })\n .partial();\n\nexport type LoggingConfig = z.infer<typeof LoggingConfigSchema>;\n\n// Request Logging Config\nexport const RequestLoggingConfigSchema = z\n .object({\n logHeaders: z.boolean().default(true),\n logBody: z.boolean().default(false),\n logResponseBody: z.boolean().default(false),\n maxBodySize: z.number().default(10 * 1024),\n redactHeaders: z.array(z.string()).optional(),\n })\n .partial();\n\nexport type RequestLoggingConfig = z.infer<typeof RequestLoggingConfigSchema>;\n\n// Redaction Config\nexport const RedactionConfigSchema = z\n .object({\n additionalPaths: z.array(z.string()).default([]),\n })\n .partial();\n\nexport type RedactionConfig = z.infer<typeof RedactionConfigSchema>;\n\n// Shutdown Config\nexport const ShutdownConfigSchema = z\n .object({\n /** Flush telemetry on uncaughtException / unhandledRejection before process exits */\n flushOnCrash: z.boolean().default(false),\n /** Grace period (ms) for flushing before forcing exit */\n flushTimeoutMs: z.number().min(100).default(5000),\n })\n .partial();\n\nexport type ShutdownConfig = z.infer<typeof ShutdownConfigSchema>;\n\n// Vault Config\nexport const VaultConfigSchema = z.object({\n enabled: z.boolean().default(false),\n address: z.string().default('https://vault.beta.commerceiq.ai'),\n authMethod: z.enum(['kubernetes', 'token']).default('kubernetes'),\n role: z.string().optional(),\n mountPoint: z.string().default('secret'),\n tokenPath: z.string().default('/var/run/secrets/kubernetes.io/serviceaccount/token'),\n k8sAuthMount: z.string().default('kubernetes'),\n namespace: z.string().optional(),\n});\n\nexport type VaultConfig = z.infer<typeof VaultConfigSchema>;\n\n// Main Foundation Config\nexport const FoundationConfigSchema = z.object({\n serviceName: z.string().min(1, 'serviceName is required'),\n serviceVersion: z.string().default(process.env.SERVICE_VERSION || '1.0.0'),\n environment: z\n .enum(['development', 'staging', 'qa', 'production'])\n .default(\n ['development', 'staging', 'qa', 'production'].includes(process.env.NODE_ENV ?? '')\n ? (process.env.NODE_ENV as 'development' | 'staging' | 'qa' | 'production')\n : 'development'\n ),\n features: FeaturesConfigSchema.default({}),\n otel: OtelConfigSchema.default({}),\n logging: LoggingConfigSchema.default({}),\n requestLogging: RequestLoggingConfigSchema.default({}),\n redaction: RedactionConfigSchema.default({}),\n shutdown: ShutdownConfigSchema.default({}),\n vault: VaultConfigSchema.default({}),\n});\n\nexport type FoundationConfig = z.infer<typeof FoundationConfigSchema>;\n\nexport type FoundationConfigInput = z.input<typeof FoundationConfigSchema> & {\n serviceName: string;\n};\n\n/** Parse and validate configuration */\nexport function parseConfig(input: FoundationConfigInput): FoundationConfig {\n const result = FoundationConfigSchema.safeParse(input);\n\n if (!result.success) {\n const errors = result.error.errors\n .map((e) => ` - ${e.path.join('.')}: ${e.message}`)\n .join('\\n');\n throw new Error(`Invalid foundation configuration:\\n${errors}`);\n }\n\n return result.data;\n}\n\n/** Get default OTEL endpoint */\nexport function getDefaultOtelEndpoint(): string {\n return process.env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_OTEL_ENDPOINT;\n}\n","/**\n * OpenTelemetry Tracing Setup\n */\n\nimport { NodeSDK } from '@opentelemetry/sdk-node';\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';\nimport { resourceFromAttributes } from '@opentelemetry/resources';\nimport { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';\nimport { trace, context, propagation, SpanStatusCode, type Tracer } from '@opentelemetry/api';\nimport { type IMetricReader } from '@opentelemetry/sdk-metrics';\nimport { type AutoInstrumentationConfig, getDefaultOtelEndpoint } from '../config';\n\nexport interface TracingOptions {\n serviceName: string;\n serviceVersion: string;\n environment: string;\n endpoint?: string;\n autoInstrumentation?: AutoInstrumentationConfig;\n /**\n * Metric reader to attach to the NodeSDK so a single SDK owns both traces and\n * metrics (one global MeterProvider, same gRPC collector). When provided, NodeSDK\n * is the sole owner of metrics; when omitted, NodeSDK is opted out of metrics\n * entirely (see below) so it never registers a stray default MeterProvider.\n */\n metricReader?: IMetricReader;\n}\n\nlet sdk: NodeSDK | null = null;\nlet isInitialized = false;\n\nconst MONITORED_MODULES = ['pg', 'mongodb', 'ioredis', 'mysql2', 'express', '@grpc/grpc-js'];\n\nfunction warnPreloadedModules(): void {\n // require.resolve / require.cache are only available in CJS contexts\n if (typeof require === 'undefined' || typeof require.cache === 'undefined') return;\n\n for (const mod of MONITORED_MODULES) {\n try {\n const resolved = require.resolve(mod);\n if (require.cache[resolved]) {\n console.warn(\n `[neoiq-foundation] \"${mod}\" was imported before tracing init. ` +\n 'Auto-instrumentation may not work for this module. ' +\n 'Use node -r @ciq-dev/neoiq-foundation-node/bootstrap or call createFoundation() first.'\n );\n }\n } catch {\n // Module not installed — no warning needed\n }\n }\n}\n\n/** Initialize OpenTelemetry tracing */\nexport function setupTracing(options: TracingOptions): void {\n if (isInitialized) {\n console.warn('[neoiq-foundation] Tracing already initialized');\n return;\n }\n\n warnPreloadedModules();\n\n const {\n serviceName,\n serviceVersion,\n environment,\n endpoint = getDefaultOtelEndpoint(),\n autoInstrumentation = {},\n metricReader,\n } = options;\n\n const resource = resourceFromAttributes({\n [ATTR_SERVICE_NAME]: serviceName,\n [ATTR_SERVICE_VERSION]: serviceVersion,\n 'deployment.environment': environment,\n });\n\n const traceExporter = new OTLPTraceExporter({ url: endpoint });\n const instrumentationConfig = buildInstrumentationConfig(autoInstrumentation);\n\n // Foundation owns every OpenTelemetry signal explicitly. Left to its own devices,\n // NodeSDK auto-configures metrics AND logs exporters from env defaults — both OTLP\n // over HTTP to localhost:4318 — which nothing listens on, producing ECONNREFUSED\n // spam every export interval. We therefore configure each signal on NodeSDK directly:\n // - traces: the explicit gRPC exporter above.\n // - metrics: the explicit gRPC reader when provided (single SDK, single global\n // MeterProvider, same collector as traces). When metrics are disabled\n // and the deployer hasn't chosen an exporter, opt NodeSDK out via\n // OTEL_METRICS_EXPORTER=none (the only switch NodeSDK exposes for that).\n // - logs: foundation logs via pino, never OTLP. Passing an empty processor list\n // stops NodeSDK from falling back to its env-default localhost:4318 log\n // exporter (`logRecordProcessors: []` takes the explicit branch and skips\n // configureLoggerProviderFromEnv()).\n if (!metricReader && !process.env.OTEL_METRICS_EXPORTER) {\n process.env.OTEL_METRICS_EXPORTER = 'none';\n }\n\n sdk = new NodeSDK({\n resource,\n traceExporter,\n ...(metricReader ? { metricReaders: [metricReader] } : {}),\n logRecordProcessors: [],\n instrumentations: [getNodeAutoInstrumentations(instrumentationConfig)],\n });\n\n sdk.start();\n isInitialized = true;\n}\n\nfunction buildInstrumentationConfig(\n config: AutoInstrumentationConfig\n): Record<string, { enabled: boolean }> {\n const mapping: Record<string, string> = {\n http: '@opentelemetry/instrumentation-http',\n fastify: '@opentelemetry/instrumentation-fastify',\n express: '@opentelemetry/instrumentation-express',\n mongodb: '@opentelemetry/instrumentation-mongodb',\n pg: '@opentelemetry/instrumentation-pg',\n mysql: '@opentelemetry/instrumentation-mysql',\n redis: '@opentelemetry/instrumentation-redis',\n ioredis: '@opentelemetry/instrumentation-ioredis',\n grpc: '@opentelemetry/instrumentation-grpc',\n fs: '@opentelemetry/instrumentation-fs',\n dns: '@opentelemetry/instrumentation-dns',\n };\n\n const result: Record<string, { enabled: boolean }> = {};\n for (const [key, instrumentationName] of Object.entries(mapping)) {\n const userSetting = config[key as keyof AutoInstrumentationConfig];\n const defaultValue = key !== 'fs' && key !== 'dns';\n result[instrumentationName] = { enabled: userSetting ?? defaultValue };\n }\n return result;\n}\n\n/** Shutdown tracing gracefully */\nexport async function shutdownTracing(): Promise<void> {\n if (!sdk) return;\n try {\n await sdk.shutdown();\n isInitialized = false;\n sdk = null;\n } catch (error) {\n console.error('[neoiq-foundation] Error shutting down tracing:', error);\n throw error;\n }\n}\n\nexport function getTracer(name: string): Tracer {\n return trace.getTracer(name);\n}\n\nexport function getActiveSpan(): ReturnType<typeof trace.getActiveSpan> {\n return trace.getActiveSpan();\n}\n\nexport function getTraceContext(): { traceId?: string; spanId?: string } {\n const span = trace.getActiveSpan();\n if (!span) return {};\n const ctx = span.spanContext();\n return { traceId: ctx.traceId, spanId: ctx.spanId };\n}\n\nexport function isTracingEnabled(): boolean {\n return isInitialized;\n}\n\nexport { trace, context, propagation, SpanStatusCode };\nexport type { Tracer };\n"],"mappings":"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"}
@@ -53,15 +53,7 @@ const FeaturesConfigSchema = zod.z.object({
53
53
  const DEFAULT_OTEL_ENDPOINT = "http://otel-stack-deployment-collector.observability.svc.cluster.local:4317";
54
54
  const OtelConfigSchema = zod.z.object({
55
55
  endpoint: zod.z.string().default(() => process.env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_OTEL_ENDPOINT),
56
- metricsIntervalMs: zod.z.number().min(1e3).default(5e3),
57
- diagLogLevel: zod.z.enum([
58
- "none",
59
- "error",
60
- "warn",
61
- "info",
62
- "debug",
63
- "verbose"
64
- ]).default("warn")
56
+ metricsIntervalMs: zod.z.number().min(1e3).default(5e3)
65
57
  });
66
58
  const LoggingConfigSchema = zod.z.object({
67
59
  level: zod.z.enum([
@@ -169,6 +161,7 @@ function setupTracing(options) {
169
161
  resource,
170
162
  traceExporter,
171
163
  ...metricReader ? { metricReaders: [metricReader] } : {},
164
+ logRecordProcessors: [],
172
165
  instrumentations: [(0, __opentelemetry_auto_instrumentations_node.getNodeAutoInstrumentations)(instrumentationConfig)]
173
166
  });
174
167
  sdk.start();
@@ -336,4 +329,4 @@ Object.defineProperty(exports, 'shutdownTracing', {
336
329
  return shutdownTracing;
337
330
  }
338
331
  });
339
- //# sourceMappingURL=tracing-BO_KNVfZ.js.map
332
+ //# sourceMappingURL=tracing-Cdy7GW7Y.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracing-Cdy7GW7Y.js","names":["input: FoundationConfigInput","sdk: NodeSDK | null","options: TracingOptions","config: AutoInstrumentationConfig","mapping: Record<string, string>","result: Record<string, { enabled: boolean }>","name: string"],"sources":["../src/config.ts","../src/features/tracing.ts"],"sourcesContent":["/**\n * Foundation Configuration with Zod Validation\n */\n\nimport { z } from 'zod';\n\n// Auto-Instrumentation Config\nexport const AutoInstrumentationConfigSchema = z\n .object({\n http: z.boolean().default(true),\n fastify: z.boolean().default(true),\n express: z.boolean().default(true),\n mongodb: z.boolean().default(true),\n pg: z.boolean().default(true),\n mysql: z.boolean().default(true),\n redis: z.boolean().default(true),\n ioredis: z.boolean().default(true),\n grpc: z.boolean().default(true),\n fs: z.boolean().default(false),\n dns: z.boolean().default(false),\n })\n .partial();\n\nexport type AutoInstrumentationConfig = z.infer<typeof AutoInstrumentationConfigSchema>;\n\n// Features Config\nexport const FeaturesConfigSchema = z\n .object({\n tracing: z.boolean().default(true),\n metrics: z.boolean().default(true),\n logging: z.boolean().default(true),\n autoInstrumentation: AutoInstrumentationConfigSchema.default({}),\n })\n .partial();\n\nexport type FeaturesConfig = z.infer<typeof FeaturesConfigSchema>;\n\n// OTEL Config\nconst DEFAULT_OTEL_ENDPOINT =\n 'http://otel-stack-deployment-collector.observability.svc.cluster.local:4317';\n\nexport const OtelConfigSchema = z.object({\n endpoint: z\n .string()\n .default(() => process.env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_OTEL_ENDPOINT),\n metricsIntervalMs: z.number().min(1000).default(5000),\n});\n\nexport type OtelConfig = z.infer<typeof OtelConfigSchema>;\n\n// Logging Config\nexport const LoggingConfigSchema = z\n .object({\n level: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n prettyPrint: z.boolean().optional(),\n })\n .partial();\n\nexport type LoggingConfig = z.infer<typeof LoggingConfigSchema>;\n\n// Request Logging Config\nexport const RequestLoggingConfigSchema = z\n .object({\n logHeaders: z.boolean().default(true),\n logBody: z.boolean().default(false),\n logResponseBody: z.boolean().default(false),\n maxBodySize: z.number().default(10 * 1024),\n redactHeaders: z.array(z.string()).optional(),\n })\n .partial();\n\nexport type RequestLoggingConfig = z.infer<typeof RequestLoggingConfigSchema>;\n\n// Redaction Config\nexport const RedactionConfigSchema = z\n .object({\n additionalPaths: z.array(z.string()).default([]),\n })\n .partial();\n\nexport type RedactionConfig = z.infer<typeof RedactionConfigSchema>;\n\n// Shutdown Config\nexport const ShutdownConfigSchema = z\n .object({\n /** Flush telemetry on uncaughtException / unhandledRejection before process exits */\n flushOnCrash: z.boolean().default(false),\n /** Grace period (ms) for flushing before forcing exit */\n flushTimeoutMs: z.number().min(100).default(5000),\n })\n .partial();\n\nexport type ShutdownConfig = z.infer<typeof ShutdownConfigSchema>;\n\n// Vault Config\nexport const VaultConfigSchema = z.object({\n enabled: z.boolean().default(false),\n address: z.string().default('https://vault.beta.commerceiq.ai'),\n authMethod: z.enum(['kubernetes', 'token']).default('kubernetes'),\n role: z.string().optional(),\n mountPoint: z.string().default('secret'),\n tokenPath: z.string().default('/var/run/secrets/kubernetes.io/serviceaccount/token'),\n k8sAuthMount: z.string().default('kubernetes'),\n namespace: z.string().optional(),\n});\n\nexport type VaultConfig = z.infer<typeof VaultConfigSchema>;\n\n// Main Foundation Config\nexport const FoundationConfigSchema = z.object({\n serviceName: z.string().min(1, 'serviceName is required'),\n serviceVersion: z.string().default(process.env.SERVICE_VERSION || '1.0.0'),\n environment: z\n .enum(['development', 'staging', 'qa', 'production'])\n .default(\n ['development', 'staging', 'qa', 'production'].includes(process.env.NODE_ENV ?? '')\n ? (process.env.NODE_ENV as 'development' | 'staging' | 'qa' | 'production')\n : 'development'\n ),\n features: FeaturesConfigSchema.default({}),\n otel: OtelConfigSchema.default({}),\n logging: LoggingConfigSchema.default({}),\n requestLogging: RequestLoggingConfigSchema.default({}),\n redaction: RedactionConfigSchema.default({}),\n shutdown: ShutdownConfigSchema.default({}),\n vault: VaultConfigSchema.default({}),\n});\n\nexport type FoundationConfig = z.infer<typeof FoundationConfigSchema>;\n\nexport type FoundationConfigInput = z.input<typeof FoundationConfigSchema> & {\n serviceName: string;\n};\n\n/** Parse and validate configuration */\nexport function parseConfig(input: FoundationConfigInput): FoundationConfig {\n const result = FoundationConfigSchema.safeParse(input);\n\n if (!result.success) {\n const errors = result.error.errors\n .map((e) => ` - ${e.path.join('.')}: ${e.message}`)\n .join('\\n');\n throw new Error(`Invalid foundation configuration:\\n${errors}`);\n }\n\n return result.data;\n}\n\n/** Get default OTEL endpoint */\nexport function getDefaultOtelEndpoint(): string {\n return process.env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_OTEL_ENDPOINT;\n}\n","/**\n * OpenTelemetry Tracing Setup\n */\n\nimport { NodeSDK } from '@opentelemetry/sdk-node';\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';\nimport { resourceFromAttributes } from '@opentelemetry/resources';\nimport { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';\nimport { trace, context, propagation, SpanStatusCode, type Tracer } from '@opentelemetry/api';\nimport { type IMetricReader } from '@opentelemetry/sdk-metrics';\nimport { type AutoInstrumentationConfig, getDefaultOtelEndpoint } from '../config';\n\nexport interface TracingOptions {\n serviceName: string;\n serviceVersion: string;\n environment: string;\n endpoint?: string;\n autoInstrumentation?: AutoInstrumentationConfig;\n /**\n * Metric reader to attach to the NodeSDK so a single SDK owns both traces and\n * metrics (one global MeterProvider, same gRPC collector). When provided, NodeSDK\n * is the sole owner of metrics; when omitted, NodeSDK is opted out of metrics\n * entirely (see below) so it never registers a stray default MeterProvider.\n */\n metricReader?: IMetricReader;\n}\n\nlet sdk: NodeSDK | null = null;\nlet isInitialized = false;\n\nconst MONITORED_MODULES = ['pg', 'mongodb', 'ioredis', 'mysql2', 'express', '@grpc/grpc-js'];\n\nfunction warnPreloadedModules(): void {\n // require.resolve / require.cache are only available in CJS contexts\n if (typeof require === 'undefined' || typeof require.cache === 'undefined') return;\n\n for (const mod of MONITORED_MODULES) {\n try {\n const resolved = require.resolve(mod);\n if (require.cache[resolved]) {\n console.warn(\n `[neoiq-foundation] \"${mod}\" was imported before tracing init. ` +\n 'Auto-instrumentation may not work for this module. ' +\n 'Use node -r @ciq-dev/neoiq-foundation-node/bootstrap or call createFoundation() first.'\n );\n }\n } catch {\n // Module not installed — no warning needed\n }\n }\n}\n\n/** Initialize OpenTelemetry tracing */\nexport function setupTracing(options: TracingOptions): void {\n if (isInitialized) {\n console.warn('[neoiq-foundation] Tracing already initialized');\n return;\n }\n\n warnPreloadedModules();\n\n const {\n serviceName,\n serviceVersion,\n environment,\n endpoint = getDefaultOtelEndpoint(),\n autoInstrumentation = {},\n metricReader,\n } = options;\n\n const resource = resourceFromAttributes({\n [ATTR_SERVICE_NAME]: serviceName,\n [ATTR_SERVICE_VERSION]: serviceVersion,\n 'deployment.environment': environment,\n });\n\n const traceExporter = new OTLPTraceExporter({ url: endpoint });\n const instrumentationConfig = buildInstrumentationConfig(autoInstrumentation);\n\n // Foundation owns every OpenTelemetry signal explicitly. Left to its own devices,\n // NodeSDK auto-configures metrics AND logs exporters from env defaults — both OTLP\n // over HTTP to localhost:4318 — which nothing listens on, producing ECONNREFUSED\n // spam every export interval. We therefore configure each signal on NodeSDK directly:\n // - traces: the explicit gRPC exporter above.\n // - metrics: the explicit gRPC reader when provided (single SDK, single global\n // MeterProvider, same collector as traces). When metrics are disabled\n // and the deployer hasn't chosen an exporter, opt NodeSDK out via\n // OTEL_METRICS_EXPORTER=none (the only switch NodeSDK exposes for that).\n // - logs: foundation logs via pino, never OTLP. Passing an empty processor list\n // stops NodeSDK from falling back to its env-default localhost:4318 log\n // exporter (`logRecordProcessors: []` takes the explicit branch and skips\n // configureLoggerProviderFromEnv()).\n if (!metricReader && !process.env.OTEL_METRICS_EXPORTER) {\n process.env.OTEL_METRICS_EXPORTER = 'none';\n }\n\n sdk = new NodeSDK({\n resource,\n traceExporter,\n ...(metricReader ? { metricReaders: [metricReader] } : {}),\n logRecordProcessors: [],\n instrumentations: [getNodeAutoInstrumentations(instrumentationConfig)],\n });\n\n sdk.start();\n isInitialized = true;\n}\n\nfunction buildInstrumentationConfig(\n config: AutoInstrumentationConfig\n): Record<string, { enabled: boolean }> {\n const mapping: Record<string, string> = {\n http: '@opentelemetry/instrumentation-http',\n fastify: '@opentelemetry/instrumentation-fastify',\n express: '@opentelemetry/instrumentation-express',\n mongodb: '@opentelemetry/instrumentation-mongodb',\n pg: '@opentelemetry/instrumentation-pg',\n mysql: '@opentelemetry/instrumentation-mysql',\n redis: '@opentelemetry/instrumentation-redis',\n ioredis: '@opentelemetry/instrumentation-ioredis',\n grpc: '@opentelemetry/instrumentation-grpc',\n fs: '@opentelemetry/instrumentation-fs',\n dns: '@opentelemetry/instrumentation-dns',\n };\n\n const result: Record<string, { enabled: boolean }> = {};\n for (const [key, instrumentationName] of Object.entries(mapping)) {\n const userSetting = config[key as keyof AutoInstrumentationConfig];\n const defaultValue = key !== 'fs' && key !== 'dns';\n result[instrumentationName] = { enabled: userSetting ?? defaultValue };\n }\n return result;\n}\n\n/** Shutdown tracing gracefully */\nexport async function shutdownTracing(): Promise<void> {\n if (!sdk) return;\n try {\n await sdk.shutdown();\n isInitialized = false;\n sdk = null;\n } catch (error) {\n console.error('[neoiq-foundation] Error shutting down tracing:', error);\n throw error;\n }\n}\n\nexport function getTracer(name: string): Tracer {\n return trace.getTracer(name);\n}\n\nexport function getActiveSpan(): ReturnType<typeof trace.getActiveSpan> {\n return trace.getActiveSpan();\n}\n\nexport function getTraceContext(): { traceId?: string; spanId?: string } {\n const span = trace.getActiveSpan();\n if (!span) return {};\n const ctx = span.spanContext();\n return { traceId: ctx.traceId, spanId: ctx.spanId };\n}\n\nexport function isTracingEnabled(): boolean {\n return isInitialized;\n}\n\nexport { trace, context, propagation, SpanStatusCode };\nexport type { Tracer };\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ciq-dev/neoiq-foundation-node",
3
- "version": "1.1.2-beta.2",
3
+ "version": "1.1.2-beta.3",
4
4
  "description": "Node.js observability foundation for CommerceIQ services. Integrates with Groundcover via OpenTelemetry.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -1 +0,0 @@
1
- {"version":3,"file":"tracing-BO_KNVfZ.js","names":["input: FoundationConfigInput","sdk: NodeSDK | null","options: TracingOptions","config: AutoInstrumentationConfig","mapping: Record<string, string>","result: Record<string, { enabled: boolean }>","name: string"],"sources":["../src/config.ts","../src/features/tracing.ts"],"sourcesContent":["/**\n * Foundation Configuration with Zod Validation\n */\n\nimport { z } from 'zod';\n\n// Auto-Instrumentation Config\nexport const AutoInstrumentationConfigSchema = z\n .object({\n http: z.boolean().default(true),\n fastify: z.boolean().default(true),\n express: z.boolean().default(true),\n mongodb: z.boolean().default(true),\n pg: z.boolean().default(true),\n mysql: z.boolean().default(true),\n redis: z.boolean().default(true),\n ioredis: z.boolean().default(true),\n grpc: z.boolean().default(true),\n fs: z.boolean().default(false),\n dns: z.boolean().default(false),\n })\n .partial();\n\nexport type AutoInstrumentationConfig = z.infer<typeof AutoInstrumentationConfigSchema>;\n\n// Features Config\nexport const FeaturesConfigSchema = z\n .object({\n tracing: z.boolean().default(true),\n metrics: z.boolean().default(true),\n logging: z.boolean().default(true),\n autoInstrumentation: AutoInstrumentationConfigSchema.default({}),\n })\n .partial();\n\nexport type FeaturesConfig = z.infer<typeof FeaturesConfigSchema>;\n\n// OTEL Config\nconst DEFAULT_OTEL_ENDPOINT =\n 'http://otel-stack-deployment-collector.observability.svc.cluster.local:4317';\n\nexport const OtelConfigSchema = z.object({\n endpoint: z\n .string()\n .default(() => process.env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_OTEL_ENDPOINT),\n metricsIntervalMs: z.number().min(1000).default(5000),\n // Level at which OpenTelemetry SDK internal logs are routed to the foundation\n // logger. This is the ONLY way OTLP export failures (e.g. the collector being\n // unreachable or rejecting telemetry) surface — they are emitted asynchronously\n // on the export interval via the diag channel, not through setup try/catch.\n // 'none' disables the bridge. Overridable at deploy time via OTEL_DIAG_LOG_LEVEL.\n diagLogLevel: z.enum(['none', 'error', 'warn', 'info', 'debug', 'verbose']).default('warn'),\n});\n\nexport type OtelConfig = z.infer<typeof OtelConfigSchema>;\n\n// Logging Config\nexport const LoggingConfigSchema = z\n .object({\n level: z.enum(['debug', 'info', 'warn', 'error']).default('info'),\n prettyPrint: z.boolean().optional(),\n })\n .partial();\n\nexport type LoggingConfig = z.infer<typeof LoggingConfigSchema>;\n\n// Request Logging Config\nexport const RequestLoggingConfigSchema = z\n .object({\n logHeaders: z.boolean().default(true),\n logBody: z.boolean().default(false),\n logResponseBody: z.boolean().default(false),\n maxBodySize: z.number().default(10 * 1024),\n redactHeaders: z.array(z.string()).optional(),\n })\n .partial();\n\nexport type RequestLoggingConfig = z.infer<typeof RequestLoggingConfigSchema>;\n\n// Redaction Config\nexport const RedactionConfigSchema = z\n .object({\n additionalPaths: z.array(z.string()).default([]),\n })\n .partial();\n\nexport type RedactionConfig = z.infer<typeof RedactionConfigSchema>;\n\n// Shutdown Config\nexport const ShutdownConfigSchema = z\n .object({\n /** Flush telemetry on uncaughtException / unhandledRejection before process exits */\n flushOnCrash: z.boolean().default(false),\n /** Grace period (ms) for flushing before forcing exit */\n flushTimeoutMs: z.number().min(100).default(5000),\n })\n .partial();\n\nexport type ShutdownConfig = z.infer<typeof ShutdownConfigSchema>;\n\n// Vault Config\nexport const VaultConfigSchema = z.object({\n enabled: z.boolean().default(false),\n address: z.string().default('https://vault.beta.commerceiq.ai'),\n authMethod: z.enum(['kubernetes', 'token']).default('kubernetes'),\n role: z.string().optional(),\n mountPoint: z.string().default('secret'),\n tokenPath: z.string().default('/var/run/secrets/kubernetes.io/serviceaccount/token'),\n k8sAuthMount: z.string().default('kubernetes'),\n namespace: z.string().optional(),\n});\n\nexport type VaultConfig = z.infer<typeof VaultConfigSchema>;\n\n// Main Foundation Config\nexport const FoundationConfigSchema = z.object({\n serviceName: z.string().min(1, 'serviceName is required'),\n serviceVersion: z.string().default(process.env.SERVICE_VERSION || '1.0.0'),\n environment: z\n .enum(['development', 'staging', 'qa', 'production'])\n .default(\n ['development', 'staging', 'qa', 'production'].includes(process.env.NODE_ENV ?? '')\n ? (process.env.NODE_ENV as 'development' | 'staging' | 'qa' | 'production')\n : 'development'\n ),\n features: FeaturesConfigSchema.default({}),\n otel: OtelConfigSchema.default({}),\n logging: LoggingConfigSchema.default({}),\n requestLogging: RequestLoggingConfigSchema.default({}),\n redaction: RedactionConfigSchema.default({}),\n shutdown: ShutdownConfigSchema.default({}),\n vault: VaultConfigSchema.default({}),\n});\n\nexport type FoundationConfig = z.infer<typeof FoundationConfigSchema>;\n\nexport type FoundationConfigInput = z.input<typeof FoundationConfigSchema> & {\n serviceName: string;\n};\n\n/** Parse and validate configuration */\nexport function parseConfig(input: FoundationConfigInput): FoundationConfig {\n const result = FoundationConfigSchema.safeParse(input);\n\n if (!result.success) {\n const errors = result.error.errors\n .map((e) => ` - ${e.path.join('.')}: ${e.message}`)\n .join('\\n');\n throw new Error(`Invalid foundation configuration:\\n${errors}`);\n }\n\n return result.data;\n}\n\n/** Get default OTEL endpoint */\nexport function getDefaultOtelEndpoint(): string {\n return process.env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_OTEL_ENDPOINT;\n}\n","/**\n * OpenTelemetry Tracing Setup\n */\n\nimport { NodeSDK } from '@opentelemetry/sdk-node';\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';\nimport { resourceFromAttributes } from '@opentelemetry/resources';\nimport { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';\nimport { trace, context, propagation, SpanStatusCode, type Tracer } from '@opentelemetry/api';\nimport { type IMetricReader } from '@opentelemetry/sdk-metrics';\nimport { type AutoInstrumentationConfig, getDefaultOtelEndpoint } from '../config';\n\nexport interface TracingOptions {\n serviceName: string;\n serviceVersion: string;\n environment: string;\n endpoint?: string;\n autoInstrumentation?: AutoInstrumentationConfig;\n /**\n * Metric reader to attach to the NodeSDK so a single SDK owns both traces and\n * metrics (one global MeterProvider, same gRPC collector). When provided, NodeSDK\n * is the sole owner of metrics; when omitted, NodeSDK is opted out of metrics\n * entirely (see below) so it never registers a stray default MeterProvider.\n */\n metricReader?: IMetricReader;\n}\n\nlet sdk: NodeSDK | null = null;\nlet isInitialized = false;\n\nconst MONITORED_MODULES = ['pg', 'mongodb', 'ioredis', 'mysql2', 'express', '@grpc/grpc-js'];\n\nfunction warnPreloadedModules(): void {\n // require.resolve / require.cache are only available in CJS contexts\n if (typeof require === 'undefined' || typeof require.cache === 'undefined') return;\n\n for (const mod of MONITORED_MODULES) {\n try {\n const resolved = require.resolve(mod);\n if (require.cache[resolved]) {\n console.warn(\n `[neoiq-foundation] \"${mod}\" was imported before tracing init. ` +\n 'Auto-instrumentation may not work for this module. ' +\n 'Use node -r @ciq-dev/neoiq-foundation-node/bootstrap or call createFoundation() first.'\n );\n }\n } catch {\n // Module not installed — no warning needed\n }\n }\n}\n\n/** Initialize OpenTelemetry tracing */\nexport function setupTracing(options: TracingOptions): void {\n if (isInitialized) {\n console.warn('[neoiq-foundation] Tracing already initialized');\n return;\n }\n\n warnPreloadedModules();\n\n const {\n serviceName,\n serviceVersion,\n environment,\n endpoint = getDefaultOtelEndpoint(),\n autoInstrumentation = {},\n metricReader,\n } = options;\n\n const resource = resourceFromAttributes({\n [ATTR_SERVICE_NAME]: serviceName,\n [ATTR_SERVICE_VERSION]: serviceVersion,\n 'deployment.environment': environment,\n });\n\n const traceExporter = new OTLPTraceExporter({ url: endpoint });\n const instrumentationConfig = buildInstrumentationConfig(autoInstrumentation);\n\n // Left to its own devices, NodeSDK auto-configures a MeterProvider from\n // OTEL_METRICS_EXPORTER (default 'otlp' over HTTP -> localhost:4318) and registers\n // it as the GLOBAL meter provider on start(). When the caller manages metrics\n // separately, that produces a duplicate global registration and ships metrics to\n // localhost:4318 (ECONNREFUSED). So:\n // - reader provided -> NodeSDK owns metrics via this gRPC reader (single SDK,\n // single global MeterProvider, same collector as traces).\n // - reader omitted -> opt NodeSDK out of metrics entirely (unless the deployer\n // explicitly set OTEL_METRICS_EXPORTER) so it registers no\n // stray provider.\n if (!metricReader && !process.env.OTEL_METRICS_EXPORTER) {\n process.env.OTEL_METRICS_EXPORTER = 'none';\n }\n\n sdk = new NodeSDK({\n resource,\n traceExporter,\n ...(metricReader ? { metricReaders: [metricReader] } : {}),\n instrumentations: [getNodeAutoInstrumentations(instrumentationConfig)],\n });\n\n sdk.start();\n isInitialized = true;\n}\n\nfunction buildInstrumentationConfig(\n config: AutoInstrumentationConfig\n): Record<string, { enabled: boolean }> {\n const mapping: Record<string, string> = {\n http: '@opentelemetry/instrumentation-http',\n fastify: '@opentelemetry/instrumentation-fastify',\n express: '@opentelemetry/instrumentation-express',\n mongodb: '@opentelemetry/instrumentation-mongodb',\n pg: '@opentelemetry/instrumentation-pg',\n mysql: '@opentelemetry/instrumentation-mysql',\n redis: '@opentelemetry/instrumentation-redis',\n ioredis: '@opentelemetry/instrumentation-ioredis',\n grpc: '@opentelemetry/instrumentation-grpc',\n fs: '@opentelemetry/instrumentation-fs',\n dns: '@opentelemetry/instrumentation-dns',\n };\n\n const result: Record<string, { enabled: boolean }> = {};\n for (const [key, instrumentationName] of Object.entries(mapping)) {\n const userSetting = config[key as keyof AutoInstrumentationConfig];\n const defaultValue = key !== 'fs' && key !== 'dns';\n result[instrumentationName] = { enabled: userSetting ?? defaultValue };\n }\n return result;\n}\n\n/** Shutdown tracing gracefully */\nexport async function shutdownTracing(): Promise<void> {\n if (!sdk) return;\n try {\n await sdk.shutdown();\n isInitialized = false;\n sdk = null;\n } catch (error) {\n console.error('[neoiq-foundation] Error shutting down tracing:', error);\n throw error;\n }\n}\n\nexport function getTracer(name: string): Tracer {\n return trace.getTracer(name);\n}\n\nexport function getActiveSpan(): ReturnType<typeof trace.getActiveSpan> {\n return trace.getActiveSpan();\n}\n\nexport function getTraceContext(): { traceId?: string; spanId?: string } {\n const span = trace.getActiveSpan();\n if (!span) return {};\n const ctx = span.spanContext();\n return { traceId: ctx.traceId, spanId: ctx.spanId };\n}\n\nexport function isTracingEnabled(): boolean {\n return isInitialized;\n}\n\nexport { trace, context, propagation, SpanStatusCode };\nexport type { Tracer };\n"],"mappings":"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"}