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
JavaScript
;
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