"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LoggingEmulator = void 0; const types_1 = require("./types"); const constants_1 = require("./constants"); const triple_beam_1 = require("triple-beam"); const WebSocket = require("ws"); const TransportStream = require("winston-transport"); const logger_1 = require("../logger"); const stripAnsi = require("strip-ansi"); class LoggingEmulator { constructor(args) { this.args = args; } start() { this.transport = new WebSocketTransport(); this.transport.start(this.getInfo()); logger_1.logger.add(this.transport); return Promise.resolve(); } connect() { return Promise.resolve(); } async stop() { if (this.transport) { logger_1.logger.remove(this.transport); return this.transport.stop(); } } getInfo() { const host = this.args.host || constants_1.Constants.getDefaultHost(); const port = this.args.port || constants_1.Constants.getDefaultPort(types_1.Emulators.LOGGING); return { name: this.getName(), host, port, }; } getName() { return types_1.Emulators.LOGGING; } } exports.LoggingEmulator = LoggingEmulator; LoggingEmulator.LOGGING_EMULATOR_ENV = "FIREBASE_LOGGING_EMULATOR_HOST"; class WebSocketTransport extends TransportStream { constructor(options = {}) { super(options); this.connections = new Set(); this.history = []; this.setMaxListeners(30); } start(options) { this.wss = new WebSocket.Server(options); this.wss.on("connection", (ws) => { this.connections.add(ws); ws.once("close", () => this.connections.delete(ws)); this.history.forEach((bundle) => { ws.send(JSON.stringify(bundle)); }); }); } stop() { return new Promise((resolve, reject) => { if (!this.wss) { return resolve(); } this.wss.close((err) => { if (err) return reject(err); resolve(); }); this.connections.forEach((socket) => socket.terminate()); }); } log(info, next) { setImmediate(() => this.emit("logged", info)); const bundle = { level: info.level, data: {}, timestamp: new Date().getTime(), message: "", }; const splat = [info.message, ...(info[triple_beam_1.SPLAT] || [])] .map((value) => { if (typeof value === "string") { try { bundle.data = Object.assign(Object.assign({}, bundle.data), JSON.parse(value)); return null; } catch (err) { return value; } } else { bundle.data = Object.assign(Object.assign({}, bundle.data), value); } }) .filter((v) => v); bundle.message = splat.join(" "); if (bundle.data && bundle.data.metadata && bundle.data.metadata.level) { bundle.level = bundle.data.metadata.level.toLowerCase(); } else { bundle.level = bundle.level.toLowerCase(); } if (bundle.data && bundle.data.metadata && bundle.data.metadata.message) { bundle.message = bundle.data.metadata.message; } bundle.message = stripAnsi(bundle.message); this.history.push(bundle); this.connections.forEach((ws) => { ws.send(JSON.stringify(bundle)); }); if (next) { next(); } } }