/** * The command to see the animation: * curl localhost:3000 * * @see https://github.com/alexeyraspopov/picocolors/blob/main/picocolors.js * @see https://github.com/sindresorhus/ansi-escapes/blob/main/index.js * @see https://github.com/sindresorhus/cli-spinners */ import { Readable } from "node:stream"; import { fastify } from "fastify"; //#region Terminal colors / ANSI const ESC = "\u001B["; const CURSOR_PREV_LINE = ESC + "F"; const RESET = "\x1b[0m"; const [BLACK_START, BLACK_END] = ["\x1b[30m", "\x1b[39m"]; const [BG_CYAN_START, BG_CYAN_END] = ["\x1b[46m", "\x1b[49m"]; const COLOR_START = BG_CYAN_START + BLACK_START; const COLOR_END = BLACK_END + BG_CYAN_END; /** {@link https://github.com/sindresorhus/cli-spinners} */ const SPINNER = [ "⢀⠀", "⡀⠀", "⠄⠀", "⢂⠀", "⡂⠀", "⠅⠀", "⢃⠀", "⡃⠀", "⠍⠀", "⢋⠀", "⡋⠀", "⠍⠁", "⢋⠁", "⡋⠁", "⠍⠉", "⠋⠉", "⠋⠉", "⠉⠙", "⠉⠙", "⠉⠩", "⠈⢙", "⠈⡙", "⢈⠩", "⡀⢙", "⠄⡙", "⢂⠩", "⡂⢘", "⠅⡘", "⢃⠨", "⡃⢐", "⠍⡐", "⢋⠠", "⡋⢀", "⠍⡁", "⢋⠁", "⡋⠁", "⠍⠉", "⠋⠉", "⠋⠉", "⠉⠙", "⠉⠙", "⠉⠩", "⠈⢙", "⠈⡙", "⠈⠩", "⠀⢙", "⠀⡙", "⠀⠩", "⠀⢘", "⠀⡘", "⠀⠨", "⠀⢐", "⠀⡐", "⠀⠠", "⠀⢀", "⠀⡀", ]; //#endregion process.on("unhandledRejection", function (err) { throw err; }); process.on("SIGINT", handleExit); process.on("SIGTERM", handleExit); function handleExit() { if (server != null) { server.close(); } } function delay(ms = 80) { return new Promise((r) => setTimeout(r, ms)); } async function animate(stream) { stream.push("\n"); for (let i = 0; i < SPINNER.length; i++) { stream.push(CURSOR_PREV_LINE); stream.push(RESET); stream.push(SPINNER[i]); stream.push(" "); const text = "Animating"; for (const [index, ch] of [...text].entries()) { const j = i % text.length; if (index === j) stream.push(COLOR_START); stream.push(ch); if (index === j) stream.push(COLOR_END); } if (((i / 3) | 0) % 2 === 0) { stream.push("…"); } else { stream.push(" "); } stream.push("\n"); await delay(); } stream.push(CURSOR_PREV_LINE); stream.push("The end! \n\n"); stream.push(null); } const server = fastify({ requestTimeout: Number.MAX_SAFE_INTEGER, logger: { level: "debug", }, }); server.get("/", (__request, reply) => { const stream = new Readable({ read() {}, }); reply.send(stream); animate(stream); return reply; }); server.setNotFoundHandler((__request, reply) => { reply.status(404); reply.send(); }); server.listen({ port: 3000, host: "localhost" }, (error) => { if (error) throw error; server.log.debug(server.printRoutes()); });