{"version":3,"file":"logger.cjs","names":["isRecord","effectiveLevel: CallableLogLevel","resolveNextTick"],"sources":["../../src/middleware/logger.ts"],"sourcesContent":["import { resolveNextTick } from \"../helpers/promises.ts\";\nimport { isRecord } from \"../helpers/types.ts\";\nimport type { LogLevel } from \"../types.ts\";\n\n/**\n * All kinds of arguments can come through\n *\n * Examples seen are\n * - string\n * - object / hash\n * - values used for string interpolation, basically anything\n *\n * See https://linear.app/inngest/issue/INN-1342/flush-logs-on-function-exitreturns for more details\n *\n * @public\n */\nexport type LogArg = unknown;\n\n/**\n * Based on https://datatracker.ietf.org/doc/html/rfc5424#autoid-11\n * it's pretty reasonable to expect a logger to have the following interfaces\n * available.\n */\nexport interface Logger {\n  info(...args: LogArg[]): void;\n  warn(...args: LogArg[]): void;\n  error(...args: LogArg[]): void;\n  debug(...args: LogArg[]): void;\n}\n\n/**\n * Numeric ranking for log levels. Higher = more severe.\n * Used to determine if a message should be logged based on configured level.\n */\nconst LOG_LEVEL_RANK = {\n  debug: 0,\n  info: 1,\n  warn: 2,\n  error: 3,\n} as const;\n\ntype CallableLogLevel = keyof typeof LOG_LEVEL_RANK;\n\n/**\n * Console-based logger. Not for production use.\n */\nexport class ConsoleLogger implements Logger {\n  private readonly level: LogLevel;\n\n  constructor(opts: { level?: LogLevel } = {}) {\n    this.level = opts.level ?? \"info\";\n  }\n\n  info(...args: LogArg[]) {\n    if (this.shouldLog(\"info\")) {\n      this.logFormatted(console.info, args);\n    }\n  }\n\n  warn(...args: LogArg[]) {\n    if (this.shouldLog(\"warn\")) {\n      this.logFormatted(console.warn, args);\n    }\n  }\n\n  error(...args: LogArg[]) {\n    if (this.shouldLog(\"error\")) {\n      this.logFormatted(console.error, args);\n    }\n  }\n\n  debug(...args: LogArg[]) {\n    if (this.shouldLog(\"debug\")) {\n      this.logFormatted(console.debug, args);\n    }\n  }\n\n  /**\n   * Detect Pino-style `(object, string, ...rest)` calls and reformat for\n   * console readability: message first, then structured fields.\n   */\n  private logFormatted(fn: (...args: LogArg[]) => void, args: LogArg[]) {\n    if (args.length > 1 && isRecord(args[0]) && typeof args[1] === \"string\") {\n      const fields = args[0];\n      const nonErrFields = Object.fromEntries(\n        Object.entries(fields).filter(([key]) => {\n          return key !== \"err\";\n        }),\n      );\n      const [, message, ...rest] = args;\n\n      fn(message);\n\n      if (fields.err) {\n        fn(fields.err);\n      }\n\n      if (Object.keys(nonErrFields).length > 0) {\n        fn(nonErrFields);\n      }\n\n      if (rest.length > 0) {\n        fn(...rest);\n      }\n\n      return;\n    }\n\n    fn(...args);\n  }\n\n  private shouldLog(level: CallableLogLevel): boolean {\n    if (this.level === \"silent\") {\n      return false;\n    }\n\n    // Map configured level to a callable level (fatal -> error)\n    let effectiveLevel: CallableLogLevel = \"info\";\n    if (this.level === \"fatal\") {\n      effectiveLevel = \"error\";\n    } else if (this.level in LOG_LEVEL_RANK) {\n      effectiveLevel = this.level as CallableLogLevel;\n    }\n\n    return LOG_LEVEL_RANK[level] >= LOG_LEVEL_RANK[effectiveLevel];\n  }\n}\n\n/**\n * ProxyLogger aims to provide a thin wrapper on user's provided logger.\n * It's expected to be turned on and off based on the function execution\n * context, so it doesn't result in duplicated logging.\n *\n * And also attempt to allow enough time for the logger to flush all logs.\n *\n * @public\n */\nexport class ProxyLogger implements Logger {\n  private readonly logger: Logger;\n  private enabled = false;\n\n  constructor(logger: Logger) {\n    this.logger = logger;\n\n    // Return a Proxy to forward arbitrary property access to the underlying\n    // logger. For example, if the user provides a logger that has a `foo`\n    // method, they can call `foo` on the ProxyLogger and it will call the\n    // underlying logger's `foo` method.\n    return new Proxy(this, {\n      get(target, prop, receiver): unknown {\n        // Handle ProxyLogger's own methods/properties.\n        if (prop in target) {\n          return Reflect.get(target, prop, receiver);\n        }\n\n        // Forward property access to the underlying logger.\n        return Reflect.get(target.logger, prop, receiver);\n      },\n    }) as ProxyLogger;\n  }\n\n  info(...args: LogArg[]) {\n    if (!this.enabled) {\n      return;\n    }\n    this.logger.info(...args);\n  }\n\n  warn(...args: LogArg[]) {\n    if (!this.enabled) {\n      return;\n    }\n    this.logger.warn(...args);\n  }\n\n  error(...args: LogArg[]) {\n    if (!this.enabled) {\n      return;\n    }\n    this.logger.error(...args);\n  }\n\n  debug(...args: LogArg[]) {\n    if (!this.enabled || !(typeof this.logger.debug === \"function\")) {\n      return;\n    }\n    this.logger.debug(...args);\n  }\n\n  enable() {\n    this.enabled = true;\n  }\n\n  disable() {\n    this.enabled = false;\n  }\n\n  async flush() {\n    // If ConsoleLogger, nothing to wait for\n    if (this.logger.constructor.name == ConsoleLogger.name) {\n      return;\n    }\n\n    const logger = this.logger as Logger & {\n      flush?: () => Promise<void> | void;\n    };\n\n    // If the logger has its own flush, defer to it\n    if (typeof logger.flush === \"function\") {\n      await logger.flush();\n      return;\n    }\n\n    // Otherwise yield one event-loop tick (non-blocking hint for buffered loggers)\n    await resolveNextTick();\n  }\n}\n"],"mappings":";;;;;;;;AAkCA,MAAM,iBAAiB;CACrB,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACR;;;;AAOD,IAAa,gBAAb,MAA6C;CAC3C,AAAiB;CAEjB,YAAY,OAA6B,EAAE,EAAE;AAC3C,OAAK,QAAQ,KAAK,SAAS;;CAG7B,KAAK,GAAG,MAAgB;AACtB,MAAI,KAAK,UAAU,OAAO,CACxB,MAAK,aAAa,QAAQ,MAAM,KAAK;;CAIzC,KAAK,GAAG,MAAgB;AACtB,MAAI,KAAK,UAAU,OAAO,CACxB,MAAK,aAAa,QAAQ,MAAM,KAAK;;CAIzC,MAAM,GAAG,MAAgB;AACvB,MAAI,KAAK,UAAU,QAAQ,CACzB,MAAK,aAAa,QAAQ,OAAO,KAAK;;CAI1C,MAAM,GAAG,MAAgB;AACvB,MAAI,KAAK,UAAU,QAAQ,CACzB,MAAK,aAAa,QAAQ,OAAO,KAAK;;;;;;CAQ1C,AAAQ,aAAa,IAAiC,MAAgB;AACpE,MAAI,KAAK,SAAS,KAAKA,uBAAS,KAAK,GAAG,IAAI,OAAO,KAAK,OAAO,UAAU;GACvE,MAAM,SAAS,KAAK;GACpB,MAAM,eAAe,OAAO,YAC1B,OAAO,QAAQ,OAAO,CAAC,QAAQ,CAAC,SAAS;AACvC,WAAO,QAAQ;KACf,CACH;GACD,MAAM,GAAG,SAAS,GAAG,QAAQ;AAE7B,MAAG,QAAQ;AAEX,OAAI,OAAO,IACT,IAAG,OAAO,IAAI;AAGhB,OAAI,OAAO,KAAK,aAAa,CAAC,SAAS,EACrC,IAAG,aAAa;AAGlB,OAAI,KAAK,SAAS,EAChB,IAAG,GAAG,KAAK;AAGb;;AAGF,KAAG,GAAG,KAAK;;CAGb,AAAQ,UAAU,OAAkC;AAClD,MAAI,KAAK,UAAU,SACjB,QAAO;EAIT,IAAIC,iBAAmC;AACvC,MAAI,KAAK,UAAU,QACjB,kBAAiB;WACR,KAAK,SAAS,eACvB,kBAAiB,KAAK;AAGxB,SAAO,eAAe,UAAU,eAAe;;;;;;;;;;;;AAanD,IAAa,cAAb,MAA2C;CACzC,AAAiB;CACjB,AAAQ,UAAU;CAElB,YAAY,QAAgB;AAC1B,OAAK,SAAS;AAMd,SAAO,IAAI,MAAM,MAAM,EACrB,IAAI,QAAQ,MAAM,UAAmB;AAEnC,OAAI,QAAQ,OACV,QAAO,QAAQ,IAAI,QAAQ,MAAM,SAAS;AAI5C,UAAO,QAAQ,IAAI,OAAO,QAAQ,MAAM,SAAS;KAEpD,CAAC;;CAGJ,KAAK,GAAG,MAAgB;AACtB,MAAI,CAAC,KAAK,QACR;AAEF,OAAK,OAAO,KAAK,GAAG,KAAK;;CAG3B,KAAK,GAAG,MAAgB;AACtB,MAAI,CAAC,KAAK,QACR;AAEF,OAAK,OAAO,KAAK,GAAG,KAAK;;CAG3B,MAAM,GAAG,MAAgB;AACvB,MAAI,CAAC,KAAK,QACR;AAEF,OAAK,OAAO,MAAM,GAAG,KAAK;;CAG5B,MAAM,GAAG,MAAgB;AACvB,MAAI,CAAC,KAAK,WAAW,EAAE,OAAO,KAAK,OAAO,UAAU,YAClD;AAEF,OAAK,OAAO,MAAM,GAAG,KAAK;;CAG5B,SAAS;AACP,OAAK,UAAU;;CAGjB,UAAU;AACR,OAAK,UAAU;;CAGjB,MAAM,QAAQ;AAEZ,MAAI,KAAK,OAAO,YAAY,QAAQ,cAAc,KAChD;EAGF,MAAM,SAAS,KAAK;AAKpB,MAAI,OAAO,OAAO,UAAU,YAAY;AACtC,SAAM,OAAO,OAAO;AACpB;;AAIF,QAAMC,kCAAiB"}