{"version":3,"file":"index.cjs","names":["LoggerlessTransport"],"sources":["../src/errors.ts","../src/utils.ts","../src/HttpTransport.ts"],"sourcesContent":["/**\n * Error thrown when HTTP request fails\n */\nexport class HttpTransportError extends Error {\n  constructor(\n    message: string,\n    public status?: number,\n    public response?: Response,\n  ) {\n    super(message);\n    this.name = \"HttpTransportError\";\n  }\n}\n\n/**\n * Error thrown when rate limit is exceeded\n */\nexport class RateLimitError extends Error {\n  constructor(\n    message: string,\n    public retryAfter: number,\n  ) {\n    super(message);\n    this.name = \"RateLimitError\";\n  }\n}\n\n/**\n * Error thrown when log entry exceeds size limits\n */\nexport class LogSizeError extends Error {\n  constructor(\n    message: string,\n    public logEntry: Record<string, any>,\n    public size: number,\n    public limit: number,\n  ) {\n    super(message);\n    this.name = \"LogSizeError\";\n  }\n}\n","import { HttpTransportError, RateLimitError } from \"./errors.js\";\n\n/**\n * Compresses data using gzip compression\n */\nexport async function compressData(data: string): Promise<Uint8Array> {\n  const encoder = new TextEncoder();\n  const dataBytes = encoder.encode(data);\n\n  // Use the CompressionStream API if available (modern browsers)\n  if (typeof CompressionStream !== \"undefined\") {\n    const stream = new CompressionStream(\"gzip\");\n    const writer = stream.writable.getWriter();\n    const reader = stream.readable.getReader();\n\n    await writer.write(dataBytes);\n    await writer.close();\n\n    const chunks: Uint8Array[] = [];\n    while (true) {\n      const { done, value } = await reader.read();\n      if (done) break;\n      chunks.push(value);\n    }\n\n    const totalLength = chunks.reduce((acc, chunk) => acc + chunk.length, 0);\n    const result = new Uint8Array(totalLength);\n    let offset = 0;\n    for (const chunk of chunks) {\n      result.set(chunk, offset);\n      offset += chunk.length;\n    }\n\n    return result;\n  }\n\n  // Fallback for Node.js or environments without CompressionStream\n  // In a real implementation, you might want to use a library like 'zlib' for Node.js\n  throw new Error(\"Gzip compression not supported in this environment\");\n}\n\n/**\n * Sends HTTP request with retry logic and rate limiting\n */\nexport async function sendWithRetry(\n  url: string,\n  method: string,\n  headers: Record<string, string>,\n  payload: string | Uint8Array,\n  maxRetries: number,\n  retryDelay: number,\n  respectRateLimit = true,\n  onDebugReqRes?: (reqRes: {\n    req: { url: string; method: string; headers: Record<string, string>; body: string | Uint8Array };\n    res: { status: number; statusText: string; headers: Record<string, string>; body: string };\n  }) => void,\n  onError?: (err: Error) => void,\n): Promise<Response> {\n  let lastError: Error;\n\n  for (let attempt = 0; attempt <= maxRetries; attempt++) {\n    try {\n      const response = await fetch(url, {\n        method,\n        headers,\n        body: payload,\n      });\n\n      // Call debug callback if provided\n      if (onDebugReqRes) {\n        try {\n          const responseBody = await response.clone().text();\n          const responseHeaders: Record<string, string> = {};\n          response.headers.forEach((value, key) => {\n            responseHeaders[key] = value;\n          });\n\n          onDebugReqRes({\n            req: {\n              url,\n              method,\n              headers,\n              body: payload,\n            },\n            res: {\n              status: response.status,\n              statusText: response.statusText,\n              headers: responseHeaders,\n              body: responseBody,\n            },\n          });\n        } catch (debugError) {\n          // Don't let debug callback errors break the main flow\n          if (onError) {\n            onError(new Error(`Debug callback error: ${debugError}`));\n          }\n        }\n      }\n\n      // Handle rate limiting\n      if (response.status === 429 && respectRateLimit) {\n        const retryAfter = response.headers.get(\"retry-after\");\n        const waitTime = retryAfter ? Number.parseInt(retryAfter, 10) * 1000 : retryDelay;\n\n        throw new RateLimitError(`Rate limit exceeded. Retry after ${waitTime}ms`, waitTime);\n      }\n\n      // Check for non-2xx status codes and log if onError is enabled\n      if (response.status < 200 || response.status >= 300) {\n        if (onError) {\n          onError(new Error(`HTTP request failed with status ${response.status}: ${response.statusText}`));\n        }\n      }\n\n      // Handle other errors\n      if (!response.ok) {\n        throw new HttpTransportError(`HTTP ${response.status}: ${response.statusText}`, response.status, response);\n      }\n\n      return response;\n    } catch (error) {\n      lastError = error as Error;\n\n      // If it's a rate limit error and we should respect it, wait and retry\n      if (error instanceof RateLimitError && respectRateLimit) {\n        await new Promise((resolve) => setTimeout(resolve, error.retryAfter));\n        continue;\n      }\n\n      // If it's the last attempt, throw the error\n      if (attempt === maxRetries) {\n        throw error;\n      }\n\n      // Wait before retrying with exponential backoff\n      const waitTime = retryDelay * 2 ** attempt;\n      await new Promise((resolve) => setTimeout(resolve, waitTime));\n    }\n  }\n\n  throw lastError!;\n}\n","import type { LoggerlessTransportConfig, LogLayerTransportParams } from \"@loglayer/transport\";\nimport { LoggerlessTransport } from \"@loglayer/transport\";\nimport { LogSizeError } from \"./errors.js\";\nimport { compressData, sendWithRetry } from \"./utils.js\";\n\n/**\n * Parameters passed to the `payloadTemplate` function.\n * Extends `LogLayerTransportParams` with a convenience `message` field\n * (the `messages` array joined with a space).\n */\nexport type HttpPayloadTemplateParams = LogLayerTransportParams & {\n  /** Convenience: messages joined with a space */\n  message: string;\n};\n\n/**\n * Configuration options for the HTTP transport.\n */\nexport interface HttpTransportConfig extends LoggerlessTransportConfig {\n  /**\n   * The URL to send logs to\n   */\n  url: string;\n  /**\n   * HTTP method to use for requests\n   * @default \"POST\"\n   */\n  method?: string;\n  /**\n   * Headers to include in the request. Can be an object or a function that returns headers.\n   */\n  headers?: Record<string, string> | (() => Record<string, string>);\n  /**\n   * Content type for single log requests. User-specified headers take precedence.\n   * @default \"application/json\"\n   */\n  contentType?: string;\n  /**\n   * Content type for batch log requests. User-specified headers take precedence.\n   * @default \"application/json\"\n   */\n  batchContentType?: string;\n  /**\n   * Optional callback for error handling\n   */\n  onError?: (err: Error) => void;\n  /**\n   * Optional callback for debugging log entries before they are sent\n   */\n  onDebug?: (entry: Record<string, any>) => void;\n  /**\n   * Optional callback for debugging HTTP requests and responses\n   */\n  onDebugReqRes?: (reqRes: {\n    req: { url: string; method: string; headers: Record<string, string>; body: string | Uint8Array };\n    res: { status: number; statusText: string; headers: Record<string, string>; body: string };\n  }) => void;\n  /**\n   * Function to transform log data into the payload format.\n   * Receives all `LogLayerTransportParams` fields plus a convenience `message`\n   * string (the `messages` array joined with a space).\n   */\n  payloadTemplate: (params: HttpPayloadTemplateParams) => string;\n  /**\n   * Whether to use gzip compression\n   * @default false\n   */\n  compression?: boolean;\n  /**\n   * Number of retry attempts before giving up\n   * @default 3\n   */\n  maxRetries?: number;\n  /**\n   * Base delay between retries in milliseconds\n   * @default 1000\n   */\n  retryDelay?: number;\n  /**\n   * Whether to respect rate limiting by waiting when a 429 response is received\n   * @default true\n   */\n  respectRateLimit?: boolean;\n  /**\n   * Whether to enable batch sending\n   * @default true\n   */\n  enableBatchSend?: boolean;\n  /**\n   * Number of log entries to batch before sending\n   * @default 100\n   */\n  batchSize?: number;\n  /**\n   * Timeout in milliseconds for sending batches regardless of size\n   * @default 5000\n   */\n  batchSendTimeout?: number;\n  /**\n   * Delimiter to use between log entries in batch mode\n   * @default \"\\n\"\n   */\n  batchSendDelimiter?: string;\n  /**\n   * Batch mode for sending multiple log entries\n   * - \"delimiter\": Join entries with a delimiter (default)\n   * - \"field\": Wrap entries in an object with a field name\n   * - \"array\": Send entries as a plain JSON array\n   * @default \"delimiter\"\n   */\n  batchMode?: \"delimiter\" | \"field\" | \"array\";\n  /**\n   * Field name to wrap batch entries in when batchMode is \"field\" (e.g., \"batch\" for Logflare)\n   * @default undefined\n   */\n  batchFieldName?: string;\n  /**\n   * Maximum size of a single log entry in bytes\n   * @default 1048576 (1MB)\n   */\n  maxLogSize?: number;\n  /**\n   * Maximum size of the payload (uncompressed) in bytes\n   * @default 5242880 (5MB)\n   */\n  maxPayloadSize?: number;\n  /**\n   * Whether to enable Next.js Edge Runtime compatibility mode\n   * When enabled, TextEncoder and compression are disabled\n   * @default false\n   */\n  enableNextJsEdgeCompat?: boolean;\n}\n\n/**\n * HttpTransport is responsible for sending logs to any HTTP endpoint.\n * It supports batching, compression, retries, and rate limiting.\n *\n * Features:\n * - Configurable HTTP method and headers\n * - Custom payload template function\n * - Gzip compression support\n * - Retry logic with exponential backoff\n * - Rate limiting support\n * - Batch sending with configurable size and timeout\n * - Error and debug callbacks\n * - Log size validation\n * - Payload size tracking for batching\n */\nexport class HttpTransport extends LoggerlessTransport {\n  private url: string;\n  private method: string;\n  private headers: Record<string, string> | (() => Record<string, string>);\n  private contentType: string;\n  private batchContentType: string;\n  private onError?: (err: Error) => void;\n  private onDebug?: (entry: Record<string, any>) => void;\n  private onDebugReqRes?: (reqRes: {\n    req: { url: string; method: string; headers: Record<string, string>; body: string | Uint8Array };\n    res: { status: number; statusText: string; headers: Record<string, string>; body: string };\n  }) => void;\n  private payloadTemplate: (params: HttpPayloadTemplateParams) => string;\n  private compression: boolean;\n  private maxRetries: number;\n  private retryDelay: number;\n  private respectRateLimit: boolean;\n  private enableBatchSend: boolean;\n  private batchSize: number;\n  private batchSendTimeout: number;\n  private batchSendDelimiter: string;\n  private batchMode: \"delimiter\" | \"field\" | \"array\";\n  private batchFieldName?: string;\n  private maxLogSize: number;\n  private maxPayloadSize: number;\n  private enableNextJsEdgeCompat: boolean;\n\n  // Batch management\n  private batchQueue: string[] = [];\n  private batchTimeout?: NodeJS.Timeout;\n  private isProcessingBatch = false;\n  private currentBatchSize = 0; // Track uncompressed size of current batch\n\n  /**\n   * Creates a new instance of HttpTransport.\n   *\n   * @param config - Configuration options for the transport\n   */\n  constructor(config: HttpTransportConfig) {\n    super(config);\n\n    this.url = config.url;\n    this.method = config.method ?? \"POST\";\n    this.headers = config.headers ?? {};\n    this.contentType = config.contentType ?? \"application/json\";\n    this.batchContentType = config.batchContentType ?? \"application/json\";\n    this.onError = config.onError;\n    this.onDebug = config.onDebug;\n    this.onDebugReqRes = config.onDebugReqRes;\n    this.payloadTemplate = config.payloadTemplate;\n    this.compression = config.compression ?? false;\n    this.maxRetries = config.maxRetries ?? 3;\n    this.retryDelay = config.retryDelay ?? 1000;\n    this.respectRateLimit = config.respectRateLimit ?? true;\n    this.enableBatchSend = config.enableBatchSend ?? true;\n    this.batchSize = config.batchSize ?? 100;\n    this.batchSendTimeout = config.batchSendTimeout ?? 5000;\n    this.batchSendDelimiter = config.batchSendDelimiter ?? \"\\n\";\n    this.batchMode = config.batchMode ?? \"delimiter\";\n    this.batchFieldName = config.batchFieldName;\n\n    // Validate that batchFieldName is provided when batchMode is \"field\"\n    if (this.batchMode === \"field\" && !this.batchFieldName) {\n      throw new Error(\"batchFieldName is required when batchMode is 'field'\");\n    }\n    this.maxLogSize = config.maxLogSize ?? 1048576; // 1MB\n    this.maxPayloadSize = config.maxPayloadSize ?? 5242880; // 5MB\n    this.enableNextJsEdgeCompat = config.enableNextJsEdgeCompat ?? false;\n  }\n\n  /**\n   * Processes and ships log entries to the HTTP endpoint.\n   *\n   * @param params - Log parameters including level, messages, and metadata\n   * @returns The original messages array\n   */\n  shipToLogger(params: LogLayerTransportParams): any[] {\n    const { messages } = params;\n    try {\n      const message = messages.join(\" \");\n\n      const payload = this.payloadTemplate({ ...params, message });\n\n      if (this.onDebug) {\n        this.onDebug({ logLevel: params.logLevel, message, data: params.data });\n      }\n\n      // Check log entry size\n      let logEntrySize: number;\n\n      if (this.enableNextJsEdgeCompat || typeof TextEncoder === \"undefined\") {\n        // Fallback for environments without TextEncoder (like Next.js Edge Runtime)\n        logEntrySize = Buffer.byteLength(payload, \"utf8\");\n      } else {\n        logEntrySize = new TextEncoder().encode(payload).length;\n      }\n\n      if (logEntrySize > this.maxLogSize) {\n        const sizeError = new LogSizeError(\n          `Log entry exceeds maximum size of ${this.maxLogSize} bytes. Size: ${logEntrySize} bytes`,\n          { logLevel: params.logLevel, message, data: params.data },\n          logEntrySize,\n          this.maxLogSize,\n        );\n\n        if (this.onError) {\n          this.onError(sizeError);\n        }\n        return messages;\n      }\n\n      if (this.enableBatchSend) {\n        this.addToBatch(payload, logEntrySize);\n      } else {\n        // Send immediately\n        this.sendPayload(payload).catch((err) => {\n          if (this.onError) {\n            this.onError(err);\n          }\n        });\n      }\n    } catch (error) {\n      if (this.onError) {\n        this.onError(error as Error);\n      }\n    }\n\n    return messages;\n  }\n\n  /**\n   * Adds a payload to the batch queue and triggers sending if conditions are met\n   */\n  private addToBatch(payload: string, logEntrySize: number): void {\n    // Check if adding this entry would exceed payload size limit\n    const payloadSizeWithEntry = this.currentBatchSize + logEntrySize + this.batchSendDelimiter.length;\n    const payloadSizeThreshold = this.maxPayloadSize * 0.9; // 90% of max payload size\n\n    // Force send if adding this entry would exceed 90% of max payload size\n    if (payloadSizeWithEntry > payloadSizeThreshold && this.batchQueue.length > 0) {\n      this.processBatch();\n    }\n\n    this.batchQueue.push(payload);\n    this.currentBatchSize += logEntrySize + this.batchSendDelimiter.length;\n\n    // Start batch timeout if not already running\n    if (!this.batchTimeout) {\n      this.batchTimeout = setTimeout(() => {\n        this.processBatch();\n      }, this.batchSendTimeout);\n    }\n\n    // Send immediately if batch size is reached\n    if (this.batchQueue.length >= this.batchSize) {\n      this.processBatch();\n    }\n  }\n\n  /**\n   * Processes the current batch and sends it to the HTTP endpoint\n   */\n  private async processBatch(): Promise<void> {\n    if (this.isProcessingBatch || this.batchQueue.length === 0) {\n      return;\n    }\n\n    this.isProcessingBatch = true;\n\n    // Clear the timeout\n    if (this.batchTimeout) {\n      clearTimeout(this.batchTimeout);\n      this.batchTimeout = undefined;\n    }\n\n    // Get the current batch\n    const batch = this.batchQueue.splice(0, this.batchSize);\n\n    // Reset batch size counter\n    this.currentBatchSize = 0;\n\n    try {\n      await this.sendBatch(batch);\n    } catch (error) {\n      if (this.onError) {\n        this.onError(error as Error);\n      }\n    } finally {\n      this.isProcessingBatch = false;\n\n      // If there are more items in the queue, process them\n      if (this.batchQueue.length > 0) {\n        this.processBatch();\n      }\n    }\n  }\n\n  /**\n   * Sends a batch of payloads to the HTTP endpoint\n   */\n  private async sendBatch(batch: string[]): Promise<void> {\n    let batchPayload: string;\n\n    switch (this.batchMode) {\n      case \"array\": {\n        // Send batch entries as a plain JSON array\n        const batchEntries = batch.map((payload) => JSON.parse(payload));\n        batchPayload = JSON.stringify(batchEntries);\n        break;\n      }\n      case \"field\": {\n        // Parse each payload as JSON and create a batch object\n        const fieldEntries = batch.map((payload) => JSON.parse(payload));\n        const batchObject = { [this.batchFieldName!]: fieldEntries };\n        batchPayload = JSON.stringify(batchObject);\n        break;\n      }\n      default:\n        // Use delimiter-based batching (default behavior)\n        batchPayload = batch.join(this.batchSendDelimiter);\n        break;\n    }\n\n    await this.sendPayload(batchPayload, this.batchContentType);\n  }\n\n  /**\n   * Sends a single payload to the HTTP endpoint\n   */\n  private async sendPayload(payload: string, contentType?: string): Promise<void> {\n    // Get headers\n    const headers: Record<string, string> = typeof this.headers === \"function\" ? this.headers() : { ...this.headers };\n\n    // Set content type - user headers take precedence\n    if (!headers[\"content-type\"]) {\n      headers[\"content-type\"] = contentType ?? this.contentType;\n    }\n\n    let finalPayload: string | Uint8Array = payload;\n\n    // Apply compression if enabled and not in Next.js Edge compatibility mode\n    if (this.compression && !this.enableNextJsEdgeCompat) {\n      try {\n        finalPayload = await compressData(payload);\n        headers[\"content-encoding\"] = \"gzip\";\n      } catch (error) {\n        // If compression fails, fall back to uncompressed\n        if (this.onError) {\n          this.onError(new Error(`Compression failed: ${error}`));\n        }\n      }\n    }\n\n    await sendWithRetry(\n      this.url,\n      this.method,\n      headers,\n      finalPayload,\n      this.maxRetries,\n      this.retryDelay,\n      this.respectRateLimit,\n      this.onDebugReqRes,\n      this.onError,\n    );\n  }\n}\n"],"mappings":"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"}