{"version":3,"file":"sentry.mjs","names":[],"sources":["../../src/modules/sentry.ts"],"sourcesContent":["import * as Sentry from '@sentry/node'\nimport type { AutocompleteInteraction } from 'discord.js'\nimport env from 'env-var'\nimport {\n  type ApplicationInteraction,\n  type SleetClient,\n  SleetModule,\n  type SleetModuleMiddleware,\n} from 'sleetcord'\n\nimport { interactionToString } from '../utils/stringify.ts'\nimport { censorPath } from './logging.ts'\n\nexport { Sentry }\n\nconst NODE_ENV: string = env.get('NODE_ENV').required().asString()\nconst SENTRY_DSN: string = env.get('SENTRY_DSN').asString() ?? ''\n\n/**\n * Init Sentry, enabling logging\n *\n * This comes with default settings for Sentry, but you can override any of them by providing options\n *\n * Requires the Sentry DSN to be set as an env var `SENTRY_DSN`\n * @param options Sentry options\n */\nexport function initSentry(options?: Sentry.NodeOptions) {\n  if (!SENTRY_DSN) {\n    console.warn('SENTRY_DSN not set, not initializing Sentry. Set it to enable Sentry.')\n    return\n  }\n\n  Sentry.init({\n    dsn: SENTRY_DSN,\n    environment: NODE_ENV,\n    integrations: [\n      Sentry.dedupeIntegration(),\n      Sentry.localVariablesIntegration({\n        captureAllExceptions: true,\n        maxExceptionsPerSecond: 5,\n      }),\n    ],\n    // Performance Monitoring\n    tracesSampleRate: 0.1,\n    // Set sampling rate for profiling - this is relative to tracesSampleRate\n    profilesSampleRate: 0.5,\n    includeLocalVariables: true,\n\n    // Censor out tokens from url breadcrumbs, they're not very useful\n    beforeBreadcrumb(breadcrumb) {\n      if (typeof breadcrumb.data?.url === 'string') {\n        breadcrumb.data.url = censorPath(breadcrumb.data.url)\n      }\n\n      return breadcrumb\n    },\n\n    // Apply any provided options\n    ...options,\n  })\n}\n\n/**\n * A module runner designed to run every module+event under a Sentry span\n * for error tracing\n * @param module The module to run\n * @param callback The callback that runs the module\n * @param event The event that will be handled by the module\n * @returns The result of running that module\n */\nexport const sentryMiddleware: SleetModuleMiddleware = async (module, event, next) => {\n  await Sentry.startSpan(\n    {\n      name: `${module.name}:${event.name}`,\n      op: 'module',\n    },\n    async (span) => {\n      const scope = Sentry.getCurrentScope()\n      scope.setTag('module', module.name)\n\n      try {\n        await next()\n      } catch (e) {\n        Sentry.captureException(e instanceof Error ? e : new Error(String(e)), {\n          tags: {\n            module: module.name,\n            type: 'unhandled-module-error',\n          },\n        })\n        span.setAttribute('error', e instanceof Error ? e.message : String(e))\n      } finally {\n        scope.clearBreadcrumbs()\n      }\n    },\n  )\n}\n\nexport const sentryLogger: SleetModule = new SleetModule(\n  {\n    name: 'sentryLogger',\n  },\n  {\n    // discord.js error\n    error(error) {\n      Sentry.captureException(error, {\n        tags: {\n          ...moduleName(this.sleet),\n          type: 'discord.js-error',\n        },\n      })\n    },\n    sleetError(message, error) {\n      Sentry.captureException(error, {\n        tags: {\n          ...moduleName(this.sleet),\n          type: 'sleet-error',\n        },\n        extra: {\n          message,\n        },\n      })\n    },\n\n    // discord.js warning\n    warn(message) {\n      Sentry.captureMessage(message, {\n        level: 'warning',\n        tags: {\n          ...moduleName(this.sleet),\n          type: 'discord.js-warning',\n        },\n      })\n    },\n    sleetWarn(message, data) {\n      Sentry.captureMessage(message, {\n        level: 'warning',\n        tags: {\n          ...moduleName(this.sleet),\n          type: 'sleet-warn',\n        },\n        extra: {\n          data,\n        },\n      })\n    },\n\n    autocompleteInteractionError: interactionErrorHandler,\n    applicationInteractionError: interactionErrorHandler,\n  },\n  {\n    middleware: SENTRY_DSN ? [sentryMiddleware] : [],\n  },\n)\n\nfunction interactionErrorHandler(\n  module: SleetModule,\n  interaction: ApplicationInteraction | AutocompleteInteraction,\n  error: unknown,\n) {\n  Sentry.captureException(error, {\n    extra: {\n      interaction: interactionToString(interaction),\n    },\n    tags: {\n      moduleName: module?.name,\n      type: 'interaction-error',\n      commandName: interaction.commandName,\n    },\n  })\n}\n\nfunction moduleName(sleet: SleetClient): { moduleName: string } | undefined {\n  const module = sleet.runningModuleStore.getStore()\n  if (module) {\n    return { moduleName: module.name }\n  }\n  return undefined\n}\n"],"mappings":";;;;;;AAeA,MAAM,WAAmB,IAAI,IAAI,WAAW,CAAC,UAAU,CAAC,UAAU;AAClE,MAAM,aAAqB,IAAI,IAAI,aAAa,CAAC,UAAU,IAAI;;;;;;;;;AAU/D,SAAgB,WAAW,SAA8B;AACvD,KAAI,CAAC,YAAY;AACf,UAAQ,KAAK,wEAAwE;AACrF;;AAGF,QAAO,KAAK;EACV,KAAK;EACL,aAAa;EACb,cAAc,CACZ,OAAO,mBAAmB,EAC1B,OAAO,0BAA0B;GAC/B,sBAAsB;GACtB,wBAAwB;GACzB,CAAC,CACH;EAED,kBAAkB;EAElB,oBAAoB;EACpB,uBAAuB;EAGvB,iBAAiB,YAAY;AAC3B,OAAI,OAAO,WAAW,MAAM,QAAQ,SAClC,YAAW,KAAK,MAAM,WAAW,WAAW,KAAK,IAAI;AAGvD,UAAO;;EAIT,GAAG;EACJ,CAAC;;;;;;;;;;AAWJ,MAAa,mBAA0C,OAAO,QAAQ,OAAO,SAAS;AACpF,OAAM,OAAO,UACX;EACE,MAAM,GAAG,OAAO,KAAK,GAAG,MAAM;EAC9B,IAAI;EACL,EACD,OAAO,SAAS;EACd,MAAM,QAAQ,OAAO,iBAAiB;AACtC,QAAM,OAAO,UAAU,OAAO,KAAK;AAEnC,MAAI;AACF,SAAM,MAAM;WACL,GAAG;AACV,UAAO,iBAAiB,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,EAAE,CAAC,EAAE,EACrE,MAAM;IACJ,QAAQ,OAAO;IACf,MAAM;IACP,EACF,CAAC;AACF,QAAK,aAAa,SAAS,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE,CAAC;YAC9D;AACR,SAAM,kBAAkB;;GAG7B;;AAGH,MAAa,eAA4B,IAAI,YAC3C,EACE,MAAM,gBACP,EACD;CAEE,MAAM,OAAO;AACX,SAAO,iBAAiB,OAAO,EAC7B,MAAM;GACJ,GAAG,WAAW,KAAK,MAAM;GACzB,MAAM;GACP,EACF,CAAC;;CAEJ,WAAW,SAAS,OAAO;AACzB,SAAO,iBAAiB,OAAO;GAC7B,MAAM;IACJ,GAAG,WAAW,KAAK,MAAM;IACzB,MAAM;IACP;GACD,OAAO,EACL,SACD;GACF,CAAC;;CAIJ,KAAK,SAAS;AACZ,SAAO,eAAe,SAAS;GAC7B,OAAO;GACP,MAAM;IACJ,GAAG,WAAW,KAAK,MAAM;IACzB,MAAM;IACP;GACF,CAAC;;CAEJ,UAAU,SAAS,MAAM;AACvB,SAAO,eAAe,SAAS;GAC7B,OAAO;GACP,MAAM;IACJ,GAAG,WAAW,KAAK,MAAM;IACzB,MAAM;IACP;GACD,OAAO,EACL,MACD;GACF,CAAC;;CAGJ,8BAA8B;CAC9B,6BAA6B;CAC9B,EACD,EACE,YAAY,aAAa,CAAC,iBAAiB,GAAG,EAAE,EACjD,CACF;AAED,SAAS,wBACP,QACA,aACA,OACA;AACA,QAAO,iBAAiB,OAAO;EAC7B,OAAO,EACL,aAAa,oBAAoB,YAAY,EAC9C;EACD,MAAM;GACJ,YAAY,QAAQ;GACpB,MAAM;GACN,aAAa,YAAY;GAC1B;EACF,CAAC;;AAGJ,SAAS,WAAW,OAAwD;CAC1E,MAAM,SAAS,MAAM,mBAAmB,UAAU;AAClD,KAAI,OACF,QAAO,EAAE,YAAY,OAAO,MAAM"}