UNPKG

apitally

Version:

Simple API monitoring & analytics for REST APIs built with Express, Fastify, NestJS, AdonisJS, Hono, H3, Elysia, Hapi, and Koa.

158 lines 5.31 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var instance_exports = {}; __export(instance_exports, { getOrCreateInstanceUuid: () => getOrCreateInstanceUuid, validateLockFiles: () => validateLockFiles }); module.exports = __toCommonJS(instance_exports); var import_node_crypto = require("node:crypto"); var import_node_fs = require("node:fs"); var import_node_os = require("node:os"); var import_node_path = require("node:path"); const TEMP_DIR = (0, import_node_path.join)((0, import_node_os.tmpdir)(), "apitally"); const MAX_SLOTS = 100; const MAX_LOCK_AGE_MS = 24 * 60 * 60 * 1e3; const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; function getOrCreateInstanceUuid(clientId, env) { try { (0, import_node_fs.mkdirSync)(TEMP_DIR, { recursive: true }); } catch { return (0, import_node_crypto.randomUUID)(); } const hash = getAppEnvHash(clientId, env); validateLockFiles(hash); for (let slot = 0; slot < MAX_SLOTS; slot++) { const pidFile = (0, import_node_path.join)(TEMP_DIR, `instance_${hash}_${slot}.pid`); const uuidFile = (0, import_node_path.join)(TEMP_DIR, `instance_${hash}_${slot}.uuid`); try { (0, import_node_fs.writeFileSync)(pidFile, String(process.pid), { flag: "wx" }); return getOrCreateUuid(uuidFile); } catch (err) { if (err.code !== "EEXIST") { continue; } } try { const pid = parseInt((0, import_node_fs.readFileSync)(pidFile, "utf-8"), 10); if (pid === process.pid) { return (0, import_node_fs.readFileSync)(uuidFile, "utf-8").trim(); } } catch { } } return (0, import_node_crypto.randomUUID)(); } __name(getOrCreateInstanceUuid, "getOrCreateInstanceUuid"); function getAppEnvHash(clientId, env) { return (0, import_node_crypto.createHash)("sha256").update(`${clientId}:${env}`).digest("hex").slice(0, 8); } __name(getAppEnvHash, "getAppEnvHash"); function getOrCreateUuid(uuidFile) { try { const existingUuid = (0, import_node_fs.readFileSync)(uuidFile, "utf-8").trim(); if (validateUuid(existingUuid)) { return existingUuid; } } catch { } const newUuid = (0, import_node_crypto.randomUUID)(); (0, import_node_fs.writeFileSync)(uuidFile, newUuid); return newUuid; } __name(getOrCreateUuid, "getOrCreateUuid"); function validateUuid(value) { return UUID_REGEX.test(value); } __name(validateUuid, "validateUuid"); function isPidAlive(pid) { try { process.kill(pid, 0); return true; } catch { return false; } } __name(isPidAlive, "isPidAlive"); function deleteFiles(...paths) { for (const path of paths) { try { (0, import_node_fs.unlinkSync)(path); } catch { } } } __name(deleteFiles, "deleteFiles"); function validateLockFiles(appEnvHash) { let files; try { files = (0, import_node_fs.readdirSync)(TEMP_DIR); } catch { return; } const prefix = `instance_${appEnvHash}_`; const uuidFiles = files.filter((f) => f.startsWith(prefix) && f.endsWith(".uuid")).sort(); const pidFiles = files.filter((f) => f.startsWith(prefix) && f.endsWith(".pid")).sort(); const seenUuids = /* @__PURE__ */ new Set(); const now = Date.now(); for (const uuidFileName of uuidFiles) { const uuidFile = (0, import_node_path.join)(TEMP_DIR, uuidFileName); const pidFile = (0, import_node_path.join)(TEMP_DIR, uuidFileName.replace(".uuid", ".pid")); try { const stat = (0, import_node_fs.statSync)(uuidFile); if (now - stat.mtimeMs > MAX_LOCK_AGE_MS) { deleteFiles(uuidFile, pidFile); continue; } const uuid = (0, import_node_fs.readFileSync)(uuidFile, "utf-8").trim(); if (!validateUuid(uuid)) { deleteFiles(uuidFile, pidFile); continue; } if (seenUuids.has(uuid)) { deleteFiles(uuidFile, pidFile); continue; } seenUuids.add(uuid); } catch { } } for (const pidFileName of pidFiles) { const pidFile = (0, import_node_path.join)(TEMP_DIR, pidFileName); try { const pid = parseInt((0, import_node_fs.readFileSync)(pidFile, "utf-8"), 10); if (!isPidAlive(pid)) { deleteFiles(pidFile); } } catch { } } } __name(validateLockFiles, "validateLockFiles"); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { getOrCreateInstanceUuid, validateLockFiles }); //# sourceMappingURL=instance.cjs.map