@syngrisi/syngrisi
Version:
Syngrisi - Visual Testing Tool
2,024 lines (1,992 loc) • 64.7 kB
JavaScript
"use strict";
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 __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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/server/services/tasks.service.ts
var tasks_service_exports = {};
__export(tasks_service_exports, {
loadTestUser: () => loadTestUser,
screenshots: () => screenshots,
status: () => status,
task_handle_database_consistency: () => task_handle_database_consistency,
task_handle_old_checks: () => task_handle_old_checks,
task_remove_old_logs: () => task_remove_old_logs,
task_test: () => task_test
});
module.exports = __toCommonJS(tasks_service_exports);
// src/server/envConfig.ts
var import_envalid = require("envalid");
var import_crypto = __toESM(require("crypto"));
var import_path = __toESM(require("path"));
var import_dotenv = __toESM(require("dotenv"));
import_dotenv.default.config();
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = "production";
}
var env = (0, import_envalid.cleanEnv)(process.env, {
NODE_ENV: (0, import_envalid.str)({ choices: ["development", "production", "test"] }),
SYNGRISI_DB_URI: (0, import_envalid.str)({ default: "mongodb://127.0.0.1:27017/SyngrisiDb" }),
SYNGRISI_APP_PORT: (0, import_envalid.port)({ default: 3e3 }),
SYNGRISI_IMAGES_PATH: (0, import_envalid.str)({ default: import_path.default.join(process.cwd(), "./.snapshots-images") }),
SYNGRISI_TMP_DIR: (0, import_envalid.str)({ default: import_path.default.join(process.cwd(), ".tmp") }),
SYNGRISI_HTTP_LOG: (0, import_envalid.bool)({ default: false }),
SYNGRISI_COVERAGE: (0, import_envalid.bool)({ default: false }),
SYNGRISI_HOSTNAME: (0, import_envalid.host)({ default: "localhost" }),
SYNGRISI_AUTH: (0, import_envalid.bool)({ default: true }),
SYNGRISI_TEST_MODE: (0, import_envalid.bool)({ default: false }),
SYNGRISI_DISABLE_FIRST_RUN: (0, import_envalid.bool)({ default: false }),
MONGODB_ROOT_USERNAME: (0, import_envalid.str)({ default: "" }),
MONGODB_ROOT_PASSWORD: (0, import_envalid.str)({ default: "" }),
LOGLEVEL: (0, import_envalid.str)({ choices: ["error", "warn", "info", "verbose", "debug", "silly"], default: "debug" }),
SYNGRISI_PAGINATION_SIZE: (0, import_envalid.num)({ default: 50 }),
SYNGRISI_DISABLE_DEV_CORS: (0, import_envalid.bool)({ default: true, devDefault: true }),
SYNGRISI_SESSION_STORE_KEY: (0, import_envalid.str)({ default: import_crypto.default.randomBytes(64).toString("hex") }),
SYNGRISI_LOG_LEVEL: (0, import_envalid.str)({ default: "debug" }),
// trunk features
SYNGRISI_TRUNK_FEATURE_AI_SEVERITY: (0, import_envalid.bool)({ default: false }),
SYNGRISI_AI_KEY: (0, import_envalid.str)({ default: "" }),
OPENAI_API_BASE_URL: (0, import_envalid.str)({ default: "https://api.openai.com/v1" }),
OPENAI_API_KEY: (0, import_envalid.str)({ default: "" })
});
// src/server/services/tasks.service.ts
var import_fs2 = __toESM(require("fs"));
var import_string_table = __toESM(require("string-table"));
// src/server/config.ts
var import_fs = __toESM(require("fs"));
var import_dotenv2 = __toESM(require("dotenv"));
// package.json
var version = "2.2.26-alpha.0";
// src/server/config.ts
var import_crypto2 = __toESM(require("crypto"));
// src/server/data/devices.json
var devices_default = [
{
os: "ios",
os_version: "16",
device: "iPhone 14 Pro Max",
realMobile: true
},
{
os: "ios",
os_version: "16",
device: "iPhone 14 Pro",
realMobile: true
},
{
os: "ios",
os_version: "16",
device: "iPhone 14 Plus",
realMobile: true
},
{
os: "ios",
os_version: "16",
device: "iPhone 14",
realMobile: true
},
{
os: "ios",
os_version: "16",
device: "iPhone 12 Pro Max",
realMobile: true
},
{
os: "ios",
os_version: "16",
device: "iPhone 12 Pro",
realMobile: true
},
{
os: "ios",
os_version: "16",
device: "iPhone 12 Mini",
realMobile: true
},
{
os: "ios",
os_version: "16",
device: "iPhone 11 Pro Max",
realMobile: true
},
{
os: "ios",
os_version: "15",
device: "iPhone XS",
realMobile: true
},
{
os: "ios",
os_version: "15",
device: "iPhone 13 Pro Max",
realMobile: true
},
{
os: "ios",
os_version: "15",
device: "iPhone 13 Pro",
realMobile: true
},
{
os: "ios",
os_version: "15",
device: "iPhone 13 Mini",
realMobile: true
},
{
os: "ios",
os_version: "15",
device: "iPhone 13",
realMobile: true
},
{
os: "ios",
os_version: "15",
device: "iPhone 11 Pro",
realMobile: true
},
{
os: "ios",
os_version: "15",
device: "iPhone 11",
realMobile: true
},
{
os: "ios",
os_version: "14",
device: "iPhone XS",
realMobile: true
},
{
os: "ios",
os_version: "14",
device: "iPhone 12 Pro Max",
realMobile: true
},
{
os: "ios",
os_version: "14",
device: "iPhone 12 Pro",
realMobile: true
},
{
os: "ios",
os_version: "14",
device: "iPhone 12 Mini",
realMobile: true
},
{
os: "ios",
os_version: "14",
device: "iPhone 12",
realMobile: true
},
{
os: "ios",
os_version: "14",
device: "iPhone 11 Pro Max",
realMobile: true
},
{
os: "ios",
os_version: "14",
device: "iPhone 11",
realMobile: true
},
{
os: "ios",
os_version: "13",
device: "iPhone XS",
realMobile: true
},
{
os: "ios",
os_version: "13",
device: "iPhone 11 Pro Max",
realMobile: true
},
{
os: "ios",
os_version: "13",
device: "iPhone 11 Pro",
realMobile: true
},
{
os: "ios",
os_version: "13",
device: "iPhone 11",
realMobile: true
},
{
os: "ios",
os_version: "12",
device: "iPhone XS",
realMobile: true
},
{
os: "ios",
os_version: "12",
device: "iPhone XS Max",
realMobile: true
},
{
os: "ios",
os_version: "15",
device: "iPhone XR",
realMobile: true
},
{
os: "ios",
os_version: "12",
device: "iPhone XR",
realMobile: true
},
{
os: "ios",
os_version: "11",
device: "iPhone X",
realMobile: true
},
{
os: "ios",
os_version: "15",
device: "iPhone 8",
realMobile: true
},
{
os: "ios",
os_version: "13",
device: "iPhone 8",
realMobile: true
},
{
os: "ios",
os_version: "12",
device: "iPhone 8",
realMobile: true
},
{
os: "ios",
os_version: "11",
device: "iPhone 8",
realMobile: true
},
{
os: "ios",
os_version: "12",
device: "iPhone 8 Plus",
realMobile: true
},
{
os: "ios",
os_version: "11",
device: "iPhone 8 Plus",
realMobile: true
},
{
os: "ios",
os_version: "12",
device: "iPhone 7",
realMobile: true
},
{
os: "ios",
os_version: "10",
device: "iPhone 7",
realMobile: true
},
{
os: "ios",
os_version: "12",
device: "iPhone 6S",
realMobile: true
},
{
os: "ios",
os_version: "11",
device: "iPhone 6S",
realMobile: true
},
{
os: "ios",
os_version: "11",
device: "iPhone 6S Plus",
realMobile: true
},
{
os: "ios",
os_version: "11",
device: "iPhone 6",
realMobile: true
},
{
os: "ios",
os_version: "15",
device: "iPhone SE 2022",
realMobile: true
},
{
os: "ios",
os_version: "13",
device: "iPhone SE 2020",
realMobile: true
},
{
os: "ios",
os_version: "11",
device: "iPhone SE",
realMobile: true
},
{
os: "ios",
os_version: "14",
device: "iPad Air 4",
realMobile: true
},
{
os: "ios",
os_version: "15",
device: "iPad 9th",
realMobile: true
},
{
os: "ios",
os_version: "16",
device: "iPad Pro 12.9 2022",
realMobile: true
},
{
os: "ios",
os_version: "16",
device: "iPad Pro 12.9 2020",
realMobile: true
},
{
os: "ios",
os_version: "16",
device: "iPad Pro 11 2022",
realMobile: true
},
{
os: "ios",
os_version: "16",
device: "iPad 10th",
realMobile: true
},
{
os: "ios",
os_version: "15",
device: "iPad Air 5",
realMobile: true
},
{
os: "ios",
os_version: "14",
device: "iPad Pro 12.9 2021",
realMobile: true
},
{
os: "ios",
os_version: "14",
device: "iPad Pro 12.9 2020",
realMobile: true
},
{
os: "ios",
os_version: "14",
device: "iPad Pro 11 2021",
realMobile: true
},
{
os: "ios",
os_version: "13",
device: "iPad Pro 12.9 2020",
realMobile: true
},
{
os: "ios",
os_version: "16",
device: "iPad 8th",
realMobile: true
},
{
os: "ios",
os_version: "15",
device: "iPad Pro 12.9 2018",
realMobile: true
},
{
os: "ios",
os_version: "15",
device: "iPad Mini 2021",
realMobile: true
},
{
os: "ios",
os_version: "14",
device: "iPad 8th",
realMobile: true
},
{
os: "ios",
os_version: "13",
device: "iPad Pro 12.9 2018",
realMobile: true
},
{
os: "ios",
os_version: "13",
device: "iPad Pro 11 2020",
realMobile: true
},
{
os: "ios",
os_version: "13",
device: "iPad Mini 2019",
realMobile: true
},
{
os: "ios",
os_version: "13",
device: "iPad Air 2019",
realMobile: true
},
{
os: "ios",
os_version: "13",
device: "iPad 7th",
realMobile: true
},
{
os: "ios",
os_version: "12",
device: "iPad Pro 12.9 2018",
realMobile: true
},
{
os: "ios",
os_version: "12",
device: "iPad Pro 11 2018",
realMobile: true
},
{
os: "ios",
os_version: "12",
device: "iPad Mini 2019",
realMobile: true
},
{
os: "ios",
os_version: "12",
device: "iPad Air 2019",
realMobile: true
},
{
os: "ios",
os_version: "11",
device: "iPad Pro 9.7 2016",
realMobile: true
},
{
os: "ios",
os_version: "11",
device: "iPad Pro 12.9 2017",
realMobile: true
},
{
os: "ios",
os_version: "11",
device: "iPad Mini 4",
realMobile: true
},
{
os: "ios",
os_version: "11",
device: "iPad 6th",
realMobile: true
},
{
os: "ios",
os_version: "11",
device: "iPad 5th",
realMobile: true
},
{
os: "android",
os_version: "12.0",
device: "Samsung Galaxy S22 Ultra",
realMobile: true
},
{
os: "android",
os_version: "12.0",
device: "Samsung Galaxy S22 Plus",
realMobile: true
},
{
os: "android",
os_version: "12.0",
device: "Samsung Galaxy S22",
realMobile: true
},
{
os: "android",
os_version: "12.0",
device: "Samsung Galaxy S21",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Samsung Galaxy S21 Ultra",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Samsung Galaxy S21",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Samsung Galaxy S21 Plus",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Samsung Galaxy S20",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Samsung Galaxy S20 Plus",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Samsung Galaxy S20 Ultra",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Samsung Galaxy M52",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Samsung Galaxy M32",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Samsung Galaxy A52",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Samsung Galaxy Note 20 Ultra",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Samsung Galaxy Note 20",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Samsung Galaxy A51",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Samsung Galaxy A11",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Samsung Galaxy S9 Plus",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Samsung Galaxy S10e",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Samsung Galaxy S10 Plus",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Samsung Galaxy S10",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Samsung Galaxy Note 10 Plus",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Samsung Galaxy Note 10",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Samsung Galaxy A10",
realMobile: true
},
{
os: "android",
os_version: "8.1",
device: "Samsung Galaxy Note 9",
realMobile: true
},
{
os: "android",
os_version: "8.1",
device: "Samsung Galaxy J7 Prime",
realMobile: true
},
{
os: "android",
os_version: "8.0",
device: "Samsung Galaxy S9 Plus",
realMobile: true
},
{
os: "android",
os_version: "8.0",
device: "Samsung Galaxy S9",
realMobile: true
},
{
os: "android",
os_version: "7.1",
device: "Samsung Galaxy Note 8",
realMobile: true
},
{
os: "android",
os_version: "7.1",
device: "Samsung Galaxy A8",
realMobile: true
},
{
os: "android",
os_version: "7.0",
device: "Samsung Galaxy S8 Plus",
realMobile: true
},
{
os: "android",
os_version: "7.0",
device: "Samsung Galaxy S8",
realMobile: true
},
{
os: "android",
os_version: "6.0",
device: "Samsung Galaxy S7",
realMobile: true
},
{
os: "android",
os_version: "5.0",
device: "Samsung Galaxy S6",
realMobile: true
},
{
os: "android",
os_version: "13.0",
device: "Google Pixel 7 Pro",
realMobile: true
},
{
os: "android",
os_version: "13.0",
device: "Google Pixel 7",
realMobile: true
},
{
os: "android",
os_version: "13.0",
device: "Google Pixel 6 Pro",
realMobile: true
},
{
os: "android",
os_version: "12.0",
device: "Google Pixel 6 Pro",
realMobile: true
},
{
os: "android",
os_version: "12.0",
device: "Google Pixel 6",
realMobile: true
},
{
os: "android",
os_version: "12.0",
device: "Google Pixel 5",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Google Pixel 5",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Google Pixel 4",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Google Pixel 4 XL",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Google Pixel 4",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Google Pixel 3",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Google Pixel 3a XL",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Google Pixel 3a",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Google Pixel 3 XL",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Google Pixel 3",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Google Pixel 2",
realMobile: true
},
{
os: "android",
os_version: "8.0",
device: "Google Pixel 2",
realMobile: true
},
{
os: "android",
os_version: "7.1",
device: "Google Pixel",
realMobile: true
},
{
os: "android",
os_version: "6.0",
device: "Google Nexus 6",
realMobile: true
},
{
os: "android",
os_version: "4.4",
device: "Google Nexus 5",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "OnePlus 9",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "OnePlus 8",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "OnePlus 7T",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "OnePlus 7",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "OnePlus 6T",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Xiaomi Redmi Note 11",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Xiaomi Redmi Note 9",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Xiaomi Redmi Note 8",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Xiaomi Redmi Note 7",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Vivo Y21",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Vivo V21",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Vivo Y50",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Oppo Reno 6",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Oppo A96",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Oppo Reno 3 Pro",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Motorola Moto G71 5G",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Motorola Moto G9 Play",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Motorola Moto G7 Play",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Huawei P30",
realMobile: true
},
{
os: "android",
os_version: "12.0",
device: "Samsung Galaxy Tab S8",
realMobile: true
},
{
os: "android",
os_version: "11.0",
device: "Samsung Galaxy Tab S7",
realMobile: true
},
{
os: "android",
os_version: "10.0",
device: "Samsung Galaxy Tab S7",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Samsung Galaxy Tab S6",
realMobile: true
},
{
os: "android",
os_version: "9.0",
device: "Samsung Galaxy Tab S5e",
realMobile: true
},
{
os: "android",
os_version: "8.1",
device: "Samsung Galaxy Tab S4",
realMobile: true
}
];
// src/server/config.ts
var customDevicesPath = "./server/data/custom_devices.json";
var logsFolder = "./logs";
import_dotenv2.default.config();
var config = {
version,
// this isn't used
getDevices: async () => {
if (import_fs.default.existsSync(customDevicesPath)) {
return [...devices_default, ...(await import(customDevicesPath)).default];
}
return devices_default;
},
defaultImagesPath: env.SYNGRISI_IMAGES_PATH,
connectionString: env.SYNGRISI_DB_URI || "mongodb://127.0.0.1:27017/SyngrisiDb",
host: env.SYNGRISI_HOSTNAME,
port: env.SYNGRISI_APP_PORT || 3e3,
backupsFolder: "./backups",
enableHttpLogger: env.SYNGRISI_HTTP_LOG,
httpLoggerFilePath: `${logsFolder}/http.log`,
storeSessionKey: env.SYNGRISI_SESSION_STORE_KEY || import_crypto2.default.randomBytes(64).toString("hex"),
codeCoverage: env.SYNGRISI_COVERAGE,
disableCors: env.SYNGRISI_DISABLE_DEV_CORS,
fileUploadMaxSize: 50 * 1024 * 1024,
testMode: env.SYNGRISI_TEST_MODE,
jsonLimit: "50mb",
tmpDir: env.SYNGRISI_TMP_DIR,
helmet: {
crossOriginEmbedderPolicy: false,
crossOriginResourcePolicy: false,
crossOriginOpenerPolicy: false,
contentSecurityPolicy: {
directives: {
// frameAncestors: ["'self'", "vscode-webview:", "vscode-resource:", "https:", "http:"],
// frameSrc: ["'self'", "vscode-webview:", "https:", "http:"],
// scriptSrc: ["'self'", "'unsafe-inline'"],
// styleSrc: ["'self'", "'unsafe-inline'"]
defaultSrc: ["'self'", "*", "'unsafe-inline'", "'unsafe-eval'", "data:", "blob:"],
frameAncestors: ["'self'", "*"],
frameSrc: ["'self'", "*"],
scriptSrc: ["'self'", "*", "'unsafe-inline'", "'unsafe-eval'"],
styleSrc: ["'self'", "*", "'unsafe-inline'"],
imgSrc: ["'self'", "*", "data:", "blob:"],
fontSrc: ["'self'", "*", "data:"],
connectSrc: ["'self'", "*"]
}
}
}
};
if (!import_fs.default.existsSync(config.defaultImagesPath)) {
import_fs.default.mkdirSync(config.defaultImagesPath, { recursive: true });
}
if (!import_fs.default.existsSync(logsFolder)) {
import_fs.default.mkdirSync(logsFolder, { recursive: true });
}
// src/server/utils/dateToISO8601.ts
var dateToISO8601 = (date) => {
return new Date(new Date(date)).toISOString().split("T")[0];
};
var dateToISO8601_default = dateToISO8601;
// src/server/utils/ProgressBar.ts
var ProgressBar = class {
constructor(length) {
this.length = length;
this.percentLenght = parseFloat((length / 100).toString());
this.prevPercent = 0;
this.currentPercent = 0;
this.progressString = "";
}
isChange(current) {
this.currentPercent = parseInt((current / this.percentLenght).toString(), 10);
if (this.prevPercent === this.currentPercent) {
return false;
}
this.prevPercent = this.currentPercent;
this.progressString += "#";
return true;
}
writeIfChange(index, count, fn, res) {
if (this.isChange(index)) {
const placeholderString = Array.from(new Array(99 - this.currentPercent)).reduce((accum) => accum += ".", "");
fn(`[${this.progressString}${placeholderString}](${index}/${count})`, res);
}
}
};
// src/server/utils/ApiError.ts
var ApiError = class extends Error {
constructor(statusCode, message, isOperational = true, stack = "") {
super(message);
this.statusCode = statusCode;
this.isOperational = isOperational;
if (stack) {
this.stack = stack;
} else {
Error.captureStackTrace(this, this.constructor);
}
}
};
var ApiError_default = ApiError;
// src/server/utils/deserializeIfJSON.ts
var import_bson = require("bson");
// src/server/models/Check.model.ts
var import_mongoose = __toESM(require("mongoose"));
// src/server/models/plugins/paginate.plugin.ts
var paginate = (schema) => {
schema.statics.paginate = async function(filter, options) {
let sort;
if (options.sortBy) {
const sortingCriteria = [];
options.sortBy.split(",").forEach((sortOption) => {
const [key, order] = sortOption.split(":");
sortingCriteria.push((order === "desc" ? "-" : "") + key);
});
sort = sortingCriteria.join(" ");
} else {
sort = { _id: -1 };
}
const limit = options.limit && parseInt(options.limit.toString(), 10) >= 0 ? parseInt(options.limit.toString(), 10) : 10;
const page = options.page && parseInt(options.page.toString(), 10) > 0 ? parseInt(options.page.toString(), 10) : 1;
const skip = (page - 1) * limit;
const countPromise = this.countDocuments(filter).exec();
let docsPromise = this.find(filter).sort(sort).skip(skip).limit(limit);
if (options.populate) {
options.populate.split(",").forEach((populateOption) => {
docsPromise = docsPromise.populate(
populateOption.split(".").reverse().reduce((a, b) => ({ path: b, populate: a }))
);
});
}
docsPromise = docsPromise.exec();
return Promise.all([countPromise, docsPromise]).then((values) => {
const [totalResults, results] = values;
const totalPages = Math.ceil(totalResults / limit);
const result = {
results,
page,
limit,
totalPages,
totalResults,
timestamp: Number(Date.now() + String(process.hrtime()[1]).slice(3, 6))
};
return Promise.resolve(result);
});
};
};
var paginate_plugin_default = paginate;
// src/server/models/plugins/toJSON.plugin.ts
var deleteAtPath = (obj, path4, index) => {
if (index === path4.length - 1) {
delete obj[path4[index]];
return;
}
deleteAtPath(obj[path4[index]], path4, index + 1);
};
var toJSON = (schema) => {
let transform;
if (schema.options.toJSON && schema.options.toJSON.transform) {
transform = schema.options.toJSON.transform;
}
schema.options.toJSON = Object.assign(schema.options.toJSON || {}, {
transform(doc, ret, options) {
Object.keys(schema.paths).forEach((path4) => {
if (schema.paths[path4].options && schema.paths[path4].options.private) {
deleteAtPath(ret, path4.split("."), 0);
}
});
ret.id = ret._id.toString();
delete ret.__v;
delete ret.createdAt;
delete ret.updatedAt;
if (transform) {
return transform(doc, ret, options);
}
}
});
};
var toJSON_plugin_default = toJSON;
// src/server/models/plugins/paginateDistinct.plugin.ts
var import_bson2 = require("bson");
var paginateDistinct = (schema) => {
schema.statics.paginateDistinct = async function(filter, options) {
let sort;
if (options.sortBy) {
options.sortBy.split(",").forEach((sortOption) => {
const [key, order] = sortOption.split(":");
sort[key] = order === "desc" ? -1 : 1;
});
} else {
sort = { _id: -1 };
}
let limit = options.limit && parseInt(options.limit.toString(), 10) >= 0 ? parseInt(options.limit.toString(), 10) : 10;
limit = limit === 0 ? 9007199254740991 : limit;
const page = options.page && parseInt(options.page.toString(), 10) > 0 ? parseInt(options.page.toString(), 10) : 1;
const skip = (page - 1) * limit;
const groupAggregateObj = { $group: { _id: `$${options.field}` } };
const documentsCount = (await this.aggregate([groupAggregateObj]).exec()).length;
const aggregateArr = [
{ $match: import_bson2.EJSON.parse(filter.filter || "{}") },
groupAggregateObj,
{ $sort: sort },
{ $skip: skip },
{ $limit: limit }
];
const aggregatedDocs = (await this.aggregate(aggregateArr)).filter((x) => x._id).map((x) => {
if (x[options.field]) {
return x[options.field][0];
}
return { name: x._id };
});
return Promise.all([documentsCount, aggregatedDocs]).then((values) => {
const [totalResults, results] = values;
const totalPages = Math.ceil(totalResults / limit);
const result = {
results,
page,
limit,
totalPages,
totalResults,
timestamp: (/* @__PURE__ */ new Date()).getTime()
};
return Promise.resolve(result);
});
};
};
var paginateDistinct_plugin_default = paginateDistinct;
// src/server/models/Check.model.ts
var CheckSchema = new import_mongoose.Schema({
name: {
type: String,
required: [true, 'CheckSchema: The "name" field must be required']
},
test: {
type: import_mongoose.Schema.Types.ObjectId,
ref: "VRSTest",
required: [true, 'CheckSchema: The "test" field must be required']
},
suite: {
type: import_mongoose.Schema.Types.ObjectId,
ref: "VRSSuite",
required: [true, 'CheckSchema: The "suite" field must be required']
},
app: {
type: import_mongoose.Schema.Types.ObjectId,
ref: "VRSApp",
required: [true, 'CheckSchema: The "app" field must be required']
},
branch: {
type: String
},
realBaselineId: {
type: import_mongoose.Schema.Types.ObjectId,
ref: "VRSBaseline"
},
baselineId: {
type: import_mongoose.Schema.Types.ObjectId,
ref: "VRSSnapshot"
},
actualSnapshotId: {
type: import_mongoose.Schema.Types.ObjectId,
ref: "VRSSnapshot"
},
diffId: {
type: import_mongoose.Schema.Types.ObjectId,
ref: "VRSSnapshot"
},
createdDate: {
type: Date,
required: true,
default: Date.now
},
updatedDate: {
type: Date
},
status: {
type: [{
type: String,
enum: {
values: ["new", "pending", "approved", "running", "passed", "failed", "aborted"],
message: "status is required"
}
}],
default: ["new"]
},
browserName: {
type: String
},
browserVersion: {
type: String
},
browserFullVersion: {
type: String
},
viewport: {
type: String
},
os: {
type: String
},
domDump: {
type: String
},
result: {
type: String,
default: "{}"
},
run: {
type: import_mongoose.Schema.Types.ObjectId
},
markedAs: {
type: String,
enum: ["bug", "accepted"]
},
markedDate: {
type: Date
},
markedById: {
type: import_mongoose.Schema.Types.ObjectId,
ref: "VRSUser"
},
markedByUsername: {
type: String
},
markedBugComment: {
type: String
},
creatorId: {
type: import_mongoose.Schema.Types.ObjectId,
ref: "VRSUser"
},
creatorUsername: {
type: String
},
failReasons: {
type: [String]
},
vOffset: {
type: String
},
topStablePixels: {
type: String
},
meta: {
type: Object
}
});
CheckSchema.plugin(toJSON_plugin_default);
CheckSchema.plugin(paginate_plugin_default);
var Check = import_mongoose.default.model("VRSCheck", CheckSchema);
var Check_model_default = Check;
// src/server/models/Log.model.ts
var import_mongoose2 = __toESM(require("mongoose"));
var LogSchema = new import_mongoose2.Schema({
timestamp: {
type: Date
},
level: {
type: String
},
message: {
type: String
},
meta: {
type: Object
},
hostname: {
type: Object
}
});
LogSchema.plugin(toJSON_plugin_default);
LogSchema.plugin(paginate_plugin_default);
var Log = import_mongoose2.default.model("VRSLog", LogSchema);
var Log_model_default = Log;
// src/server/models/App.model.ts
var import_mongoose3 = __toESM(require("mongoose"));
var AppSchema = new import_mongoose3.Schema({
name: {
type: String,
default: "Others",
unique: true,
required: [true, 'AppSchema: The "name" field must be required']
},
description: {
type: String
},
version: {
type: String
},
updatedDate: {
type: Date
},
createdDate: {
type: Date
},
meta: {
type: Object
}
});
AppSchema.plugin(paginate_plugin_default);
AppSchema.plugin(toJSON_plugin_default);
var App = import_mongoose3.default.model("VRSApp", AppSchema);
// src/server/models/Snapshot.model.ts
var import_mongoose4 = __toESM(require("mongoose"));
var SnapshotSchema = new import_mongoose4.Schema({
name: {
type: String,
required: [true, 'SnapshotSchema: The "name" field must be required']
},
path: {
type: String
},
filename: {
type: String
},
imghash: {
type: String,
required: [true, 'SnapshotSchema: The "imghash" field must be required']
},
createdDate: {
type: Date,
default: Date.now
},
vOffset: {
type: Number
},
hOffset: {
type: Number
}
});
SnapshotSchema.plugin(toJSON_plugin_default);
SnapshotSchema.plugin(paginate_plugin_default);
var Snapshot = import_mongoose4.default.model("VRSSnapshot", SnapshotSchema);
var Snapshot_model_default = Snapshot;
// src/server/models/AppSettings.model.ts
var import_mongoose5 = __toESM(require("mongoose"));
var AppSettingsSchema = new import_mongoose5.Schema({
name: {
type: String,
unique: true,
required: [true, 'AppSettingsSchema: The "name" field must be required']
},
label: {
type: String,
required: [true, 'AppSettingsSchema: The "label" field must be required']
},
description: {
type: String
},
type: {
type: String,
required: [true, 'AppSettingsSchema: The "type" field must be required']
},
value: {
type: import_mongoose5.Schema.Types.Mixed,
required: [true, 'AppSettingsSchema: The "value" field must be required']
},
env_variable: {
type: String
},
enabled: {
type: Boolean
}
});
AppSettingsSchema.plugin(toJSON_plugin_default);
var AppSettings = import_mongoose5.default.model("VRSAppSettings", AppSettingsSchema);
// src/server/models/Suite.model.ts
var import_mongoose6 = __toESM(require("mongoose"));
var SuiteSchema = new import_mongoose6.Schema({
name: {
type: String,
default: "Others",
unique: true,
required: [true, 'SuiteSchema: The "name" field must be required']
},
tags: {
type: [String]
},
app: {
type: import_mongoose6.Schema.Types.ObjectId,
ref: "VRSApp",
required: [true, 'SuiteSchema: The "app" field must be required']
},
description: {
type: String
},
updatedDate: {
type: Date,
default: Date.now
},
createdDate: {
type: Date
},
meta: {
type: Object
}
});
SuiteSchema.plugin(paginate_plugin_default);
SuiteSchema.plugin(toJSON_plugin_default);
var Suite = import_mongoose6.default.model("VRSSuite", SuiteSchema);
var Suite_model_default = Suite;
// src/server/models/Run.model.ts
var import_mongoose7 = __toESM(require("mongoose"));
var RunSchema = new import_mongoose7.Schema({
name: {
type: String,
required: [true, 'RunSchema: The "name" field must be required']
},
app: {
type: import_mongoose7.Schema.Types.ObjectId,
ref: "VRSApp",
required: [true, 'RunSchema: The "app" field must be required']
},
ident: {
type: String,
unique: true,
required: [true, 'RunSchema: The "ident" field must be required']
},
description: {
type: String
},
updatedDate: {
type: Date,
default: Date.now
},
createdDate: {
type: Date
},
parameters: {
type: [String]
},
meta: {
type: Object
}
});
RunSchema.plugin(paginate_plugin_default);
RunSchema.plugin(toJSON_plugin_default);
var Run = import_mongoose7.default.model("VRSRun", RunSchema);
var Run_model_default = Run;
// src/server/models/User.model.ts
var import_mongoose8 = __toESM(require("mongoose"));
var import_passport_local_mongoose = __toESM(require("passport-local-mongoose"));
var UserSchema = new import_mongoose8.Schema({
username: {
type: String,
unique: true,
required: [true, 'UserSchema: The "username" field must be required']
},
firstName: {
type: String,
required: [true, 'UserSchema: The "firstName" field must be required']
},
lastName: {
type: String,
required: [true, 'UserSchema: The "lastName" field must be required']
},
role: {
type: String,
enum: ["admin", "reviewer", "user"],
required: [true, 'UserSchema: The "role" field must be required']
},
password: {
type: String
},
token: {
type: String
},
apiKey: {
type: String
},
createdDate: {
type: Date
},
updatedDate: {
type: Date
},
expiration: {
type: Date
},
meta: {
type: Object
}
});
UserSchema.statics.isEmailTaken = async function(username, excludeUserId) {
const user = await this.findOne({ username, _id: { $ne: excludeUserId } });
return !!user;
};
UserSchema.plugin(toJSON_plugin_default);
UserSchema.plugin(paginate_plugin_default);
UserSchema.plugin(import_passport_local_mongoose.default, { hashField: "password" });
var User = import_mongoose8.default.model("VRSUser", UserSchema);
var User_model_default = User;
// src/server/models/Baseline.model.ts
var import_mongoose9 = __toESM(require("mongoose"));
var BaselineSchema = new import_mongoose9.Schema({
snapshootId: {
type: import_mongoose9.Schema.Types.ObjectId
},
name: {
type: String,
required: [true, 'VRSBaselineSchema: The "name" field must be required']
},
app: {
type: import_mongoose9.Schema.Types.ObjectId,
ref: "VRSApp",
required: [true, 'VRSBaselineSchema: The "app" field must be required']
},
branch: {
type: String
},
browserName: {
type: String
},
browserVersion: {
type: String
},
browserFullVersion: {
type: String
},
viewport: {
type: String
},
os: {
type: String
},
markedAs: {
type: String,
enum: ["bug", "accepted"]
},
lastMarkedDate: {
type: Date
},
createdDate: {
type: Date
},
updatedDate: {
type: Date
},
markedById: {
type: import_mongoose9.Schema.Types.ObjectId,
ref: "VRSUser"
},
markedByUsername: {
type: String
},
ignoreRegions: {
type: String
},
boundRegions: {
type: String
},
matchType: {
type: String,
enum: ["antialiasing", "nothing", "colors"]
},
meta: {
type: Object
}
});
BaselineSchema.plugin(toJSON_plugin_default);
BaselineSchema.plugin(paginate_plugin_default);
var Baseline = import_mongoose9.default.model("VRSBaseline", BaselineSchema);
var Baseline_model_default = Baseline;
// src/server/models/Test.model.ts
var import_mongoose10 = __toESM(require("mongoose"));
var TestSchema = new import_mongoose10.Schema(
{
name: {
type: String,
required: "TestSchema: the test name is empty"
},
description: {
type: String
},
status: {
type: String
},
browserName: {
type: String
},
browserVersion: {
type: String
},
branch: {
type: String
},
tags: {
type: [String]
},
viewport: {
type: String
},
calculatedViewport: {
type: String
},
os: {
type: String
},
app: {
type: import_mongoose10.Schema.Types.ObjectId,
ref: "VRSApp",
required: [true, 'TestSchema: The "app" field must be required']
},
blinking: {
type: Number,
default: 0
},
updatedDate: {
type: Date
},
startDate: {
type: Date
},
checks: [
{
type: import_mongoose10.default.Schema.Types.ObjectId,
ref: "VRSCheck"
}
],
suite: {
type: import_mongoose10.Schema.Types.ObjectId,
ref: "VRSSuite"
},
run: {
type: import_mongoose10.Schema.Types.ObjectId,
ref: "VRSRun"
},
markedAs: {
type: String,
enum: ["Bug", "Accepted", "Unaccepted", "Partially"]
},
creatorId: {
type: import_mongoose10.Schema.Types.ObjectId,
ref: "VRSUser"
},
creatorUsername: {
type: String
},
meta: {
type: Object
}
},
{ strictQuery: true }
);
TestSchema.plugin(toJSON_plugin_default);
TestSchema.plugin(paginate_plugin_default);
TestSchema.plugin(paginateDistinct_plugin_default);
var Test = import_mongoose10.default.model("VRSTest", TestSchema);
var Test_model_default = Test;
// src/server/utils/subDays.ts
var subDays = (date, days) => {
const result = new Date(date);
result.setDate(result.getDate() - days);
return result;
};
var subDays_default = subDays;
// src/server/lib/logger.ts
var import_winston = __toESM(require("winston"));
var import_winston_mongodb = require("winston-mongodb");
var import_chalk = require("chalk");
// src/server/utils/formatISOToDateTime.ts
function formatISOToDateTime(isoDateString) {
const date = new Date(isoDateString);
return `${date.toISOString().slice(0, 10)} ${date.toTimeString().slice(0, 8)}`;
}
var formatISOToDateTime_default = formatISOToDateTime;
// src/server/lib/logger.ts
var import_path2 = __toESM(require("path"));
var logLevel = env.SYNGRISI_LOG_LEVEL;
function getScriptLine() {
const stack = new Error().stack;
if (stack) {
const stackLines = stack.split("\n");
let loggerLineIndex = -1;
for (let i = 0; i < stackLines.length; i++) {
if (stackLines[i].includes("lib/logger")) {
loggerLineIndex = i;
}
}
const targetLineIndex = loggerLineIndex + 1;
if (targetLineIndex >= 0 && targetLineIndex < stackLines.length) {
const targetLine = stackLines[targetLineIndex];
const match = targetLine.match(/at\s+(?:.+\s+\()?(.+):(\d+):(\d+)\)?/);
if (match) {
const scriptPath = match[1];
const relativePath = import_path2.default.relative(process.cwd(), scriptPath);
const lineNumber = match[2];
return `${relativePath}:${lineNumber}`;
}
}
}
return "unknown";
}
function createWinstonLogger(opts) {
return import_winston.default.createLogger({
transports: [
new import_winston.default.transports.Console({
level: logLevel || "silly",
format: import_winston.default.format.combine(
import_winston.default.format.colorize(),
import_winston.default.format.timestamp(),
import_winston.default.format.ms(),
import_winston.default.format.metadata(),
import_winston.default.format.printf((info) => {
const user = info.metadata.user ? (0, import_chalk.blue)(` <${info.metadata.user}>`) : "";
const ref = info.metadata.ref ? (0, import_chalk.gray)(` ${info.metadata.ref}`) : "";
const msgType = info.metadata.msgType ? ` ${info.metadata.msgType}` : "";
const itemType = info.metadata.itemType ? (0, import_chalk.magenta)(` ${info.metadata.itemType}`) : "";
const scope = info.metadata.scope ? (0, import_chalk.magenta)(` [${info.metadata.scope}] `) : (0, import_chalk.magenta)(` [${getScriptLine()}] `);
const msg = typeof info.message === "object" ? `
${JSON.stringify(info.message, null, 2)}` : info.message;
return `${info.level} ${scope}${formatISOToDateTime_default(info.metadata.timestamp)} ${info.metadata.ms}${user}${ref}${msgType}${itemType} '${msg}'`;
}),
import_winston.default.format.padLevels()
)
}),
new import_winston.default.transports.MongoDB({
level: logLevel || "debug",
format: import_winston.default.format.combine(
import_winston.default.format.timestamp(),
import_winston.default.format.json(),
import_winston.default.format.metadata()
),
options: {
useUnifiedTopology: true
},
db: opts.dbConnectionString,
collection: "vrslogs"
})
]
});
}
var Logger = class _Logger {
constructor(opts = { dbConnectionString: config.connectionString }) {
this.winstonLogger = createWinstonLogger(opts);
}
static mergeMeta(objects) {
return objects.reduce((acc, obj) => {
return { ...acc, ...obj };
}, {});
}
log(severity, msg, meta) {
const mergedMeta = _Logger.mergeMeta(meta);
if (!mergedMeta.scope) {
mergedMeta.scope = getScriptLine();
}
const formattedMsg = typeof msg === "object" ? JSON.stringify(msg, null, 2) : msg;
this.winstonLogger.log(severity, formattedMsg, mergedMeta);
}
error(msg, ...meta) {
let message = String(msg);
let code = 0;
if (msg instanceof Object) {
message = JSON.stringify(msg);
}
if (msg instanceof Error) {
message = msg.stack;
}
if (msg instanceof ApiError_default) {
code = msg.statusCode;
}
this.log("error", `${code !== 0 ? "[" + code + "]" : ""}${message}
stacktrace: ${new Error().stack}`, meta);
}
warn(msg, ...meta) {
this.log("warn", `${msg}
stacktrace: ${new Error().stack}`, meta);
}
info(msg, ...meta) {
this.log("info", msg, meta);
}
verbose(msg, ...meta) {
this.log("verbose", msg, meta);
}
debug(msg, ...meta) {
this.log("debug", msg, meta);
}
silly(msg, ...meta) {
this.log("silly", msg, meta);
}
};
var logger_default = new Logger();
// src/seeds/testAdmin.json
var testAdmin_default = {
username: "Test",
firstName: "Test",
lastName: "Admin",
role: "admin",
openPassw: "123456aA-",
password: "5b8d4960316d1fb0c92498c90da6c397cdf247cae71f01467a88e2b42d7af6f5ac7ca75d3bea6e3e0078111a2e5dfc1611f9a9a8908a5a3af5bcd64c42989608977de192829bdf8ada113a60f8f0704443c659789761865e29a3103dbf0773f5bf31e4685d475ece56afaceb949b6e7467eaa287a02e4142d095bcbf84acaefe47ee080799a28188890d39d3397e285d8b46c9a0efe9517428825b64ee1ebcc96d92c084733db866c767341381b6254aaa1ef36d1bf3d24e3f5b8d8b6b4080589b130e9c90914a3da74e5b6adf5f569bfd77460abae8ae4f87c2a375397a37f09861b9e114cead0cc34fff2d631fd4294260dea17e4fe098940dbee2cb80c62eb3701d40f5b204de776b8252d55e5f567c599b1fbcdae79278d1f375a4c8244a26a3b721dbeec56c8f39b3eb810942d392aae371ea81ded6b820dd4b489566a33c495f5c291ff238d07202d2ff04c52426828e44af98ec056a42d13f4b166ec170083e2fff9efe2b8cfdde529f3bce56b8427cf2d188861808ad07fd13e073b2a804e818b2882c13f559d52420b49f301263a9de34fe22b6df4a82ae70e7e4c29c88479878d2c21fbb810532532e7ad9a28f610b63033520e703f178e7b44d3e101ec0d4339c085ccc8bb290b3cb996c75c2b8deaacba8098b9ec02c7e47542891da3bd887c31cd8e0bdfa56bb844b1703368afe8dc42d668ff2e3374b939b4f",
apiKey: "",
salt: "c6211751bdc372f491a86bcbd8e4196dc393d14e14e5f17019d5c317afd5bc27"
};
// src/server/services/tasks.service.ts
var import_path3 = __toESM(require("path"));
var stringTable = import_string_table.default;
function taskOutput(msg, res) {
res.write(`${msg.toString()}
`);
logger_default.debug(msg.toString());
}
function parseHrtimeToSeconds(hrtime) {
return (hrtime[0] + hrtime[1] / 1e9).toFixed(3);
}
var status = async (currentUser) => {
const count = await User_model_default.countDocuments().exec();
logger_default.silly(`server status: check users counts: ${count}`);
if (count > 1) {
return { alive: true, currentUser: currentUser?.username };
}
return { alive: false };
};
var screenshots = async () => {
const files = import_fs2.default.readdirSync(config.defaultImagesPath);
return files;
};
var loadTestUser = async () => {
const logOpts = {
itemType: "user",
msgType: "LOAD",
ref: "Administrator"
};
if (!env.SYNGRISI_TEST_MODE) {
return { message: "the feature works only in test mode" };
}
const testAdmin = await User_model_default.findOne({ username: "Test" }).exec();
if (!testAdmin) {
logger_default.info("create the test Administrator", logOpts);
const admin = await User_model_default.create(testAdmin_default);
logger_default.info(`test Administrator with id: '${admin._id}' was created`, logOpts);
return admin;
}
logger_default.info(`test admin is exists: ${JSON.stringify(testAdmin, null, 2)}`, logOpts);
return { msg: `already exist '${testAdmin}'` };
};
var task_handle_database_consistency = async (options, res) => {
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Content-Encoding": "none",
"x-no-compression": "true"
});
try {
const startTime = process.hrtime();
taskOutput("- starting...\n", res);
taskOutput("---------------------------------", res);
taskOutput("STAGE #1: Calculate Common stats", res);
taskOutput("get runs data", res);
const allRunsBefore = await Run_model_default.find().exec();
taskOutput("get suites data", res);
const allSuitesBefore = await Suite_model_default.find().exec();
taskOutput("get tests data", res);
const allTestsBefore = await Test_model_default.find().lean().exec();
taskOutput("get checks data", res);
const allChecksBefore = await Check_model_default.find().lean().exec();
taskOutput("get snapshots data", res);
const allSnapshotsBefore = await Snapshot_model_default.find().lean().exec();
taskOutput("get files data", res);
const allFilesBefore = (await import_fs2.promises.readdir(config.defaultImagesPath, { withFileTypes: true })).filter((item) => !item.isDirectory()).map((x) => x.name).filter((x) => x.includes(".png"));
taskOutput("-----------------------------", res);
const beforeStatTable = stringTable.create([
{ item: "suites", count: allSuitesBefore.length },
{ item: "runs", count: allRunsBefore.length },
{ item: "tests", count: allTestsBefore.length },
{ item: "checks", count: allChecksBefore.length },
{ item: "snapshots", count: allSnapshotsBefore.length },
{ item: "files", count: allFilesBefore.length }
]);
res.flush();
taskOutput(beforeStatTable, res);
taskOutput("---------------------------------", res);
taskOutput("STAGE #2: Calculate Inconsistent Items", res);
taskOutput("> calculate abandoned snapshots", res);
const abandonedSnapshots = allSnapshotsBefore.filter((sn) => !import_fs2.default.existsSync(import_path3.default.join(config.defaultImagesPath, sn.filename)));
taskOutput("> calculate abandoned files", res);
const snapshotsUniqueFiles = Array.from(new Set(allSnapshotsBefore.map((x) => x.filename)));
const abandonedFiles = [];
const progress = new ProgressBar(allFilesBefore.length);
for (const [index, file] of allFilesBefore.entries()) {
setTimeout(() => {
progress.writeIfChange(index, allFilesBefore.length, taskOutput, res);
}, 10);
if (!snapshotsUniqueF