UNPKG

autotel

Version:
1 lines 7.55 kB
{"version":3,"sources":["../src/decorators.ts"],"names":["getConfig","createTraceContext","SpanStatusCode"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAmGO,SAAS,KAAA,CACd,eACA,YAAA,EAIK;AAEL,EAAA,MAAM,IAAA,GACJ,OAAO,aAAA,KAAkB,QAAA,GAAW,gBAAgB,aAAA,EAAe,IAAA;AASrE,EAAA,OAAO,SACL,gBACA,OAAA,EACG;AACH,IAAA,MAAM,UAAA,GAAa,MAAA,CAAO,OAAA,CAAQ,IAAI,CAAA;AAKtC,IAAA,MAAM,SAAA,GAAY,cAAA,EAAgB,QAAA,EAAS,IAAK,EAAA;AAChD,IAAA,MAAM,UACJ,cAAA,KACC,cAAA,CAAe,aAAa,IAAA,KAAS,eAAA,IACpC,UAAU,IAAA,EAAK,CAAE,UAAA,CAAW,QAAQ,KACnC,SAAA,CAAU,QAAA,CAAS,eAAe,CAAA,IAAK,SAAA,CAAU,SAAS,OAAO,CAAA;AAAA,IAElE,UAAA,CAAW,KAAK,SAAS,CAAA,CAAA;AAE7B,IAAA,IAAI,CAAC,OAAA,EAAS;AAEZ,MAAA,OAAO,cAAA;AAAA,IACT;AAEA,IAAA,MAAM,WAAW,IAAA,IAAQ,UAAA;AAEzB,IAAA,OAAO,kBAEF,IAAA,EACe;AAClB,MAAA,MAAM,SAASA,2BAAA,EAAU;AACzB,MAAA,MAAM,SAAS,MAAA,CAAO,MAAA;AAEtB,MAAA,OAAO,MAAA,CAAO,eAAA,CAAgB,QAAA,EAAU,OAAO,IAAA,KAAS;AACtD,QAAA,IAAI;AAEF,UAAA,MAAM,GAAA,GAAoBC,qCAAmB,IAAI,CAAA;AAEjD,UAAA,MAAM,cAAe,IAAA,CAAgC,GAAA;AACrD,UAAA,IAAI;AACF,YAAC,KAAgC,GAAA,GAAM,GAAA;AACvC,YAAA,MAAM,MAAA,GAAS,MAAM,cAAA,CAAe,KAAA,CAAM,MAAM,IAAU,CAAA;AAC1D,YAAA,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAMC,kBAAA,CAAe,IAAI,CAAA;AAC1C,YAAA,OAAO,MAAA;AAAA,UACT,CAAA,SAAE;AAEA,YAAA,IAAI,gBAAgB,KAAA,CAAA,EAAW;AAC7B,cAAA,OAAQ,IAAA,CAAgC,GAAA;AAAA,YAC1C,CAAA,MAAO;AACL,cAAC,KAAgC,GAAA,GAAM,WAAA;AAAA,YACzC;AAAA,UACF;AAAA,QACF,SAAS,KAAA,EAAO;AACd,UAAA,IAAA,CAAK,SAAA,CAAU;AAAA,YACb,MAAMA,kBAAA,CAAe,KAAA;AAAA,YACrB,OAAA,EAAS,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU;AAAA,WACnD,CAAA;AACD,UAAA,IAAA,CAAK,eAAA;AAAA,YACH,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC;AAAA,WAC1D;AACA,UAAA,MAAM,KAAA;AAAA,QACR,CAAA,SAAE;AACA,UAAA,IAAA,CAAK,GAAA,EAAI;AAAA,QACX;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,EACF,CAAA;AACF","file":"decorators.cjs","sourcesContent":["/**\n * TypeScript 5+ Decorators for autotel\n *\n * Provides @Trace decorator for class-based code.\n *\n * **Requires TypeScript 5.0+**\n *\n * @example Method decorator\n * ```typescript\n * import { Trace } from 'autotel/decorators'\n *\n * class OrderService {\n * @Trace('order.create', { withMetrics: true })\n * async createOrder(data: OrderData) {\n * return await db.orders.create(data)\n * }\n *\n * @Trace() // Uses method name as span name\n * async processPayment(orderId: string) {\n * return await stripe.charge(orderId)\n * }\n * }\n * ```\n */\n\nimport type { TracingOptions, TraceContext } from './functional';\nimport { getConfig } from './config';\nimport { SpanStatusCode } from '@opentelemetry/api';\nimport { createTraceContext } from './trace-context';\n\n/**\n * Options for @Trace method decorator\n */\nexport interface TraceDecoratorOptions extends Omit<TracingOptions, 'name'> {\n /**\n * Custom span name. If not provided, uses the method name.\n */\n name?: string;\n}\n\n/**\n * @Trace - Method decorator for fine-grained tracing\n *\n * Wraps a class method with automatic tracing. Supports both patterns:\n * - Simple: method doesn't use ctx\n * - Advanced: method accesses ctx via this.ctx\n *\n * @example Simple usage (no ctx)\n * ```typescript\n * class OrderService {\n * @Trace()\n * async createOrder(data: OrderData) {\n * return await db.orders.create(data)\n * }\n * }\n * ```\n *\n * @example With custom name and options\n * ```typescript\n * class PaymentService {\n * @Trace('payment.charge', { withMetrics: true })\n * async chargeCard(amount: number) {\n * return await stripe.charges.create({ amount })\n * }\n * }\n * ```\n *\n * @example Accessing ctx\n * ```typescript\n * interface WithTraceContext {\n * ctx?: TraceContext\n * }\n *\n * class UserService {\n * @Trace()\n * async createUser(data: UserData) {\n * // Access ctx via this.ctx (available during execution)\n * const ctx = (this as unknown as WithTraceContext).ctx\n * if (ctx) {\n * ctx.setAttribute('user.id', data.id)\n * }\n * return await db.users.create(data)\n * }\n * }\n * ```\n */\nexport function Trace(\n options?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T;\nexport function Trace(\n name?: string,\n options?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T;\nexport function Trace(\n nameOrOptions?: string | TraceDecoratorOptions,\n maybeOptions?: TraceDecoratorOptions,\n): <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n) => T {\n // Parse arguments\n const name =\n typeof nameOrOptions === 'string' ? nameOrOptions : nameOrOptions?.name;\n // Options are used in the returned decorator function, not here\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const _options: TraceDecoratorOptions =\n typeof nameOrOptions === 'string'\n ? maybeOptions || {}\n : nameOrOptions || {};\n\n // TypeScript 5+ decorator signature\n return function <T extends (...args: unknown[]) => Promise<unknown>>(\n originalMethod: T,\n context: ClassMethodDecoratorContext,\n ): T {\n const methodName = String(context.name);\n\n // Skip if not an async function\n // Check multiple ways to detect async functions (for different transpilation environments)\n // TypeScript decorators run at class definition time, so we need robust detection\n const methodStr = originalMethod?.toString() || '';\n const isAsync =\n originalMethod &&\n (originalMethod.constructor?.name === 'AsyncFunction' ||\n methodStr.trim().startsWith('async ') ||\n (methodStr.includes('[native code]') && methodStr.includes('async')) ||\n // Fallback: if function has async in its string representation\n /async\\s+/.test(methodStr));\n\n if (!isAsync) {\n // Not an async function, return as-is\n return originalMethod;\n }\n\n const spanName = name || methodName;\n\n return async function <This>(\n this: This,\n ...args: unknown[]\n ): Promise<unknown> {\n const config = getConfig();\n const tracer = config.tracer;\n\n return tracer.startActiveSpan(spanName, async (span) => {\n try {\n // Make ctx available via this.ctx for methods that need it\n const ctx: TraceContext = createTraceContext(span);\n\n const originalCtx = (this as { ctx?: TraceContext }).ctx;\n try {\n (this as { ctx?: TraceContext }).ctx = ctx;\n const result = await originalMethod.apply(this, args as []);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } finally {\n // Restore original ctx\n if (originalCtx === undefined) {\n delete (this as { ctx?: TraceContext }).ctx;\n } else {\n (this as { ctx?: TraceContext }).ctx = originalCtx;\n }\n }\n } catch (error) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : 'Unknown error',\n });\n span.recordException(\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n } finally {\n span.end();\n }\n });\n } as T;\n };\n}\n\n// Re-export types for convenience\n\nexport { type TraceContext, type TracingOptions } from './functional';\n"]}