autotel-edge 3.15.1 → 3.16.1

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.
@@ -5,7 +5,7 @@ import { ParentBasedSampler, AlwaysOnSampler } from '@opentelemetry/sdk-trace-ba
5
5
  import { createContextKey, context } from '@opentelemetry/api';
6
6
 
7
7
  // src/core/exporter.ts
8
- var PACKAGE_VERSION = "3.15.1";
8
+ var PACKAGE_VERSION = "3.16.1";
9
9
  var defaultHeaders = {
10
10
  accept: "application/json",
11
11
  "content-type": "application/json",
@@ -306,5 +306,5 @@ function createInitialiser(config) {
306
306
  }
307
307
 
308
308
  export { OTLPExporter, createInitialiser, getActiveConfig, parseConfig, setConfig };
309
- //# sourceMappingURL=chunk-ICBZ6ZUQ.js.map
310
- //# sourceMappingURL=chunk-ICBZ6ZUQ.js.map
309
+ //# sourceMappingURL=chunk-D2WERTLK.js.map
310
+ //# sourceMappingURL=chunk-D2WERTLK.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/exporter.ts","../src/types.ts","../src/core/spanprocessor.ts","../src/core/config.ts"],"names":["api_context"],"mappings":"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","file":"chunk-ICBZ6ZUQ.js","sourcesContent":["/**\n * Lightweight OTLP exporter for edge environments\n * Ported and adapted from @microlabs/\n *\n * This exporter is much smaller than the standard @opentelemetry/exporter-trace-otlp-http\n * because it uses fetch() directly instead of Node.js http/https modules.\n */\n\nimport type { ExportResult } from '@opentelemetry/core';\nimport { ExportResultCode } from '@opentelemetry/core';\nimport { OTLPExporterError } from '@opentelemetry/otlp-exporter-base';\nimport { JsonTraceSerializer } from '@opentelemetry/otlp-transformer';\nimport type { SpanExporter } from '@opentelemetry/sdk-trace-base';\nimport type { OTLPExporterConfig } from '../types';\n\n// Version is injected at build time via tsup define\n// This avoids runtime filesystem access which isn't available in edge environments\nconst PACKAGE_VERSION = process.env.AUTOTEL_EDGE_VERSION || '0.1.1';\n\nconst defaultHeaders: Record<string, string> = {\n accept: 'application/json',\n 'content-type': 'application/json',\n 'user-agent': `autotel-edge v${PACKAGE_VERSION}`,\n};\n\n/**\n * Minimal OTLP exporter using fetch()\n */\nexport class OTLPExporter implements SpanExporter {\n private headers: Record<string, string>;\n private url: string;\n\n constructor(config: OTLPExporterConfig) {\n this.url = config.url;\n this.headers = Object.assign({}, defaultHeaders, config.headers);\n }\n\n export(items: any[], resultCallback: (result: ExportResult) => void): void {\n this._export(items)\n .then(() => {\n resultCallback({ code: ExportResultCode.SUCCESS });\n })\n .catch((error) => {\n resultCallback({ code: ExportResultCode.FAILED, error });\n });\n }\n\n private _export(items: any[]): Promise<unknown> {\n return new Promise<void>((resolve, reject) => {\n try {\n this.send(items, resolve, reject);\n } catch (error) {\n reject(error);\n }\n });\n }\n\n send(\n items: any[],\n onSuccess: () => void,\n onError: (error: OTLPExporterError) => void,\n ): void {\n const decoder = new TextDecoder();\n const exportMessage = JsonTraceSerializer.serializeRequest(items);\n\n const body = decoder.decode(exportMessage);\n const params: RequestInit = {\n method: 'POST',\n headers: this.headers,\n body,\n };\n\n fetch(this.url, params)\n .then((response) => {\n if (response.ok) {\n onSuccess();\n } else {\n onError(\n new OTLPExporterError(\n `Exporter received a statusCode: ${response.status}`,\n ),\n );\n }\n })\n .catch((error) => {\n onError(\n new OTLPExporterError(\n `Exception during export: ${error.toString()}`,\n error.code,\n error.stack,\n ),\n );\n });\n }\n\n async shutdown(): Promise<void> {\n // No-op for edge environments\n }\n}\n","/**\n * Shared types for autotel-edge\n */\n\nimport type {\n Attributes,\n Context,\n Span,\n SpanOptions,\n TextMapPropagator,\n} from '@opentelemetry/api';\nimport type {\n ReadableSpan,\n Sampler,\n SpanExporter,\n SpanProcessor,\n} from '@opentelemetry/sdk-trace-base';\n\n// Re-export commonly used types\n\n\n/**\n * Extended SpanOptions with per-span sampler support\n */\nexport interface ExtendedSpanOptions extends SpanOptions {\n sampler?: Sampler;\n}\n\n/**\n * Trigger types for edge handlers\n * Can be a Request or any vendor-specific trigger type\n */\nexport type Trigger =\n | Request\n | DOConstructorTrigger\n | WorkflowTrigger\n | 'do-alarm'\n | unknown;\n\nexport interface DOConstructorTrigger {\n id: string;\n name?: string;\n}\n\nexport interface WorkflowTrigger {\n type: 'workflow';\n name: string;\n}\n\n/**\n * Config types\n */\nexport interface OTLPExporterConfig {\n url: string;\n headers?: Record<string, string>;\n}\n\nexport type ExporterConfig = OTLPExporterConfig | SpanExporter;\n\nexport interface ServiceConfig {\n name: string;\n namespace?: string;\n version?: string;\n}\n\nexport interface ParentRatioSamplingConfig {\n acceptRemote?: boolean;\n ratio: number;\n}\n\ntype HeadSamplerConf = Sampler | ParentRatioSamplingConfig;\n\nexport interface SamplingConfig<HS extends HeadSamplerConf = HeadSamplerConf> {\n headSampler?: HS;\n tailSampler?: TailSampleFn;\n}\n\nexport interface InstrumentationOptions {\n instrumentGlobalFetch?: boolean;\n instrumentGlobalCache?: boolean;\n /**\n * Disable instrumentation entirely (useful for local development)\n * When enabled, the handler is returned as-is without any instrumentation\n * @default false\n */\n disabled?: boolean;\n}\n\n/**\n * Utility types\n */\nexport type OrPromise<T> = T | Promise<T>;\n\n/**\n * Adapter event types\n */\nexport type FunnelStepStatus =\n | 'started'\n | 'completed'\n | 'abandoned'\n | 'failed'\n | (string & {});\n\nexport type OutcomeStatus =\n | 'success'\n | 'failure'\n | 'partial'\n | (string & {});\n\nexport interface EdgeEventBase {\n [key: string]: unknown;\n service: string;\n timestamp: number;\n attributes: Record<string, unknown>;\n traceId?: string;\n spanId?: string;\n correlationId?: string;\n name: string; // Normalized event name for easy access\n}\n\nexport interface EdgeTrackEvent extends EdgeEventBase {\n type: 'event';\n event: string;\n}\n\nexport interface EdgeFunnelStepEvent extends EdgeEventBase {\n type: 'funnel-step';\n funnel: string;\n status: FunnelStepStatus;\n}\n\nexport interface EdgeOutcomeEvent extends EdgeEventBase {\n type: 'outcome';\n operation: string;\n outcome: OutcomeStatus;\n}\n\nexport interface EdgeValueEvent extends EdgeEventBase {\n type: 'value';\n metric: string;\n value: number;\n}\n\nexport type EdgeEvent =\n | EdgeTrackEvent\n | EdgeFunnelStepEvent\n | EdgeOutcomeEvent\n | EdgeValueEvent;\n\nexport type EdgeSubscriber = (event: EdgeEvent) => OrPromise<void>;\n\nexport interface FetcherConfig {\n includeTraceContext?: boolean | ((request: Request) => boolean);\n}\n\nexport interface PostProcessParams {\n /**\n * The request object that was passed to the fetch handler.\n */\n request: Request;\n /**\n * The generated response object.\n */\n response: Response;\n /**\n * A readable version of the span object that can be used to access the span's attributes and events.\n */\n readable: ReadableSpan;\n}\n\nexport interface FetchHandlerConfig {\n /**\n * Whether to enable context propagation for incoming requests to `fetch`.\n * This enables or disables distributed tracing from W3C Trace Context headers.\n * @default true\n */\n acceptTraceContext?: boolean | ((request: Request) => boolean);\n /**\n * Allows further customization of the generated span, based on the request/response data.\n */\n postProcess?: (span: Span, ctx: PostProcessParams) => void;\n}\n\nexport interface HandlerConfig {\n fetch?: FetchHandlerConfig;\n}\n\nexport interface DataSafetyConfig {\n /** Redact query parameters from URL attributes (default: false) */\n redactQueryParams?: boolean;\n /** Control D1 SQL statement capture: 'full' (default), 'obfuscated', or 'off' */\n captureDbStatement?: 'off' | 'obfuscated' | 'full';\n /** Only capture these email headers (lowercase). When set, other headers are excluded. */\n emailHeaderAllowlist?: string[];\n}\n\ninterface EdgeConfigBase {\n service: ServiceConfig;\n handlers?: HandlerConfig;\n fetch?: FetcherConfig;\n postProcessor?: PostProcessorFn;\n sampling?: SamplingConfig;\n propagator?: TextMapPropagator;\n instrumentation?: InstrumentationOptions;\n subscribers?: EdgeSubscriber[];\n /** Opt-in data safety controls for sensitive attribute capture */\n dataSafety?: DataSafetyConfig;\n}\n\ninterface EdgeConfigExporter extends EdgeConfigBase {\n exporter: ExporterConfig;\n}\n\ninterface EdgeConfigSpanProcessors extends EdgeConfigBase {\n spanProcessors: SpanProcessor | SpanProcessor[];\n}\n\nexport type EdgeConfig = EdgeConfigExporter | EdgeConfigSpanProcessors;\n\nexport function isSpanProcessorConfig(\n config: EdgeConfig,\n): config is EdgeConfigSpanProcessors {\n return !!(config as EdgeConfigSpanProcessors).spanProcessors;\n}\n\nexport interface ResolvedEdgeConfig extends EdgeConfigBase {\n handlers: Required<HandlerConfig>;\n fetch: Required<FetcherConfig>;\n postProcessor: PostProcessorFn;\n sampling: Required<SamplingConfig<Sampler>>;\n spanProcessors: SpanProcessor[];\n propagator: TextMapPropagator;\n instrumentation: InstrumentationOptions;\n subscribers: EdgeSubscriber[];\n}\n\n/**\n * Function types\n */\nexport type ResolveConfigFn<Env = any> = (\n env: Env,\n trigger: Trigger,\n) => EdgeConfig;\nexport type ConfigurationOption = EdgeConfig | ResolveConfigFn;\n\nexport type PostProcessorFn = (spans: ReadableSpan[]) => ReadableSpan[];\nexport type TailSampleFn = (traceInfo: LocalTrace) => boolean;\n\nexport interface LocalTrace {\n traceId: string;\n spans: ReadableSpan[];\n localRootSpan: ReadableSpan;\n}\n\n/**\n * Span processor with flush support\n */\nexport type TraceFlushableSpanProcessor = SpanProcessor & {\n forceFlush: (traceId?: string) => Promise<void>;\n};\n\n/**\n * Handler instrumentation\n */\nexport interface InitialSpanInfo {\n name: string;\n options: SpanOptions;\n context?: Context;\n}\n\nexport interface HandlerInstrumentation<T extends Trigger, R extends any> {\n getInitialSpanInfo: (trigger: T) => InitialSpanInfo;\n getAttributesFromResult?: (result: Awaited<R>) => Attributes;\n instrumentTrigger?: (trigger: T) => T;\n executionSucces?: (span: Span, trigger: T, result: Awaited<R>) => void;\n executionFailed?: (span: Span, trigger: T, error?: any) => void;\n}\n\n/**\n * Utility types\n */\n\nexport {type Attributes, type Context, type Span, type SpanOptions} from '@opentelemetry/api';\nexport {type ReadableSpan} from '@opentelemetry/sdk-trace-base';","/**\n * Span processor with flush and tail sampling support\n */\n\nimport type { Context } from '@opentelemetry/api';\nimport type {\n ReadableSpan,\n Span,\n SpanExporter,\n SpanProcessor,\n} from '@opentelemetry/sdk-trace-base';\nimport type { PostProcessorFn, TailSampleFn, LocalTrace } from '../types';\n\n/**\n * Span processor that supports flush by trace ID and tail sampling\n */\nexport class SpanProcessorWithFlush implements SpanProcessor {\n private exporter: SpanExporter;\n private postProcessor?: PostProcessorFn;\n private spans: Map<string, ReadableSpan[]> = new Map();\n\n constructor(exporter: SpanExporter, postProcessor?: PostProcessorFn) {\n this.exporter = exporter;\n this.postProcessor = postProcessor;\n }\n\n onStart(_span: Span, _parentContext: Context): void {\n // No-op for now\n }\n\n onEnd(span: ReadableSpan): void {\n const traceId = span.spanContext().traceId;\n\n if (!this.spans.has(traceId)) {\n this.spans.set(traceId, []);\n }\n\n this.spans.get(traceId)!.push(span);\n }\n\n /**\n * Force flush spans for a specific trace\n */\n async forceFlush(traceId?: string): Promise<void> {\n if (traceId) {\n const spans = this.spans.get(traceId);\n if (spans && spans.length > 0) {\n await this.exportSpans(spans);\n this.spans.delete(traceId);\n }\n } else {\n // Flush all traces\n const promises: Promise<void>[] = [];\n for (const [id, spans] of this.spans.entries()) {\n promises.push(this.exportSpans(spans));\n this.spans.delete(id);\n }\n await Promise.all(promises);\n }\n }\n\n async shutdown(): Promise<void> {\n await this.forceFlush();\n if (this.exporter) {\n await this.exporter.shutdown();\n }\n }\n\n /**\n * Export spans with post-processing\n * Errors are caught and logged but don't throw to prevent worker instability\n */\n private async exportSpans(spans: ReadableSpan[]): Promise<void> {\n if (spans.length === 0) return;\n if (!this.exporter) return; // No exporter configured (e.g., in tests)\n\n let processedSpans = spans;\n\n if (this.postProcessor) {\n try {\n processedSpans = this.postProcessor(spans);\n } catch (error) {\n // Post-processor errors should not prevent export\n console.error('[autotel-edge] Post-processor error:', error);\n // Continue with original spans\n processedSpans = spans;\n }\n }\n\n return new Promise((resolve) => {\n this.exporter.export(processedSpans, (result) => {\n if (result.code === 0) {\n // SUCCESS\n resolve();\n } else {\n // Log but don't reject - exporter failures shouldn't crash the worker\n console.error(\n '[autotel-edge] Exporter error:',\n result.error?.message || 'Unknown error',\n );\n resolve(); // Resolve instead of reject to prevent unhandled promise rejection\n }\n });\n });\n }\n}\n\n/**\n * Span processor that supports tail sampling decisions\n */\nexport class TailSamplingSpanProcessor implements SpanProcessor {\n private wrapped: SpanProcessorWithFlush;\n private tailSampler?: TailSampleFn;\n private traces: Map<string, LocalTrace> = new Map();\n\n constructor(\n exporter: SpanExporter,\n postProcessor?: PostProcessorFn,\n tailSampler?: TailSampleFn,\n ) {\n this.wrapped = new SpanProcessorWithFlush(exporter, postProcessor);\n this.tailSampler = tailSampler;\n }\n\n onStart(span: Span, parentContext: Context): void {\n this.wrapped.onStart(span, parentContext);\n }\n\n onEnd(span: ReadableSpan): void {\n const traceId = span.spanContext().traceId;\n const spanId = span.spanContext().spanId;\n const parentSpanId = 'parentSpanId' in span ? span.parentSpanId : undefined;\n\n // Initialize trace if not exists\n if (!this.traces.has(traceId)) {\n this.traces.set(traceId, {\n traceId,\n spans: [],\n localRootSpan: undefined as any, // Will be set when we identify the local root\n });\n }\n\n const trace = this.traces.get(traceId)!;\n\n // Determine if this span is a local root by checking if its parent is in buffered spans\n // A span is a local root if:\n // 1. It has no parentSpanId (definitive root)\n // 2. Its parentSpanId doesn't match any already-buffered span (remote parent = distributed trace entry)\n const hasLocalParent = parentSpanId &&\n trace.spans.some(s => s.spanContext().spanId === parentSpanId);\n\n // Set localRootSpan if this is the local root (no local parent found in buffer)\n if (!hasLocalParent) {\n trace.localRootSpan = span;\n }\n\n trace.spans.push(span); // Buffer the span AFTER checking parent relationships\n\n // Auto-flush decision: only auto-flush for normal traces (no parentSpanId at all)\n // For distributed traces (parentSpanId present), we rely on explicit forceFlush() from instrument.ts\n // This ensures we don't trigger before all spans have been buffered\n const isDefinitiveRoot = !parentSpanId;\n const shouldAutoFlush = isDefinitiveRoot && trace.localRootSpan &&\n trace.localRootSpan.spanContext().spanId === spanId;\n\n if (shouldAutoFlush) {\n if (this.tailSampler) {\n const shouldKeep = this.tailSampler(trace);\n\n if (shouldKeep) {\n // Export ALL buffered spans in the trace\n for (const bufferedSpan of trace.spans) {\n this.wrapped.onEnd(bufferedSpan);\n }\n // Force flush to actually export the spans\n void this.wrapped.forceFlush(traceId);\n }\n // If not keeping, just drop all spans (don't export)\n } else {\n // No tail sampler, export all buffered spans\n for (const bufferedSpan of trace.spans) {\n this.wrapped.onEnd(bufferedSpan);\n }\n // Force flush to actually export the spans\n void this.wrapped.forceFlush(traceId);\n }\n\n // Clean up trace after decision\n this.traces.delete(traceId);\n }\n // If not local root span, just buffer it - don't export yet\n }\n\n async forceFlush(traceId?: string): Promise<void> {\n if (traceId) {\n // Make tail sampling decision for this specific trace before flushing\n const trace = this.traces.get(traceId);\n if (trace) {\n // Ensure localRootSpan is set (fallback to first span if not)\n // This handles distributed traces where no span has undefined parentSpanId\n if (!trace.localRootSpan && trace.spans.length > 0) {\n trace.localRootSpan = trace.spans[0];\n }\n\n if (this.tailSampler) {\n const shouldKeep = this.tailSampler(trace);\n\n if (shouldKeep) {\n // Export ALL buffered spans in the trace\n for (const bufferedSpan of trace.spans) {\n this.wrapped.onEnd(bufferedSpan);\n }\n }\n } else {\n // No tail sampler, export all buffered spans\n for (const bufferedSpan of trace.spans) {\n this.wrapped.onEnd(bufferedSpan);\n }\n }\n\n // Clean up trace after decision\n this.traces.delete(traceId);\n }\n }\n return this.wrapped.forceFlush(traceId);\n }\n\n async shutdown(): Promise<void> {\n this.traces.clear();\n return this.wrapped.shutdown();\n }\n}\n","/**\n * Configuration system for autotel-edge\n */\n\nimport { W3CTraceContextPropagator } from '@opentelemetry/core';\nimport { ParentBasedSampler, AlwaysOnSampler } from '@opentelemetry/sdk-trace-base';\nimport { context as api_context, createContextKey, type Context } from '@opentelemetry/api';\nimport type {\n EdgeConfig,\n ResolvedEdgeConfig,\n ConfigurationOption,\n Trigger,\n ParentRatioSamplingConfig,\n} from '../types';\nimport { isSpanProcessorConfig } from '../types';\nimport { OTLPExporter } from './exporter';\nimport { TailSamplingSpanProcessor } from './spanprocessor';\n\n/**\n * Type for config initialization function\n */\nexport type Initialiser = (env: any, trigger: Trigger) => ResolvedEdgeConfig;\n\n/**\n * Context key for storing config (isolates config per-request)\n */\nconst CONFIG_KEY = createContextKey('autotel-edge-config');\n\n/**\n * Get the currently active config from context\n *\n * This reads the config from the active context, ensuring each request\n * has its own isolated config even when multiple requests are in-flight.\n */\nexport function getActiveConfig(): ResolvedEdgeConfig | null {\n const value = api_context.active().getValue(CONFIG_KEY) as\n | ResolvedEdgeConfig\n | null\n | undefined;\n return value ?? null;\n}\n\n/**\n * Set the active config in context\n *\n * Returns a new context with the config stored. This context should be\n * used with api_context.with() to ensure the config is isolated per-request.\n *\n * @example\n * ```typescript\n * const config = parseConfig({ service: { name: 'my-service' } });\n * const context = setConfig(config);\n *\n * api_context.with(context, () => {\n * // Config is available here via getActiveConfig()\n * });\n * ```\n */\nexport function setConfig(config: ResolvedEdgeConfig): Context {\n return api_context.active().setValue(CONFIG_KEY, config);\n}\n\n/**\n * Parse and validate configuration\n */\nexport function parseConfig(config: EdgeConfig): ResolvedEdgeConfig {\n // Parse head sampler\n const headSampler =\n config.sampling?.headSampler ??\n new ParentBasedSampler({\n root: new AlwaysOnSampler(),\n });\n\n const parsedHeadSampler =\n typeof headSampler === 'object' && 'ratio' in headSampler\n ? createParentRatioSampler(headSampler)\n : headSampler;\n\n // Parse tail sampler (default: keep sampled or error traces)\n const tailSampler =\n config.sampling?.tailSampler ??\n ((traceInfo) => {\n const localRootSpan = traceInfo.localRootSpan;\n const ctx = localRootSpan.spanContext();\n // Keep if sampled or if root span has error\n return (ctx.traceFlags & 1) === 1 || localRootSpan.status.code === 2; // SAMPLED flag | ERROR status\n });\n\n // Parse exporter - use TailSamplingSpanProcessor when tail sampler is present\n const spanProcessors = isSpanProcessorConfig(config)\n ? Array.isArray(config.spanProcessors)\n ? config.spanProcessors\n : [config.spanProcessors]\n : [\n // Use TailSamplingSpanProcessor to enable tail sampling\n new TailSamplingSpanProcessor(\n typeof config.exporter === 'object' && 'url' in config.exporter\n ? new OTLPExporter(config.exporter)\n : config.exporter,\n config.postProcessor,\n tailSampler, // Wire up the tail sampler!\n ),\n ];\n\n // Build resolved config\n const resolved: ResolvedEdgeConfig = {\n service: config.service,\n handlers: {\n fetch: config.handlers?.fetch ?? {},\n },\n fetch: {\n includeTraceContext: config.fetch?.includeTraceContext ?? true,\n },\n postProcessor: config.postProcessor ?? ((spans) => spans),\n sampling: {\n headSampler: parsedHeadSampler,\n tailSampler,\n },\n spanProcessors,\n propagator: config.propagator ?? new W3CTraceContextPropagator(),\n instrumentation: {\n instrumentGlobalFetch: config.instrumentation?.instrumentGlobalFetch ?? true,\n instrumentGlobalCache: config.instrumentation?.instrumentGlobalCache ?? false,\n disabled: config.instrumentation?.disabled ?? false,\n },\n subscribers: config.subscribers ?? [],\n dataSafety: config.dataSafety,\n };\n\n return resolved;\n}\n\n/**\n * Create a parent-based ratio sampler\n */\nfunction createParentRatioSampler(config: ParentRatioSamplingConfig) {\n const { ratio, acceptRemote = true } = config;\n\n // Simple ratio sampler\n const ratioSampler = {\n shouldSample: () => ({\n decision: Math.random() < ratio ? 1 : 0, // RECORD_AND_SAMPLED : NOT_RECORD\n attributes: {},\n }),\n toString: () => `ParentRatioSampler{ratio=${ratio}}`,\n };\n\n if (acceptRemote) {\n return new ParentBasedSampler({ root: ratioSampler as any });\n }\n\n return ratioSampler;\n}\n\n/**\n * Create a config initializer function\n */\nexport function createInitialiser(config: ConfigurationOption): Initialiser {\n if (typeof config === 'function') {\n return (env, trigger) => {\n const conf = parseConfig(config(env, trigger));\n return conf;\n };\n } else {\n const parsed = parseConfig(config);\n return () => parsed;\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/core/exporter.ts","../src/types.ts","../src/core/spanprocessor.ts","../src/core/config.ts"],"names":["api_context"],"mappings":"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","file":"chunk-D2WERTLK.js","sourcesContent":["/**\n * Lightweight OTLP exporter for edge environments\n * Ported and adapted from @microlabs/\n *\n * This exporter is much smaller than the standard @opentelemetry/exporter-trace-otlp-http\n * because it uses fetch() directly instead of Node.js http/https modules.\n */\n\nimport type { ExportResult } from '@opentelemetry/core';\nimport { ExportResultCode } from '@opentelemetry/core';\nimport { OTLPExporterError } from '@opentelemetry/otlp-exporter-base';\nimport { JsonTraceSerializer } from '@opentelemetry/otlp-transformer';\nimport type { SpanExporter } from '@opentelemetry/sdk-trace-base';\nimport type { OTLPExporterConfig } from '../types';\n\n// Version is injected at build time via tsup define\n// This avoids runtime filesystem access which isn't available in edge environments\nconst PACKAGE_VERSION = process.env.AUTOTEL_EDGE_VERSION || '0.1.1';\n\nconst defaultHeaders: Record<string, string> = {\n accept: 'application/json',\n 'content-type': 'application/json',\n 'user-agent': `autotel-edge v${PACKAGE_VERSION}`,\n};\n\n/**\n * Minimal OTLP exporter using fetch()\n */\nexport class OTLPExporter implements SpanExporter {\n private headers: Record<string, string>;\n private url: string;\n\n constructor(config: OTLPExporterConfig) {\n this.url = config.url;\n this.headers = Object.assign({}, defaultHeaders, config.headers);\n }\n\n export(items: any[], resultCallback: (result: ExportResult) => void): void {\n this._export(items)\n .then(() => {\n resultCallback({ code: ExportResultCode.SUCCESS });\n })\n .catch((error) => {\n resultCallback({ code: ExportResultCode.FAILED, error });\n });\n }\n\n private _export(items: any[]): Promise<unknown> {\n return new Promise<void>((resolve, reject) => {\n try {\n this.send(items, resolve, reject);\n } catch (error) {\n reject(error);\n }\n });\n }\n\n send(\n items: any[],\n onSuccess: () => void,\n onError: (error: OTLPExporterError) => void,\n ): void {\n const decoder = new TextDecoder();\n const exportMessage = JsonTraceSerializer.serializeRequest(items);\n\n const body = decoder.decode(exportMessage);\n const params: RequestInit = {\n method: 'POST',\n headers: this.headers,\n body,\n };\n\n fetch(this.url, params)\n .then((response) => {\n if (response.ok) {\n onSuccess();\n } else {\n onError(\n new OTLPExporterError(\n `Exporter received a statusCode: ${response.status}`,\n ),\n );\n }\n })\n .catch((error) => {\n onError(\n new OTLPExporterError(\n `Exception during export: ${error.toString()}`,\n error.code,\n error.stack,\n ),\n );\n });\n }\n\n async shutdown(): Promise<void> {\n // No-op for edge environments\n }\n}\n","/**\n * Shared types for autotel-edge\n */\n\nimport type {\n Attributes,\n Context,\n Span,\n SpanOptions,\n TextMapPropagator,\n} from '@opentelemetry/api';\nimport type {\n ReadableSpan,\n Sampler,\n SpanExporter,\n SpanProcessor,\n} from '@opentelemetry/sdk-trace-base';\n\n// Re-export commonly used types\n\n\n/**\n * Extended SpanOptions with per-span sampler support\n */\nexport interface ExtendedSpanOptions extends SpanOptions {\n sampler?: Sampler;\n}\n\n/**\n * Trigger types for edge handlers\n * Can be a Request or any vendor-specific trigger type\n */\nexport type Trigger =\n | Request\n | DOConstructorTrigger\n | WorkflowTrigger\n | 'do-alarm'\n | unknown;\n\nexport interface DOConstructorTrigger {\n id: string;\n name?: string;\n}\n\nexport interface WorkflowTrigger {\n type: 'workflow';\n name: string;\n}\n\n/**\n * Config types\n */\nexport interface OTLPExporterConfig {\n url: string;\n headers?: Record<string, string>;\n}\n\nexport type ExporterConfig = OTLPExporterConfig | SpanExporter;\n\nexport interface ServiceConfig {\n name: string;\n namespace?: string;\n version?: string;\n}\n\nexport interface ParentRatioSamplingConfig {\n acceptRemote?: boolean;\n ratio: number;\n}\n\ntype HeadSamplerConf = Sampler | ParentRatioSamplingConfig;\n\nexport interface SamplingConfig<HS extends HeadSamplerConf = HeadSamplerConf> {\n headSampler?: HS;\n tailSampler?: TailSampleFn;\n}\n\nexport interface InstrumentationOptions {\n instrumentGlobalFetch?: boolean;\n instrumentGlobalCache?: boolean;\n /**\n * Disable instrumentation entirely (useful for local development)\n * When enabled, the handler is returned as-is without any instrumentation\n * @default false\n */\n disabled?: boolean;\n}\n\n/**\n * Utility types\n */\nexport type OrPromise<T> = T | Promise<T>;\n\n/**\n * Adapter event types\n */\nexport type FunnelStepStatus =\n | 'started'\n | 'completed'\n | 'abandoned'\n | 'failed'\n | (string & {});\n\nexport type OutcomeStatus =\n | 'success'\n | 'failure'\n | 'partial'\n | (string & {});\n\nexport interface EdgeEventBase {\n [key: string]: unknown;\n service: string;\n timestamp: number;\n attributes: Record<string, unknown>;\n traceId?: string;\n spanId?: string;\n correlationId?: string;\n name: string; // Normalized event name for easy access\n}\n\nexport interface EdgeTrackEvent extends EdgeEventBase {\n type: 'event';\n event: string;\n}\n\nexport interface EdgeFunnelStepEvent extends EdgeEventBase {\n type: 'funnel-step';\n funnel: string;\n status: FunnelStepStatus;\n}\n\nexport interface EdgeOutcomeEvent extends EdgeEventBase {\n type: 'outcome';\n operation: string;\n outcome: OutcomeStatus;\n}\n\nexport interface EdgeValueEvent extends EdgeEventBase {\n type: 'value';\n metric: string;\n value: number;\n}\n\nexport type EdgeEvent =\n | EdgeTrackEvent\n | EdgeFunnelStepEvent\n | EdgeOutcomeEvent\n | EdgeValueEvent;\n\nexport type EdgeSubscriber = (event: EdgeEvent) => OrPromise<void>;\n\nexport interface FetcherConfig {\n includeTraceContext?: boolean | ((request: Request) => boolean);\n}\n\nexport interface PostProcessParams {\n /**\n * The request object that was passed to the fetch handler.\n */\n request: Request;\n /**\n * The generated response object.\n */\n response: Response;\n /**\n * A readable version of the span object that can be used to access the span's attributes and events.\n */\n readable: ReadableSpan;\n}\n\nexport interface FetchHandlerConfig {\n /**\n * Whether to enable context propagation for incoming requests to `fetch`.\n * This enables or disables distributed tracing from W3C Trace Context headers.\n * @default true\n */\n acceptTraceContext?: boolean | ((request: Request) => boolean);\n /**\n * Allows further customization of the generated span, based on the request/response data.\n */\n postProcess?: (span: Span, ctx: PostProcessParams) => void;\n}\n\nexport interface HandlerConfig {\n fetch?: FetchHandlerConfig;\n}\n\nexport interface DataSafetyConfig {\n /** Redact query parameters from URL attributes (default: false) */\n redactQueryParams?: boolean;\n /** Control D1 SQL statement capture: 'full' (default), 'obfuscated', or 'off' */\n captureDbStatement?: 'off' | 'obfuscated' | 'full';\n /** Only capture these email headers (lowercase). When set, other headers are excluded. */\n emailHeaderAllowlist?: string[];\n}\n\ninterface EdgeConfigBase {\n service: ServiceConfig;\n handlers?: HandlerConfig;\n fetch?: FetcherConfig;\n postProcessor?: PostProcessorFn;\n sampling?: SamplingConfig;\n propagator?: TextMapPropagator;\n instrumentation?: InstrumentationOptions;\n subscribers?: EdgeSubscriber[];\n /** Opt-in data safety controls for sensitive attribute capture */\n dataSafety?: DataSafetyConfig;\n}\n\ninterface EdgeConfigExporter extends EdgeConfigBase {\n exporter: ExporterConfig;\n}\n\ninterface EdgeConfigSpanProcessors extends EdgeConfigBase {\n spanProcessors: SpanProcessor | SpanProcessor[];\n}\n\nexport type EdgeConfig = EdgeConfigExporter | EdgeConfigSpanProcessors;\n\nexport function isSpanProcessorConfig(\n config: EdgeConfig,\n): config is EdgeConfigSpanProcessors {\n return !!(config as EdgeConfigSpanProcessors).spanProcessors;\n}\n\nexport interface ResolvedEdgeConfig extends EdgeConfigBase {\n handlers: Required<HandlerConfig>;\n fetch: Required<FetcherConfig>;\n postProcessor: PostProcessorFn;\n sampling: Required<SamplingConfig<Sampler>>;\n spanProcessors: SpanProcessor[];\n propagator: TextMapPropagator;\n instrumentation: InstrumentationOptions;\n subscribers: EdgeSubscriber[];\n}\n\n/**\n * Function types\n */\nexport type ResolveConfigFn<Env = any> = (\n env: Env,\n trigger: Trigger,\n) => EdgeConfig;\nexport type ConfigurationOption = EdgeConfig | ResolveConfigFn;\n\nexport type PostProcessorFn = (spans: ReadableSpan[]) => ReadableSpan[];\nexport type TailSampleFn = (traceInfo: LocalTrace) => boolean;\n\nexport interface LocalTrace {\n traceId: string;\n spans: ReadableSpan[];\n localRootSpan: ReadableSpan;\n}\n\n/**\n * Span processor with flush support\n */\nexport type TraceFlushableSpanProcessor = SpanProcessor & {\n forceFlush: (traceId?: string) => Promise<void>;\n};\n\n/**\n * Handler instrumentation\n */\nexport interface InitialSpanInfo {\n name: string;\n options: SpanOptions;\n context?: Context;\n}\n\nexport interface HandlerInstrumentation<T extends Trigger, R extends any> {\n getInitialSpanInfo: (trigger: T) => InitialSpanInfo;\n getAttributesFromResult?: (result: Awaited<R>) => Attributes;\n instrumentTrigger?: (trigger: T) => T;\n executionSucces?: (span: Span, trigger: T, result: Awaited<R>) => void;\n executionFailed?: (span: Span, trigger: T, error?: any) => void;\n}\n\n/**\n * Utility types\n */\n\nexport {type Attributes, type Context, type Span, type SpanOptions} from '@opentelemetry/api';\nexport {type ReadableSpan} from '@opentelemetry/sdk-trace-base';","/**\n * Span processor with flush and tail sampling support\n */\n\nimport type { Context } from '@opentelemetry/api';\nimport type {\n ReadableSpan,\n Span,\n SpanExporter,\n SpanProcessor,\n} from '@opentelemetry/sdk-trace-base';\nimport type { PostProcessorFn, TailSampleFn, LocalTrace } from '../types';\n\n/**\n * Span processor that supports flush by trace ID and tail sampling\n */\nexport class SpanProcessorWithFlush implements SpanProcessor {\n private exporter: SpanExporter;\n private postProcessor?: PostProcessorFn;\n private spans: Map<string, ReadableSpan[]> = new Map();\n\n constructor(exporter: SpanExporter, postProcessor?: PostProcessorFn) {\n this.exporter = exporter;\n this.postProcessor = postProcessor;\n }\n\n onStart(_span: Span, _parentContext: Context): void {\n // No-op for now\n }\n\n onEnd(span: ReadableSpan): void {\n const traceId = span.spanContext().traceId;\n\n if (!this.spans.has(traceId)) {\n this.spans.set(traceId, []);\n }\n\n this.spans.get(traceId)!.push(span);\n }\n\n /**\n * Force flush spans for a specific trace\n */\n async forceFlush(traceId?: string): Promise<void> {\n if (traceId) {\n const spans = this.spans.get(traceId);\n if (spans && spans.length > 0) {\n await this.exportSpans(spans);\n this.spans.delete(traceId);\n }\n } else {\n // Flush all traces\n const promises: Promise<void>[] = [];\n for (const [id, spans] of this.spans.entries()) {\n promises.push(this.exportSpans(spans));\n this.spans.delete(id);\n }\n await Promise.all(promises);\n }\n }\n\n async shutdown(): Promise<void> {\n await this.forceFlush();\n if (this.exporter) {\n await this.exporter.shutdown();\n }\n }\n\n /**\n * Export spans with post-processing\n * Errors are caught and logged but don't throw to prevent worker instability\n */\n private async exportSpans(spans: ReadableSpan[]): Promise<void> {\n if (spans.length === 0) return;\n if (!this.exporter) return; // No exporter configured (e.g., in tests)\n\n let processedSpans = spans;\n\n if (this.postProcessor) {\n try {\n processedSpans = this.postProcessor(spans);\n } catch (error) {\n // Post-processor errors should not prevent export\n console.error('[autotel-edge] Post-processor error:', error);\n // Continue with original spans\n processedSpans = spans;\n }\n }\n\n return new Promise((resolve) => {\n this.exporter.export(processedSpans, (result) => {\n if (result.code === 0) {\n // SUCCESS\n resolve();\n } else {\n // Log but don't reject - exporter failures shouldn't crash the worker\n console.error(\n '[autotel-edge] Exporter error:',\n result.error?.message || 'Unknown error',\n );\n resolve(); // Resolve instead of reject to prevent unhandled promise rejection\n }\n });\n });\n }\n}\n\n/**\n * Span processor that supports tail sampling decisions\n */\nexport class TailSamplingSpanProcessor implements SpanProcessor {\n private wrapped: SpanProcessorWithFlush;\n private tailSampler?: TailSampleFn;\n private traces: Map<string, LocalTrace> = new Map();\n\n constructor(\n exporter: SpanExporter,\n postProcessor?: PostProcessorFn,\n tailSampler?: TailSampleFn,\n ) {\n this.wrapped = new SpanProcessorWithFlush(exporter, postProcessor);\n this.tailSampler = tailSampler;\n }\n\n onStart(span: Span, parentContext: Context): void {\n this.wrapped.onStart(span, parentContext);\n }\n\n onEnd(span: ReadableSpan): void {\n const traceId = span.spanContext().traceId;\n const spanId = span.spanContext().spanId;\n const parentSpanId = 'parentSpanId' in span ? span.parentSpanId : undefined;\n\n // Initialize trace if not exists\n if (!this.traces.has(traceId)) {\n this.traces.set(traceId, {\n traceId,\n spans: [],\n localRootSpan: undefined as any, // Will be set when we identify the local root\n });\n }\n\n const trace = this.traces.get(traceId)!;\n\n // Determine if this span is a local root by checking if its parent is in buffered spans\n // A span is a local root if:\n // 1. It has no parentSpanId (definitive root)\n // 2. Its parentSpanId doesn't match any already-buffered span (remote parent = distributed trace entry)\n const hasLocalParent = parentSpanId &&\n trace.spans.some(s => s.spanContext().spanId === parentSpanId);\n\n // Set localRootSpan if this is the local root (no local parent found in buffer)\n if (!hasLocalParent) {\n trace.localRootSpan = span;\n }\n\n trace.spans.push(span); // Buffer the span AFTER checking parent relationships\n\n // Auto-flush decision: only auto-flush for normal traces (no parentSpanId at all)\n // For distributed traces (parentSpanId present), we rely on explicit forceFlush() from instrument.ts\n // This ensures we don't trigger before all spans have been buffered\n const isDefinitiveRoot = !parentSpanId;\n const shouldAutoFlush = isDefinitiveRoot && trace.localRootSpan &&\n trace.localRootSpan.spanContext().spanId === spanId;\n\n if (shouldAutoFlush) {\n if (this.tailSampler) {\n const shouldKeep = this.tailSampler(trace);\n\n if (shouldKeep) {\n // Export ALL buffered spans in the trace\n for (const bufferedSpan of trace.spans) {\n this.wrapped.onEnd(bufferedSpan);\n }\n // Force flush to actually export the spans\n void this.wrapped.forceFlush(traceId);\n }\n // If not keeping, just drop all spans (don't export)\n } else {\n // No tail sampler, export all buffered spans\n for (const bufferedSpan of trace.spans) {\n this.wrapped.onEnd(bufferedSpan);\n }\n // Force flush to actually export the spans\n void this.wrapped.forceFlush(traceId);\n }\n\n // Clean up trace after decision\n this.traces.delete(traceId);\n }\n // If not local root span, just buffer it - don't export yet\n }\n\n async forceFlush(traceId?: string): Promise<void> {\n if (traceId) {\n // Make tail sampling decision for this specific trace before flushing\n const trace = this.traces.get(traceId);\n if (trace) {\n // Ensure localRootSpan is set (fallback to first span if not)\n // This handles distributed traces where no span has undefined parentSpanId\n if (!trace.localRootSpan && trace.spans.length > 0) {\n trace.localRootSpan = trace.spans[0];\n }\n\n if (this.tailSampler) {\n const shouldKeep = this.tailSampler(trace);\n\n if (shouldKeep) {\n // Export ALL buffered spans in the trace\n for (const bufferedSpan of trace.spans) {\n this.wrapped.onEnd(bufferedSpan);\n }\n }\n } else {\n // No tail sampler, export all buffered spans\n for (const bufferedSpan of trace.spans) {\n this.wrapped.onEnd(bufferedSpan);\n }\n }\n\n // Clean up trace after decision\n this.traces.delete(traceId);\n }\n }\n return this.wrapped.forceFlush(traceId);\n }\n\n async shutdown(): Promise<void> {\n this.traces.clear();\n return this.wrapped.shutdown();\n }\n}\n","/**\n * Configuration system for autotel-edge\n */\n\nimport { W3CTraceContextPropagator } from '@opentelemetry/core';\nimport { ParentBasedSampler, AlwaysOnSampler } from '@opentelemetry/sdk-trace-base';\nimport { context as api_context, createContextKey, type Context } from '@opentelemetry/api';\nimport type {\n EdgeConfig,\n ResolvedEdgeConfig,\n ConfigurationOption,\n Trigger,\n ParentRatioSamplingConfig,\n} from '../types';\nimport { isSpanProcessorConfig } from '../types';\nimport { OTLPExporter } from './exporter';\nimport { TailSamplingSpanProcessor } from './spanprocessor';\n\n/**\n * Type for config initialization function\n */\nexport type Initialiser = (env: any, trigger: Trigger) => ResolvedEdgeConfig;\n\n/**\n * Context key for storing config (isolates config per-request)\n */\nconst CONFIG_KEY = createContextKey('autotel-edge-config');\n\n/**\n * Get the currently active config from context\n *\n * This reads the config from the active context, ensuring each request\n * has its own isolated config even when multiple requests are in-flight.\n */\nexport function getActiveConfig(): ResolvedEdgeConfig | null {\n const value = api_context.active().getValue(CONFIG_KEY) as\n | ResolvedEdgeConfig\n | null\n | undefined;\n return value ?? null;\n}\n\n/**\n * Set the active config in context\n *\n * Returns a new context with the config stored. This context should be\n * used with api_context.with() to ensure the config is isolated per-request.\n *\n * @example\n * ```typescript\n * const config = parseConfig({ service: { name: 'my-service' } });\n * const context = setConfig(config);\n *\n * api_context.with(context, () => {\n * // Config is available here via getActiveConfig()\n * });\n * ```\n */\nexport function setConfig(config: ResolvedEdgeConfig): Context {\n return api_context.active().setValue(CONFIG_KEY, config);\n}\n\n/**\n * Parse and validate configuration\n */\nexport function parseConfig(config: EdgeConfig): ResolvedEdgeConfig {\n // Parse head sampler\n const headSampler =\n config.sampling?.headSampler ??\n new ParentBasedSampler({\n root: new AlwaysOnSampler(),\n });\n\n const parsedHeadSampler =\n typeof headSampler === 'object' && 'ratio' in headSampler\n ? createParentRatioSampler(headSampler)\n : headSampler;\n\n // Parse tail sampler (default: keep sampled or error traces)\n const tailSampler =\n config.sampling?.tailSampler ??\n ((traceInfo) => {\n const localRootSpan = traceInfo.localRootSpan;\n const ctx = localRootSpan.spanContext();\n // Keep if sampled or if root span has error\n return (ctx.traceFlags & 1) === 1 || localRootSpan.status.code === 2; // SAMPLED flag | ERROR status\n });\n\n // Parse exporter - use TailSamplingSpanProcessor when tail sampler is present\n const spanProcessors = isSpanProcessorConfig(config)\n ? Array.isArray(config.spanProcessors)\n ? config.spanProcessors\n : [config.spanProcessors]\n : [\n // Use TailSamplingSpanProcessor to enable tail sampling\n new TailSamplingSpanProcessor(\n typeof config.exporter === 'object' && 'url' in config.exporter\n ? new OTLPExporter(config.exporter)\n : config.exporter,\n config.postProcessor,\n tailSampler, // Wire up the tail sampler!\n ),\n ];\n\n // Build resolved config\n const resolved: ResolvedEdgeConfig = {\n service: config.service,\n handlers: {\n fetch: config.handlers?.fetch ?? {},\n },\n fetch: {\n includeTraceContext: config.fetch?.includeTraceContext ?? true,\n },\n postProcessor: config.postProcessor ?? ((spans) => spans),\n sampling: {\n headSampler: parsedHeadSampler,\n tailSampler,\n },\n spanProcessors,\n propagator: config.propagator ?? new W3CTraceContextPropagator(),\n instrumentation: {\n instrumentGlobalFetch: config.instrumentation?.instrumentGlobalFetch ?? true,\n instrumentGlobalCache: config.instrumentation?.instrumentGlobalCache ?? false,\n disabled: config.instrumentation?.disabled ?? false,\n },\n subscribers: config.subscribers ?? [],\n dataSafety: config.dataSafety,\n };\n\n return resolved;\n}\n\n/**\n * Create a parent-based ratio sampler\n */\nfunction createParentRatioSampler(config: ParentRatioSamplingConfig) {\n const { ratio, acceptRemote = true } = config;\n\n // Simple ratio sampler\n const ratioSampler = {\n shouldSample: () => ({\n decision: Math.random() < ratio ? 1 : 0, // RECORD_AND_SAMPLED : NOT_RECORD\n attributes: {},\n }),\n toString: () => `ParentRatioSampler{ratio=${ratio}}`,\n };\n\n if (acceptRemote) {\n return new ParentBasedSampler({ root: ratioSampler as any });\n }\n\n return ratioSampler;\n}\n\n/**\n * Create a config initializer function\n */\nexport function createInitialiser(config: ConfigurationOption): Initialiser {\n if (typeof config === 'function') {\n return (env, trigger) => {\n const conf = parseConfig(config(env, trigger));\n return conf;\n };\n } else {\n const parsed = parseConfig(config);\n return () => parsed;\n }\n}\n"]}
package/dist/events.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { E as EdgeEvent, O as OrPromise, F as FunnelStepStatus, a as OutcomeStatus } from './types-BOs00OpG.js';
2
- export { c as EdgeFunnelStepEvent, d as EdgeOutcomeEvent, b as EdgeTrackEvent, e as EdgeValueEvent } from './types-BOs00OpG.js';
1
+ import { E as EdgeEvent, O as OrPromise, F as FunnelStepStatus, a as OutcomeStatus } from './types-CZFcIjJ4.js';
2
+ export { b as EdgeFunnelStepEvent, c as EdgeOutcomeEvent, d as EdgeTrackEvent, e as EdgeValueEvent } from './types-CZFcIjJ4.js';
3
3
  import '@opentelemetry/api';
4
4
  import '@opentelemetry/sdk-trace-base';
5
5
 
package/dist/events.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getActiveConfig } from './chunk-ICBZ6ZUQ.js';
1
+ import { getActiveConfig } from './chunk-D2WERTLK.js';
2
2
  import { trace } from '@opentelemetry/api';
3
3
 
4
4
  var DEFAULT_SERVICE_NAME = "edge-service";
package/dist/index.d.ts CHANGED
@@ -5,8 +5,8 @@ import { Resource } from '@opentelemetry/resources';
5
5
  import { ReadableSpan, TimedEvent, SpanProcessor, SpanExporter, TracerConfig, Sampler } from '@opentelemetry/sdk-trace-base';
6
6
  export { ReadableSpan } from '@opentelemetry/sdk-trace-base';
7
7
  import { OTLPExporterError } from '@opentelemetry/otlp-exporter-base';
8
- import { f as OTLPExporterConfig, g as EdgeConfig, R as ResolvedEdgeConfig, C as ConfigurationOption, h as Trigger } from './types-BOs00OpG.js';
9
- export { D as DOConstructorTrigger, o as DataSafetyConfig, n as EdgeSubscriber, i as ExporterConfig, H as HandlerInstrumentation, m as InitialSpanInfo, I as InstrumentationOptions, L as LocalTrace, P as PostProcessorFn, k as ResolveConfigFn, j as SamplingConfig, S as ServiceConfig, T as TailSampleFn, l as TraceFlushableSpanProcessor, W as WorkflowTrigger } from './types-BOs00OpG.js';
8
+ import { f as OTLPExporterConfig, g as Trigger, R as ResolvedEdgeConfig, C as ConfigurationOption, h as EdgeConfig } from './types-CZFcIjJ4.js';
9
+ export { D as DOConstructorTrigger, i as DataSafetyConfig, j as EdgeSubscriber, k as ExporterConfig, H as HandlerInstrumentation, I as InitialSpanInfo, l as InstrumentationOptions, L as LocalTrace, P as PostProcessorFn, m as ResolveConfigFn, S as SamplingConfig, n as ServiceConfig, T as TailSampleFn, o as TraceFlushableSpanProcessor, W as WorkflowTrigger } from './types-CZFcIjJ4.js';
10
10
  export { Buffer } from 'node:buffer';
11
11
  export { ParsedError, parseError } from './parse-error.js';
12
12
 
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- export { OTLPExporter, createInitialiser, getActiveConfig, parseConfig, setConfig } from './chunk-ICBZ6ZUQ.js';
1
+ export { OTLPExporter, createInitialiser, getActiveConfig, parseConfig, setConfig } from './chunk-D2WERTLK.js';
2
2
  export { parseError } from './chunk-M7Z4P5MC.js';
3
3
  import { sanitizeAttributes, isAttributeValue, isTimeInput, hrTimeDuration } from '@opentelemetry/core';
4
4
  import { SEMATTRS_EXCEPTION_MESSAGE, SEMATTRS_EXCEPTION_TYPE, SEMATTRS_EXCEPTION_STACKTRACE } from '@opentelemetry/semantic-conventions';
5
- import { context, trace, ROOT_CONTEXT, SpanStatusCode } from '@opentelemetry/api';
5
+ import { trace, context, ROOT_CONTEXT, SpanStatusCode } from '@opentelemetry/api';
6
6
  export { context, propagation } from '@opentelemetry/api';
7
7
  import { RandomIdGenerator, SamplingDecision } from '@opentelemetry/sdk-trace-base';
8
8
  import { AsyncLocalStorage } from 'async_hooks';
package/dist/logger.d.ts CHANGED
@@ -16,6 +16,12 @@ interface EdgeLogger {
16
16
  error(msg: string, error?: Error | unknown, attrs?: Record<string, any>): void;
17
17
  warn(msg: string, attrs?: Record<string, any>): void;
18
18
  debug(msg: string, attrs?: Record<string, any>): void;
19
+ /**
20
+ * Create a child logger with merged bindings.
21
+ * Like pino's child() — every log call from the child
22
+ * includes the parent's attrs plus the child's bindings.
23
+ */
24
+ child(bindings: Record<string, any>): EdgeLogger;
19
25
  }
20
26
  /**
21
27
  * Get the active log level from context (if set)
@@ -66,6 +72,7 @@ declare function runWithLogLevel<T>(level: LogLevel, callback: () => T): T;
66
72
  declare function createEdgeLogger(service: string, options?: {
67
73
  level?: LogLevel;
68
74
  pretty?: boolean;
75
+ bindings?: Record<string, any>;
69
76
  }): EdgeLogger;
70
77
  /**
71
78
  * Helper to get trace context (useful for BYOL - Bring Your Own Logger)
package/dist/logger.js CHANGED
@@ -23,6 +23,7 @@ function getTraceContext() {
23
23
  function createEdgeLogger(service, options) {
24
24
  const defaultLevel = options?.level || "info";
25
25
  const pretty = options?.pretty || false;
26
+ const defaultBindings = options?.bindings || {};
26
27
  const levelPriority = {
27
28
  none: -1,
28
29
  debug: 0,
@@ -42,6 +43,7 @@ function createEdgeLogger(service, options) {
42
43
  level,
43
44
  service,
44
45
  msg,
46
+ ...defaultBindings,
45
47
  ...attrs,
46
48
  ...ctx,
47
49
  // Auto-inject traceId, spanId, correlationId
@@ -49,15 +51,19 @@ function createEdgeLogger(service, options) {
49
51
  };
50
52
  if (pretty) {
51
53
  const traceInfo = ctx ? ` [${ctx.traceId.slice(0, 8)}.../${ctx.spanId.slice(0, 8)}...]` : "";
54
+ const prettyAttrs = {
55
+ ...defaultBindings,
56
+ ...attrs
57
+ };
52
58
  console.log(
53
59
  `[${level.toUpperCase()}]${traceInfo} ${service}: ${msg}`,
54
- attrs || ""
60
+ Object.keys(prettyAttrs).length > 0 ? prettyAttrs : ""
55
61
  );
56
62
  } else {
57
63
  console.log(JSON.stringify(logEntry));
58
64
  }
59
65
  };
60
- return {
66
+ const logger = {
61
67
  info: (msg, attrs) => log("info", msg, attrs),
62
68
  error: (msg, error, attrs) => {
63
69
  const errorAttrs = error instanceof Error ? {
@@ -69,8 +75,14 @@ function createEdgeLogger(service, options) {
69
75
  log("error", msg, errorAttrs);
70
76
  },
71
77
  warn: (msg, attrs) => log("warn", msg, attrs),
72
- debug: (msg, attrs) => log("debug", msg, attrs)
78
+ debug: (msg, attrs) => log("debug", msg, attrs),
79
+ child: (bindings) => createEdgeLogger(service, {
80
+ level: defaultLevel,
81
+ pretty,
82
+ bindings: { ...defaultBindings, ...bindings }
83
+ })
73
84
  };
85
+ return logger;
74
86
  }
75
87
  function getEdgeTraceContext() {
76
88
  return getTraceContext();
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/logger.ts"],"names":["api_context"],"mappings":"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","file":"logger.js","sourcesContent":["/**\n * Zero-dependency structured logger for edge environments\n *\n * This logger is ~100 LOC and provides:\n * - Structured JSON logging\n * - Auto trace context injection (traceId, spanId)\n * - Dynamic log level control (per-request via context)\n * - Level support (info, error, warn, debug)\n * - Zero dependencies (console-based)\n *\n * Unlike Pino/Winston (~500KB), this is <1KB minified!\n */\n\nimport { trace, context as api_context, createContextKey } from '@opentelemetry/api';\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';\n\n/**\n * Context key for storing active log level (enables per-request log levels)\n */\nconst LOG_LEVEL_KEY = createContextKey('autotel-edge-log-level');\n\nexport interface EdgeLogger {\n info(msg: string, attrs?: Record<string, any>): void;\n error(msg: string, error?: Error | unknown, attrs?: Record<string, any>): void;\n warn(msg: string, attrs?: Record<string, any>): void;\n debug(msg: string, attrs?: Record<string, any>): void;\n}\n\n/**\n * Get the active log level from context (if set)\n * Falls back to undefined if no log level is set in context\n */\nexport function getActiveLogLevel(): LogLevel | undefined {\n return api_context.active().getValue(LOG_LEVEL_KEY) as LogLevel | undefined;\n}\n\n/**\n * Run a function with a specific log level\n * The log level is stored in OpenTelemetry context and applies to all logger calls within the callback\n *\n * This works in edge runtimes (uses OTel context, not Node.js AsyncLocalStorage)\n *\n * @example\n * ```typescript\n * // Enable debug logging for a specific request\n * runWithLogLevel('debug', () => {\n * log.debug('This will be logged')\n * processRequest()\n * })\n *\n * // Disable logging temporarily\n * runWithLogLevel('none', () => {\n * log.info('This will NOT be logged')\n * })\n * ```\n */\nexport function runWithLogLevel<T>(level: LogLevel, callback: () => T): T {\n const ctx = api_context.active().setValue(LOG_LEVEL_KEY, level);\n return api_context.with(ctx, callback);\n}\n\n/**\n * Get current trace context from active span\n */\nfunction getTraceContext():\n | { traceId: string; spanId: string; correlationId: string }\n | null {\n const span = trace.getActiveSpan();\n if (!span) return null;\n\n const ctx = span.spanContext();\n return {\n traceId: ctx.traceId,\n spanId: ctx.spanId,\n correlationId: ctx.traceId.slice(0, 16), // First 16 chars for grouping\n };\n}\n\n/**\n * Create a lightweight structured logger\n *\n * @param service - Service name for logging\n * @param options - Optional configuration\n *\n * @example\n * ```typescript\n * const log = createEdgeLogger('user-service')\n *\n * log.info('Creating user', { email: 'test@example.com' })\n * // Output: {\"level\":\"info\",\"service\":\"user-service\",\"msg\":\"Creating user\",\n * // \"email\":\"test@example.com\",\"traceId\":\"...\",\"spanId\":\"...\"}\n *\n * // Dynamic log level control per-request\n * runWithLogLevel('debug', () => {\n * log.debug('This will be logged even if logger was created with level: \"info\"')\n * })\n * ```\n */\nexport function createEdgeLogger(\n service: string,\n options?: {\n level?: LogLevel;\n pretty?: boolean; // For development\n },\n): EdgeLogger {\n const defaultLevel = options?.level || 'info';\n const pretty = options?.pretty || false;\n\n const levelPriority: Record<LogLevel, number> = {\n none: -1,\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n };\n\n const shouldLog = (level: LogLevel): boolean => {\n // Priority: context level > options level > 'info' default\n const activeLevel = getActiveLogLevel() ?? defaultLevel;\n\n // 'none' means suppress all logging\n if (activeLevel === 'none') return false;\n\n return levelPriority[level] >= levelPriority[activeLevel];\n };\n\n const log = (\n level: 'info' | 'error' | 'warn' | 'debug',\n msg: string,\n attrs?: Record<string, any>,\n ) => {\n if (!shouldLog(level)) return;\n\n const ctx = getTraceContext();\n const logEntry: Record<string, any> = {\n level,\n service,\n msg,\n ...attrs,\n ...ctx, // Auto-inject traceId, spanId, correlationId\n timestamp: new Date().toISOString(),\n };\n\n if (pretty) {\n // Pretty print for development\n const traceInfo = ctx\n ? ` [${ctx.traceId.slice(0, 8)}.../${ctx.spanId.slice(0, 8)}...]`\n : '';\n console.log(\n `[${level.toUpperCase()}]${traceInfo} ${service}: ${msg}`,\n attrs || '',\n );\n } else {\n // Structured JSON for production\n console.log(JSON.stringify(logEntry));\n }\n };\n\n return {\n info: (msg: string, attrs?: Record<string, any>) => log('info', msg, attrs),\n\n error: (msg: string, error?: Error | unknown, attrs?: Record<string, any>) => {\n const errorAttrs = error instanceof Error\n ? {\n error: error.message,\n stack: error.stack,\n name: error.name,\n ...attrs,\n }\n : { error: String(error), ...attrs };\n\n log('error', msg, errorAttrs);\n },\n\n warn: (msg: string, attrs?: Record<string, any>) => log('warn', msg, attrs),\n\n debug: (msg: string, attrs?: Record<string, any>) => log('debug', msg, attrs),\n };\n}\n\n/**\n * Helper to get trace context (useful for BYOL - Bring Your Own Logger)\n *\n * @example\n * ```typescript\n * import bunyan from 'bunyan'\n * import { getEdgeTraceContext } from 'autotel-edge/api/logger'\n *\n * const bunyanLogger = bunyan.createLogger({ name: 'myapp' })\n * const ctx = getEdgeTraceContext()\n * bunyanLogger.info({ ...ctx, email: 'test@example.com' }, 'Creating user')\n * ```\n */\nexport function getEdgeTraceContext() {\n return getTraceContext();\n}\n"]}
1
+ {"version":3,"sources":["../src/api/logger.ts"],"names":["api_context"],"mappings":";;;AAwBA,IAAM,aAAA,GAAgB,iBAAiB,wBAAwB,CAAA;AAuBxD,SAAS,iBAAA,GAA0C;AACxD,EAAA,OAAOA,OAAA,CAAY,MAAA,EAAO,CAAE,QAAA,CAAS,aAAa,CAAA;AACpD;AAsBO,SAAS,eAAA,CAAmB,OAAiB,QAAA,EAAsB;AACxE,EAAA,MAAM,MAAMA,OAAA,CAAY,MAAA,EAAO,CAAE,QAAA,CAAS,eAAe,KAAK,CAAA;AAC9D,EAAA,OAAOA,OAAA,CAAY,IAAA,CAAK,GAAA,EAAK,QAAQ,CAAA;AACvC;AAKA,SAAS,eAAA,GAIA;AACP,EAAA,MAAM,IAAA,GAAO,MAAM,aAAA,EAAc;AACjC,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAElB,EAAA,MAAM,GAAA,GAAM,KAAK,WAAA,EAAY;AAC7B,EAAA,OAAO;AAAA,IACL,SAAS,GAAA,CAAI,OAAA;AAAA,IACb,QAAQ,GAAA,CAAI,MAAA;AAAA,IACZ,aAAA,EAAe,GAAA,CAAI,OAAA,CAAQ,KAAA,CAAM,GAAG,EAAE;AAAA;AAAA,GACxC;AACF;AAsBO,SAAS,gBAAA,CACd,SACA,OAAA,EAKY;AACZ,EAAA,MAAM,YAAA,GAAe,SAAS,KAAA,IAAS,MAAA;AACvC,EAAA,MAAM,MAAA,GAAS,SAAS,MAAA,IAAU,KAAA;AAClC,EAAA,MAAM,eAAA,GAAkB,OAAA,EAAS,QAAA,IAAY,EAAC;AAE9C,EAAA,MAAM,aAAA,GAA0C;AAAA,IAC9C,IAAA,EAAM,EAAA;AAAA,IACN,KAAA,EAAO,CAAA;AAAA,IACP,IAAA,EAAM,CAAA;AAAA,IACN,IAAA,EAAM,CAAA;AAAA,IACN,KAAA,EAAO;AAAA,GACT;AAEA,EAAA,MAAM,SAAA,GAAY,CAAC,KAAA,KAA6B;AAE9C,IAAA,MAAM,WAAA,GAAc,mBAAkB,IAAK,YAAA;AAG3C,IAAA,IAAI,WAAA,KAAgB,QAAQ,OAAO,KAAA;AAEnC,IAAA,OAAO,aAAA,CAAc,KAAK,CAAA,IAAK,aAAA,CAAc,WAAW,CAAA;AAAA,EAC1D,CAAA;AAEA,EAAA,MAAM,GAAA,GAAM,CACV,KAAA,EACA,GAAA,EACA,KAAA,KACG;AACH,IAAA,IAAI,CAAC,SAAA,CAAU,KAAK,CAAA,EAAG;AAEvB,IAAA,MAAM,MAAM,eAAA,EAAgB;AAC5B,IAAA,MAAM,QAAA,GAAgC;AAAA,MACpC,KAAA;AAAA,MACA,OAAA;AAAA,MACA,GAAA;AAAA,MACA,GAAG,eAAA;AAAA,MACH,GAAG,KAAA;AAAA,MACH,GAAG,GAAA;AAAA;AAAA,MACH,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,KACpC;AAEA,IAAA,IAAI,MAAA,EAAQ;AAEV,MAAA,MAAM,YAAY,GAAA,GACd,CAAA,EAAA,EAAK,GAAA,CAAI,OAAA,CAAQ,MAAM,CAAA,EAAG,CAAC,CAAC,CAAA,IAAA,EAAO,IAAI,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,IAAA,CAAA,GACzD,EAAA;AACJ,MAAA,MAAM,WAAA,GAAc;AAAA,QAClB,GAAG,eAAA;AAAA,QACH,GAAG;AAAA,OACL;AACA,MAAA,OAAA,CAAQ,GAAA;AAAA,QACN,CAAA,CAAA,EAAI,MAAM,WAAA,EAAa,IAAI,SAAS,CAAA,CAAA,EAAI,OAAO,CAAA,EAAA,EAAK,GAAG,CAAA,CAAA;AAAA,QACvD,OAAO,IAAA,CAAK,WAAW,CAAA,CAAE,MAAA,GAAS,IAAI,WAAA,GAAc;AAAA,OACtD;AAAA,IACF,CAAA,MAAO;AAEL,MAAA,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAC,CAAA;AAAA,IACtC;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,MAAA,GAAqB;AAAA,IACzB,MAAM,CAAC,GAAA,EAAa,UAAgC,GAAA,CAAI,MAAA,EAAQ,KAAK,KAAK,CAAA;AAAA,IAE1E,KAAA,EAAO,CACL,GAAA,EACA,KAAA,EACA,KAAA,KACG;AACH,MAAA,MAAM,UAAA,GACJ,iBAAiB,KAAA,GACb;AAAA,QACE,OAAO,KAAA,CAAM,OAAA;AAAA,QACb,OAAO,KAAA,CAAM,KAAA;AAAA,QACb,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,GAAG;AAAA,UAEL,EAAE,KAAA,EAAO,OAAO,KAAK,CAAA,EAAG,GAAG,KAAA,EAAM;AAEvC,MAAA,GAAA,CAAI,OAAA,EAAS,KAAK,UAAU,CAAA;AAAA,IAC9B,CAAA;AAAA,IAEA,MAAM,CAAC,GAAA,EAAa,UAAgC,GAAA,CAAI,MAAA,EAAQ,KAAK,KAAK,CAAA;AAAA,IAE1E,OAAO,CAAC,GAAA,EAAa,UACnB,GAAA,CAAI,OAAA,EAAS,KAAK,KAAK,CAAA;AAAA,IAEzB,KAAA,EAAO,CAAC,QAAA,KACN,gBAAA,CAAiB,OAAA,EAAS;AAAA,MACxB,KAAA,EAAO,YAAA;AAAA,MACP,MAAA;AAAA,MACA,QAAA,EAAU,EAAE,GAAG,eAAA,EAAiB,GAAG,QAAA;AAAS,KAC7C;AAAA,GACL;AAEA,EAAA,OAAO,MAAA;AACT;AAeO,SAAS,mBAAA,GAAsB;AACpC,EAAA,OAAO,eAAA,EAAgB;AACzB","file":"logger.js","sourcesContent":["/**\n * Zero-dependency structured logger for edge environments\n *\n * This logger is ~100 LOC and provides:\n * - Structured JSON logging\n * - Auto trace context injection (traceId, spanId)\n * - Dynamic log level control (per-request via context)\n * - Level support (info, error, warn, debug)\n * - Zero dependencies (console-based)\n *\n * Unlike Pino/Winston (~500KB), this is <1KB minified!\n */\n\nimport {\n trace,\n context as api_context,\n createContextKey,\n} from '@opentelemetry/api';\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';\n\n/**\n * Context key for storing active log level (enables per-request log levels)\n */\nconst LOG_LEVEL_KEY = createContextKey('autotel-edge-log-level');\n\nexport interface EdgeLogger {\n info(msg: string, attrs?: Record<string, any>): void;\n error(\n msg: string,\n error?: Error | unknown,\n attrs?: Record<string, any>,\n ): void;\n warn(msg: string, attrs?: Record<string, any>): void;\n debug(msg: string, attrs?: Record<string, any>): void;\n /**\n * Create a child logger with merged bindings.\n * Like pino's child() — every log call from the child\n * includes the parent's attrs plus the child's bindings.\n */\n child(bindings: Record<string, any>): EdgeLogger;\n}\n\n/**\n * Get the active log level from context (if set)\n * Falls back to undefined if no log level is set in context\n */\nexport function getActiveLogLevel(): LogLevel | undefined {\n return api_context.active().getValue(LOG_LEVEL_KEY) as LogLevel | undefined;\n}\n\n/**\n * Run a function with a specific log level\n * The log level is stored in OpenTelemetry context and applies to all logger calls within the callback\n *\n * This works in edge runtimes (uses OTel context, not Node.js AsyncLocalStorage)\n *\n * @example\n * ```typescript\n * // Enable debug logging for a specific request\n * runWithLogLevel('debug', () => {\n * log.debug('This will be logged')\n * processRequest()\n * })\n *\n * // Disable logging temporarily\n * runWithLogLevel('none', () => {\n * log.info('This will NOT be logged')\n * })\n * ```\n */\nexport function runWithLogLevel<T>(level: LogLevel, callback: () => T): T {\n const ctx = api_context.active().setValue(LOG_LEVEL_KEY, level);\n return api_context.with(ctx, callback);\n}\n\n/**\n * Get current trace context from active span\n */\nfunction getTraceContext(): {\n traceId: string;\n spanId: string;\n correlationId: string;\n} | null {\n const span = trace.getActiveSpan();\n if (!span) return null;\n\n const ctx = span.spanContext();\n return {\n traceId: ctx.traceId,\n spanId: ctx.spanId,\n correlationId: ctx.traceId.slice(0, 16), // First 16 chars for grouping\n };\n}\n\n/**\n * Create a lightweight structured logger\n *\n * @param service - Service name for logging\n * @param options - Optional configuration\n *\n * @example\n * ```typescript\n * const log = createEdgeLogger('user-service')\n *\n * log.info('Creating user', { email: 'test@example.com' })\n * // Output: {\"level\":\"info\",\"service\":\"user-service\",\"msg\":\"Creating user\",\n * // \"email\":\"test@example.com\",\"traceId\":\"...\",\"spanId\":\"...\"}\n *\n * // Dynamic log level control per-request\n * runWithLogLevel('debug', () => {\n * log.debug('This will be logged even if logger was created with level: \"info\"')\n * })\n * ```\n */\nexport function createEdgeLogger(\n service: string,\n options?: {\n level?: LogLevel;\n pretty?: boolean; // For development\n bindings?: Record<string, any>; // Default attributes merged into every log (used by child())\n },\n): EdgeLogger {\n const defaultLevel = options?.level || 'info';\n const pretty = options?.pretty || false;\n const defaultBindings = options?.bindings || {};\n\n const levelPriority: Record<LogLevel, number> = {\n none: -1,\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n };\n\n const shouldLog = (level: LogLevel): boolean => {\n // Priority: context level > options level > 'info' default\n const activeLevel = getActiveLogLevel() ?? defaultLevel;\n\n // 'none' means suppress all logging\n if (activeLevel === 'none') return false;\n\n return levelPriority[level] >= levelPriority[activeLevel];\n };\n\n const log = (\n level: 'info' | 'error' | 'warn' | 'debug',\n msg: string,\n attrs?: Record<string, any>,\n ) => {\n if (!shouldLog(level)) return;\n\n const ctx = getTraceContext();\n const logEntry: Record<string, any> = {\n level,\n service,\n msg,\n ...defaultBindings,\n ...attrs,\n ...ctx, // Auto-inject traceId, spanId, correlationId\n timestamp: new Date().toISOString(),\n };\n\n if (pretty) {\n // Pretty print for development\n const traceInfo = ctx\n ? ` [${ctx.traceId.slice(0, 8)}.../${ctx.spanId.slice(0, 8)}...]`\n : '';\n const prettyAttrs = {\n ...defaultBindings,\n ...attrs,\n };\n console.log(\n `[${level.toUpperCase()}]${traceInfo} ${service}: ${msg}`,\n Object.keys(prettyAttrs).length > 0 ? prettyAttrs : '',\n );\n } else {\n // Structured JSON for production\n console.log(JSON.stringify(logEntry));\n }\n };\n\n const logger: EdgeLogger = {\n info: (msg: string, attrs?: Record<string, any>) => log('info', msg, attrs),\n\n error: (\n msg: string,\n error?: Error | unknown,\n attrs?: Record<string, any>,\n ) => {\n const errorAttrs =\n error instanceof Error\n ? {\n error: error.message,\n stack: error.stack,\n name: error.name,\n ...attrs,\n }\n : { error: String(error), ...attrs };\n\n log('error', msg, errorAttrs);\n },\n\n warn: (msg: string, attrs?: Record<string, any>) => log('warn', msg, attrs),\n\n debug: (msg: string, attrs?: Record<string, any>) =>\n log('debug', msg, attrs),\n\n child: (bindings: Record<string, any>) =>\n createEdgeLogger(service, {\n level: defaultLevel,\n pretty,\n bindings: { ...defaultBindings, ...bindings },\n }),\n };\n\n return logger;\n}\n\n/**\n * Helper to get trace context (useful for BYOL - Bring Your Own Logger)\n *\n * @example\n * ```typescript\n * import bunyan from 'bunyan'\n * import { getEdgeTraceContext } from 'autotel-edge/api/logger'\n *\n * const bunyanLogger = bunyan.createLogger({ name: 'myapp' })\n * const ctx = getEdgeTraceContext()\n * bunyanLogger.info({ ...ctx, email: 'test@example.com' }, 'Creating user')\n * ```\n */\nexport function getEdgeTraceContext() {\n return getTraceContext();\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { T as TailSampleFn, L as LocalTrace } from './types-BOs00OpG.js';
1
+ import { T as TailSampleFn, L as LocalTrace } from './types-CZFcIjJ4.js';
2
2
  import '@opentelemetry/api';
3
3
  import '@opentelemetry/sdk-trace-base';
4
4
 
@@ -193,4 +193,4 @@ interface HandlerInstrumentation<T extends Trigger, R extends any> {
193
193
  executionFailed?: (span: Span, trigger: T, error?: any) => void;
194
194
  }
195
195
 
196
- export type { ConfigurationOption as C, DOConstructorTrigger as D, EdgeEvent as E, FunnelStepStatus as F, HandlerInstrumentation as H, InstrumentationOptions as I, LocalTrace as L, OrPromise as O, PostProcessorFn as P, ResolvedEdgeConfig as R, ServiceConfig as S, TailSampleFn as T, WorkflowTrigger as W, OutcomeStatus as a, EdgeTrackEvent as b, EdgeFunnelStepEvent as c, EdgeOutcomeEvent as d, EdgeValueEvent as e, OTLPExporterConfig as f, EdgeConfig as g, Trigger as h, ExporterConfig as i, SamplingConfig as j, ResolveConfigFn as k, TraceFlushableSpanProcessor as l, InitialSpanInfo as m, EdgeSubscriber as n, DataSafetyConfig as o };
196
+ export type { ConfigurationOption as C, DOConstructorTrigger as D, EdgeEvent as E, FunnelStepStatus as F, HandlerInstrumentation as H, InitialSpanInfo as I, LocalTrace as L, OrPromise as O, PostProcessorFn as P, ResolvedEdgeConfig as R, SamplingConfig as S, TailSampleFn as T, WorkflowTrigger as W, OutcomeStatus as a, EdgeFunnelStepEvent as b, EdgeOutcomeEvent as c, EdgeTrackEvent as d, EdgeValueEvent as e, OTLPExporterConfig as f, Trigger as g, EdgeConfig as h, DataSafetyConfig as i, EdgeSubscriber as j, ExporterConfig as k, InstrumentationOptions as l, ResolveConfigFn as m, ServiceConfig as n, TraceFlushableSpanProcessor as o };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autotel-edge",
3
- "version": "3.15.1",
3
+ "version": "3.16.1",
4
4
  "description": "Vendor-agnostic OpenTelemetry for edge runtimes - foundation for Cloudflare, Vercel, Netlify, Deno",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -62,15 +62,15 @@
62
62
  "@opentelemetry/resources": "^2.6.0",
63
63
  "@opentelemetry/sdk-trace-base": "^2.6.0",
64
64
  "@opentelemetry/semantic-conventions": "^1.40.0",
65
- "@tanstack/intent": "^0.0.13"
65
+ "@tanstack/intent": "^0.0.23"
66
66
  },
67
67
  "devDependencies": {
68
68
  "@opentelemetry/context-async-hooks": "^2.6.0",
69
- "@types/node": "^25.3.5",
69
+ "@types/node": "^25.5.0",
70
70
  "rimraf": "^6.1.3",
71
71
  "tsup": "^8.5.1",
72
72
  "typescript": "^5.9.3",
73
- "vitest": "^4.0.18",
73
+ "vitest": "^4.1.0",
74
74
  "vitest-mock-extended": "^3.1.0"
75
75
  },
76
76
  "repository": {
@@ -123,7 +123,9 @@ describe('Edge Logger', () => {
123
123
  };
124
124
 
125
125
  // Mock trace.getActiveSpan to return our span
126
- const getActiveSpanSpy = vi.spyOn(trace, 'getActiveSpan').mockReturnValue(mockSpan as any);
126
+ const getActiveSpanSpy = vi
127
+ .spyOn(trace, 'getActiveSpan')
128
+ .mockReturnValue(mockSpan as any);
127
129
 
128
130
  logger.info('message with trace');
129
131
 
@@ -195,7 +197,9 @@ describe('Edge Logger', () => {
195
197
  expect(consoleLogSpy).toHaveBeenCalledOnce();
196
198
  const logOutput = JSON.parse(consoleLogSpy.mock.calls[0][0]);
197
199
 
198
- expect(logOutput.timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/);
200
+ expect(logOutput.timestamp).toMatch(
201
+ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/,
202
+ );
199
203
  });
200
204
  });
201
205
 
@@ -264,6 +268,104 @@ describe('Edge Logger', () => {
264
268
  });
265
269
  });
266
270
 
271
+ describe('child()', () => {
272
+ it('should create a child logger with merged bindings', () => {
273
+ const logger = createEdgeLogger('test-service');
274
+ const child = logger.child({ requestId: 'req-123' });
275
+
276
+ child.info('child message', { extra: 'data' });
277
+
278
+ expect(consoleLogSpy).toHaveBeenCalledOnce();
279
+ const logOutput = JSON.parse(consoleLogSpy.mock.calls[0][0]);
280
+
281
+ expect(logOutput).toMatchObject({
282
+ level: 'info',
283
+ service: 'test-service',
284
+ msg: 'child message',
285
+ requestId: 'req-123',
286
+ extra: 'data',
287
+ });
288
+ });
289
+
290
+ it('should merge parent bindings with child bindings', () => {
291
+ const logger = createEdgeLogger('test-service');
292
+ const child = logger.child({ requestId: 'req-123' });
293
+ const grandchild = child.child({ userId: 'user-456' });
294
+
295
+ grandchild.info('deep message');
296
+
297
+ expect(consoleLogSpy).toHaveBeenCalledOnce();
298
+ const logOutput = JSON.parse(consoleLogSpy.mock.calls[0][0]);
299
+
300
+ expect(logOutput).toMatchObject({
301
+ msg: 'deep message',
302
+ requestId: 'req-123',
303
+ userId: 'user-456',
304
+ });
305
+ });
306
+
307
+ it('should allow child attrs to override bindings', () => {
308
+ const logger = createEdgeLogger('test-service');
309
+ const child = logger.child({ env: 'staging' });
310
+
311
+ child.info('override', { env: 'production' });
312
+
313
+ expect(consoleLogSpy).toHaveBeenCalledOnce();
314
+ const logOutput = JSON.parse(consoleLogSpy.mock.calls[0][0]);
315
+
316
+ // Call-time attrs override bindings
317
+ expect(logOutput.env).toBe('production');
318
+ });
319
+
320
+ it('should return an EdgeLogger from child()', () => {
321
+ const logger = createEdgeLogger('test-service');
322
+ const child = logger.child({ key: 'val' });
323
+
324
+ expect(child.info).toBeDefined();
325
+ expect(child.error).toBeDefined();
326
+ expect(child.warn).toBeDefined();
327
+ expect(child.debug).toBeDefined();
328
+ expect(child.child).toBeDefined();
329
+ });
330
+
331
+ it('should chain child() calls', () => {
332
+ const logger = createEdgeLogger('test-service');
333
+ const child = logger.child({ a: 1 }).child({ b: 2 }).child({ c: 3 });
334
+
335
+ child.info('chained');
336
+
337
+ expect(consoleLogSpy).toHaveBeenCalledOnce();
338
+ const logOutput = JSON.parse(consoleLogSpy.mock.calls[0][0]);
339
+
340
+ expect(logOutput).toMatchObject({ a: 1, b: 2, c: 3 });
341
+ });
342
+
343
+ it('should not affect parent logger', () => {
344
+ const logger = createEdgeLogger('test-service');
345
+ const child = logger.child({ childOnly: 'yes' });
346
+
347
+ logger.info('parent message');
348
+
349
+ expect(consoleLogSpy).toHaveBeenCalledOnce();
350
+ const logOutput = JSON.parse(consoleLogSpy.mock.calls[0][0]);
351
+
352
+ expect(logOutput.childOnly).toBeUndefined();
353
+ });
354
+
355
+ it('should include child bindings in pretty mode', () => {
356
+ const logger = createEdgeLogger('test-service', { pretty: true });
357
+ const child = logger.child({ requestId: 'req-123' });
358
+
359
+ child.info('pretty child', { extra: 'data' });
360
+
361
+ expect(consoleLogSpy).toHaveBeenCalledOnce();
362
+ expect(consoleLogSpy.mock.calls[0][1]).toMatchObject({
363
+ requestId: 'req-123',
364
+ extra: 'data',
365
+ });
366
+ });
367
+ });
368
+
267
369
  describe('Dynamic log level control', () => {
268
370
  it('should override log level via runWithLogLevel', () => {
269
371
  const logger = createEdgeLogger('test-service', { level: 'info' });
package/src/api/logger.ts CHANGED
@@ -11,7 +11,11 @@
11
11
  * Unlike Pino/Winston (~500KB), this is <1KB minified!
12
12
  */
13
13
 
14
- import { trace, context as api_context, createContextKey } from '@opentelemetry/api';
14
+ import {
15
+ trace,
16
+ context as api_context,
17
+ createContextKey,
18
+ } from '@opentelemetry/api';
15
19
 
16
20
  export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';
17
21
 
@@ -22,9 +26,19 @@ const LOG_LEVEL_KEY = createContextKey('autotel-edge-log-level');
22
26
 
23
27
  export interface EdgeLogger {
24
28
  info(msg: string, attrs?: Record<string, any>): void;
25
- error(msg: string, error?: Error | unknown, attrs?: Record<string, any>): void;
29
+ error(
30
+ msg: string,
31
+ error?: Error | unknown,
32
+ attrs?: Record<string, any>,
33
+ ): void;
26
34
  warn(msg: string, attrs?: Record<string, any>): void;
27
35
  debug(msg: string, attrs?: Record<string, any>): void;
36
+ /**
37
+ * Create a child logger with merged bindings.
38
+ * Like pino's child() — every log call from the child
39
+ * includes the parent's attrs plus the child's bindings.
40
+ */
41
+ child(bindings: Record<string, any>): EdgeLogger;
28
42
  }
29
43
 
30
44
  /**
@@ -63,9 +77,11 @@ export function runWithLogLevel<T>(level: LogLevel, callback: () => T): T {
63
77
  /**
64
78
  * Get current trace context from active span
65
79
  */
66
- function getTraceContext():
67
- | { traceId: string; spanId: string; correlationId: string }
68
- | null {
80
+ function getTraceContext(): {
81
+ traceId: string;
82
+ spanId: string;
83
+ correlationId: string;
84
+ } | null {
69
85
  const span = trace.getActiveSpan();
70
86
  if (!span) return null;
71
87
 
@@ -102,10 +118,12 @@ export function createEdgeLogger(
102
118
  options?: {
103
119
  level?: LogLevel;
104
120
  pretty?: boolean; // For development
121
+ bindings?: Record<string, any>; // Default attributes merged into every log (used by child())
105
122
  },
106
123
  ): EdgeLogger {
107
124
  const defaultLevel = options?.level || 'info';
108
125
  const pretty = options?.pretty || false;
126
+ const defaultBindings = options?.bindings || {};
109
127
 
110
128
  const levelPriority: Record<LogLevel, number> = {
111
129
  none: -1,
@@ -137,6 +155,7 @@ export function createEdgeLogger(
137
155
  level,
138
156
  service,
139
157
  msg,
158
+ ...defaultBindings,
140
159
  ...attrs,
141
160
  ...ctx, // Auto-inject traceId, spanId, correlationId
142
161
  timestamp: new Date().toISOString(),
@@ -147,9 +166,13 @@ export function createEdgeLogger(
147
166
  const traceInfo = ctx
148
167
  ? ` [${ctx.traceId.slice(0, 8)}.../${ctx.spanId.slice(0, 8)}...]`
149
168
  : '';
169
+ const prettyAttrs = {
170
+ ...defaultBindings,
171
+ ...attrs,
172
+ };
150
173
  console.log(
151
174
  `[${level.toUpperCase()}]${traceInfo} ${service}: ${msg}`,
152
- attrs || '',
175
+ Object.keys(prettyAttrs).length > 0 ? prettyAttrs : '',
153
176
  );
154
177
  } else {
155
178
  // Structured JSON for production
@@ -157,26 +180,41 @@ export function createEdgeLogger(
157
180
  }
158
181
  };
159
182
 
160
- return {
183
+ const logger: EdgeLogger = {
161
184
  info: (msg: string, attrs?: Record<string, any>) => log('info', msg, attrs),
162
185
 
163
- error: (msg: string, error?: Error | unknown, attrs?: Record<string, any>) => {
164
- const errorAttrs = error instanceof Error
165
- ? {
166
- error: error.message,
167
- stack: error.stack,
168
- name: error.name,
169
- ...attrs,
170
- }
171
- : { error: String(error), ...attrs };
186
+ error: (
187
+ msg: string,
188
+ error?: Error | unknown,
189
+ attrs?: Record<string, any>,
190
+ ) => {
191
+ const errorAttrs =
192
+ error instanceof Error
193
+ ? {
194
+ error: error.message,
195
+ stack: error.stack,
196
+ name: error.name,
197
+ ...attrs,
198
+ }
199
+ : { error: String(error), ...attrs };
172
200
 
173
201
  log('error', msg, errorAttrs);
174
202
  },
175
203
 
176
204
  warn: (msg: string, attrs?: Record<string, any>) => log('warn', msg, attrs),
177
205
 
178
- debug: (msg: string, attrs?: Record<string, any>) => log('debug', msg, attrs),
206
+ debug: (msg: string, attrs?: Record<string, any>) =>
207
+ log('debug', msg, attrs),
208
+
209
+ child: (bindings: Record<string, any>) =>
210
+ createEdgeLogger(service, {
211
+ level: defaultLevel,
212
+ pretty,
213
+ bindings: { ...defaultBindings, ...bindings },
214
+ }),
179
215
  };
216
+
217
+ return logger;
180
218
  }
181
219
 
182
220
  /**