Object.defineProperty(exports, '__esModule', { value: true });
//#region rolldown:runtime
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
	if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
		key = keys[i];
		if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
			get: ((k) => from[k]).bind(null, key),
			enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
		});
	}
	return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
	value: mod,
	enumerable: true
}) : target, mod));

//#endregion
const pino_abstract_transport = __toESM(require("pino-abstract-transport"));
const node_util = __toESM(require("node:util"));

//#region src/debug.ts
var debug_default = (0, node_util.debuglog)("pino-loki");

//#endregion
//#region src/constants.ts
const LokiLogLevel = {
	Info: "info",
	Debug: "debug",
	Error: "error",
	Warning: "warning",
	Critical: "critical"
};

//#endregion
//#region src/get.ts
/**
* Dynamically get a nested value from an array or object with a
* string.
*/
function get(value, path, defaultValue) {
	const segments = path.split(/[.[\]]/g);
	let current = value;
	for (const key of segments) {
		if (current === null) return defaultValue;
		if (current === void 0) return defaultValue;
		const unquotedKey = key.replace(/["']/g, "");
		if (unquotedKey.trim() === "") continue;
		current = current[unquotedKey];
	}
	if (current === void 0) return defaultValue;
	return current;
}

//#endregion
//#region src/format_mesage.ts
function formatLog(options) {
	const { log, logFormat } = options;
	if (logFormat && typeof logFormat === "string") return logFormat.replace(/{([^{}]+)}/g, (_match, p1) => get(log, p1) || "");
	if (logFormat && typeof logFormat === "function") return logFormat(options.log);
	throw new Error("Message format must be a string or a function. Received: " + typeof logFormat);
}

//#endregion
//#region src/log_builder.ts
const NANOSECONDS_LENGTH = 19;
/**
* Converts a Pino log to a Loki log
*/
var LogBuilder = class {
	#propsToLabels;
	#levelMap;
	constructor(options) {
		this.#propsToLabels = options?.propsToLabels || [];
		this.#levelMap = Object.assign({
			10: LokiLogLevel.Debug,
			20: LokiLogLevel.Debug,
			30: LokiLogLevel.Info,
			40: LokiLogLevel.Warning,
			50: LokiLogLevel.Error,
			60: LokiLogLevel.Critical
		}, options?.levelMap);
	}
	/**
	* Builds a timestamp string from a Pino log object.
	* @returns A string representing the timestamp in nanoseconds.
	*/
	#buildTimestamp(log, replaceTimestamp) {
		if (replaceTimestamp) return ((/* @__PURE__ */ new Date()).getTime() * 1e6).toString();
		const time = log.time || Date.now();
		const strTime = time.toString();
		if (strTime.length === NANOSECONDS_LENGTH) return strTime;
		const missingFactor = 10 ** (19 - strTime.length);
		return (time * missingFactor).toString();
	}
	/**
	* Stringify the log object. If convertArrays is true then it will convert
	* arrays to objects with indexes as keys.
	*/
	#stringifyLog(log, convertArrays) {
		return JSON.stringify(log, (_, value) => {
			if (!convertArrays) return value;
			if (Array.isArray(value)) return Object.fromEntries(value.map((value$1, index) => [index, value$1]));
			return value;
		});
	}
	#buildLabelsFromProps(log) {
		const labels = {};
		for (const prop of this.#propsToLabels) if (log[prop]) labels[prop] = log[prop];
		return labels;
	}
	/**
	* Convert a level to a human readable status
	*/
	statusFromLevel(level) {
		return this.#levelMap[level] || LokiLogLevel.Info;
	}
	/**
	* Build a loki log entry from a pino log
	*/
	build(options) {
		const status = this.statusFromLevel(options.log.level);
		const time = this.#buildTimestamp(options.log, options.replaceTimestamp);
		const propsLabels = this.#buildLabelsFromProps(options.log);
		const hostname = options.log.hostname;
		options.log.hostname = void 0;
		const structuredMetadata = options.structuredMetaKey ? options.log[options.structuredMetaKey] : void 0;
		const formattedMessage = options.logFormat ? formatLog({
			logFormat: options.logFormat,
			log: {
				...options.log,
				lokilevel: status
			}
		}) : this.#stringifyLog(options.log, options.convertArrays);
		return {
			stream: {
				level: status,
				hostname,
				...options.additionalLabels,
				...propsLabels
			},
			values: [structuredMetadata ? [
				time,
				formattedMessage,
				structuredMetadata
			] : [time, formattedMessage]]
		};
	}
};

//#endregion
//#region src/log_pusher.ts
var RequestError = class extends Error {
	responseBody;
	constructor(message, responseBody) {
		super(message);
		this.name = "RequestError";
		this.responseBody = responseBody;
	}
};
/**
* Responsible for pushing logs to Loki
*/
var LogPusher = class {
	#options;
	#logBuilder;
	constructor(options) {
		this.#options = options;
		this.#logBuilder = new LogBuilder({
			levelMap: options.levelMap,
			propsToLabels: options.propsToLabels
		});
	}
	/**
	* Handle push failures
	*/
	#handleFailure(err) {
		if (this.#options.silenceErrors === true) return;
		if (err instanceof RequestError) {
			console.error(err.message + "\n" + err.responseBody);
			return;
		}
		console.error("Got unknown error when trying to send log to Loki, error output:", err);
	}
	/**
	* Push one or multiples logs entries to Loki
	*/
	async push(logs) {
		if (!Array.isArray(logs)) logs = [logs];
		const lokiLogs = logs.map((log) => this.#logBuilder.build({
			log,
			replaceTimestamp: this.#options.replaceTimestamp,
			additionalLabels: this.#options.labels,
			convertArrays: this.#options.convertArrays,
			structuredMetaKey: this.#options.structuredMetaKey,
			logFormat: this.#options.logFormat
		}));
		debug_default(`[LogPusher] pushing ${lokiLogs.length} logs to Loki`);
		try {
			const response = await fetch(new URL(this.#options.endpoint ?? "loki/api/v1/push", this.#options.host), {
				method: "POST",
				signal: AbortSignal.timeout(this.#options.timeout ?? 3e4),
				headers: {
					...this.#options.headers,
					...this.#options.basicAuth && { Authorization: "Basic " + Buffer.from(`${this.#options.basicAuth.username}:${this.#options.basicAuth.password}`).toString("base64") },
					"Content-Type": "application/json"
				},
				body: JSON.stringify({ streams: lokiLogs })
			});
			if (!response.ok) throw new RequestError("Got error when trying to send log to loki", await response.text());
		} catch (err) {
			this.#handleFailure(err);
		}
		debug_default(`[LogPusher] pushed ${lokiLogs.length} logs to Loki`, { logs: lokiLogs });
	}
};

//#endregion
//#region src/index.ts
/**
* Resolves the options for the Pino Loki transport
*/
function resolveOptions(options) {
	return {
		...options,
		endpoint: options.endpoint ?? "loki/api/v1/push",
		timeout: options.timeout ?? 3e4,
		silenceErrors: options.silenceErrors ?? false,
		batching: options.batching ?? true,
		interval: options.interval ?? 5,
		replaceTimestamp: options.replaceTimestamp ?? false,
		propsToLabels: options.propsToLabels ?? [],
		convertArrays: options.convertArrays ?? false,
		structuredMetaKey: options.structuredMetaKey,
		logFormat: options.logFormat
	};
}
function pinoLoki(userOptions) {
	const options = resolveOptions(userOptions);
	const logPusher = new LogPusher(options);
	debug_default(`[PinoLoki] initialized with options: ${JSON.stringify(options)}`);
	let batchInterval;
	let pinoLogBuffer = [];
	return (0, pino_abstract_transport.default)(async (source) => {
		if (options.batching) batchInterval = setInterval(async () => {
			debug_default(`Batch interval reached, sending ${pinoLogBuffer.length} logs to Loki`);
			if (pinoLogBuffer.length === 0) return;
			logPusher.push(pinoLogBuffer);
			pinoLogBuffer = [];
		}, options.interval * 1e3);
		for await (const obj of source) {
			if (options.batching) {
				pinoLogBuffer.push(obj);
				continue;
			}
			logPusher.push(obj);
		}
	}, { async close() {
		if (options.batching) {
			clearInterval(batchInterval);
			await logPusher.push(pinoLogBuffer);
		}
	} });
}
var src_default = pinoLoki;

//#endregion
exports.LokiLogLevel = LokiLogLevel;
exports.default = src_default;
exports.pinoLoki = pinoLoki;