From 51571ce78e439e11b6222e30c1cbcc766b523169 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Tue, 14 Oct 2025 16:04:20 +0700 Subject: [PATCH 01/62] Setup Development --- .gitignore | 2 + config/config.js | 16 + helpers/jwt.js | 0 migrations/20251014084226-create-user.js | 41 + migrations/20251014084227-create-post.js | 37 + migrations/20251014084228-create-image.js | 31 + migrations/20251014084230-create-like.js | 31 + migrations/20251014084231-create-category.js | 28 + migrations/20251014084233-create-chat.js | 34 + migrations/20251014084234-create-message.js | 37 + models/category.js | 24 + models/chat.js | 28 + models/image.js | 25 + models/index.js | 43 + models/like.js | 26 + models/message.js | 30 + models/post.js | 30 + models/user.js | 63 + package-lock.json | 3198 ++++++++++++++++++ package.json | 37 + 20 files changed, 3761 insertions(+) create mode 100644 .gitignore create mode 100644 config/config.js create mode 100644 helpers/jwt.js create mode 100644 migrations/20251014084226-create-user.js create mode 100644 migrations/20251014084227-create-post.js create mode 100644 migrations/20251014084228-create-image.js create mode 100644 migrations/20251014084230-create-like.js create mode 100644 migrations/20251014084231-create-category.js create mode 100644 migrations/20251014084233-create-chat.js create mode 100644 migrations/20251014084234-create-message.js create mode 100644 models/category.js create mode 100644 models/chat.js create mode 100644 models/image.js create mode 100644 models/index.js create mode 100644 models/like.js create mode 100644 models/message.js create mode 100644 models/post.js create mode 100644 models/user.js create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1dcef2d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +.env \ No newline at end of file diff --git a/config/config.js b/config/config.js new file mode 100644 index 0000000..a61105d --- /dev/null +++ b/config/config.js @@ -0,0 +1,16 @@ +require("dotenv").config(); + +module.exports = { + development: { + url: process.env.DATABASE_URL, + dialect: "postgres", + }, + test: { + url: process.env.DATABASE_URL, + dialect: "postgres", + }, + production: { + url: process.env.DATABASE_URL, + dialect: "postgres", + }, +}; diff --git a/helpers/jwt.js b/helpers/jwt.js new file mode 100644 index 0000000..e69de29 diff --git a/migrations/20251014084226-create-user.js b/migrations/20251014084226-create-user.js new file mode 100644 index 0000000..2295a42 --- /dev/null +++ b/migrations/20251014084226-create-user.js @@ -0,0 +1,41 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('Users', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + username: { + type: Sequelize.STRING + }, + email: { + type: Sequelize.STRING, + unique:true + }, + password: { + type: Sequelize.STRING + }, + profilePic: { + type: Sequelize.STRING + }, + bio: { + type: Sequelize.TEXT + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('Users'); + } +}; \ No newline at end of file diff --git a/migrations/20251014084227-create-post.js b/migrations/20251014084227-create-post.js new file mode 100644 index 0000000..1851960 --- /dev/null +++ b/migrations/20251014084227-create-post.js @@ -0,0 +1,37 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('Posts', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + content: { + type: Sequelize.TEXT + }, + isPrivate: { + type: Sequelize.BOOLEAN + }, + UserId: { + type: Sequelize.INTEGER + }, + CategoryId: { + type: Sequelize.INTEGER + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('Posts'); + } +}; \ No newline at end of file diff --git a/migrations/20251014084228-create-image.js b/migrations/20251014084228-create-image.js new file mode 100644 index 0000000..96cf6bc --- /dev/null +++ b/migrations/20251014084228-create-image.js @@ -0,0 +1,31 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('Images', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + imageUrl: { + type: Sequelize.STRING + }, + PostId: { + type: Sequelize.INTEGER + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('Images'); + } +}; \ No newline at end of file diff --git a/migrations/20251014084230-create-like.js b/migrations/20251014084230-create-like.js new file mode 100644 index 0000000..49fec63 --- /dev/null +++ b/migrations/20251014084230-create-like.js @@ -0,0 +1,31 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('Likes', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + UserId: { + type: Sequelize.INTEGER + }, + PostId: { + type: Sequelize.INTEGER + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('Likes'); + } +}; \ No newline at end of file diff --git a/migrations/20251014084231-create-category.js b/migrations/20251014084231-create-category.js new file mode 100644 index 0000000..f20ff44 --- /dev/null +++ b/migrations/20251014084231-create-category.js @@ -0,0 +1,28 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('Categories', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + name: { + type: Sequelize.STRING + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('Categories'); + } +}; \ No newline at end of file diff --git a/migrations/20251014084233-create-chat.js b/migrations/20251014084233-create-chat.js new file mode 100644 index 0000000..5e42f68 --- /dev/null +++ b/migrations/20251014084233-create-chat.js @@ -0,0 +1,34 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('Chats', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + isAIChat: { + type: Sequelize.BOOLEAN + }, + UserId: { + type: Sequelize.INTEGER + }, + partnerId: { + type: Sequelize.INTEGER + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('Chats'); + } +}; \ No newline at end of file diff --git a/migrations/20251014084234-create-message.js b/migrations/20251014084234-create-message.js new file mode 100644 index 0000000..c5d4028 --- /dev/null +++ b/migrations/20251014084234-create-message.js @@ -0,0 +1,37 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('Messages', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + ChatId: { + type: Sequelize.INTEGER + }, + senderId: { + type: Sequelize.INTEGER + }, + receiverId: { + type: Sequelize.INTEGER + }, + content: { + type: Sequelize.TEXT + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('Messages'); + } +}; \ No newline at end of file diff --git a/models/category.js b/models/category.js new file mode 100644 index 0000000..85e673b --- /dev/null +++ b/models/category.js @@ -0,0 +1,24 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class Category extends Model { + /** + * Helper method for defining associations. + * This method is not a part of Sequelize lifecycle. + * The `models/index` file will call this method automatically. + */ + static associate(models) { + Category.hasMany(models.Post); + } + + } + Category.init({ + name: DataTypes.STRING + }, { + sequelize, + modelName: 'Category', + }); + return Category; +}; \ No newline at end of file diff --git a/models/chat.js b/models/chat.js new file mode 100644 index 0000000..bb8aa6b --- /dev/null +++ b/models/chat.js @@ -0,0 +1,28 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class Chat extends Model { + /** + * Helper method for defining associations. + * This method is not a part of Sequelize lifecycle. + * The `models/index` file will call this method automatically. + */ + static associate(models) { + Chat.belongsTo(models.User, { as: "user", foreignKey: "UserId" }); + Chat.belongsTo(models.User, { as: "partner", foreignKey: "partnerId" }); + Chat.hasMany(models.Message); + } + + } + Chat.init({ + isAIChat: DataTypes.BOOLEAN, + UserId: DataTypes.INTEGER, + partnerId: DataTypes.INTEGER + }, { + sequelize, + modelName: 'Chat', + }); + return Chat; +}; \ No newline at end of file diff --git a/models/image.js b/models/image.js new file mode 100644 index 0000000..7fddad1 --- /dev/null +++ b/models/image.js @@ -0,0 +1,25 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class Image extends Model { + /** + * Helper method for defining associations. + * This method is not a part of Sequelize lifecycle. + * The `models/index` file will call this method automatically. + */ + static associate(models) { + Image.belongsTo(models.Post); + } + + } + Image.init({ + imageUrl: DataTypes.STRING, + PostId: DataTypes.INTEGER + }, { + sequelize, + modelName: 'Image', + }); + return Image; +}; \ No newline at end of file diff --git a/models/index.js b/models/index.js new file mode 100644 index 0000000..024200e --- /dev/null +++ b/models/index.js @@ -0,0 +1,43 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const Sequelize = require('sequelize'); +const process = require('process'); +const basename = path.basename(__filename); +const env = process.env.NODE_ENV || 'development'; +const config = require(__dirname + '/../config/config.json')[env]; +const db = {}; + +let sequelize; +if (config.use_env_variable) { + sequelize = new Sequelize(process.env[config.use_env_variable], config); +} else { + sequelize = new Sequelize(config.database, config.username, config.password, config); +} + +fs + .readdirSync(__dirname) + .filter(file => { + return ( + file.indexOf('.') !== 0 && + file !== basename && + file.slice(-3) === '.js' && + file.indexOf('.test.js') === -1 + ); + }) + .forEach(file => { + const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes); + db[model.name] = model; + }); + +Object.keys(db).forEach(modelName => { + if (db[modelName].associate) { + db[modelName].associate(db); + } +}); + +db.sequelize = sequelize; +db.Sequelize = Sequelize; + +module.exports = db; diff --git a/models/like.js b/models/like.js new file mode 100644 index 0000000..82126a9 --- /dev/null +++ b/models/like.js @@ -0,0 +1,26 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class Like extends Model { + /** + * Helper method for defining associations. + * This method is not a part of Sequelize lifecycle. + * The `models/index` file will call this method automatically. + */ + static associate(models) { + Like.belongsTo(models.User); + Like.belongsTo(models.Post); + } + + } + Like.init({ + UserId: DataTypes.INTEGER, + PostId: DataTypes.INTEGER + }, { + sequelize, + modelName: 'Like', + }); + return Like; +}; \ No newline at end of file diff --git a/models/message.js b/models/message.js new file mode 100644 index 0000000..cc81bf1 --- /dev/null +++ b/models/message.js @@ -0,0 +1,30 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class Message extends Model { + /** + * Helper method for defining associations. + * This method is not a part of Sequelize lifecycle. + * The `models/index` file will call this method automatically. + */ + static associate(models) { + Message.belongsTo(models.Chat); + Message.belongsTo(models.User, { as: "sender", foreignKey: "senderId" }); + Message.belongsTo(models.User, { as: "receiver", foreignKey: "receiverId" }); + } + + + } + Message.init({ + ChatId: DataTypes.INTEGER, + senderId: DataTypes.INTEGER, + receiverId: DataTypes.INTEGER, + content: DataTypes.TEXT + }, { + sequelize, + modelName: 'Message', + }); + return Message; +}; \ No newline at end of file diff --git a/models/post.js b/models/post.js new file mode 100644 index 0000000..8aea41d --- /dev/null +++ b/models/post.js @@ -0,0 +1,30 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class Post extends Model { + /** + * Helper method for defining associations. + * This method is not a part of Sequelize lifecycle. + * The `models/index` file will call this method automatically. + */ + static associate(models) { + Post.belongsTo(models.User); + Post.belongsTo(models.Category); + Post.hasMany(models.Image); + Post.hasMany(models.Like) + } + + } + Post.init({ + content: DataTypes.TEXT, + isPrivate: DataTypes.BOOLEAN, + UserId: DataTypes.INTEGER, + CategoryId: DataTypes.INTEGER + }, { + sequelize, + modelName: 'Post', + }); + return Post; +}; \ No newline at end of file diff --git a/models/user.js b/models/user.js new file mode 100644 index 0000000..b26586e --- /dev/null +++ b/models/user.js @@ -0,0 +1,63 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class User extends Model { + /** + * Helper method for defining associations. + * This method is not a part of Sequelize lifecycle. + * The `models/index` file will call this method automatically. + */ + static associate(models) { + User.hasMany(models.Post); + User.hasMany(models.Like); + User.hasMany(models.Chat, { foreignKey: "UserId" }); + User.hasMany(models.Chat, { foreignKey: "partnerId" }); + User.hasMany(models.Message, { foreignKey: "senderId" }); + User.hasMany(models.Message, { foreignKey: "receiverId" }); + } + + } + User.init({ + username: { + type: DataTypes.STRING, + allowNull: false, + validate: { + notEmpty: { msg: `Username is required` }, + notNull: { msg: `Username is required` } + } + }, + email: { + type: DataTypes.STRING, + allowNull: false, + unique: { msg: `Email is already registered` }, + validate: { + notEmpty: { msg: `Email is required` }, + notNull: { msg: `Email is required` }, + isEmail: { msg: `Invalid email format` } + } + }, + password: { + type: DataTypes.STRING, + allowNull: false, + validate: { + notEmpty: { msg: `Password is required` }, + notNull: { msg: `Password is required` } + } + }, + profilePic: { + type: DataTypes.STRING, + }, + bio: DataTypes.TEXT + }, { + sequelize, + modelName: 'User', + hooks: { + beforeCreate: async (user) => { + user.password = await bcrypt.hash(user.password, 10); + } + } + }); + return User; +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..9cd39fd --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3198 @@ +{ + "name": "dummy-instagram", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "dummy-instagram", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "bcrypt": "^6.0.0", + "cloudinary": "^2.7.0", + "cors": "^2.8.5", + "dotenv": "^17.2.3", + "express": "^5.1.0", + "jsonwebtoken": "^9.0.2", + "multer": "^2.0.2", + "pg": "^8.16.3", + "pg-hstore": "^2.3.4", + "sequelize": "^6.37.7", + "socket.io": "^4.8.1" + }, + "devDependencies": { + "nodemon": "^3.1.10", + "sequelize-cli": "^6.6.3" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.7.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.2.tgz", + "integrity": "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.14.0" + } + }, + "node_modules/@types/validator": { + "version": "13.15.3", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.3.tgz", + "integrity": "sha512-7bcUmDyS6PN3EuD9SlGGOxM77F8WLVsrwkxyWxKnxzmXoequ6c7741QBrANq6htVRGOITJ7z72mTP6Z4XyuG+Q==", + "license": "MIT" + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.0", + "node-gyp-build": "^4.8.4" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/cloudinary": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-2.7.0.tgz", + "integrity": "sha512-qrqDn31+qkMCzKu1GfRpzPNAO86jchcNwEHCUiqvPHNSFqu7FTNF9FuAkBUyvM1CFFgFPu64NT0DyeREwLwK0w==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.21", + "q": "^1.5.1" + }, + "engines": { + "node": ">=9" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dotenv": { + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dottie": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz", + "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==", + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/editorconfig": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", + "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" + }, + "bin": { + "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/inflection": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz", + "integrity": "sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==", + "engines": [ + "node >= 0.4.0" + ], + "license": "MIT" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-beautify": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.4.tgz", + "integrity": "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.4", + "glob": "^10.4.2", + "js-cookie": "^3.0.5", + "nopt": "^7.2.1" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.48.tgz", + "integrity": "sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==", + "license": "MIT", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", + "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "concat-stream": "^2.0.0", + "mkdirp": "^0.5.6", + "object-assign": "^4.1.1", + "type-is": "^1.6.18", + "xtend": "^4.0.2" + }, + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/multer/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-addon-api": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", + "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/nodemon": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", + "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pg": { + "version": "8.16.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", + "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.9.1", + "pg-pool": "^3.10.1", + "pg-protocol": "^1.10.3", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.2.7" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz", + "integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz", + "integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==", + "license": "MIT" + }, + "node_modules/pg-hstore": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/pg-hstore/-/pg-hstore-2.3.4.tgz", + "integrity": "sha512-N3SGs/Rf+xA1M2/n0JBiXFDVMzdekwLZLAO0g7mpDY9ouX+fDI7jS6kTq3JujmYbtNSJ53TJ0q4G98KVZSM4EA==", + "license": "MIT", + "dependencies": { + "underscore": "^1.13.1" + }, + "engines": { + "node": ">= 0.8.x" + } + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz", + "integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz", + "integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true, + "license": "ISC" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", + "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.7.0", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/retry-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-7.1.1.tgz", + "integrity": "sha512-hMD7odLOt3LkTjcif8aRZqi/hybjpLNgSk5oF5FCowfCjok6LukpN2bDX7R5wDmbgBQFn7YoBxSagmtXHaJYJw==", + "license": "MIT" + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/sequelize": { + "version": "6.37.7", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.37.7.tgz", + "integrity": "sha512-mCnh83zuz7kQxxJirtFD7q6Huy6liPanI67BSlbzSYgVNl5eXVdE2CN1FuAeZwG1SNpGsNRCV+bJAVVnykZAFA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/sequelize" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.1.8", + "@types/validator": "^13.7.17", + "debug": "^4.3.4", + "dottie": "^2.0.6", + "inflection": "^1.13.4", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "moment-timezone": "^0.5.43", + "pg-connection-string": "^2.6.1", + "retry-as-promised": "^7.0.4", + "semver": "^7.5.4", + "sequelize-pool": "^7.1.0", + "toposort-class": "^1.0.1", + "uuid": "^8.3.2", + "validator": "^13.9.0", + "wkx": "^0.5.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependenciesMeta": { + "ibm_db": { + "optional": true + }, + "mariadb": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-hstore": { + "optional": true + }, + "snowflake-sdk": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, + "node_modules/sequelize-cli": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-6.6.3.tgz", + "integrity": "sha512-1YYPrcSRt/bpMDDSKM5ubY1mnJ2TEwIaGZcqITw4hLtGtE64nIqaBnLtMvH8VKHg6FbWpXTiFNc2mS/BtQCXZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fs-extra": "^9.1.0", + "js-beautify": "1.15.4", + "lodash": "^4.17.21", + "picocolors": "^1.1.1", + "resolve": "^1.22.1", + "umzug": "^2.3.0", + "yargs": "^16.2.0" + }, + "bin": { + "sequelize": "lib/sequelize", + "sequelize-cli": "lib/sequelize" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sequelize-pool": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-7.1.0.tgz", + "integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/socket.io": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "license": "MIT", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg==", + "license": "MIT" + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/umzug": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", + "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "^3.7.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/underscore": { + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", + "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validator": { + "version": "13.15.15", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.15.tgz", + "integrity": "sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wkx": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", + "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..a0096c8 --- /dev/null +++ b/package.json @@ -0,0 +1,37 @@ +{ + "name": "dummy-instagram", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Joshua080324/Dummy-Instagram.git" + }, + "keywords": [], + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/Joshua080324/Dummy-Instagram/issues" + }, + "homepage": "https://github.com/Joshua080324/Dummy-Instagram#readme", + "dependencies": { + "bcrypt": "^6.0.0", + "cloudinary": "^2.7.0", + "cors": "^2.8.5", + "dotenv": "^17.2.3", + "express": "^5.1.0", + "jsonwebtoken": "^9.0.2", + "multer": "^2.0.2", + "pg": "^8.16.3", + "pg-hstore": "^2.3.4", + "sequelize": "^6.37.7", + "socket.io": "^4.8.1" + }, + "devDependencies": { + "nodemon": "^3.1.10", + "sequelize-cli": "^6.6.3" + } +} From aee714fe98c93c9a2dc8cbf361ea8e1984b3a57d Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Tue, 14 Oct 2025 16:12:20 +0700 Subject: [PATCH 02/62] Helpers setup --- helpers/authMiddleware.js | 19 +++++++++++++++++++ helpers/handleError.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 helpers/authMiddleware.js create mode 100644 helpers/handleError.js diff --git a/helpers/authMiddleware.js b/helpers/authMiddleware.js new file mode 100644 index 0000000..6c5039a --- /dev/null +++ b/helpers/authMiddleware.js @@ -0,0 +1,19 @@ +const { verifyToken } = require("./jwt"); +const { User } = require("../models"); + +module.exports = async function authMiddleware(req, res, next) { + try { + const token = req.headers.authorization?.split(" ")[1]; + if (!token) throw { name: "Unauthorized" }; + + const decoded = verifyToken(token); + const user = await User.findByPk(decoded.id); + if (!user) throw { name: "Unauthorized" }; + + req.user = user; + next(); + } catch (err) { + console.error(err); + res.status(401).json({ message: "Unauthorized access" }); + } +}; diff --git a/helpers/handleError.js b/helpers/handleError.js new file mode 100644 index 0000000..af2684f --- /dev/null +++ b/helpers/handleError.js @@ -0,0 +1,30 @@ +function handleError(err, res) { + console.error("Error:", err); + + if (err.name === "Unauthorized") { + return res.status(401).json({ message: "Unauthorized access" }); + } + + if (err.name === "InvalidLogin") { + return res.status(401).json({ message: "Invalid email or password" }); + } + + if (err.name === "NotFound") { + return res.status(404).json({ message: "Data not found" }); + } + + if (err.name === "BadRequest") { + return res.status(400).json({ message: err.message || "Bad request" }); + } + + if (err.name === "SequelizeValidationError" || err.name === "SequelizeUniqueConstraintError") { + const messages = err.errors.map(e => e.message); + return res.status(400).json({ message: messages }); + } + + return res.status(500).json({ + message: "Internal Server Error", + }); +} + +module.exports = handleError; From 7bc3e0ead0dc921ff34c7d4d69ac12ed0c5d40d7 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Tue, 14 Oct 2025 16:57:44 +0700 Subject: [PATCH 03/62] Update &Create userController --- app.js | 22 +++++++++++++++++ controllers/userController.js | 45 +++++++++++++++++++++++++++++++++++ helpers/handleError.js | 2 +- models/user.js | 1 + routes/index.js | 0 5 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 app.js create mode 100644 controllers/userController.js create mode 100644 routes/index.js diff --git a/app.js b/app.js new file mode 100644 index 0000000..a1a8c1e --- /dev/null +++ b/app.js @@ -0,0 +1,22 @@ +require('dotenv').config(); +const express = require('express'); +const app = express(); +const port = process.env.PORT || 3000; +const handleError = require('./helpers/handleError'); +const routes = require('./routes'); + + +//middleware +app.use(express.json()); +app.use(express.urlencoded({ extended: true })); + +//router +app.use(routes); + +//error handler +app.use(handleError); + +//server +app.listen(port, () => { + console.log(`Example app listening on port http://localhost:${port}`) +}) \ No newline at end of file diff --git a/controllers/userController.js b/controllers/userController.js new file mode 100644 index 0000000..28090f9 --- /dev/null +++ b/controllers/userController.js @@ -0,0 +1,45 @@ +const { User } = require('../models'); +const bcrypt = require('bcryptjs'); +const { signToken } = require('../helpers/jwt'); + +class UserController { + static async register(req, res, next) { + try { + const { username, email, password } = req.body; + const newUser = await User.create({ username, email, password }); + res.status(201).json({ + id: newUser.id, + username: newUser.username, + email: newUser.email, + }); + } catch (err) { + next(err); + } + } + + static async login(req, res, next) { + try { + const { email, password } = req.body; + if (!email || !password) { + throw { name: 'BadRequest', message: 'Email and password are required' }; + } + + const user = await User.findOne({ where: { email } }); + if (!user) { + throw { name: 'InvalidLogin' }; + } + + const isPasswordValid = bcrypt.compareSync(password, user.password); + if (!isPasswordValid) { + throw { name: 'InvalidLogin' }; + } + + const token = signToken({ id: user.id }); + res.status(200).json({ access_token: token }); + } catch (err) { + next(err); + } + } +} + +module.exports = UserController; \ No newline at end of file diff --git a/helpers/handleError.js b/helpers/handleError.js index af2684f..8376234 100644 --- a/helpers/handleError.js +++ b/helpers/handleError.js @@ -1,4 +1,4 @@ -function handleError(err, res) { +function handleError(err, req,res, next) { console.error("Error:", err); if (err.name === "Unauthorized") { diff --git a/models/user.js b/models/user.js index b26586e..aca07ee 100644 --- a/models/user.js +++ b/models/user.js @@ -1,4 +1,5 @@ 'use strict'; +const bcrypt = require('bcryptjs'); const { Model } = require('sequelize'); diff --git a/routes/index.js b/routes/index.js new file mode 100644 index 0000000..e69de29 From 5fbeef0e8caafc891f19bcb80d692835fb6977b3 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Tue, 14 Oct 2025 17:47:59 +0700 Subject: [PATCH 04/62] Login Google --- controllers/userController.js | 30 +++++++++++ package-lock.json | 95 +++++++++++++++++++++++++++++++++++ package.json | 2 + routes/index.js | 9 ++++ routes/userRotuter.js | 10 ++++ 5 files changed, 146 insertions(+) create mode 100644 routes/userRotuter.js diff --git a/controllers/userController.js b/controllers/userController.js index 28090f9..5ff01ca 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -40,6 +40,36 @@ class UserController { next(err); } } + + static async googleSignIn(req, res, next) { + try { + const { google_token } = req.body; + + const ticket = await client.verifyIdToken({ + idToken: google_token, + audience: process.env.GOOGLE_CLIENT_ID, + }); + const payload = ticket.getPayload(); + + const [user, created] = await User.findOrCreate({ + where: { email: payload.email }, + defaults: { + username: payload.name, + email: payload.email, + password: Math.random().toString(36), + profilePic: payload.picture, + }, + hooks: false + }); + + + const access_token = signToken({ id: user.id }); + res.status(200).json({ access_token }); + + } catch (err) { + next(err); + } + } } module.exports = UserController; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9cd39fd..30694d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,8 @@ "express": "^5.1.0", "jsonwebtoken": "^9.0.2", "multer": "^2.0.2", + "passport": "^0.7.0", + "passport-google-oauth20": "^2.0.0", "pg": "^8.16.3", "pg-hstore": "^2.3.4", "sequelize": "^6.37.7", @@ -202,6 +204,15 @@ "node": "^4.5.0 || >= 5.9" } }, + "node_modules/base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/bcrypt": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", @@ -1778,6 +1789,12 @@ "node": ">=0.10.0" } }, + "node_modules/oauth": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.10.2.tgz", + "integrity": "sha512-JtFnB+8nxDEXgNyniwz573xxbKSOu3R8D40xQKqcjwJ2CDkYqUDI53o6IuzDJBx60Z8VKCm271+t8iFjakrl8Q==", + "license": "MIT" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -1836,6 +1853,64 @@ "node": ">= 0.8" } }, + "node_modules/passport": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", + "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", + "license": "MIT", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-google-oauth20": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz", + "integrity": "sha512-KSk6IJ15RoxuGq7D1UKK/8qKhNfzbLeLrG3gkLZ7p4A6DBCcv7xpyQwuXtWdpyR0+E0mwkpjY1VfPOhxQrKzdQ==", + "license": "MIT", + "dependencies": { + "passport-oauth2": "1.x.x" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/passport-oauth2": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.8.0.tgz", + "integrity": "sha512-cjsQbOrXIDE4P8nNb3FQRCCmJJ/utnFKEz2NX209f7KOHPoX18gF7gBzBbLLsj2/je4KrgiwLLGjf0lm9rtTBA==", + "license": "MIT", + "dependencies": { + "base64url": "3.x.x", + "oauth": "0.10.x", + "passport-strategy": "1.x.x", + "uid2": "0.0.x", + "utils-merge": "1.x.x" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -1880,6 +1955,11 @@ "url": "https://opencollective.com/express" } }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, "node_modules/pg": { "version": "8.16.3", "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", @@ -2867,6 +2947,12 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "license": "MIT" }, + "node_modules/uid2": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz", + "integrity": "sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==", + "license": "MIT" + }, "node_modules/umzug": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", @@ -2924,6 +3010,15 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", diff --git a/package.json b/package.json index a0096c8..7acd690 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,8 @@ "express": "^5.1.0", "jsonwebtoken": "^9.0.2", "multer": "^2.0.2", + "passport": "^0.7.0", + "passport-google-oauth20": "^2.0.0", "pg": "^8.16.3", "pg-hstore": "^2.3.4", "sequelize": "^6.37.7", diff --git a/routes/index.js b/routes/index.js index e69de29..61a2abb 100644 --- a/routes/index.js +++ b/routes/index.js @@ -0,0 +1,9 @@ +const express = require('express'); +const router = express.Router(); +const userRouter = require('./userRouter'); +const postRouter = require('./postRouter'); + +router.use('/users', userRouter); +router.use('/posts', postRouter); + +module.exports = router; \ No newline at end of file diff --git a/routes/userRotuter.js b/routes/userRotuter.js new file mode 100644 index 0000000..f42509e --- /dev/null +++ b/routes/userRotuter.js @@ -0,0 +1,10 @@ +const express = require('express'); +const UserController = require('../controllers/userController'); +const router = express.Router(); + +router.post('/register', UserController.register); +router.post('/login', UserController.login); + +router.post('/auth/google', UserController.googleSignIn); + +module.exports = router; \ No newline at end of file From 9be27cf1ed6aebb251b313caad7e562dc21eaa93 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Tue, 14 Oct 2025 19:43:26 +0700 Subject: [PATCH 05/62] Gambaran awal controller user & post --- controllers/postController.js | 42 +++++++++ controllers/userController.js | 108 +++++++++++------------ models/index.js | 9 +- models/post.js | 13 ++- package-lock.json | 10 +++ package.json | 2 +- routes/index.js | 4 +- routes/postRouter.js | 9 ++ routes/{userRotuter.js => userRouter.js} | 1 - 9 files changed, 136 insertions(+), 62 deletions(-) create mode 100644 controllers/postController.js create mode 100644 routes/postRouter.js rename routes/{userRotuter.js => userRouter.js} (99%) diff --git a/controllers/postController.js b/controllers/postController.js new file mode 100644 index 0000000..d8bcfcc --- /dev/null +++ b/controllers/postController.js @@ -0,0 +1,42 @@ +const { Post, Image, User, Category } = require("../models"); + +class PostController { + static async createPost(req, res, next) { + try { + const { content, isPrivate, categoryId, imageUrls } = req.body; + const post = await Post.create({ + content, + isPrivate, + CategoryId: categoryId, + UserId: req.user.id, + }); + + if (imageUrls && imageUrls.length > 0) { + const imageData = imageUrls.map((url) => ({ + imageUrl: url, + PostId: post.id, + })); + await Image.bulkCreate(imageData); + } + + res.status(201).json({ message: "Post created successfully", post }); + } catch (err) { + next(err); + } + } + + static async getAllPublicPosts(req, res, next) { + try { + const posts = await Post.findAll({ + where: { isPrivate: false }, + include: [{ model: User, attributes: ["username", "profilePic"] }, Image, Category], + order: [["createdAt", "DESC"]], + }); + res.json(posts); + } catch (err) { + next(err); + } + } +} + +module.exports = PostController; \ No newline at end of file diff --git a/controllers/userController.js b/controllers/userController.js index 5ff01ca..a64c7b2 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -3,73 +3,73 @@ const bcrypt = require('bcryptjs'); const { signToken } = require('../helpers/jwt'); class UserController { - static async register(req, res, next) { - try { - const { username, email, password } = req.body; - const newUser = await User.create({ username, email, password }); - res.status(201).json({ - id: newUser.id, - username: newUser.username, - email: newUser.email, - }); - } catch (err) { - next(err); + static async register(req, res, next) { + try { + const { username, email, password } = req.body; + const newUser = await User.create({ username, email, password }); + res.status(201).json({ + id: newUser.id, + username: newUser.username, + email: newUser.email, + }); + } catch (err) { + next(err); + } } - } - static async login(req, res, next) { - try { - const { email, password } = req.body; - if (!email || !password) { - throw { name: 'BadRequest', message: 'Email and password are required' }; - } + static async login(req, res, next) { + try { + const { email, password } = req.body; + if (!email || !password) { + throw { name: 'BadRequest', message: 'Email and password are required' }; + } - const user = await User.findOne({ where: { email } }); - if (!user) { - throw { name: 'InvalidLogin' }; - } + const user = await User.findOne({ where: { email } }); + if (!user) { + throw { name: 'InvalidLogin' }; + } - const isPasswordValid = bcrypt.compareSync(password, user.password); - if (!isPasswordValid) { - throw { name: 'InvalidLogin' }; - } + const isPasswordValid = bcrypt.compareSync(password, user.password); + if (!isPasswordValid) { + throw { name: 'InvalidLogin' }; + } - const token = signToken({ id: user.id }); - res.status(200).json({ access_token: token }); - } catch (err) { - next(err); + const token = signToken({ id: user.id }); + res.status(200).json({ access_token: token }); + } catch (err) { + next(err); + } } - } static async googleSignIn(req, res, next) { - try { - const { google_token } = req.body; + try { + const { google_token } = req.body; - const ticket = await client.verifyIdToken({ - idToken: google_token, - audience: process.env.GOOGLE_CLIENT_ID, - }); - const payload = ticket.getPayload(); + const ticket = await client.verifyIdToken({ + idToken: google_token, + audience: process.env.GOOGLE_CLIENT_ID, + }); + const payload = ticket.getPayload(); - const [user, created] = await User.findOrCreate({ - where: { email: payload.email }, - defaults: { - username: payload.name, - email: payload.email, - password: Math.random().toString(36), - profilePic: payload.picture, - }, - hooks: false - }); + const [user, created] = await User.findOrCreate({ + where: { email: payload.email }, + defaults: { + username: payload.name, + email: payload.email, + password: Math.random().toString(36), + profilePic: payload.picture, + }, + hooks: false + }); - - const access_token = signToken({ id: user.id }); - res.status(200).json({ access_token }); - } catch (err) { - next(err); + const access_token = signToken({ id: user.id }); + res.status(200).json({ access_token }); + + } catch (err) { + next(err); + } } - } } module.exports = UserController; \ No newline at end of file diff --git a/models/index.js b/models/index.js index 024200e..9eefedb 100644 --- a/models/index.js +++ b/models/index.js @@ -6,12 +6,13 @@ const Sequelize = require('sequelize'); const process = require('process'); const basename = path.basename(__filename); const env = process.env.NODE_ENV || 'development'; -const config = require(__dirname + '/../config/config.json')[env]; +const config = require(__dirname + '/../config/config.js')[env]; // <-- Perubahan di sini const db = {}; let sequelize; -if (config.use_env_variable) { - sequelize = new Sequelize(process.env[config.use_env_variable], config); +// Menggunakan URL dari config.js +if (config.url) { + sequelize = new Sequelize(config.url, config); } else { sequelize = new Sequelize(config.database, config.username, config.password, config); } @@ -40,4 +41,4 @@ Object.keys(db).forEach(modelName => { db.sequelize = sequelize; db.Sequelize = Sequelize; -module.exports = db; +module.exports = db; \ No newline at end of file diff --git a/models/post.js b/models/post.js index 8aea41d..a5b557e 100644 --- a/models/post.js +++ b/models/post.js @@ -18,7 +18,18 @@ module.exports = (sequelize, DataTypes) => { } Post.init({ - content: DataTypes.TEXT, + content: { + type: DataTypes.TEXT, + allowNull: false, + validate: { + notEmpty: { + msg: "Content is required" + }, + notNull: { + msg: "Content is required" + } + } + }, isPrivate: DataTypes.BOOLEAN, UserId: DataTypes.INTEGER, CategoryId: DataTypes.INTEGER diff --git a/package-lock.json b/package-lock.json index 30694d8..1a881dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "ISC", "dependencies": { "bcrypt": "^6.0.0", + "bcryptjs": "^3.0.2", "cloudinary": "^2.7.0", "cors": "^2.8.5", "dotenv": "^17.2.3", @@ -227,6 +228,15 @@ "node": ">= 18" } }, + "node_modules/bcryptjs": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", + "integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==", + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", diff --git a/package.json b/package.json index 7acd690..c4e0744 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "homepage": "https://github.com/Joshua080324/Dummy-Instagram#readme", "dependencies": { - "bcrypt": "^6.0.0", + "bcryptjs": "^3.0.2", "cloudinary": "^2.7.0", "cors": "^2.8.5", "dotenv": "^17.2.3", diff --git a/routes/index.js b/routes/index.js index 61a2abb..dd0f9ff 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,6 +1,8 @@ const express = require('express'); const router = express.Router(); -const userRouter = require('./userRouter'); + + +const userRouter = require('./userRouter'); const postRouter = require('./postRouter'); router.use('/users', userRouter); diff --git a/routes/postRouter.js b/routes/postRouter.js new file mode 100644 index 0000000..c1f5e94 --- /dev/null +++ b/routes/postRouter.js @@ -0,0 +1,9 @@ +const express = require("express"); +const router = express.Router(); +const PostController = require("../controllers/postController"); +const auth = require("../helpers/authMiddleware"); + +router.post("/", auth, PostController.createPost); +router.get("/", PostController.getAllPublicPosts); + +module.exports = router; diff --git a/routes/userRotuter.js b/routes/userRouter.js similarity index 99% rename from routes/userRotuter.js rename to routes/userRouter.js index f42509e..f6f7abb 100644 --- a/routes/userRotuter.js +++ b/routes/userRouter.js @@ -4,7 +4,6 @@ const router = express.Router(); router.post('/register', UserController.register); router.post('/login', UserController.login); - router.post('/auth/google', UserController.googleSignIn); module.exports = router; \ No newline at end of file From 186e720ab35c64d25b203ef0e64677ec11d5f014 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Tue, 14 Oct 2025 20:20:53 +0700 Subject: [PATCH 06/62] Update post & cloudinary --- controllers/postController.js | 151 ++++++++++++++++++++++++++-------- helpers/cloudinary.js | 22 +++++ routes/postRouter.js | 13 ++- 3 files changed, 149 insertions(+), 37 deletions(-) create mode 100644 helpers/cloudinary.js diff --git a/controllers/postController.js b/controllers/postController.js index d8bcfcc..120c113 100644 --- a/controllers/postController.js +++ b/controllers/postController.js @@ -1,42 +1,123 @@ -const { Post, Image, User, Category } = require("../models"); +const { Post, Image, Like, User, Category } = require("../models"); class PostController { - static async createPost(req, res, next) { - try { - const { content, isPrivate, categoryId, imageUrls } = req.body; - const post = await Post.create({ - content, - isPrivate, - CategoryId: categoryId, - UserId: req.user.id, - }); - - if (imageUrls && imageUrls.length > 0) { - const imageData = imageUrls.map((url) => ({ - imageUrl: url, - PostId: post.id, - })); - await Image.bulkCreate(imageData); - } - - res.status(201).json({ message: "Post created successfully", post }); - } catch (err) { - next(err); + // CREATE POST + static async createPost(req, res, next) { + try { + const { content, isPrivate, categoryId } = req.body; + + // Buat post baru + const post = await Post.create({ + content, + isPrivate, + CategoryId: categoryId || null, + UserId: req.user.id, + }); + + // Jika ada file yang di-upload, simpan URL-nya + if (req.files && req.files.length > 0) { + const images = req.files.map((file) => ({ + imageUrl: file.path, // multer-storage-cloudinary menyediakan URL di file.path + PostId: post.id, + })); + await Image.bulkCreate(images); + } + + res.status(201).json({ message: "Post created successfully", post }); + } catch (err) { + next(err); + } + } + + // READ ALL PUBLIC POSTS + static async getAllPublicPosts(req, res, next) { + try { + const posts = await Post.findAll({ + where: { isPrivate: false }, + include: [ + { model: User, attributes: ["id", "username", "profilePic"] }, + { model: Image }, + { model: Category, attributes: ["name"] }, + { model: Like }, + ], + order: [["createdAt", "DESC"]], + }); + res.json(posts); + } catch (err) { + next(err); + } } - } - - static async getAllPublicPosts(req, res, next) { - try { - const posts = await Post.findAll({ - where: { isPrivate: false }, - include: [{ model: User, attributes: ["username", "profilePic"] }, Image, Category], - order: [["createdAt", "DESC"]], - }); - res.json(posts); - } catch (err) { - next(err); + + // READ USER'S OWN POSTS + static async getMyPosts(req, res, next) { + try { + const posts = await Post.findAll({ + where: { UserId: req.user.id }, + include: [Image, Category, Like], + order: [["createdAt", "DESC"]], + }); + res.json(posts); + } catch (err) { + next(err); + } + } + + // UPDATE POST + static async updatePost(req, res, next) { + try { + const { id } = req.params; + const { content, isPrivate, categoryId } = req.body; + + const post = await Post.findByPk(id); + if (!post) throw { name: "NotFound" }; + if (post.UserId !== req.user.id) throw { name: "Unauthorized" }; + + await post.update({ content, isPrivate, CategoryId: categoryId }); + res.json({ message: "Post updated successfully", post }); + } catch (err) { + next(err); + } + } + + // DELETE POST + static async deletePost(req, res, next) { + try { + const { id } = req.params; + const post = await Post.findByPk(id); + if (!post) throw { name: "NotFound" }; + if (post.UserId !== req.user.id) throw { name: "Unauthorized" }; + + await post.destroy(); + res.json({ message: "Post deleted successfully" }); + } catch (err) { + next(err); + } + } + + // LIKE / UNLIKE POST + static async toggleLike(req, res, next) { + try { + const { id } = req.params; + const post = await Post.findByPk(id); + if (!post) throw { name: "NotFound" }; + + const existingLike = await Like.findOne({ + where: { UserId: req.user.id, PostId: id }, + }); + + let message; + if (existingLike) { + await existingLike.destroy(); + message = "Post unliked"; + } else { + await Like.create({ UserId: req.user.id, PostId: id }); + message = "Post liked"; + } + res.json({ message }); + } catch (err) { + next(err); + } } - } } module.exports = PostController; \ No newline at end of file diff --git a/helpers/cloudinary.js b/helpers/cloudinary.js new file mode 100644 index 0000000..059f0e3 --- /dev/null +++ b/helpers/cloudinary.js @@ -0,0 +1,22 @@ +const cloudinary = require("cloudinary").v2; +const { CloudinaryStorage } = require("multer-storage-cloudinary"); +const multer = require("multer"); + +cloudinary.config({ + cloud_name: process.env.CLOUDINARY_CLOUD_NAME, + api_key: process.env.CLOUDINARY_API_KEY, + api_secret: process.env.CLOUDINARY_SECRET, +}); + +const storage = new CloudinaryStorage({ + cloudinary, + params: { + folder: "DummyInstagram_Posts", + allowed_formats: ["jpg", "png", "jpeg"], + transformation: [{ quality: "auto", fetch_format: "auto" }], + }, +}); + +const upload = multer({ storage }); + +module.exports = upload; \ No newline at end of file diff --git a/routes/postRouter.js b/routes/postRouter.js index c1f5e94..0254e8c 100644 --- a/routes/postRouter.js +++ b/routes/postRouter.js @@ -2,8 +2,17 @@ const express = require("express"); const router = express.Router(); const PostController = require("../controllers/postController"); const auth = require("../helpers/authMiddleware"); +const upload = require("../helpers/cloudinary"); + +// Terapkan middleware upload. 'images' adalah nama field, 5 adalah batas maksimal file. +router.post("/", auth, upload.array("images", 5), PostController.createPost); -router.post("/", auth, PostController.createPost); router.get("/", PostController.getAllPublicPosts); +router.get("/me", auth, PostController.getMyPosts); + +router.put("/:id", auth, PostController.updatePost); +router.delete("/:id", auth, PostController.deletePost); + +router.post("/:id/like", auth, PostController.toggleLike); -module.exports = router; +module.exports = router; \ No newline at end of file From dac17e6c0957aca31490b86d91c8726e86f988f6 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Wed, 15 Oct 2025 10:35:23 +0700 Subject: [PATCH 07/62] Server Overall Done (still progress...) --- app.js | 40 +++- controllers/aiController.js | 20 ++ controllers/chatController.js | 151 +++++++++++++++ controllers/userController.js | 5 + helpers/aiHelper.js | 36 ++++ helpers/aiRecommendation.js | 68 +++++++ helpers/authMiddleware.js | 3 +- helpers/jwt.js | 12 ++ models/chat.js | 2 +- package-lock.json | 341 ++++++++++++++++++++++++++++++---- package.json | 5 +- routes/aiRouter.js | 9 + routes/chatRouter.js | 23 +++ routes/index.js | 7 +- routes/userRouter.js | 1 + 15 files changed, 677 insertions(+), 46 deletions(-) create mode 100644 controllers/aiController.js create mode 100644 controllers/chatController.js create mode 100644 helpers/aiHelper.js create mode 100644 helpers/aiRecommendation.js create mode 100644 routes/aiRouter.js create mode 100644 routes/chatRouter.js diff --git a/app.js b/app.js index a1a8c1e..09e2a57 100644 --- a/app.js +++ b/app.js @@ -4,19 +4,45 @@ const app = express(); const port = process.env.PORT || 3000; const handleError = require('./helpers/handleError'); const routes = require('./routes'); +const cors = require('cors'); +const http = require('http'); +const server = http.createServer(app); +const { Server } = require("socket.io"); +const io = new Server(server, { + cors: { + origin: "*", + } +}); -//middleware +app.set('socketio', io); + +// Middleware +app.use(cors()); app.use(express.json()); app.use(express.urlencoded({ extended: true })); -//router +// Router app.use(routes); -//error handler +// Error handler app.use(handleError); -//server -app.listen(port, () => { - console.log(`Example app listening on port http://localhost:${port}`) -}) \ No newline at end of file +// Koneksi Socket.IO +io.on('connection', (socket) => { + // console.log(' User connected:', socket.id); + + socket.on('join_chat', (chatId) => { + socket.join(`chat_${chatId}`); + // console.log(`User ${socket.id} joined room: chat_${chatId}`); + }); + + socket.on('disconnect', () => { + // console.log(' User disconnected:', socket.id); + }); +}); + + +server.listen(port, () => { + console.log(`App listening on port http://localhost:${port}`); +}); \ No newline at end of file diff --git a/controllers/aiController.js b/controllers/aiController.js new file mode 100644 index 0000000..dc742aa --- /dev/null +++ b/controllers/aiController.js @@ -0,0 +1,20 @@ +const { getAIRecommendations } = require("../helpers/aiRecommendation"); + +class AIController { + static async getRecommendations(req, res, next) { + try { + const userId = req.user.id; + const posts = await getAIRecommendations(userId); + + res.json({ + message: "Rekomendasi berhasil dibuat", + count: posts.length, + data: posts, + }); + } catch (err) { + next(err); + } + } +} + +module.exports = AIController; \ No newline at end of file diff --git a/controllers/chatController.js b/controllers/chatController.js new file mode 100644 index 0000000..022fef8 --- /dev/null +++ b/controllers/chatController.js @@ -0,0 +1,151 @@ +const { Chat, Message, User, Sequelize } = require("../models"); +const { Op } = Sequelize; +const { askGemini } = require("../helpers/aiHelper"); + +class ChatController { + // Mencegah duplikasi chat + static async createOrGetChat(req, res, next) { + try { + const { partnerId } = req.body; + const userId = req.user.id; + + if (partnerId == userId) { // Validasi agar tidak chat dengan diri sendiri + throw { name: "BadRequest", message: "You cannot create a chat with yourself." }; + } + + // Cari chat yang sudah ada antara kedua user + const [chat, created] = await Chat.findOrCreate({ + where: { + [Op.or]: [ + { UserId: userId, partnerId: partnerId }, + { UserId: partnerId, partnerId: userId }, + ], + isAIChat: false + }, + defaults: { + UserId: userId, + partnerId: partnerId, + }, + }); + + res.status(created ? 201 : 200).json(chat); + } catch (err) { + next(err); + } + } + + // Menampilkan semua chat dimana user terlibat + static async getUserChats(req, res, next) { + try { + const userId = req.user.id; + const chats = await Chat.findAll({ + where: { + [Op.or]: [{ UserId: userId }, { partnerId: userId }], + }, + include: [ + { model: User, as: "creator", attributes: ["id", "username", "profilePic"] }, + { model: User, as: "partner", attributes: ["id", "username", "profilePic"] }, + ], + order: [["updatedAt", "DESC"]], + }); + + res.json(chats); + } catch (err) { + next(err); + } + } + + // Menambahkan validasi keamanan + static async getChatMessages(req, res, next) { + try { + const { chatId } = req.params; + const userId = req.user.id; + + // Validasi: Pastikan user adalah bagian dari chat ini + const chat = await Chat.findByPk(chatId); + if (!chat || (chat.UserId !== userId && chat.partnerId !== userId)) { + throw { name: "Forbidden" }; + } + + const messages = await Message.findAll({ + where: { ChatId: chatId }, + include: [{ model: User, as: "sender", attributes: ["id", "username"] }], + order: [["createdAt", "ASC"]], + }); + + res.json(messages); + } catch (err) { + next(err); + } + } + + static async createAIChat(req, res, next) { + try { + const userId = req.user.id; + const [chat, created] = await Chat.findOrCreate({ + where: { + UserId: userId, + isAIChat: true, + }, + defaults: { + UserId: userId, + isAIChat: true, + partnerId: null, // Tidak ada partner untuk AI chat + }, + }); + res.status(created ? 201 : 200).json(chat); + } catch (err) { + next(err); + } + } + + // Menambahkan validasi keamanan & menyederhanakan + static async sendMessage(req, res, next) { + try { + const { chatId } = req.params; + const { content } = req.body; + const userId = req.user.id; + const io = req.app.get("socketio"); + + const chat = await Chat.findByPk(chatId); + if (!chat) { + throw { name: "NotFound", message: "Chat not found" }; + } + + + // User harus menjadi pembuat atau partner dari chat tersebut. + const isAuthorized = chat.UserId === userId || chat.partnerId === userId; + if (!isAuthorized) { + throw { name: "Forbidden", message: "You are not authorized to access this chat" }; + } + + // 1. Simpan dan kirim pesan dari user + const userMessage = await Message.create({ + ChatId: chatId, + senderId: userId, + content, + }); + + io.to(`chat_${chatId}`).emit("receive_message", userMessage); + + if (chat.isAIChat) { + const aiResponseText = await askGemini(content); + + const aiMessage = await Message.create({ + ChatId: chatId, + senderId: null, + content: aiResponseText, + }); + + io.to(`chat_${chatId}`).emit("receive_message", aiMessage); + } + + await chat.save(); + res.status(201).json(userMessage); + } catch (err) { + next(err); + } + } +} + +module.exports = ChatController; \ No newline at end of file diff --git a/controllers/userController.js b/controllers/userController.js index a64c7b2..4fad517 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -1,6 +1,9 @@ const { User } = require('../models'); const bcrypt = require('bcryptjs'); const { signToken } = require('../helpers/jwt'); +const { OAuth2Client } = require('google-auth-library'); +const client = new OAuth2Client(); +const axios = require('axios'); class UserController { static async register(req, res, next) { @@ -70,6 +73,8 @@ class UserController { next(err); } } + + } module.exports = UserController; \ No newline at end of file diff --git a/helpers/aiHelper.js b/helpers/aiHelper.js new file mode 100644 index 0000000..351c42b --- /dev/null +++ b/helpers/aiHelper.js @@ -0,0 +1,36 @@ +const { GoogleGenerativeAI } = require("@google/generative-ai"); + +const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY); +const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" }); + +//cleaning text function +function cleanText(text = "") { + return text + // Hapus heading markdown dan pemisah + .replace(/^#+\s*/gm, "") + .replace(/---+/g, " ") + // Hapus bullet dan angka daftar + .replace(/^\s*\d+\.\s*/gm, "") + .replace(/^\s*-\s*/gm, "") + .replace(/\*/g, "") + // Hapus kutipan berlebih + .replace(/["โ€œโ€โ€˜โ€™]/g, '"') + // Rapikan whitespace + .replace(/\r?\n+/g, " ") + .replace(/\s{2,}/g, " ") + .trim(); +} + + +async function askGemini(prompt) { + try { + const result = await model.generateContent(prompt); + const rawText = result.response.text(); + return cleanText(rawText); + } catch (err) { + console.error("โŒ Error from Gemini:", err); + return "Maaf, saya mengalami kesulitan menjawab saat ini."; + } +} + +module.exports = { askGemini }; diff --git a/helpers/aiRecommendation.js b/helpers/aiRecommendation.js new file mode 100644 index 0000000..7f37e4a --- /dev/null +++ b/helpers/aiRecommendation.js @@ -0,0 +1,68 @@ +const { GoogleGenerativeAI } = require("@google/generative-ai"); +const { Post, Like, Category, User } = require("../models"); +const { Op } = require("sequelize"); + +const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY); +const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" }); + +async function getAIRecommendations(userId) { + try { + const likedPosts = await Like.findAll({ + where: { UserId: userId }, + include: [{ model: Post, include: [Category] }], + }); + + if (likedPosts.length < 3) { //minimal 3 likes + return Post.findAll({ + where: { isPrivate: false }, + include: [Category, User, Like], + order: [["createdAt", "DESC"]], + limit: 10, + }); + } + + const userInterests = likedPosts + .map((l) => `- "${l.Post.content}" (Kategori: ${l.Post.Category?.name || "Umum"})`) + .join("\n"); + + const prompt = ` + Anda adalah sistem rekomendasi konten yang cerdas untuk aplikasi media sosial. + Seorang pengguna menyukai postingan-postingan berikut: + ${userInterests} + + Berdasarkan daftar di atas, berikan 3 tampilan kategori yang paling relevan dengan minat pengguna. + Balas HANYA dengan nama kategori, dipisahkan oleh koma (contoh: Teknologi, Makanan, Olahraga). + `; + + const result = await model.generateContent(prompt); + const categoriesText = result.response.text(); + const categories = categoriesText.split(",").map((c) => c.trim()); + + const recommendedPosts = await Post.findAll({ + where: { + isPrivate: false, + UserId: { [Op.ne]: userId }, // Jangan tampilkan post milik sendiri + }, + include: [ + { model: Category, where: { name: { [Op.in]: categories } } }, + User, + Like, + ], + order: [["createdAt", "DESC"]], + limit: 20, + }); + + return recommendedPosts; + } catch (err) { + console.error("Error getting AI recommendations:", err); + // Jika AI gagal, berikan rekomendasi default (post publik terbaru) + return Post.findAll({ + where: { isPrivate: false }, + include: [Category, User, Like], + order: [["createdAt", "DESC"]], + limit: 10, + }); + } +} + +module.exports = { getAIRecommendations }; \ No newline at end of file diff --git a/helpers/authMiddleware.js b/helpers/authMiddleware.js index 6c5039a..df1aeb8 100644 --- a/helpers/authMiddleware.js +++ b/helpers/authMiddleware.js @@ -9,11 +9,10 @@ module.exports = async function authMiddleware(req, res, next) { const decoded = verifyToken(token); const user = await User.findByPk(decoded.id); if (!user) throw { name: "Unauthorized" }; - req.user = user; next(); } catch (err) { console.error(err); - res.status(401).json({ message: "Unauthorized access" }); + next(err); } }; diff --git a/helpers/jwt.js b/helpers/jwt.js index e69de29..ad7373b 100644 --- a/helpers/jwt.js +++ b/helpers/jwt.js @@ -0,0 +1,12 @@ +const jwt = require('jsonwebtoken'); +const secret = process.env.JWT_SECRET; + +function signToken(payload) { + return jwt.sign(payload, secret); +} + +function verifyToken(token) { + return jwt.verify(token, secret); +} + +module.exports = { signToken, verifyToken }; \ No newline at end of file diff --git a/models/chat.js b/models/chat.js index bb8aa6b..2c17896 100644 --- a/models/chat.js +++ b/models/chat.js @@ -10,7 +10,7 @@ module.exports = (sequelize, DataTypes) => { * The `models/index` file will call this method automatically. */ static associate(models) { - Chat.belongsTo(models.User, { as: "user", foreignKey: "UserId" }); + Chat.belongsTo(models.User, { as: "creator", foreignKey: "UserId" }); Chat.belongsTo(models.User, { as: "partner", foreignKey: "partnerId" }); Chat.hasMany(models.Message); } diff --git a/package-lock.json b/package-lock.json index 1a881dc..9b26423 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,14 +9,16 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "bcrypt": "^6.0.0", + "@google/generative-ai": "^0.24.1", "bcryptjs": "^3.0.2", - "cloudinary": "^2.7.0", + "cloudinary": "^1.41.3", "cors": "^2.8.5", "dotenv": "^17.2.3", "express": "^5.1.0", + "google-auth-library": "^10.4.0", "jsonwebtoken": "^9.0.2", "multer": "^2.0.2", + "multer-storage-cloudinary": "^4.0.0", "passport": "^0.7.0", "passport-google-oauth20": "^2.0.0", "pg": "^8.16.3", @@ -29,6 +31,15 @@ "sequelize-cli": "^6.6.3" } }, + "node_modules/@google/generative-ai": { + "version": "0.24.1", + "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz", + "integrity": "sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -133,6 +144,15 @@ "node": ">= 0.6" } }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/ansi-regex": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", @@ -196,6 +216,26 @@ "dev": true, "license": "MIT" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", @@ -214,20 +254,6 @@ "node": ">=6.0.0" } }, - "node_modules/bcrypt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz", - "integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "node-addon-api": "^8.3.0", - "node-gyp-build": "^4.8.4" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/bcryptjs": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", @@ -237,6 +263,15 @@ "bcrypt": "bin/bcrypt" } }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -479,16 +514,27 @@ } }, "node_modules/cloudinary": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-2.7.0.tgz", - "integrity": "sha512-qrqDn31+qkMCzKu1GfRpzPNAO86jchcNwEHCUiqvPHNSFqu7FTNF9FuAkBUyvM1CFFgFPu64NT0DyeREwLwK0w==", + "version": "1.41.3", + "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-1.41.3.tgz", + "integrity": "sha512-4o84y+E7dbif3lMns+p3UW6w6hLHEifbX/7zBJvaih1E9QNMZITENQ14GPYJC4JmhygYXsuuBb9bRA3xWEoOfg==", "license": "MIT", "dependencies": { + "cloudinary-core": "^2.13.0", + "core-js": "^3.30.1", "lodash": "^4.17.21", "q": "^1.5.1" }, "engines": { - "node": ">=9" + "node": ">=0.6" + } + }, + "node_modules/cloudinary-core": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/cloudinary-core/-/cloudinary-core-2.14.0.tgz", + "integrity": "sha512-L+kjoYgU+5wyiPkSnmeCbmtT6DwSyYUN/WoI/fEb6Xsx2gtB3iuf/50W0SvcQkeKzllfH5Knh8I4ST924DkkRw==", + "license": "MIT", + "peerDependencies": { + "lodash": ">=4.0" } }, "node_modules/color-convert": { @@ -593,6 +639,17 @@ "node": ">=6.6.0" } }, + "node_modules/core-js": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz", + "integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", @@ -621,6 +678,15 @@ "node": ">= 8" } }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -948,6 +1014,35 @@ "url": "https://opencollective.com/express" } }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -995,6 +1090,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1053,6 +1160,34 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gaxios": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.2.tgz", + "integrity": "sha512-/Szrn8nr+2TsQT1Gp8iIe/BEytJmbyfrbFh419DfGQSkEgNEhbPi7JRJuughjkTzPWgU9gBQf5AVu3DbHt0OXA==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gcp-metadata": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-7.0.1.tgz", + "integrity": "sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -1160,6 +1295,54 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/google-auth-library": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.4.0.tgz", + "integrity": "sha512-CmIrSy1bqMQUsPmA9+hcSbAXL80cFhu40cGMUjCaLpNKVzzvi+0uAHq8GNZxkoGYIsTX4ZQ7e4aInAqWxgn4fg==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.0.0", + "gcp-metadata": "^7.0.0", + "google-logging-utils": "^1.0.0", + "gtoken": "^8.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-auth-library/node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/google-auth-library/node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/google-logging-utils": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.1.tgz", + "integrity": "sha512-rcX58I7nqpu4mbKztFeOAObbomBbHU2oIb/d3tJfF3dizGSApqtSwYJigGCooHdnMyQBIw8BrWyK96w3YXgr6A==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -1179,6 +1362,40 @@ "dev": true, "license": "ISC" }, + "node_modules/gtoken": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz", + "integrity": "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==", + "license": "MIT", + "dependencies": { + "gaxios": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gtoken/node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/gtoken/node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -1238,6 +1455,19 @@ "node": ">= 0.8" } }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -1421,6 +1651,15 @@ "node": ">=14" } }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, "node_modules/jsonfile": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", @@ -1672,6 +1911,15 @@ "node": ">= 10.16.0" } }, + "node_modules/multer-storage-cloudinary": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/multer-storage-cloudinary/-/multer-storage-cloudinary-4.0.0.tgz", + "integrity": "sha512-25lm9R6o5dWrHLqLvygNX+kBOxprzpmZdnVKH4+r68WcfCt8XV6xfQaMuAg+kUE5Xmr8mJNA4gE0AcBj9FJyWA==", + "license": "MIT", + "peerDependencies": { + "cloudinary": "^1.21.0" + } + }, "node_modules/multer/node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -1724,24 +1972,42 @@ "node": ">= 0.6" } }, - "node_modules/node-addon-api": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.5.0.tgz", - "integrity": "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==", + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], "license": "MIT", "engines": { - "node": "^18 || ^20 || >= 21" + "node": ">=10.5.0" } }, - "node_modules/node-gyp-build": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, "node_modules/nodemon": { @@ -3056,6 +3322,15 @@ "node": ">= 0.8" } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index c4e0744..5054d8f 100644 --- a/package.json +++ b/package.json @@ -18,13 +18,16 @@ }, "homepage": "https://github.com/Joshua080324/Dummy-Instagram#readme", "dependencies": { + "@google/generative-ai": "^0.24.1", "bcryptjs": "^3.0.2", - "cloudinary": "^2.7.0", + "cloudinary": "^1.41.3", "cors": "^2.8.5", "dotenv": "^17.2.3", "express": "^5.1.0", + "google-auth-library": "^10.4.0", "jsonwebtoken": "^9.0.2", "multer": "^2.0.2", + "multer-storage-cloudinary": "^4.0.0", "passport": "^0.7.0", "passport-google-oauth20": "^2.0.0", "pg": "^8.16.3", diff --git a/routes/aiRouter.js b/routes/aiRouter.js new file mode 100644 index 0000000..1162469 --- /dev/null +++ b/routes/aiRouter.js @@ -0,0 +1,9 @@ +const express = require('express'); +const router = express.Router(); +const AIController = require('../controllers/aiController'); +const auth = require('../helpers/authMiddleware'); + +// Endpoint untuk mendapatkan rekomendasi post +router.get('/recommendations', auth, AIController.getRecommendations); + +module.exports = router; \ No newline at end of file diff --git a/routes/chatRouter.js b/routes/chatRouter.js new file mode 100644 index 0000000..f00586b --- /dev/null +++ b/routes/chatRouter.js @@ -0,0 +1,23 @@ +const express = require('express'); +const router = express.Router(); +const ChatController = require('../controllers/chatController'); +const auth = require('../helpers/authMiddleware'); + +router.use(auth); + +// Membuat chat AI +router.post('/ai', ChatController.createAIChat); + +// Membuat atau mendapatkan chat dengan user lain +router.post('/', ChatController.createOrGetChat); + +// Mendapatkan semua chat milik user yang sedang login +router.get('/', ChatController.getUserChats); + +// Mendapatkan semua pesan dalam sebuah chat +router.get('/:chatId/messages', ChatController.getChatMessages); + +// Mengirim pesan ke sebuah chat +router.post('/:chatId/messages', ChatController.sendMessage); + +module.exports = router; \ No newline at end of file diff --git a/routes/index.js b/routes/index.js index dd0f9ff..af879df 100644 --- a/routes/index.js +++ b/routes/index.js @@ -1,11 +1,14 @@ const express = require('express'); const router = express.Router(); - -const userRouter = require('./userRouter'); +const userRouter = require('./userRouter'); const postRouter = require('./postRouter'); +const chatRouter = require('./chatRouter'); +const aiRouter = require('./aiRouter'); router.use('/users', userRouter); router.use('/posts', postRouter); +router.use('/chats', chatRouter); +router.use('/ai', aiRouter); module.exports = router; \ No newline at end of file diff --git a/routes/userRouter.js b/routes/userRouter.js index f6f7abb..6fb928b 100644 --- a/routes/userRouter.js +++ b/routes/userRouter.js @@ -6,4 +6,5 @@ router.post('/register', UserController.register); router.post('/login', UserController.login); router.post('/auth/google', UserController.googleSignIn); + module.exports = router; \ No newline at end of file From 65c55610116bdfcc27376f6f62f1d53d29174887 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Wed, 15 Oct 2025 11:05:56 +0700 Subject: [PATCH 08/62] Debug UserController --- controllers/userController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/userController.js b/controllers/userController.js index 4fad517..4c54b3f 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -3,7 +3,7 @@ const bcrypt = require('bcryptjs'); const { signToken } = require('../helpers/jwt'); const { OAuth2Client } = require('google-auth-library'); const client = new OAuth2Client(); -const axios = require('axios'); + class UserController { static async register(req, res, next) { From 1fc1d237344f78d0d18a0c147cba7456798652b5 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Wed, 15 Oct 2025 13:03:08 +0700 Subject: [PATCH 09/62] fix bug & create testing --- app.js | 8 +- config/config.js | 28 +- config/simpleJestReporter.js | 33 + controllers/aiController.js | 9 +- controllers/postController.js | 218 +- coverage/clover.xml | 313 + coverage/coverage-final.json | 17 + coverage/lcov-report/aiController.js.html | 142 + coverage/lcov-report/base.css | 224 + coverage/lcov-report/block-navigation.js | 87 + coverage/lcov-report/chatController.js.html | 535 ++ coverage/lcov-report/config/config.js.html | 175 + coverage/lcov-report/config/index.html | 116 + .../controllers/aiController.js.html | 160 + .../controllers/chatController.js.html | 535 ++ coverage/lcov-report/controllers/index.html | 161 + .../controllers/postController.js.html | 451 ++ .../controllers/userController.js.html | 322 + coverage/lcov-report/favicon.png | Bin 0 -> 445 bytes coverage/lcov-report/helpers/aiHelper.js.html | 193 + .../helpers/aiRecommendation.js.html | 286 + coverage/lcov-report/helpers/index.html | 146 + coverage/lcov-report/helpers/jwt.js.html | 118 + coverage/lcov-report/index.html | 161 + coverage/lcov-report/models/category.js.html | 154 + coverage/lcov-report/models/chat.js.html | 166 + coverage/lcov-report/models/image.js.html | 157 + coverage/lcov-report/models/index.html | 221 + coverage/lcov-report/models/index.js.html | 214 + coverage/lcov-report/models/like.js.html | 160 + coverage/lcov-report/models/message.js.html | 172 + coverage/lcov-report/models/post.js.html | 205 + coverage/lcov-report/models/user.js.html | 274 + coverage/lcov-report/postController.js.html | 451 ++ coverage/lcov-report/prettify.css | 1 + coverage/lcov-report/prettify.js | 2 + coverage/lcov-report/sort-arrow-sprite.png | Bin 0 -> 138 bytes coverage/lcov-report/sorter.js | 210 + coverage/lcov-report/userController.js.html | 322 + coverage/lcov.info | 549 ++ package-lock.json | 5964 ++++++++++++++--- package.json | 13 +- tests/unit/aiController.test.js | 76 + tests/unit/chatController.test.js | 156 + tests/unit/postController.test.js | 178 + tests/unit/userController.error.test.js | 20 + 46 files changed, 12943 insertions(+), 1160 deletions(-) create mode 100644 config/simpleJestReporter.js create mode 100644 coverage/clover.xml create mode 100644 coverage/coverage-final.json create mode 100644 coverage/lcov-report/aiController.js.html create mode 100644 coverage/lcov-report/base.css create mode 100644 coverage/lcov-report/block-navigation.js create mode 100644 coverage/lcov-report/chatController.js.html create mode 100644 coverage/lcov-report/config/config.js.html create mode 100644 coverage/lcov-report/config/index.html create mode 100644 coverage/lcov-report/controllers/aiController.js.html create mode 100644 coverage/lcov-report/controllers/chatController.js.html create mode 100644 coverage/lcov-report/controllers/index.html create mode 100644 coverage/lcov-report/controllers/postController.js.html create mode 100644 coverage/lcov-report/controllers/userController.js.html create mode 100644 coverage/lcov-report/favicon.png create mode 100644 coverage/lcov-report/helpers/aiHelper.js.html create mode 100644 coverage/lcov-report/helpers/aiRecommendation.js.html create mode 100644 coverage/lcov-report/helpers/index.html create mode 100644 coverage/lcov-report/helpers/jwt.js.html create mode 100644 coverage/lcov-report/index.html create mode 100644 coverage/lcov-report/models/category.js.html create mode 100644 coverage/lcov-report/models/chat.js.html create mode 100644 coverage/lcov-report/models/image.js.html create mode 100644 coverage/lcov-report/models/index.html create mode 100644 coverage/lcov-report/models/index.js.html create mode 100644 coverage/lcov-report/models/like.js.html create mode 100644 coverage/lcov-report/models/message.js.html create mode 100644 coverage/lcov-report/models/post.js.html create mode 100644 coverage/lcov-report/models/user.js.html create mode 100644 coverage/lcov-report/postController.js.html create mode 100644 coverage/lcov-report/prettify.css create mode 100644 coverage/lcov-report/prettify.js create mode 100644 coverage/lcov-report/sort-arrow-sprite.png create mode 100644 coverage/lcov-report/sorter.js create mode 100644 coverage/lcov-report/userController.js.html create mode 100644 coverage/lcov.info create mode 100644 tests/unit/aiController.test.js create mode 100644 tests/unit/chatController.test.js create mode 100644 tests/unit/postController.test.js create mode 100644 tests/unit/userController.error.test.js diff --git a/app.js b/app.js index 09e2a57..4f6ad2a 100644 --- a/app.js +++ b/app.js @@ -28,17 +28,17 @@ app.use(routes); // Error handler app.use(handleError); -// Koneksi Socket.IO +// +++ Logika koneksi Socket.IO +++ io.on('connection', (socket) => { - // console.log(' User connected:', socket.id); + console.log('โœ… User connected:', socket.id); socket.on('join_chat', (chatId) => { socket.join(`chat_${chatId}`); - // console.log(`User ${socket.id} joined room: chat_${chatId}`); + console.log(`User ${socket.id} joined room: chat_${chatId}`); }); socket.on('disconnect', () => { - // console.log(' User disconnected:', socket.id); + console.log('โŒ User disconnected:', socket.id); }); }); diff --git a/config/config.js b/config/config.js index a61105d..bb238f7 100644 --- a/config/config.js +++ b/config/config.js @@ -1,16 +1,30 @@ -require("dotenv").config(); +/** + * Sequelize configuration file + * Provides sensible defaults for development/test/production + * Uses environment variables when available so CI/production can override. + */ module.exports = { development: { - url: process.env.DATABASE_URL, - dialect: "postgres", + // Use single env var 'db' as connection URL for now (e.g. postgres://user:pass@host:port/db) + url: process.env.db || null, + dialect: 'postgres', + logging: false, + define: { timestamps: true }, + dialectOptions: process.env.DB_SSL === 'true' ? { ssl: { rejectUnauthorized: false } } : {}, }, + test: { - url: process.env.DATABASE_URL, - dialect: "postgres", + url: process.env.db || null, + dialect: 'postgres', + logging: false, + dialectOptions: process.env.DB_SSL === 'true' ? { ssl: { rejectUnauthorized: false } } : {}, }, + production: { - url: process.env.DATABASE_URL, - dialect: "postgres", + url: process.env.db || null, + dialect: 'postgres', + logging: false, + dialectOptions: process.env.DB_SSL === 'true' ? { ssl: { rejectUnauthorized: false } } : {}, }, }; diff --git a/config/simpleJestReporter.js b/config/simpleJestReporter.js new file mode 100644 index 0000000..5eb969c --- /dev/null +++ b/config/simpleJestReporter.js @@ -0,0 +1,33 @@ +class SimpleJestReporter { + constructor(globalConfig, options) { + this._globalConfig = globalConfig; + this._options = options; + this.passed = []; + } + + onTestResult(test, testResult) { + testResult.testResults.forEach((assertion) => { + if (assertion.status === 'passed') { + this.passed.push({ fullName: assertion.fullName, file: testResult.testFilePath }); + } + }); + } + + onRunComplete(contexts, results) { + console.log('\n=== Ringkasan Test (passed) ==='); + if (this.passed.length === 0) { + console.log('Tidak ada test yang lulus.'); + } else { + this.passed.forEach((p) => { + console.log(`- ${p.fullName}`); + }); + } + console.log(`\nTotal: ${results.numPassedTests} passed, ${results.numTotalTests} total`); + // print failed tests briefly + if (results.numFailedTests > 0) { + console.log(`\nFailed: ${results.numFailedTests} tests. Lihat output lengkap dengan --reporters=default atau jalankan 'npm run test:coverage'.`); + } + } +} + +module.exports = SimpleJestReporter; diff --git a/controllers/aiController.js b/controllers/aiController.js index dc742aa..9ba5bec 100644 --- a/controllers/aiController.js +++ b/controllers/aiController.js @@ -3,10 +3,15 @@ const { getAIRecommendations } = require("../helpers/aiRecommendation"); class AIController { static async getRecommendations(req, res, next) { try { + + if (!req.user || !req.user.id) { + throw { name: "Unauthorized" }; + } + const userId = req.user.id; const posts = await getAIRecommendations(userId); - res.json({ + res.status(200).json({ message: "Rekomendasi berhasil dibuat", count: posts.length, data: posts, @@ -17,4 +22,4 @@ class AIController { } } -module.exports = AIController; \ No newline at end of file +module.exports = AIController; diff --git a/controllers/postController.js b/controllers/postController.js index 120c113..35a984f 100644 --- a/controllers/postController.js +++ b/controllers/postController.js @@ -1,123 +1,127 @@ const { Post, Image, Like, User, Category } = require("../models"); class PostController { - // CREATE POST - static async createPost(req, res, next) { - try { - const { content, isPrivate, categoryId } = req.body; - - // Buat post baru - const post = await Post.create({ - content, - isPrivate, - CategoryId: categoryId || null, - UserId: req.user.id, - }); - - // Jika ada file yang di-upload, simpan URL-nya - if (req.files && req.files.length > 0) { - const images = req.files.map((file) => ({ - imageUrl: file.path, // multer-storage-cloudinary menyediakan URL di file.path - PostId: post.id, - })); - await Image.bulkCreate(images); - } - - res.status(201).json({ message: "Post created successfully", post }); - } catch (err) { - next(err); - } + // CREATE POST + static async createPost(req, res, next) { + try { + const { content, isPrivate, categoryId } = req.body; + + // Validation: make sure there is at least 1 image + if (!req.files || req.files.length === 0) { + throw { name: "BadRequest", message: "At least one image is required to create a post." }; + } + + // Create a new post + const post = await Post.create({ + content, + isPrivate, + CategoryId: categoryId || null, + UserId: req.user.id, + }); + + // Save all images to the Image table + const images = req.files.map((file) => ({ + imageUrl: file.path, + PostId: post.id, + })); + + await Image.bulkCreate(images); + + res.status(201).json({ message: "Post created successfully", post }); + } catch (err) { + next(err); } + } - // READ ALL PUBLIC POSTS - static async getAllPublicPosts(req, res, next) { - try { - const posts = await Post.findAll({ - where: { isPrivate: false }, - include: [ - { model: User, attributes: ["id", "username", "profilePic"] }, - { model: Image }, - { model: Category, attributes: ["name"] }, - { model: Like }, - ], - order: [["createdAt", "DESC"]], - }); - res.json(posts); - } catch (err) { - next(err); - } + // READ ALL PUBLIC POSTS + static async getAllPublicPosts(req, res, next) { + try { + const posts = await Post.findAll({ + where: { isPrivate: false }, + include: [ + { model: User, attributes: ["id", "username", "profilePic"] }, + { model: Image }, + { model: Category, attributes: ["name"] }, + { model: Like }, + ], + order: [["createdAt", "DESC"]], + }); + res.json(posts); + } catch (err) { + next(err); } + } - // READ USER'S OWN POSTS - static async getMyPosts(req, res, next) { - try { - const posts = await Post.findAll({ - where: { UserId: req.user.id }, - include: [Image, Category, Like], - order: [["createdAt", "DESC"]], - }); - res.json(posts); - } catch (err) { - next(err); - } + // READ USER'S OWN POSTS + static async getMyPosts(req, res, next) { + try { + const posts = await Post.findAll({ + where: { UserId: req.user.id }, + include: [Image, Category, Like], + order: [["createdAt", "DESC"]], + }); + res.json(posts); + } catch (err) { + next(err); } + } - // UPDATE POST - static async updatePost(req, res, next) { - try { - const { id } = req.params; - const { content, isPrivate, categoryId } = req.body; - - const post = await Post.findByPk(id); - if (!post) throw { name: "NotFound" }; - if (post.UserId !== req.user.id) throw { name: "Unauthorized" }; - - await post.update({ content, isPrivate, CategoryId: categoryId }); - res.json({ message: "Post updated successfully", post }); - } catch (err) { - next(err); - } + // UPDATE POST + static async updatePost(req, res, next) { + try { + const { id } = req.params; + const { content, isPrivate, categoryId } = req.body; + + const post = await Post.findByPk(id); + if (!post) throw { name: "NotFound" }; + if (post.UserId !== req.user.id) throw { name: "Unauthorized" }; + + await post.update({ content, isPrivate, CategoryId: categoryId }); + res.json({ message: "Post updated successfully", post }); + } catch (err) { + next(err); } + } + + // DELETE POST + static async deletePost(req, res, next) { + try { + const { id } = req.params; + const post = await Post.findByPk(id); + if (!post) throw { name: "NotFound" }; + if (post.UserId !== req.user.id) throw { name: "Unauthorized" }; - // DELETE POST - static async deletePost(req, res, next) { - try { - const { id } = req.params; - const post = await Post.findByPk(id); - if (!post) throw { name: "NotFound" }; - if (post.UserId !== req.user.id) throw { name: "Unauthorized" }; - - await post.destroy(); - res.json({ message: "Post deleted successfully" }); - } catch (err) { - next(err); - } + await post.destroy(); + res.json({ message: "Post deleted successfully" }); + } catch (err) { + next(err); } + } + + // LIKE / UNLIKE POST + static async toggleLike(req, res, next) { + try { + const { id } = req.params; + const post = await Post.findByPk(id); + if (!post) throw { name: "NotFound" }; + + const existingLike = await Like.findOne({ + where: { UserId: req.user.id, PostId: id }, + }); - // LIKE / UNLIKE POST - static async toggleLike(req, res, next) { - try { - const { id } = req.params; - const post = await Post.findByPk(id); - if (!post) throw { name: "NotFound" }; - - const existingLike = await Like.findOne({ - where: { UserId: req.user.id, PostId: id }, - }); - - let message; - if (existingLike) { - await existingLike.destroy(); - message = "Post unliked"; - } else { - await Like.create({ UserId: req.user.id, PostId: id }); - message = "Post liked"; - } - res.json({ message }); - } catch (err) { - next(err); - } + let message; + if (existingLike) { + await existingLike.destroy(); + message = "Post unliked"; + } else { + await Like.create({ UserId: req.user.id, PostId: id }); + message = "Post liked"; + } + res.json({ message }); + } catch (err) { + next(err); } + } } -module.exports = PostController; \ No newline at end of file +module.exports = PostController; diff --git a/coverage/clover.xml b/coverage/clover.xml new file mode 100644 index 0000000..59359f5 --- /dev/null +++ b/coverage/clover.xml @@ -0,0 +1,313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/coverage/coverage-final.json b/coverage/coverage-final.json new file mode 100644 index 0000000..174468c --- /dev/null +++ b/coverage/coverage-final.json @@ -0,0 +1,17 @@ +{"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\config\\config.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\config\\config.js","statementMap":{"0":{"start":{"line":7,"column":0},"end":{"line":30,"column":2}}},"fnMap":{},"branchMap":{"0":{"loc":{"start":{"line":10,"column":9},"end":{"line":10,"column":31}},"type":"binary-expr","locations":[{"start":{"line":10,"column":9},"end":{"line":10,"column":23}},{"start":{"line":10,"column":27},"end":{"line":10,"column":31}}],"line":10},"1":{"loc":{"start":{"line":14,"column":20},"end":{"line":14,"column":95}},"type":"cond-expr","locations":[{"start":{"line":14,"column":52},"end":{"line":14,"column":90}},{"start":{"line":14,"column":93},"end":{"line":14,"column":95}}],"line":14},"2":{"loc":{"start":{"line":18,"column":9},"end":{"line":18,"column":31}},"type":"binary-expr","locations":[{"start":{"line":18,"column":9},"end":{"line":18,"column":23}},{"start":{"line":18,"column":27},"end":{"line":18,"column":31}}],"line":18},"3":{"loc":{"start":{"line":21,"column":20},"end":{"line":21,"column":95}},"type":"cond-expr","locations":[{"start":{"line":21,"column":52},"end":{"line":21,"column":90}},{"start":{"line":21,"column":93},"end":{"line":21,"column":95}}],"line":21},"4":{"loc":{"start":{"line":25,"column":9},"end":{"line":25,"column":31}},"type":"binary-expr","locations":[{"start":{"line":25,"column":9},"end":{"line":25,"column":23}},{"start":{"line":25,"column":27},"end":{"line":25,"column":31}}],"line":25},"5":{"loc":{"start":{"line":28,"column":20},"end":{"line":28,"column":95}},"type":"cond-expr","locations":[{"start":{"line":28,"column":52},"end":{"line":28,"column":90}},{"start":{"line":28,"column":93},"end":{"line":28,"column":95}}],"line":28}},"s":{"0":1},"f":{},"b":{"0":[1,1],"1":[0,1],"2":[1,1],"3":[0,1],"4":[1,1],"5":[0,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"bec8f2a99a18a70f3b396d89e4fed820a24144aa"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js","statementMap":{"0":{"start":{"line":1,"column":33},"end":{"line":1,"column":71}},"1":{"start":{"line":5,"column":4},"end":{"line":21,"column":5}},"2":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"3":{"start":{"line":8,"column":8},"end":{"line":8,"column":39}},"4":{"start":{"line":11,"column":21},"end":{"line":11,"column":32}},"5":{"start":{"line":12,"column":20},"end":{"line":12,"column":54}},"6":{"start":{"line":14,"column":6},"end":{"line":18,"column":9}},"7":{"start":{"line":20,"column":6},"end":{"line":20,"column":16}},"8":{"start":{"line":25,"column":0},"end":{"line":25,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":4,"column":2},"end":{"line":4,"column":3}},"loc":{"start":{"line":4,"column":50},"end":{"line":22,"column":3}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"type":"if","locations":[{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":10},"end":{"line":7,"column":35}},"type":"binary-expr","locations":[{"start":{"line":7,"column":10},"end":{"line":7,"column":19}},{"start":{"line":7,"column":23},"end":{"line":7,"column":35}}],"line":7}},"s":{"0":1,"1":4,"2":4,"3":1,"4":3,"5":3,"6":2,"7":2,"8":1},"f":{"0":4},"b":{"0":[1,3],"1":[4,3]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"5a3a8d6179df7a779a1e7786dcd48a5a6657888b"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js","statementMap":{"0":{"start":{"line":1,"column":43},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":24}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":52}},"3":{"start":{"line":8,"column":8},"end":{"line":34,"column":9}},"4":{"start":{"line":9,"column":34},"end":{"line":9,"column":42}},"5":{"start":{"line":10,"column":27},"end":{"line":10,"column":38}},"6":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"7":{"start":{"line":13,"column":16},"end":{"line":13,"column":97}},"8":{"start":{"line":17,"column":36},"end":{"line":29,"column":14}},"9":{"start":{"line":31,"column":12},"end":{"line":31,"column":55}},"10":{"start":{"line":33,"column":12},"end":{"line":33,"column":22}},"11":{"start":{"line":39,"column":8},"end":{"line":55,"column":9}},"12":{"start":{"line":40,"column":27},"end":{"line":40,"column":38}},"13":{"start":{"line":41,"column":26},"end":{"line":50,"column":14}},"14":{"start":{"line":52,"column":12},"end":{"line":52,"column":28}},"15":{"start":{"line":54,"column":12},"end":{"line":54,"column":22}},"16":{"start":{"line":60,"column":8},"end":{"line":79,"column":9}},"17":{"start":{"line":61,"column":31},"end":{"line":61,"column":41}},"18":{"start":{"line":62,"column":27},"end":{"line":62,"column":38}},"19":{"start":{"line":65,"column":25},"end":{"line":65,"column":52}},"20":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"21":{"start":{"line":67,"column":16},"end":{"line":67,"column":44}},"22":{"start":{"line":70,"column":29},"end":{"line":74,"column":14}},"23":{"start":{"line":76,"column":12},"end":{"line":76,"column":31}},"24":{"start":{"line":78,"column":12},"end":{"line":78,"column":22}},"25":{"start":{"line":83,"column":8},"end":{"line":99,"column":9}},"26":{"start":{"line":84,"column":27},"end":{"line":84,"column":38}},"27":{"start":{"line":85,"column":36},"end":{"line":95,"column":14}},"28":{"start":{"line":96,"column":12},"end":{"line":96,"column":55}},"29":{"start":{"line":98,"column":12},"end":{"line":98,"column":22}},"30":{"start":{"line":104,"column":8},"end":{"line":147,"column":9}},"31":{"start":{"line":105,"column":31},"end":{"line":105,"column":41}},"32":{"start":{"line":106,"column":32},"end":{"line":106,"column":40}},"33":{"start":{"line":107,"column":27},"end":{"line":107,"column":38}},"34":{"start":{"line":108,"column":23},"end":{"line":108,"column":46}},"35":{"start":{"line":110,"column":25},"end":{"line":110,"column":52}},"36":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"37":{"start":{"line":112,"column":16},"end":{"line":112,"column":70}},"38":{"start":{"line":117,"column":33},"end":{"line":117,"column":84}},"39":{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},"40":{"start":{"line":119,"column":16},"end":{"line":119,"column":99}},"41":{"start":{"line":123,"column":32},"end":{"line":127,"column":14}},"42":{"start":{"line":129,"column":12},"end":{"line":129,"column":73}},"43":{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},"44":{"start":{"line":132,"column":39},"end":{"line":132,"column":63}},"45":{"start":{"line":134,"column":34},"end":{"line":138,"column":18}},"46":{"start":{"line":140,"column":16},"end":{"line":140,"column":75}},"47":{"start":{"line":143,"column":12},"end":{"line":143,"column":30}},"48":{"start":{"line":144,"column":12},"end":{"line":144,"column":46}},"49":{"start":{"line":146,"column":12},"end":{"line":146,"column":22}},"50":{"start":{"line":151,"column":0},"end":{"line":151,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":4},"end":{"line":7,"column":5}},"loc":{"start":{"line":7,"column":49},"end":{"line":35,"column":5}},"line":7},"1":{"name":"(anonymous_1)","decl":{"start":{"line":38,"column":4},"end":{"line":38,"column":5}},"loc":{"start":{"line":38,"column":46},"end":{"line":56,"column":5}},"line":38},"2":{"name":"(anonymous_2)","decl":{"start":{"line":59,"column":4},"end":{"line":59,"column":5}},"loc":{"start":{"line":59,"column":49},"end":{"line":80,"column":5}},"line":59},"3":{"name":"(anonymous_3)","decl":{"start":{"line":82,"column":4},"end":{"line":82,"column":5}},"loc":{"start":{"line":82,"column":46},"end":{"line":100,"column":5}},"line":82},"4":{"name":"(anonymous_4)","decl":{"start":{"line":103,"column":4},"end":{"line":103,"column":5}},"loc":{"start":{"line":103,"column":45},"end":{"line":148,"column":5}},"line":103}},"branchMap":{"0":{"loc":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"type":"if","locations":[{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},{"start":{},"end":{}}],"line":12},"1":{"loc":{"start":{"line":31,"column":23},"end":{"line":31,"column":42}},"type":"cond-expr","locations":[{"start":{"line":31,"column":33},"end":{"line":31,"column":36}},{"start":{"line":31,"column":39},"end":{"line":31,"column":42}}],"line":31},"2":{"loc":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"type":"if","locations":[{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},{"start":{},"end":{}}],"line":66},"3":{"loc":{"start":{"line":66,"column":16},"end":{"line":66,"column":78}},"type":"binary-expr","locations":[{"start":{"line":66,"column":16},"end":{"line":66,"column":21}},{"start":{"line":66,"column":26},"end":{"line":66,"column":48}},{"start":{"line":66,"column":52},"end":{"line":66,"column":77}}],"line":66},"4":{"loc":{"start":{"line":96,"column":23},"end":{"line":96,"column":42}},"type":"cond-expr","locations":[{"start":{"line":96,"column":33},"end":{"line":96,"column":36}},{"start":{"line":96,"column":39},"end":{"line":96,"column":42}}],"line":96},"5":{"loc":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"type":"if","locations":[{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},{"start":{},"end":{}}],"line":111},"6":{"loc":{"start":{"line":117,"column":33},"end":{"line":117,"column":84}},"type":"binary-expr","locations":[{"start":{"line":117,"column":33},"end":{"line":117,"column":55}},{"start":{"line":117,"column":59},"end":{"line":117,"column":84}}],"line":117},"7":{"loc":{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},"type":"if","locations":[{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},{"start":{},"end":{}}],"line":118},"8":{"loc":{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},"type":"if","locations":[{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},{"start":{},"end":{}}],"line":131}},"s":{"0":1,"1":1,"2":1,"3":3,"4":3,"5":3,"6":3,"7":1,"8":2,"9":2,"10":1,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":4,"31":4,"32":4,"33":4,"34":4,"35":4,"36":4,"37":1,"38":3,"39":3,"40":1,"41":2,"42":2,"43":2,"44":1,"45":1,"46":1,"47":2,"48":2,"49":2,"50":1},"f":{"0":3,"1":0,"2":0,"3":0,"4":4},"b":{"0":[1,2],"1":[1,1],"2":[0,0],"3":[0,0,0],"4":[0,0],"5":[1,3],"6":[3,1],"7":[1,2],"8":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2917d152140ab09724020f4ab1282f6f8aefef73"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js","statementMap":{"0":{"start":{"line":1,"column":46},"end":{"line":1,"column":66}},"1":{"start":{"line":6,"column":8},"end":{"line":29,"column":9}},"2":{"start":{"line":7,"column":55},"end":{"line":7,"column":63}},"3":{"start":{"line":10,"column":25},"end":{"line":15,"column":14}},"4":{"start":{"line":18,"column":12},"end":{"line":24,"column":13}},"5":{"start":{"line":19,"column":31},"end":{"line":22,"column":19}},"6":{"start":{"line":19,"column":56},"end":{"line":22,"column":17}},"7":{"start":{"line":23,"column":16},"end":{"line":23,"column":47}},"8":{"start":{"line":26,"column":12},"end":{"line":26,"column":81}},"9":{"start":{"line":28,"column":12},"end":{"line":28,"column":22}},"10":{"start":{"line":34,"column":8},"end":{"line":48,"column":9}},"11":{"start":{"line":35,"column":26},"end":{"line":44,"column":14}},"12":{"start":{"line":45,"column":12},"end":{"line":45,"column":28}},"13":{"start":{"line":47,"column":12},"end":{"line":47,"column":22}},"14":{"start":{"line":53,"column":8},"end":{"line":62,"column":9}},"15":{"start":{"line":54,"column":26},"end":{"line":58,"column":14}},"16":{"start":{"line":59,"column":12},"end":{"line":59,"column":28}},"17":{"start":{"line":61,"column":12},"end":{"line":61,"column":22}},"18":{"start":{"line":67,"column":8},"end":{"line":79,"column":9}},"19":{"start":{"line":68,"column":27},"end":{"line":68,"column":37}},"20":{"start":{"line":69,"column":55},"end":{"line":69,"column":63}},"21":{"start":{"line":71,"column":25},"end":{"line":71,"column":48}},"22":{"start":{"line":72,"column":12},"end":{"line":72,"column":50}},"23":{"start":{"line":72,"column":23},"end":{"line":72,"column":50}},"24":{"start":{"line":73,"column":12},"end":{"line":73,"column":76}},"25":{"start":{"line":73,"column":45},"end":{"line":73,"column":76}},"26":{"start":{"line":75,"column":12},"end":{"line":75,"column":78}},"27":{"start":{"line":76,"column":12},"end":{"line":76,"column":69}},"28":{"start":{"line":78,"column":12},"end":{"line":78,"column":22}},"29":{"start":{"line":84,"column":8},"end":{"line":94,"column":9}},"30":{"start":{"line":85,"column":27},"end":{"line":85,"column":37}},"31":{"start":{"line":86,"column":25},"end":{"line":86,"column":48}},"32":{"start":{"line":87,"column":12},"end":{"line":87,"column":50}},"33":{"start":{"line":87,"column":23},"end":{"line":87,"column":50}},"34":{"start":{"line":88,"column":12},"end":{"line":88,"column":76}},"35":{"start":{"line":88,"column":45},"end":{"line":88,"column":76}},"36":{"start":{"line":90,"column":12},"end":{"line":90,"column":33}},"37":{"start":{"line":91,"column":12},"end":{"line":91,"column":63}},"38":{"start":{"line":93,"column":12},"end":{"line":93,"column":22}},"39":{"start":{"line":99,"column":8},"end":{"line":119,"column":9}},"40":{"start":{"line":100,"column":27},"end":{"line":100,"column":37}},"41":{"start":{"line":101,"column":25},"end":{"line":101,"column":48}},"42":{"start":{"line":102,"column":12},"end":{"line":102,"column":50}},"43":{"start":{"line":102,"column":23},"end":{"line":102,"column":50}},"44":{"start":{"line":104,"column":33},"end":{"line":106,"column":14}},"45":{"start":{"line":109,"column":12},"end":{"line":115,"column":13}},"46":{"start":{"line":110,"column":16},"end":{"line":110,"column":45}},"47":{"start":{"line":111,"column":16},"end":{"line":111,"column":41}},"48":{"start":{"line":113,"column":16},"end":{"line":113,"column":71}},"49":{"start":{"line":114,"column":16},"end":{"line":114,"column":39}},"50":{"start":{"line":116,"column":12},"end":{"line":116,"column":34}},"51":{"start":{"line":118,"column":12},"end":{"line":118,"column":22}},"52":{"start":{"line":123,"column":0},"end":{"line":123,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":4},"end":{"line":5,"column":5}},"loc":{"start":{"line":5,"column":44},"end":{"line":30,"column":5}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":19,"column":45},"end":{"line":19,"column":46}},"loc":{"start":{"line":19,"column":56},"end":{"line":22,"column":17}},"line":19},"2":{"name":"(anonymous_2)","decl":{"start":{"line":33,"column":4},"end":{"line":33,"column":5}},"loc":{"start":{"line":33,"column":51},"end":{"line":49,"column":5}},"line":33},"3":{"name":"(anonymous_3)","decl":{"start":{"line":52,"column":4},"end":{"line":52,"column":5}},"loc":{"start":{"line":52,"column":44},"end":{"line":63,"column":5}},"line":52},"4":{"name":"(anonymous_4)","decl":{"start":{"line":66,"column":4},"end":{"line":66,"column":5}},"loc":{"start":{"line":66,"column":44},"end":{"line":80,"column":5}},"line":66},"5":{"name":"(anonymous_5)","decl":{"start":{"line":83,"column":4},"end":{"line":83,"column":5}},"loc":{"start":{"line":83,"column":44},"end":{"line":95,"column":5}},"line":83},"6":{"name":"(anonymous_6)","decl":{"start":{"line":98,"column":4},"end":{"line":98,"column":5}},"loc":{"start":{"line":98,"column":44},"end":{"line":120,"column":5}},"line":98}},"branchMap":{"0":{"loc":{"start":{"line":13,"column":28},"end":{"line":13,"column":46}},"type":"binary-expr","locations":[{"start":{"line":13,"column":28},"end":{"line":13,"column":38}},{"start":{"line":13,"column":42},"end":{"line":13,"column":46}}],"line":13},"1":{"loc":{"start":{"line":18,"column":12},"end":{"line":24,"column":13}},"type":"if","locations":[{"start":{"line":18,"column":12},"end":{"line":24,"column":13}},{"start":{},"end":{}}],"line":18},"2":{"loc":{"start":{"line":18,"column":16},"end":{"line":18,"column":49}},"type":"binary-expr","locations":[{"start":{"line":18,"column":16},"end":{"line":18,"column":25}},{"start":{"line":18,"column":29},"end":{"line":18,"column":49}}],"line":18},"3":{"loc":{"start":{"line":72,"column":12},"end":{"line":72,"column":50}},"type":"if","locations":[{"start":{"line":72,"column":12},"end":{"line":72,"column":50}},{"start":{},"end":{}}],"line":72},"4":{"loc":{"start":{"line":73,"column":12},"end":{"line":73,"column":76}},"type":"if","locations":[{"start":{"line":73,"column":12},"end":{"line":73,"column":76}},{"start":{},"end":{}}],"line":73},"5":{"loc":{"start":{"line":87,"column":12},"end":{"line":87,"column":50}},"type":"if","locations":[{"start":{"line":87,"column":12},"end":{"line":87,"column":50}},{"start":{},"end":{}}],"line":87},"6":{"loc":{"start":{"line":88,"column":12},"end":{"line":88,"column":76}},"type":"if","locations":[{"start":{"line":88,"column":12},"end":{"line":88,"column":76}},{"start":{},"end":{}}],"line":88},"7":{"loc":{"start":{"line":102,"column":12},"end":{"line":102,"column":50}},"type":"if","locations":[{"start":{"line":102,"column":12},"end":{"line":102,"column":50}},{"start":{},"end":{}}],"line":102},"8":{"loc":{"start":{"line":109,"column":12},"end":{"line":115,"column":13}},"type":"if","locations":[{"start":{"line":109,"column":12},"end":{"line":115,"column":13}},{"start":{"line":112,"column":19},"end":{"line":115,"column":13}}],"line":109}},"s":{"0":1,"1":2,"2":2,"3":2,"4":2,"5":1,"6":2,"7":1,"8":2,"9":0,"10":1,"11":1,"12":1,"13":0,"14":0,"15":0,"16":0,"17":0,"18":2,"19":2,"20":2,"21":2,"22":2,"23":0,"24":2,"25":1,"26":1,"27":1,"28":1,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":2,"40":2,"41":2,"42":2,"43":0,"44":2,"45":2,"46":1,"47":1,"48":1,"49":1,"50":2,"51":0,"52":1},"f":{"0":2,"1":2,"2":1,"3":0,"4":2,"5":0,"6":2},"b":{"0":[2,1],"1":[1,1],"2":[2,2],"3":[0,2],"4":[1,1],"5":[0,0],"6":[0,0],"7":[0,2],"8":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"611903ee95c16bde9bc49db059f4f96f8b5ab109"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js","statementMap":{"0":{"start":{"line":1,"column":17},"end":{"line":1,"column":37}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":47}},"3":{"start":{"line":4,"column":25},"end":{"line":4,"column":55}},"4":{"start":{"line":5,"column":15},"end":{"line":5,"column":33}},"5":{"start":{"line":10,"column":8},"end":{"line":20,"column":9}},"6":{"start":{"line":11,"column":50},"end":{"line":11,"column":58}},"7":{"start":{"line":12,"column":28},"end":{"line":12,"column":76}},"8":{"start":{"line":13,"column":12},"end":{"line":17,"column":15}},"9":{"start":{"line":19,"column":12},"end":{"line":19,"column":22}},"10":{"start":{"line":24,"column":8},"end":{"line":44,"column":9}},"11":{"start":{"line":25,"column":40},"end":{"line":25,"column":48}},"12":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"13":{"start":{"line":27,"column":16},"end":{"line":27,"column":89}},"14":{"start":{"line":30,"column":25},"end":{"line":30,"column":65}},"15":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"16":{"start":{"line":32,"column":16},"end":{"line":32,"column":47}},"17":{"start":{"line":35,"column":36},"end":{"line":35,"column":79}},"18":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"19":{"start":{"line":37,"column":16},"end":{"line":37,"column":47}},"20":{"start":{"line":40,"column":26},"end":{"line":40,"column":52}},"21":{"start":{"line":41,"column":12},"end":{"line":41,"column":58}},"22":{"start":{"line":43,"column":12},"end":{"line":43,"column":22}},"23":{"start":{"line":48,"column":8},"end":{"line":74,"column":9}},"24":{"start":{"line":49,"column":37},"end":{"line":49,"column":45}},"25":{"start":{"line":51,"column":27},"end":{"line":54,"column":14}},"26":{"start":{"line":55,"column":28},"end":{"line":55,"column":47}},"27":{"start":{"line":57,"column":36},"end":{"line":66,"column":14}},"28":{"start":{"line":69,"column":33},"end":{"line":69,"column":59}},"29":{"start":{"line":70,"column":12},"end":{"line":70,"column":51}},"30":{"start":{"line":73,"column":12},"end":{"line":73,"column":22}},"31":{"start":{"line":80,"column":0},"end":{"line":80,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":9,"column":4},"end":{"line":9,"column":5}},"loc":{"start":{"line":9,"column":42},"end":{"line":21,"column":5}},"line":9},"1":{"name":"(anonymous_1)","decl":{"start":{"line":23,"column":4},"end":{"line":23,"column":5}},"loc":{"start":{"line":23,"column":39},"end":{"line":45,"column":5}},"line":23},"2":{"name":"(anonymous_2)","decl":{"start":{"line":47,"column":4},"end":{"line":47,"column":5}},"loc":{"start":{"line":47,"column":46},"end":{"line":75,"column":5}},"line":47}},"branchMap":{"0":{"loc":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"type":"if","locations":[{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},{"start":{},"end":{}}],"line":26},"1":{"loc":{"start":{"line":26,"column":16},"end":{"line":26,"column":35}},"type":"binary-expr","locations":[{"start":{"line":26,"column":16},"end":{"line":26,"column":22}},{"start":{"line":26,"column":26},"end":{"line":26,"column":35}}],"line":26},"2":{"loc":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"type":"if","locations":[{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},{"start":{},"end":{}}],"line":31},"3":{"loc":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"type":"if","locations":[{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},{"start":{},"end":{}}],"line":36}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":0,"6":0,"7":0,"8":0,"9":0,"10":1,"11":1,"12":1,"13":0,"14":1,"15":1,"16":1,"17":0,"18":0,"19":0,"20":0,"21":0,"22":1,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":1},"f":{"0":0,"1":1,"2":0},"b":{"0":[0,1],"1":[1,1],"2":[1,0],"3":[0,0]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"80370fa376eb20e9088f533698882ee10ddf85dd"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":3,"column":14},"end":{"line":3,"column":64}},"2":{"start":{"line":4,"column":14},"end":{"line":4,"column":67}},"3":{"start":{"line":8,"column":2},"end":{"line":21,"column":12}},"4":{"start":{"line":26,"column":2},"end":{"line":33,"column":3}},"5":{"start":{"line":27,"column":19},"end":{"line":27,"column":54}},"6":{"start":{"line":28,"column":20},"end":{"line":28,"column":42}},"7":{"start":{"line":29,"column":4},"end":{"line":29,"column":30}},"8":{"start":{"line":31,"column":4},"end":{"line":31,"column":47}},"9":{"start":{"line":32,"column":4},"end":{"line":32,"column":63}},"10":{"start":{"line":36,"column":0},"end":{"line":36,"column":31}}},"fnMap":{"0":{"name":"cleanText","decl":{"start":{"line":7,"column":9},"end":{"line":7,"column":18}},"loc":{"start":{"line":7,"column":30},"end":{"line":22,"column":1}},"line":7},"1":{"name":"askGemini","decl":{"start":{"line":25,"column":15},"end":{"line":25,"column":24}},"loc":{"start":{"line":25,"column":33},"end":{"line":34,"column":1}},"line":25}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":19},"end":{"line":7,"column":28}},"type":"default-arg","locations":[{"start":{"line":7,"column":26},"end":{"line":7,"column":28}}],"line":7}},"s":{"0":1,"1":1,"2":1,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":1},"f":{"0":0,"1":0},"b":{"0":[0]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"3e77ad823eae243bd1e4e7cac77dbdff43a6f7dc"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":39},"end":{"line":2,"column":59}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":35}},"3":{"start":{"line":5,"column":14},"end":{"line":5,"column":64}},"4":{"start":{"line":6,"column":14},"end":{"line":6,"column":67}},"5":{"start":{"line":9,"column":2},"end":{"line":65,"column":3}},"6":{"start":{"line":10,"column":23},"end":{"line":13,"column":6}},"7":{"start":{"line":15,"column":4},"end":{"line":22,"column":5}},"8":{"start":{"line":16,"column":6},"end":{"line":21,"column":9}},"9":{"start":{"line":24,"column":26},"end":{"line":26,"column":17}},"10":{"start":{"line":25,"column":18},"end":{"line":25,"column":88}},"11":{"start":{"line":28,"column":19},"end":{"line":35,"column":5}},"12":{"start":{"line":37,"column":19},"end":{"line":37,"column":54}},"13":{"start":{"line":38,"column":27},"end":{"line":38,"column":49}},"14":{"start":{"line":39,"column":23},"end":{"line":39,"column":69}},"15":{"start":{"line":39,"column":60},"end":{"line":39,"column":68}},"16":{"start":{"line":41,"column":29},"end":{"line":53,"column":6}},"17":{"start":{"line":55,"column":4},"end":{"line":55,"column":28}},"18":{"start":{"line":57,"column":4},"end":{"line":57,"column":60}},"19":{"start":{"line":59,"column":4},"end":{"line":64,"column":7}},"20":{"start":{"line":68,"column":0},"end":{"line":68,"column":42}}},"fnMap":{"0":{"name":"getAIRecommendations","decl":{"start":{"line":8,"column":15},"end":{"line":8,"column":35}},"loc":{"start":{"line":8,"column":44},"end":{"line":66,"column":1}},"line":8},"1":{"name":"(anonymous_1)","decl":{"start":{"line":25,"column":11},"end":{"line":25,"column":12}},"loc":{"start":{"line":25,"column":18},"end":{"line":25,"column":88}},"line":25},"2":{"name":"(anonymous_2)","decl":{"start":{"line":39,"column":53},"end":{"line":39,"column":54}},"loc":{"start":{"line":39,"column":60},"end":{"line":39,"column":68}},"line":39}},"branchMap":{"0":{"loc":{"start":{"line":15,"column":4},"end":{"line":22,"column":5}},"type":"if","locations":[{"start":{"line":15,"column":4},"end":{"line":22,"column":5}},{"start":{},"end":{}}],"line":15},"1":{"loc":{"start":{"line":25,"column":54},"end":{"line":25,"column":85}},"type":"binary-expr","locations":[{"start":{"line":25,"column":54},"end":{"line":25,"column":75}},{"start":{"line":25,"column":79},"end":{"line":25,"column":85}}],"line":25}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":1},"f":{"0":0,"1":0,"2":0},"b":{"0":[0,0],"1":[0,0]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"e1ea4577adfa0d0a6ebf7a252cc3decd0146686c"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js","statementMap":{"0":{"start":{"line":1,"column":12},"end":{"line":1,"column":35}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":37}},"2":{"start":{"line":5,"column":2},"end":{"line":5,"column":35}},"3":{"start":{"line":9,"column":2},"end":{"line":9,"column":35}},"4":{"start":{"line":12,"column":0},"end":{"line":12,"column":44}}},"fnMap":{"0":{"name":"signToken","decl":{"start":{"line":4,"column":9},"end":{"line":4,"column":18}},"loc":{"start":{"line":4,"column":28},"end":{"line":6,"column":1}},"line":4},"1":{"name":"verifyToken","decl":{"start":{"line":8,"column":9},"end":{"line":8,"column":20}},"loc":{"start":{"line":8,"column":28},"end":{"line":10,"column":1}},"line":8}},"branchMap":{},"s":{"0":1,"1":1,"2":0,"3":0,"4":1},"f":{"0":0,"1":0},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"d7b8e9b1304ab0135964e79a9372e3a90c422c73"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\category.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\category.js","statementMap":{"0":{"start":{"line":4,"column":4},"end":{"line":4,"column":24}},"1":{"start":{"line":5,"column":0},"end":{"line":24,"column":2}},"2":{"start":{"line":13,"column":7},"end":{"line":13,"column":37}},"3":{"start":{"line":17,"column":2},"end":{"line":22,"column":5}},"4":{"start":{"line":23,"column":2},"end":{"line":23,"column":18}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":18}},"loc":{"start":{"line":5,"column":43},"end":{"line":24,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":12,"column":4},"end":{"line":12,"column":5}},"loc":{"start":{"line":12,"column":29},"end":{"line":14,"column":5}},"line":12}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1},"f":{"0":1,"1":1},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"b53232249d0460508d5c1dbe8d528418cdcc35d8"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\chat.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\chat.js","statementMap":{"0":{"start":{"line":4,"column":4},"end":{"line":4,"column":24}},"1":{"start":{"line":5,"column":0},"end":{"line":28,"column":2}},"2":{"start":{"line":13,"column":6},"end":{"line":13,"column":75}},"3":{"start":{"line":14,"column":6},"end":{"line":14,"column":78}},"4":{"start":{"line":15,"column":6},"end":{"line":15,"column":35}},"5":{"start":{"line":19,"column":2},"end":{"line":26,"column":5}},"6":{"start":{"line":27,"column":2},"end":{"line":27,"column":14}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":18}},"loc":{"start":{"line":5,"column":43},"end":{"line":28,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":12,"column":4},"end":{"line":12,"column":5}},"loc":{"start":{"line":12,"column":29},"end":{"line":16,"column":5}},"line":12}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1},"f":{"0":1,"1":1},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"7caac22d588d58e8129c102294bf5cd40ad1cd38"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\image.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\image.js","statementMap":{"0":{"start":{"line":4,"column":4},"end":{"line":4,"column":24}},"1":{"start":{"line":5,"column":0},"end":{"line":25,"column":2}},"2":{"start":{"line":13,"column":6},"end":{"line":13,"column":35}},"3":{"start":{"line":17,"column":2},"end":{"line":23,"column":5}},"4":{"start":{"line":24,"column":2},"end":{"line":24,"column":15}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":18}},"loc":{"start":{"line":5,"column":43},"end":{"line":25,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":12,"column":4},"end":{"line":12,"column":5}},"loc":{"start":{"line":12,"column":29},"end":{"line":14,"column":5}},"line":12}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1},"f":{"0":1,"1":1},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"ad242b102cc5ff6596aad3f625f0c4c4d99fd50c"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\index.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\index.js","statementMap":{"0":{"start":{"line":3,"column":11},"end":{"line":3,"column":24}},"1":{"start":{"line":4,"column":13},"end":{"line":4,"column":28}},"2":{"start":{"line":5,"column":18},"end":{"line":5,"column":38}},"3":{"start":{"line":6,"column":16},"end":{"line":6,"column":34}},"4":{"start":{"line":7,"column":17},"end":{"line":7,"column":42}},"5":{"start":{"line":8,"column":12},"end":{"line":8,"column":49}},"6":{"start":{"line":9,"column":15},"end":{"line":9,"column":63}},"7":{"start":{"line":10,"column":11},"end":{"line":10,"column":13}},"8":{"start":{"line":14,"column":0},"end":{"line":18,"column":1}},"9":{"start":{"line":15,"column":2},"end":{"line":15,"column":48}},"10":{"start":{"line":17,"column":2},"end":{"line":17,"column":87}},"11":{"start":{"line":20,"column":0},"end":{"line":33,"column":5}},"12":{"start":{"line":23,"column":4},"end":{"line":28,"column":6}},"13":{"start":{"line":31,"column":18},"end":{"line":31,"column":85}},"14":{"start":{"line":32,"column":4},"end":{"line":32,"column":27}},"15":{"start":{"line":35,"column":0},"end":{"line":39,"column":3}},"16":{"start":{"line":36,"column":2},"end":{"line":38,"column":3}},"17":{"start":{"line":37,"column":4},"end":{"line":37,"column":32}},"18":{"start":{"line":41,"column":0},"end":{"line":41,"column":25}},"19":{"start":{"line":42,"column":0},"end":{"line":42,"column":25}},"20":{"start":{"line":44,"column":0},"end":{"line":44,"column":20}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":22,"column":10},"end":{"line":22,"column":11}},"loc":{"start":{"line":22,"column":18},"end":{"line":29,"column":3}},"line":22},"1":{"name":"(anonymous_1)","decl":{"start":{"line":30,"column":11},"end":{"line":30,"column":12}},"loc":{"start":{"line":30,"column":19},"end":{"line":33,"column":3}},"line":30},"2":{"name":"(anonymous_2)","decl":{"start":{"line":35,"column":24},"end":{"line":35,"column":25}},"loc":{"start":{"line":35,"column":37},"end":{"line":39,"column":1}},"line":35}},"branchMap":{"0":{"loc":{"start":{"line":8,"column":12},"end":{"line":8,"column":49}},"type":"binary-expr","locations":[{"start":{"line":8,"column":12},"end":{"line":8,"column":32}},{"start":{"line":8,"column":36},"end":{"line":8,"column":49}}],"line":8},"1":{"loc":{"start":{"line":14,"column":0},"end":{"line":18,"column":1}},"type":"if","locations":[{"start":{"line":14,"column":0},"end":{"line":18,"column":1}},{"start":{"line":16,"column":7},"end":{"line":18,"column":1}}],"line":14},"2":{"loc":{"start":{"line":24,"column":6},"end":{"line":27,"column":37}},"type":"binary-expr","locations":[{"start":{"line":24,"column":6},"end":{"line":24,"column":29}},{"start":{"line":25,"column":6},"end":{"line":25,"column":23}},{"start":{"line":26,"column":6},"end":{"line":26,"column":30}},{"start":{"line":27,"column":6},"end":{"line":27,"column":37}}],"line":24},"3":{"loc":{"start":{"line":36,"column":2},"end":{"line":38,"column":3}},"type":"if","locations":[{"start":{"line":36,"column":2},"end":{"line":38,"column":3}},{"start":{},"end":{}}],"line":36}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":0,"10":1,"11":1,"12":8,"13":7,"14":7,"15":1,"16":7,"17":7,"18":1,"19":1,"20":1},"f":{"0":8,"1":7,"2":7},"b":{"0":[1,0],"1":[0,1],"2":[8,8,7,7],"3":[7,0]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"ad9a3acf31fd8d390059597bddf05e175c1c0a76"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\like.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\like.js","statementMap":{"0":{"start":{"line":4,"column":4},"end":{"line":4,"column":24}},"1":{"start":{"line":5,"column":0},"end":{"line":26,"column":2}},"2":{"start":{"line":13,"column":6},"end":{"line":13,"column":34}},"3":{"start":{"line":14,"column":6},"end":{"line":14,"column":34}},"4":{"start":{"line":18,"column":2},"end":{"line":24,"column":5}},"5":{"start":{"line":25,"column":2},"end":{"line":25,"column":14}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":18}},"loc":{"start":{"line":5,"column":43},"end":{"line":26,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":12,"column":4},"end":{"line":12,"column":5}},"loc":{"start":{"line":12,"column":29},"end":{"line":15,"column":5}},"line":12}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1},"f":{"0":1,"1":1},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"0f603675acb1a50d3a6b5fb0a972d9e3bd0ccc14"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\message.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\message.js","statementMap":{"0":{"start":{"line":4,"column":4},"end":{"line":4,"column":24}},"1":{"start":{"line":5,"column":0},"end":{"line":30,"column":2}},"2":{"start":{"line":13,"column":6},"end":{"line":13,"column":37}},"3":{"start":{"line":14,"column":6},"end":{"line":14,"column":79}},"4":{"start":{"line":15,"column":6},"end":{"line":15,"column":83}},"5":{"start":{"line":20,"column":2},"end":{"line":28,"column":5}},"6":{"start":{"line":29,"column":2},"end":{"line":29,"column":17}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":18}},"loc":{"start":{"line":5,"column":43},"end":{"line":30,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":12,"column":4},"end":{"line":12,"column":5}},"loc":{"start":{"line":12,"column":29},"end":{"line":16,"column":5}},"line":12}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1},"f":{"0":1,"1":1},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"553fc9afc1fb2df94bb07a5c6cb7643b1ae674f1"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\post.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\post.js","statementMap":{"0":{"start":{"line":4,"column":4},"end":{"line":4,"column":24}},"1":{"start":{"line":5,"column":0},"end":{"line":41,"column":2}},"2":{"start":{"line":13,"column":6},"end":{"line":13,"column":34}},"3":{"start":{"line":14,"column":6},"end":{"line":14,"column":38}},"4":{"start":{"line":15,"column":6},"end":{"line":15,"column":33}},"5":{"start":{"line":16,"column":6},"end":{"line":16,"column":31}},"6":{"start":{"line":20,"column":2},"end":{"line":39,"column":5}},"7":{"start":{"line":40,"column":2},"end":{"line":40,"column":14}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":18}},"loc":{"start":{"line":5,"column":43},"end":{"line":41,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":12,"column":4},"end":{"line":12,"column":5}},"loc":{"start":{"line":12,"column":29},"end":{"line":17,"column":5}},"line":12}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1},"f":{"0":1,"1":1},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"9537a9db377628a5370ed1047cf38655e378cc14"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\user.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\user.js","statementMap":{"0":{"start":{"line":2,"column":15},"end":{"line":2,"column":34}},"1":{"start":{"line":5,"column":4},"end":{"line":5,"column":24}},"2":{"start":{"line":6,"column":0},"end":{"line":64,"column":2}},"3":{"start":{"line":14,"column":6},"end":{"line":14,"column":32}},"4":{"start":{"line":15,"column":6},"end":{"line":15,"column":32}},"5":{"start":{"line":16,"column":6},"end":{"line":16,"column":58}},"6":{"start":{"line":17,"column":6},"end":{"line":17,"column":61}},"7":{"start":{"line":18,"column":6},"end":{"line":18,"column":63}},"8":{"start":{"line":19,"column":6},"end":{"line":19,"column":65}},"9":{"start":{"line":23,"column":2},"end":{"line":62,"column":5}},"10":{"start":{"line":59,"column":8},"end":{"line":59,"column":61}},"11":{"start":{"line":63,"column":2},"end":{"line":63,"column":14}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":18}},"loc":{"start":{"line":6,"column":43},"end":{"line":64,"column":1}},"line":6},"1":{"name":"(anonymous_1)","decl":{"start":{"line":13,"column":4},"end":{"line":13,"column":5}},"loc":{"start":{"line":13,"column":29},"end":{"line":20,"column":5}},"line":13},"2":{"name":"(anonymous_2)","decl":{"start":{"line":58,"column":20},"end":{"line":58,"column":21}},"loc":{"start":{"line":58,"column":36},"end":{"line":60,"column":7}},"line":58}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":0,"11":1},"f":{"0":1,"1":1,"2":0},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"660187373a96a123a305b9a8b65a489cb753d5c5"} +} diff --git a/coverage/lcov-report/aiController.js.html b/coverage/lcov-report/aiController.js.html new file mode 100644 index 0000000..e30f707 --- /dev/null +++ b/coverage/lcov-report/aiController.js.html @@ -0,0 +1,142 @@ + + + + + + Code coverage report for aiController.js + + + + + + + + + +
+
+

All files aiController.js

+
+ +
+ 85.71% + Statements + 6/7 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 1/1 +
+ + +
+ 85.71% + Lines + 6/7 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +201x +  +  +  +1x +1x +1x +  +1x +  +  +  +  +  +  +  +  +  +  +1x
const { getAIRecommendations } = require("../helpers/aiRecommendation");
+ 
+class AIController {
+  static async getRecommendations(req, res, next) {
+    try {
+      const userId = req.user.id;
+      const posts = await getAIRecommendations(userId);
+ 
+      res.json({
+        message: "Rekomendasi berhasil dibuat",
+        count: posts.length,
+        data: posts,
+      });
+    } catch (err) {
+      next(err);
+    }
+  }
+}
+ 
+module.exports = AIController;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/base.css b/coverage/lcov-report/base.css new file mode 100644 index 0000000..f418035 --- /dev/null +++ b/coverage/lcov-report/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/coverage/lcov-report/block-navigation.js b/coverage/lcov-report/block-navigation.js new file mode 100644 index 0000000..530d1ed --- /dev/null +++ b/coverage/lcov-report/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selector that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/coverage/lcov-report/chatController.js.html b/coverage/lcov-report/chatController.js.html new file mode 100644 index 0000000..476d7ac --- /dev/null +++ b/coverage/lcov-report/chatController.js.html @@ -0,0 +1,535 @@ + + + + + + Code coverage report for chatController.js + + + + + + + + + +
+
+

All files chatController.js

+
+ +
+ 27.45% + Statements + 14/51 +
+ + +
+ 10.52% + Branches + 2/19 +
+ + +
+ 40% + Functions + 2/5 +
+ + +
+ 27.45% + Lines + 14/51 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +1511x +1x +1x +  +  +  +  +1x +1x +1x +  +1x +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x
const { Chat, Message, User, Sequelize } = require("../models");
+const { Op } = Sequelize;
+const { askGemini } = require("../helpers/aiHelper");
+ 
+class ChatController {
+    // Mencegah duplikasi chat
+    static async createOrGetChat(req, res, next) {
+        try {
+            const { partnerId } = req.body;
+            const userId = req.user.id;
+ 
+            Iif (partnerId == userId) { //  Validasi agar tidak chat dengan diri sendiri
+                throw { name: "BadRequest", message: "You cannot create a chat with yourself." };
+            }
+ 
+            // Cari chat yang sudah ada antara kedua user
+            const [chat, created] = await Chat.findOrCreate({
+                where: {
+                    [Op.or]: [
+                        { UserId: userId, partnerId: partnerId },
+                        { UserId: partnerId, partnerId: userId },
+                    ],
+                    isAIChat: false
+                },
+                defaults: {
+                    UserId: userId,
+                    partnerId: partnerId,
+                },
+            });
+ 
+            res.status(created ? 201 : 200).json(chat);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // Menampilkan semua chat dimana user terlibat
+    static async getUserChats(req, res, next) {
+        try {
+            const userId = req.user.id;
+            const chats = await Chat.findAll({
+                where: {
+                    [Op.or]: [{ UserId: userId }, { partnerId: userId }],
+                },
+                include: [
+                    { model: User, as: "creator", attributes: ["id", "username", "profilePic"] },
+                    { model: User, as: "partner", attributes: ["id", "username", "profilePic"] },
+                ],
+                order: [["updatedAt", "DESC"]],
+            });
+ 
+            res.json(chats);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // Menambahkan validasi keamanan
+    static async getChatMessages(req, res, next) {
+        try {
+            const { chatId } = req.params;
+            const userId = req.user.id;
+ 
+            // Validasi: Pastikan user adalah bagian dari chat ini
+            const chat = await Chat.findByPk(chatId);
+            if (!chat || (chat.UserId !== userId && chat.partnerId !== userId)) {
+                throw { name: "Forbidden" };
+            }
+ 
+            const messages = await Message.findAll({
+                where: { ChatId: chatId },
+                include: [{ model: User, as: "sender", attributes: ["id", "username"] }],
+                order: [["createdAt", "ASC"]],
+            });
+ 
+            res.json(messages);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    static async createAIChat(req, res, next) {
+        try {
+            const userId = req.user.id;
+            const [chat, created] = await Chat.findOrCreate({
+                where: {
+                    UserId: userId,
+                    isAIChat: true,
+                },
+                defaults: {
+                    UserId: userId,
+                    isAIChat: true,
+                    partnerId: null, // Tidak ada partner untuk AI chat
+                },
+            });
+            res.status(created ? 201 : 200).json(chat);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // Menambahkan validasi keamanan & menyederhanakan
+    static async sendMessage(req, res, next) {
+        try {
+            const { chatId } = req.params;
+            const { content } = req.body;
+            const userId = req.user.id;
+            const io = req.app.get("socketio");
+ 
+            const chat = await Chat.findByPk(chatId);
+            if (!chat) {
+                throw { name: "NotFound", message: "Chat not found" };
+            }
+ 
+ 
+            // User harus menjadi pembuat atau partner dari chat tersebut.
+            const isAuthorized = chat.UserId === userId || chat.partnerId === userId;
+            if (!isAuthorized) {
+                throw { name: "Forbidden", message: "You are not authorized to access this chat" };
+            }
+ 
+            // 1. Simpan dan kirim pesan dari user
+            const userMessage = await Message.create({
+                ChatId: chatId,
+                senderId: userId,
+                content,
+            });
+ 
+            io.to(`chat_${chatId}`).emit("receive_message", userMessage);
+ 
+            if (chat.isAIChat) {
+                const aiResponseText = await askGemini(content);
+ 
+                const aiMessage = await Message.create({
+                    ChatId: chatId,
+                    senderId: null,
+                    content: aiResponseText,
+                });
+ 
+                io.to(`chat_${chatId}`).emit("receive_message", aiMessage);
+            }
+ 
+            await chat.save();
+            res.status(201).json(userMessage);
+        } catch (err) {
+            next(err);
+        }
+    }
+}
+ 
+module.exports = ChatController;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/config/config.js.html b/coverage/lcov-report/config/config.js.html new file mode 100644 index 0000000..e71cb97 --- /dev/null +++ b/coverage/lcov-report/config/config.js.html @@ -0,0 +1,175 @@ + + + + + + Code coverage report for config/config.js + + + + + + + + + +
+
+

All files / config config.js

+
+ +
+ 100% + Statements + 1/1 +
+ + +
+ 75% + Branches + 9/12 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 1/1 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
/**
+ * Sequelize configuration file
+ * Provides sensible defaults for development/test/production
+ * Uses environment variables when available so CI/production can override.
+ */
+ 
+module.exports = {
+  development: {
+    // Use single env var 'db' as connection URL for now (e.g. postgres://user:pass@host:port/db)
+    url: process.env.db || null,
+    dialect: 'postgres',
+    logging: false,
+    define: { timestamps: true },
+    dialectOptions: process.env.DB_SSL === 'true' ? { ssl: { rejectUnauthorized: false } } : {},
+  },
+ 
+  test: {
+    url: process.env.db || null,
+    dialect: 'postgres',
+    logging: false,
+    dialectOptions: process.env.DB_SSL === 'true' ? { ssl: { rejectUnauthorized: false } } : {},
+  },
+ 
+  production: {
+    url: process.env.db || null,
+    dialect: 'postgres',
+    logging: false,
+    dialectOptions: process.env.DB_SSL === 'true' ? { ssl: { rejectUnauthorized: false } } : {},
+  },
+};
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/config/index.html b/coverage/lcov-report/config/index.html new file mode 100644 index 0000000..1188bf3 --- /dev/null +++ b/coverage/lcov-report/config/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for config + + + + + + + + + +
+
+

All files config

+
+ +
+ 100% + Statements + 1/1 +
+ + +
+ 75% + Branches + 9/12 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 1/1 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
config.js +
+
100%1/175%9/12100%0/0100%1/1
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/controllers/aiController.js.html b/coverage/lcov-report/controllers/aiController.js.html new file mode 100644 index 0000000..64c0809 --- /dev/null +++ b/coverage/lcov-report/controllers/aiController.js.html @@ -0,0 +1,160 @@ + + + + + + Code coverage report for controllers/aiController.js + + + + + + + + + +
+
+

All files / controllers aiController.js

+
+ +
+ 100% + Statements + 9/9 +
+ + +
+ 100% + Branches + 4/4 +
+ + +
+ 100% + Functions + 1/1 +
+ + +
+ 100% + Lines + 9/9 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +261x +  +  +  +4x +  +4x +1x +  +  +3x +3x +  +2x +  +  +  +  +  +2x +  +  +  +  +1x + 
const { getAIRecommendations } = require("../helpers/aiRecommendation");
+ 
+class AIController {
+  static async getRecommendations(req, res, next) {
+    try {
+ 
+      if (!req.user || !req.user.id) {
+        throw { name: "Unauthorized" };
+      }
+ 
+      const userId = req.user.id;
+      const posts = await getAIRecommendations(userId);
+ 
+      res.status(200).json({
+        message: "Rekomendasi berhasil dibuat",
+        count: posts.length,
+        data: posts,
+      });
+    } catch (err) {
+      next(err);
+    }
+  }
+}
+ 
+module.exports = AIController;
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/controllers/chatController.js.html b/coverage/lcov-report/controllers/chatController.js.html new file mode 100644 index 0000000..5557817 --- /dev/null +++ b/coverage/lcov-report/controllers/chatController.js.html @@ -0,0 +1,535 @@ + + + + + + Code coverage report for controllers/chatController.js + + + + + + + + + +
+
+

All files / controllers chatController.js

+
+ +
+ 62.74% + Statements + 32/51 +
+ + +
+ 63.15% + Branches + 12/19 +
+ + +
+ 40% + Functions + 2/5 +
+ + +
+ 62.74% + Lines + 32/51 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +1511x +1x +1x +  +  +  +  +3x +3x +3x +  +3x +1x +  +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +4x +4x +4x +4x +4x +  +4x +4x +1x +  +  +  +  +3x +3x +1x +  +  +  +2x +  +  +  +  +  +2x +  +2x +1x +  +1x +  +  +  +  +  +1x +  +  +2x +2x +  +2x +  +  +  +  +1x
const { Chat, Message, User, Sequelize } = require("../models");
+const { Op } = Sequelize;
+const { askGemini } = require("../helpers/aiHelper");
+ 
+class ChatController {
+    // Mencegah duplikasi chat
+    static async createOrGetChat(req, res, next) {
+        try {
+            const { partnerId } = req.body;
+            const userId = req.user.id;
+ 
+            if (partnerId == userId) { //  Validasi agar tidak chat dengan diri sendiri
+                throw { name: "BadRequest", message: "You cannot create a chat with yourself." };
+            }
+ 
+            // Cari chat yang sudah ada antara kedua user
+            const [chat, created] = await Chat.findOrCreate({
+                where: {
+                    [Op.or]: [
+                        { UserId: userId, partnerId: partnerId },
+                        { UserId: partnerId, partnerId: userId },
+                    ],
+                    isAIChat: false
+                },
+                defaults: {
+                    UserId: userId,
+                    partnerId: partnerId,
+                },
+            });
+ 
+            res.status(created ? 201 : 200).json(chat);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // Menampilkan semua chat dimana user terlibat
+    static async getUserChats(req, res, next) {
+        try {
+            const userId = req.user.id;
+            const chats = await Chat.findAll({
+                where: {
+                    [Op.or]: [{ UserId: userId }, { partnerId: userId }],
+                },
+                include: [
+                    { model: User, as: "creator", attributes: ["id", "username", "profilePic"] },
+                    { model: User, as: "partner", attributes: ["id", "username", "profilePic"] },
+                ],
+                order: [["updatedAt", "DESC"]],
+            });
+ 
+            res.json(chats);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // Menambahkan validasi keamanan
+    static async getChatMessages(req, res, next) {
+        try {
+            const { chatId } = req.params;
+            const userId = req.user.id;
+ 
+            // Validasi: Pastikan user adalah bagian dari chat ini
+            const chat = await Chat.findByPk(chatId);
+            if (!chat || (chat.UserId !== userId && chat.partnerId !== userId)) {
+                throw { name: "Forbidden" };
+            }
+ 
+            const messages = await Message.findAll({
+                where: { ChatId: chatId },
+                include: [{ model: User, as: "sender", attributes: ["id", "username"] }],
+                order: [["createdAt", "ASC"]],
+            });
+ 
+            res.json(messages);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    static async createAIChat(req, res, next) {
+        try {
+            const userId = req.user.id;
+            const [chat, created] = await Chat.findOrCreate({
+                where: {
+                    UserId: userId,
+                    isAIChat: true,
+                },
+                defaults: {
+                    UserId: userId,
+                    isAIChat: true,
+                    partnerId: null, // Tidak ada partner untuk AI chat
+                },
+            });
+            res.status(created ? 201 : 200).json(chat);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // Menambahkan validasi keamanan & menyederhanakan
+    static async sendMessage(req, res, next) {
+        try {
+            const { chatId } = req.params;
+            const { content } = req.body;
+            const userId = req.user.id;
+            const io = req.app.get("socketio");
+ 
+            const chat = await Chat.findByPk(chatId);
+            if (!chat) {
+                throw { name: "NotFound", message: "Chat not found" };
+            }
+ 
+ 
+            // User harus menjadi pembuat atau partner dari chat tersebut.
+            const isAuthorized = chat.UserId === userId || chat.partnerId === userId;
+            if (!isAuthorized) {
+                throw { name: "Forbidden", message: "You are not authorized to access this chat" };
+            }
+ 
+            // 1. Simpan dan kirim pesan dari user
+            const userMessage = await Message.create({
+                ChatId: chatId,
+                senderId: userId,
+                content,
+            });
+ 
+            io.to(`chat_${chatId}`).emit("receive_message", userMessage);
+ 
+            if (chat.isAIChat) {
+                const aiResponseText = await askGemini(content);
+ 
+                const aiMessage = await Message.create({
+                    ChatId: chatId,
+                    senderId: null,
+                    content: aiResponseText,
+                });
+ 
+                io.to(`chat_${chatId}`).emit("receive_message", aiMessage);
+            }
+ 
+            await chat.save();
+            res.status(201).json(userMessage);
+        } catch (err) {
+            next(err);
+        }
+    }
+}
+ 
+module.exports = ChatController;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/controllers/index.html b/coverage/lcov-report/controllers/index.html new file mode 100644 index 0000000..84e57c0 --- /dev/null +++ b/coverage/lcov-report/controllers/index.html @@ -0,0 +1,161 @@ + + + + + + Code coverage report for controllers + + + + + + + + + +
+
+

All files controllers

+
+ +
+ 60.68% + Statements + 88/145 +
+ + +
+ 65.3% + Branches + 32/49 +
+ + +
+ 56.25% + Functions + 9/16 +
+ + +
+ 61.87% + Lines + 86/139 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
aiController.js +
+
100%9/9100%4/4100%1/1100%9/9
chatController.js +
+
62.74%32/5163.15%12/1940%2/562.74%32/51
postController.js +
+
64.15%34/5366.66%12/1871.42%5/768.08%32/47
userController.js +
+
40.62%13/3250%4/833.33%1/340.62%13/32
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/controllers/postController.js.html b/coverage/lcov-report/controllers/postController.js.html new file mode 100644 index 0000000..a5ecd28 --- /dev/null +++ b/coverage/lcov-report/controllers/postController.js.html @@ -0,0 +1,451 @@ + + + + + + Code coverage report for controllers/postController.js + + + + + + + + + +
+
+

All files / controllers postController.js

+
+ +
+ 64.15% + Statements + 34/53 +
+ + +
+ 66.66% + Branches + 12/18 +
+ + +
+ 71.42% + Functions + 5/7 +
+ + +
+ 68.08% + Lines + 32/47 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +1231x +  +  +  +  +2x +2x +  +  +2x +  +  +  +  +  +  +  +2x +2x +  +  +  +1x +  +  +2x +  +  +  +  +  +  +  +1x +1x +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +2x +2x +  +2x +2x +2x +  +1x +1x +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +2x +2x +2x +  +2x +  +  +  +  +2x +1x +1x +  +1x +1x +  +2x +  +  +  +  +  +  +1x
const { Post, Image, Like, User, Category } = require("../models");
+ 
+class PostController {
+    // CREATE POST
+    static async createPost(req, res, next) {
+        try {
+            const { content, isPrivate, categoryId } = req.body;
+ 
+            // Buat post baru
+            const post = await Post.create({
+                content,
+                isPrivate,
+                CategoryId: categoryId || null,
+                UserId: req.user.id,
+            });
+ 
+            // Jika ada file yang di-upload, simpan URL-nya
+            if (req.files && req.files.length > 0) {
+                const images = req.files.map((file) => ({
+                    imageUrl: file.path, // multer-storage-cloudinary menyediakan URL di file.path
+                    PostId: post.id,
+                }));
+                await Image.bulkCreate(images);
+            }
+ 
+            res.status(201).json({ message: "Post created successfully", post });
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // READ ALL PUBLIC POSTS
+    static async getAllPublicPosts(req, res, next) {
+        try {
+            const posts = await Post.findAll({
+                where: { isPrivate: false },
+                include: [
+                    { model: User, attributes: ["id", "username", "profilePic"] },
+                    { model: Image },
+                    { model: Category, attributes: ["name"] },
+                    { model: Like },
+                ],
+                order: [["createdAt", "DESC"]],
+            });
+            res.json(posts);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // READ USER'S OWN POSTS
+    static async getMyPosts(req, res, next) {
+        try {
+            const posts = await Post.findAll({
+                where: { UserId: req.user.id },
+                include: [Image, Category, Like],
+                order: [["createdAt", "DESC"]],
+            });
+            res.json(posts);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // UPDATE POST
+    static async updatePost(req, res, next) {
+        try {
+            const { id } = req.params;
+            const { content, isPrivate, categoryId } = req.body;
+ 
+            const post = await Post.findByPk(id);
+            Iif (!post) throw { name: "NotFound" };
+            if (post.UserId !== req.user.id) throw { name: "Unauthorized" };
+ 
+            await post.update({ content, isPrivate, CategoryId: categoryId });
+            res.json({ message: "Post updated successfully", post });
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // DELETE POST
+    static async deletePost(req, res, next) {
+        try {
+            const { id } = req.params;
+            const post = await Post.findByPk(id);
+            if (!post) throw { name: "NotFound" };
+            if (post.UserId !== req.user.id) throw { name: "Unauthorized" };
+ 
+            await post.destroy();
+            res.json({ message: "Post deleted successfully" });
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // LIKE / UNLIKE POST
+    static async toggleLike(req, res, next) {
+        try {
+            const { id } = req.params;
+            const post = await Post.findByPk(id);
+            Iif (!post) throw { name: "NotFound" };
+ 
+            const existingLike = await Like.findOne({
+                where: { UserId: req.user.id, PostId: id },
+            });
+ 
+            let message;
+            if (existingLike) {
+                await existingLike.destroy();
+                message = "Post unliked";
+            } else {
+                await Like.create({ UserId: req.user.id, PostId: id });
+                message = "Post liked";
+            }
+            res.json({ message });
+        } catch (err) {
+            next(err);
+        }
+    }
+}
+ 
+module.exports = PostController;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/controllers/userController.js.html b/coverage/lcov-report/controllers/userController.js.html new file mode 100644 index 0000000..dd626ee --- /dev/null +++ b/coverage/lcov-report/controllers/userController.js.html @@ -0,0 +1,322 @@ + + + + + + Code coverage report for controllers/userController.js + + + + + + + + + +
+
+

All files / controllers userController.js

+
+ +
+ 40.62% + Statements + 13/32 +
+ + +
+ 50% + Branches + 4/8 +
+ + +
+ 33.33% + Functions + 1/3 +
+ + +
+ 40.62% + Lines + 13/32 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +801x +1x +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x
const { User } = require('../models');
+const bcrypt = require('bcryptjs');
+const { signToken } = require('../helpers/jwt');
+const { OAuth2Client } = require('google-auth-library');
+const client = new OAuth2Client();
+ 
+ 
+class UserController {
+    static async register(req, res, next) {
+        try {
+            const { username, email, password } = req.body;
+            const newUser = await User.create({ username, email, password });
+            res.status(201).json({
+                id: newUser.id,
+                username: newUser.username,
+                email: newUser.email,
+            });
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    static async login(req, res, next) {
+        try {
+            const { email, password } = req.body;
+            Iif (!email || !password) {
+                throw { name: 'BadRequest', message: 'Email and password are required' };
+            }
+ 
+            const user = await User.findOne({ where: { email } });
+            Eif (!user) {
+                throw { name: 'InvalidLogin' };
+            }
+ 
+            const isPasswordValid = bcrypt.compareSync(password, user.password);
+            if (!isPasswordValid) {
+                throw { name: 'InvalidLogin' };
+            }
+ 
+            const token = signToken({ id: user.id });
+            res.status(200).json({ access_token: token });
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    static async googleSignIn(req, res, next) {
+        try {
+            const { google_token } = req.body;
+ 
+            const ticket = await client.verifyIdToken({
+                idToken: google_token,
+                audience: process.env.GOOGLE_CLIENT_ID,
+            });
+            const payload = ticket.getPayload();
+ 
+            const [user, created] = await User.findOrCreate({
+                where: { email: payload.email },
+                defaults: {
+                    username: payload.name,
+                    email: payload.email,
+                    password: Math.random().toString(36),
+                    profilePic: payload.picture,
+                },
+                hooks: false
+            });
+ 
+ 
+            const access_token = signToken({ id: user.id });
+            res.status(200).json({ access_token });
+ 
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    
+}
+ 
+module.exports = UserController;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/favicon.png b/coverage/lcov-report/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..c1525b811a167671e9de1fa78aab9f5c0b61cef7 GIT binary patch literal 445 zcmV;u0Yd(XP))rP{nL}Ln%S7`m{0DjX9TLF* zFCb$4Oi7vyLOydb!7n&^ItCzb-%BoB`=x@N2jll2Nj`kauio%aw_@fe&*}LqlFT43 z8doAAe))z_%=P%v^@JHp3Hjhj^6*Kr_h|g_Gr?ZAa&y>wxHE99Gk>A)2MplWz2xdG zy8VD2J|Uf#EAw*bo5O*PO_}X2Tob{%bUoO2G~T`@%S6qPyc}VkhV}UifBuRk>%5v( z)x7B{I~z*k<7dv#5tC+m{km(D087J4O%+<<;K|qwefb6@GSX45wCK}Sn*> + + + + Code coverage report for helpers/aiHelper.js + + + + + + + + + +
+
+

All files / helpers aiHelper.js

+
+ +
+ 36.36% + Statements + 4/11 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/2 +
+ + +
+ 36.36% + Lines + 4/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +371x +  +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x + 
const { GoogleGenerativeAI } = require("@google/generative-ai");
+ 
+const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
+const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
+ 
+//cleaning text function
+function cleanText(text = "") {
+  return text
+    // Hapus heading markdown dan pemisah
+    .replace(/^#+\s*/gm, "")       
+    .replace(/---+/g, " ")         
+    // Hapus bullet dan angka daftar
+    .replace(/^\s*\d+\.\s*/gm, "") 
+    .replace(/^\s*-\s*/gm, "")     
+    .replace(/\*/g, "")            
+    // Hapus kutipan berlebih
+    .replace(/["โ€œโ€โ€˜โ€™]/g, '"')      
+    // Rapikan whitespace
+    .replace(/\r?\n+/g, " ")       
+    .replace(/\s{2,}/g, " ")       
+    .trim();
+}
+ 
+ 
+async function askGemini(prompt) {
+  try {
+    const result = await model.generateContent(prompt);
+    const rawText = result.response.text();
+    return cleanText(rawText);
+  } catch (err) {
+    console.error("โŒ Error from Gemini:", err);
+    return "Maaf, saya mengalami kesulitan menjawab saat ini.";
+  }
+}
+ 
+module.exports = { askGemini };
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/helpers/aiRecommendation.js.html b/coverage/lcov-report/helpers/aiRecommendation.js.html new file mode 100644 index 0000000..e6f385e --- /dev/null +++ b/coverage/lcov-report/helpers/aiRecommendation.js.html @@ -0,0 +1,286 @@ + + + + + + Code coverage report for helpers/aiRecommendation.js + + + + + + + + + +
+
+

All files / helpers aiRecommendation.js

+
+ +
+ 28.57% + Statements + 6/21 +
+ + +
+ 0% + Branches + 0/4 +
+ + +
+ 0% + Functions + 0/3 +
+ + +
+ 30% + Lines + 6/20 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +681x +1x +1x +  +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x
const { GoogleGenerativeAI } = require("@google/generative-ai");
+const { Post, Like, Category, User } = require("../models");
+const { Op } = require("sequelize");
+ 
+const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
+const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
+ 
+async function getAIRecommendations(userId) {
+  try {
+    const likedPosts = await Like.findAll({
+      where: { UserId: userId },
+      include: [{ model: Post, include: [Category] }],
+    });
+ 
+    if (likedPosts.length < 3) {  //minimal 3 likes
+      return Post.findAll({
+        where: { isPrivate: false },
+        include: [Category, User, Like],
+        order: [["createdAt", "DESC"]],
+        limit: 10,
+      });
+    }
+ 
+    const userInterests = likedPosts
+      .map((l) => `- "${l.Post.content}" (Kategori: ${l.Post.Category?.name || "Umum"})`)
+      .join("\n");
+ 
+    const prompt = `
+      Anda adalah sistem rekomendasi konten yang cerdas untuk aplikasi media sosial.
+      Seorang pengguna menyukai postingan-postingan berikut:
+      ${userInterests}
+ 
+      Berdasarkan daftar di atas, berikan 3 tampilan kategori yang paling relevan dengan minat pengguna.
+      Balas HANYA dengan nama kategori, dipisahkan oleh koma (contoh: Teknologi, Makanan, Olahraga).
+    `;
+ 
+    const result = await model.generateContent(prompt);
+    const categoriesText = result.response.text();
+    const categories = categoriesText.split(",").map((c) => c.trim());
+ 
+    const recommendedPosts = await Post.findAll({
+      where: {
+        isPrivate: false,
+        UserId: { [Op.ne]: userId }, // Jangan tampilkan post milik sendiri
+      },
+      include: [
+        { model: Category, where: { name: { [Op.in]: categories } } },
+        User,
+        Like,
+      ],
+      order: [["createdAt", "DESC"]],
+      limit: 20,
+    });
+ 
+    return recommendedPosts;
+  } catch (err) {
+    console.error("Error getting AI recommendations:", err);
+    // Jika AI gagal, berikan rekomendasi default (post publik terbaru)
+    return Post.findAll({
+      where: { isPrivate: false },
+      include: [Category, User, Like],
+      order: [["createdAt", "DESC"]],
+      limit: 10,
+    });
+  }
+}
+ 
+module.exports = { getAIRecommendations };
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/helpers/index.html b/coverage/lcov-report/helpers/index.html new file mode 100644 index 0000000..5cace47 --- /dev/null +++ b/coverage/lcov-report/helpers/index.html @@ -0,0 +1,146 @@ + + + + + + Code coverage report for helpers + + + + + + + + + +
+
+

All files helpers

+
+ +
+ 35.13% + Statements + 13/37 +
+ + +
+ 0% + Branches + 0/5 +
+ + +
+ 0% + Functions + 0/7 +
+ + +
+ 36.11% + Lines + 13/36 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
aiHelper.js +
+
36.36%4/110%0/10%0/236.36%4/11
aiRecommendation.js +
+
28.57%6/210%0/40%0/330%6/20
jwt.js +
+
60%3/5100%0/00%0/260%3/5
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/helpers/jwt.js.html b/coverage/lcov-report/helpers/jwt.js.html new file mode 100644 index 0000000..f3270df --- /dev/null +++ b/coverage/lcov-report/helpers/jwt.js.html @@ -0,0 +1,118 @@ + + + + + + Code coverage report for helpers/jwt.js + + + + + + + + + +
+
+

All files / helpers jwt.js

+
+ +
+ 60% + Statements + 3/5 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 0% + Functions + 0/2 +
+ + +
+ 60% + Lines + 3/5 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +121x +1x +  +  +  +  +  +  +  +  +  +1x
const jwt = require('jsonwebtoken');
+const secret = process.env.JWT_SECRET;
+ 
+function signToken(payload) {
+  return jwt.sign(payload, secret);
+}
+ 
+function verifyToken(token) {
+  return jwt.verify(token, secret);
+}
+ 
+module.exports = { signToken, verifyToken };
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/index.html b/coverage/lcov-report/index.html new file mode 100644 index 0000000..0917a4c --- /dev/null +++ b/coverage/lcov-report/index.html @@ -0,0 +1,161 @@ + + + + + + Code coverage report for All files + + + + + + + + + +
+
+

All files

+
+ +
+ 67.32% + Statements + 171/254 +
+ + +
+ 63.15% + Branches + 48/76 +
+ + +
+ 63.41% + Functions + 26/41 +
+ + +
+ 68.42% + Lines + 169/247 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
config +
+
100%1/175%9/12100%0/0100%1/1
controllers +
+
60.68%88/14565.3%32/4956.25%9/1661.87%86/139
helpers +
+
35.13%13/370%0/50%0/736.11%13/36
models +
+
97.18%69/7170%7/1094.44%17/1897.18%69/71
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/category.js.html b/coverage/lcov-report/models/category.js.html new file mode 100644 index 0000000..d90f7a8 --- /dev/null +++ b/coverage/lcov-report/models/category.js.html @@ -0,0 +1,154 @@ + + + + + + Code coverage report for models/category.js + + + + + + + + + +
+
+

All files / models category.js

+
+ +
+ 100% + Statements + 5/5 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 5/5 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24  +  +  +1x +1x +  +  +  +  +  +  +  +1x +  +  +  +1x +  +  +  +  +  +1x + 
'use strict';
+const {
+  Model
+} = require('sequelize');
+module.exports = (sequelize, DataTypes) => {
+  class Category extends Model {
+    /**
+     * Helper method for defining associations.
+     * This method is not a part of Sequelize lifecycle.
+     * The `models/index` file will call this method automatically.
+     */
+    static associate(models) {
+       Category.hasMany(models.Post);
+    }
+ 
+  }
+  Category.init({
+    name: DataTypes.STRING
+  }, {
+    sequelize,
+    modelName: 'Category',
+  });
+  return Category;
+};
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/chat.js.html b/coverage/lcov-report/models/chat.js.html new file mode 100644 index 0000000..be01356 --- /dev/null +++ b/coverage/lcov-report/models/chat.js.html @@ -0,0 +1,166 @@ + + + + + + Code coverage report for models/chat.js + + + + + + + + + +
+
+

All files / models chat.js

+
+ +
+ 100% + Statements + 7/7 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 7/7 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28  +  +  +1x +1x +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +1x +  +  +  +  +  +  +  +1x + 
'use strict';
+const {
+  Model
+} = require('sequelize');
+module.exports = (sequelize, DataTypes) => {
+  class Chat extends Model {
+    /**
+     * Helper method for defining associations.
+     * This method is not a part of Sequelize lifecycle.
+     * The `models/index` file will call this method automatically.
+     */
+    static associate(models) {
+      Chat.belongsTo(models.User, { as: "creator", foreignKey: "UserId" }); 
+      Chat.belongsTo(models.User, { as: "partner", foreignKey: "partnerId" });
+      Chat.hasMany(models.Message);
+    }
+ 
+  }
+  Chat.init({
+    isAIChat: DataTypes.BOOLEAN,
+    UserId: DataTypes.INTEGER,
+    partnerId: DataTypes.INTEGER
+  }, {
+    sequelize,
+    modelName: 'Chat',
+  });
+  return Chat;
+};
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/image.js.html b/coverage/lcov-report/models/image.js.html new file mode 100644 index 0000000..8d76a7a --- /dev/null +++ b/coverage/lcov-report/models/image.js.html @@ -0,0 +1,157 @@ + + + + + + Code coverage report for models/image.js + + + + + + + + + +
+
+

All files / models image.js

+
+ +
+ 100% + Statements + 5/5 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 5/5 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25  +  +  +1x +1x +  +  +  +  +  +  +  +1x +  +  +  +1x +  +  +  +  +  +  +1x + 
'use strict';
+const {
+  Model
+} = require('sequelize');
+module.exports = (sequelize, DataTypes) => {
+  class Image extends Model {
+    /**
+     * Helper method for defining associations.
+     * This method is not a part of Sequelize lifecycle.
+     * The `models/index` file will call this method automatically.
+     */
+    static associate(models) {
+      Image.belongsTo(models.Post);
+    }
+ 
+  }
+  Image.init({
+    imageUrl: DataTypes.STRING,
+    PostId: DataTypes.INTEGER
+  }, {
+    sequelize,
+    modelName: 'Image',
+  });
+  return Image;
+};
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/index.html b/coverage/lcov-report/models/index.html new file mode 100644 index 0000000..6a8fec7 --- /dev/null +++ b/coverage/lcov-report/models/index.html @@ -0,0 +1,221 @@ + + + + + + Code coverage report for models + + + + + + + + + +
+
+

All files models

+
+ +
+ 97.18% + Statements + 69/71 +
+ + +
+ 70% + Branches + 7/10 +
+ + +
+ 94.44% + Functions + 17/18 +
+ + +
+ 97.18% + Lines + 69/71 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
category.js +
+
100%5/5100%0/0100%2/2100%5/5
chat.js +
+
100%7/7100%0/0100%2/2100%7/7
image.js +
+
100%5/5100%0/0100%2/2100%5/5
index.js +
+
95.23%20/2170%7/10100%3/395.23%20/21
like.js +
+
100%6/6100%0/0100%2/2100%6/6
message.js +
+
100%7/7100%0/0100%2/2100%7/7
post.js +
+
100%8/8100%0/0100%2/2100%8/8
user.js +
+
91.66%11/12100%0/066.66%2/391.66%11/12
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/index.js.html b/coverage/lcov-report/models/index.js.html new file mode 100644 index 0000000..417016d --- /dev/null +++ b/coverage/lcov-report/models/index.js.html @@ -0,0 +1,214 @@ + + + + + + Code coverage report for models/index.js + + + + + + + + + +
+
+

All files / models index.js

+
+ +
+ 95.23% + Statements + 20/21 +
+ + +
+ 70% + Branches + 7/10 +
+ + +
+ 100% + Functions + 3/3 +
+ + +
+ 95.23% + Lines + 20/21 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44  +  +1x +1x +1x +1x +1x +1x +1x +1x +  +  +  +1x +  +  +1x +  +  +1x +  +  +8x +  +  +  +  +  +  +  +7x +7x +  +  +1x +7x +7x +  +  +  +1x +1x +  +1x
'use strict';
+ 
+const fs = require('fs');
+const path = require('path');
+const Sequelize = require('sequelize');
+const process = require('process');
+const basename = path.basename(__filename);
+const env = process.env.NODE_ENV || 'development';
+const config = require(__dirname + '/../config/config.js')[env]; // <-- Perubahan di sini
+const db = {};
+ 
+let sequelize;
+// Menggunakan URL dari config.js
+Iif (config.url) {
+  sequelize = new Sequelize(config.url, config);
+} else {
+  sequelize = new Sequelize(config.database, config.username, config.password, config);
+}
+ 
+fs
+  .readdirSync(__dirname)
+  .filter(file => {
+    return (
+      file.indexOf('.') !== 0 &&
+      file !== basename &&
+      file.slice(-3) === '.js' &&
+      file.indexOf('.test.js') === -1
+    );
+  })
+  .forEach(file => {
+    const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
+    db[model.name] = model;
+  });
+ 
+Object.keys(db).forEach(modelName => {
+  Eif (db[modelName].associate) {
+    db[modelName].associate(db);
+  }
+});
+ 
+db.sequelize = sequelize;
+db.Sequelize = Sequelize;
+ 
+module.exports = db;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/like.js.html b/coverage/lcov-report/models/like.js.html new file mode 100644 index 0000000..a9dcc41 --- /dev/null +++ b/coverage/lcov-report/models/like.js.html @@ -0,0 +1,160 @@ + + + + + + Code coverage report for models/like.js + + + + + + + + + +
+
+

All files / models like.js

+
+ +
+ 100% + Statements + 6/6 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 6/6 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26  +  +  +1x +1x +  +  +  +  +  +  +  +1x +1x +  +  +  +1x +  +  +  +  +  +  +1x + 
'use strict';
+const {
+  Model
+} = require('sequelize');
+module.exports = (sequelize, DataTypes) => {
+  class Like extends Model {
+    /**
+     * Helper method for defining associations.
+     * This method is not a part of Sequelize lifecycle.
+     * The `models/index` file will call this method automatically.
+     */
+    static associate(models) {
+      Like.belongsTo(models.User);
+      Like.belongsTo(models.Post);
+    }
+ 
+  }
+  Like.init({
+    UserId: DataTypes.INTEGER,
+    PostId: DataTypes.INTEGER
+  }, {
+    sequelize,
+    modelName: 'Like',
+  });
+  return Like;
+};
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/message.js.html b/coverage/lcov-report/models/message.js.html new file mode 100644 index 0000000..2a83b49 --- /dev/null +++ b/coverage/lcov-report/models/message.js.html @@ -0,0 +1,172 @@ + + + + + + Code coverage report for models/message.js + + + + + + + + + +
+
+

All files / models message.js

+
+ +
+ 100% + Statements + 7/7 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 7/7 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30  +  +  +1x +1x +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +  +1x +  +  +  +  +  +  +  +  +1x + 
'use strict';
+const {
+  Model
+} = require('sequelize');
+module.exports = (sequelize, DataTypes) => {
+  class Message extends Model {
+    /**
+     * Helper method for defining associations.
+     * This method is not a part of Sequelize lifecycle.
+     * The `models/index` file will call this method automatically.
+     */
+    static associate(models) {
+      Message.belongsTo(models.Chat);
+      Message.belongsTo(models.User, { as: "sender", foreignKey: "senderId" });
+      Message.belongsTo(models.User, { as: "receiver", foreignKey: "receiverId" });
+    }
+ 
+ 
+  }
+  Message.init({
+    ChatId: DataTypes.INTEGER,
+    senderId: DataTypes.INTEGER,
+    receiverId: DataTypes.INTEGER,
+    content: DataTypes.TEXT
+  }, {
+    sequelize,
+    modelName: 'Message',
+  });
+  return Message;
+};
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/post.js.html b/coverage/lcov-report/models/post.js.html new file mode 100644 index 0000000..760098b --- /dev/null +++ b/coverage/lcov-report/models/post.js.html @@ -0,0 +1,205 @@ + + + + + + Code coverage report for models/post.js + + + + + + + + + +
+
+

All files / models post.js

+
+ +
+ 100% + Statements + 8/8 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 8/8 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41  +  +  +1x +1x +  +  +  +  +  +  +  +1x +1x +1x +1x +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x + 
'use strict';
+const {
+  Model
+} = require('sequelize');
+module.exports = (sequelize, DataTypes) => {
+  class Post extends Model {
+    /**
+     * Helper method for defining associations.
+     * This method is not a part of Sequelize lifecycle.
+     * The `models/index` file will call this method automatically.
+     */
+    static associate(models) {
+      Post.belongsTo(models.User);
+      Post.belongsTo(models.Category);
+      Post.hasMany(models.Image);
+      Post.hasMany(models.Like)
+    }
+ 
+  }
+  Post.init({
+    content: {
+      type: DataTypes.TEXT,
+      allowNull: false,
+      validate: {
+        notEmpty: {
+          msg: "Content is required"
+        },
+        notNull: {
+          msg: "Content is required"
+        }
+      }
+    },
+    isPrivate: DataTypes.BOOLEAN,
+    UserId: DataTypes.INTEGER,
+    CategoryId: DataTypes.INTEGER
+  }, {
+    sequelize,
+    modelName: 'Post',
+  });
+  return Post;
+};
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/user.js.html b/coverage/lcov-report/models/user.js.html new file mode 100644 index 0000000..f95affd --- /dev/null +++ b/coverage/lcov-report/models/user.js.html @@ -0,0 +1,274 @@ + + + + + + Code coverage report for models/user.js + + + + + + + + + +
+
+

All files / models user.js

+
+ +
+ 91.66% + Statements + 11/12 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 66.66% + Functions + 2/3 +
+ + +
+ 91.66% + Lines + 11/12 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64  +1x +  +  +1x +1x +  +  +  +  +  +  +  +1x +1x +1x +1x +1x +1x +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x + 
'use strict';
+const bcrypt = require('bcryptjs'); 
+const {
+  Model
+} = require('sequelize');
+module.exports = (sequelize, DataTypes) => {
+  class User extends Model {
+    /**
+     * Helper method for defining associations.
+     * This method is not a part of Sequelize lifecycle.
+     * The `models/index` file will call this method automatically.
+     */
+    static associate(models) {
+      User.hasMany(models.Post);
+      User.hasMany(models.Like);
+      User.hasMany(models.Chat, { foreignKey: "UserId" });
+      User.hasMany(models.Chat, { foreignKey: "partnerId" });
+      User.hasMany(models.Message, { foreignKey: "senderId" });
+      User.hasMany(models.Message, { foreignKey: "receiverId" });
+    }
+ 
+  }
+  User.init({
+    username: {
+      type: DataTypes.STRING,
+      allowNull: false,
+      validate: {
+        notEmpty: { msg: `Username is required` },
+        notNull: { msg: `Username is required` }
+      }
+    },
+    email: {
+      type: DataTypes.STRING,
+      allowNull: false,
+      unique: { msg: `Email is already registered` },
+      validate: {
+        notEmpty: { msg: `Email is required` },
+        notNull: { msg: `Email is required` },
+        isEmail: { msg: `Invalid email format` }
+      }
+    },
+    password: {
+      type: DataTypes.STRING,
+      allowNull: false,
+      validate: {
+        notEmpty: { msg: `Password is required` },
+        notNull: { msg: `Password is required` }
+      }
+    },
+    profilePic: {
+      type: DataTypes.STRING,
+    },
+    bio: DataTypes.TEXT
+  }, {
+    sequelize,
+    modelName: 'User',
+    hooks: {
+      beforeCreate: async (user) => {
+        user.password = await bcrypt.hash(user.password, 10);
+      }
+    }
+  });
+  return User;
+};
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/postController.js.html b/coverage/lcov-report/postController.js.html new file mode 100644 index 0000000..390b625 --- /dev/null +++ b/coverage/lcov-report/postController.js.html @@ -0,0 +1,451 @@ + + + + + + Code coverage report for postController.js + + + + + + + + + +
+
+

All files postController.js

+
+ +
+ 18.86% + Statements + 10/53 +
+ + +
+ 27.77% + Branches + 5/18 +
+ + +
+ 28.57% + Functions + 2/7 +
+ + +
+ 21.27% + Lines + 10/47 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +1231x +  +  +  +  +1x +1x +  +  +1x +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +1x +1x +  +  +  +  +  +  +  +  +  +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x
const { Post, Image, Like, User, Category } = require("../models");
+ 
+class PostController {
+    // CREATE POST
+    static async createPost(req, res, next) {
+        try {
+            const { content, isPrivate, categoryId } = req.body;
+ 
+            // Buat post baru
+            const post = await Post.create({
+                content,
+                isPrivate,
+                CategoryId: categoryId || null,
+                UserId: req.user.id,
+            });
+ 
+            // Jika ada file yang di-upload, simpan URL-nya
+            Iif (req.files && req.files.length > 0) {
+                const images = req.files.map((file) => ({
+                    imageUrl: file.path, // multer-storage-cloudinary menyediakan URL di file.path
+                    PostId: post.id,
+                }));
+                await Image.bulkCreate(images);
+            }
+ 
+            res.status(201).json({ message: "Post created successfully", post });
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // READ ALL PUBLIC POSTS
+    static async getAllPublicPosts(req, res, next) {
+        try {
+            const posts = await Post.findAll({
+                where: { isPrivate: false },
+                include: [
+                    { model: User, attributes: ["id", "username", "profilePic"] },
+                    { model: Image },
+                    { model: Category, attributes: ["name"] },
+                    { model: Like },
+                ],
+                order: [["createdAt", "DESC"]],
+            });
+            res.json(posts);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // READ USER'S OWN POSTS
+    static async getMyPosts(req, res, next) {
+        try {
+            const posts = await Post.findAll({
+                where: { UserId: req.user.id },
+                include: [Image, Category, Like],
+                order: [["createdAt", "DESC"]],
+            });
+            res.json(posts);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // UPDATE POST
+    static async updatePost(req, res, next) {
+        try {
+            const { id } = req.params;
+            const { content, isPrivate, categoryId } = req.body;
+ 
+            const post = await Post.findByPk(id);
+            if (!post) throw { name: "NotFound" };
+            if (post.UserId !== req.user.id) throw { name: "Unauthorized" };
+ 
+            await post.update({ content, isPrivate, CategoryId: categoryId });
+            res.json({ message: "Post updated successfully", post });
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // DELETE POST
+    static async deletePost(req, res, next) {
+        try {
+            const { id } = req.params;
+            const post = await Post.findByPk(id);
+            if (!post) throw { name: "NotFound" };
+            if (post.UserId !== req.user.id) throw { name: "Unauthorized" };
+ 
+            await post.destroy();
+            res.json({ message: "Post deleted successfully" });
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // LIKE / UNLIKE POST
+    static async toggleLike(req, res, next) {
+        try {
+            const { id } = req.params;
+            const post = await Post.findByPk(id);
+            if (!post) throw { name: "NotFound" };
+ 
+            const existingLike = await Like.findOne({
+                where: { UserId: req.user.id, PostId: id },
+            });
+ 
+            let message;
+            if (existingLike) {
+                await existingLike.destroy();
+                message = "Post unliked";
+            } else {
+                await Like.create({ UserId: req.user.id, PostId: id });
+                message = "Post liked";
+            }
+            res.json({ message });
+        } catch (err) {
+            next(err);
+        }
+    }
+}
+ 
+module.exports = PostController;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/prettify.css b/coverage/lcov-report/prettify.css new file mode 100644 index 0000000..b317a7c --- /dev/null +++ b/coverage/lcov-report/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/coverage/lcov-report/prettify.js b/coverage/lcov-report/prettify.js new file mode 100644 index 0000000..b322523 --- /dev/null +++ b/coverage/lcov-report/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/coverage/lcov-report/sort-arrow-sprite.png b/coverage/lcov-report/sort-arrow-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed68316eb3f65dec9063332d2f69bf3093bbfab GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qh}Z>jv*C{$p!i!8j}?a+@3A= zIAGwzjijN=FBi!|L1t?LM;Q;gkwn>2cAy-KV{dn nf0J1DIvEHQu*n~6U}x}qyky7vi4|9XhBJ7&`njxgN@xNA8m%nc literal 0 HcmV?d00001 diff --git a/coverage/lcov-report/sorter.js b/coverage/lcov-report/sorter.js new file mode 100644 index 0000000..4ed70ae --- /dev/null +++ b/coverage/lcov-report/sorter.js @@ -0,0 +1,210 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + function onFilterInput() { + const searchValue = document.getElementById('fileSearch').value; + const rows = document.getElementsByTagName('tbody')[0].children; + + // Try to create a RegExp from the searchValue. If it fails (invalid regex), + // it will be treated as a plain text search + let searchRegex; + try { + searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive + } catch (error) { + searchRegex = null; + } + + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + let isMatch = false; + + if (searchRegex) { + // If a valid regex was created, use it for matching + isMatch = searchRegex.test(row.textContent); + } else { + // Otherwise, fall back to the original plain text search + isMatch = row.textContent + .toLowerCase() + .includes(searchValue.toLowerCase()); + } + + row.style.display = isMatch ? '' : 'none'; + } + } + + // loads the search box + function addSearchBox() { + var template = document.getElementById('filterTemplate'); + var templateClone = template.content.cloneNode(true); + templateClone.getElementById('fileSearch').oninput = onFilterInput; + template.parentElement.appendChild(templateClone); + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/coverage/lcov-report/userController.js.html b/coverage/lcov-report/userController.js.html new file mode 100644 index 0000000..f81df23 --- /dev/null +++ b/coverage/lcov-report/userController.js.html @@ -0,0 +1,322 @@ + + + + + + Code coverage report for userController.js + + + + + + + + + +
+
+

All files userController.js

+
+ +
+ 59.37% + Statements + 19/32 +
+ + +
+ 62.5% + Branches + 5/8 +
+ + +
+ 66.66% + Functions + 2/3 +
+ + +
+ 59.37% + Lines + 19/32 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +801x +1x +1x +1x +1x +  +  +  +  +1x +1x +1x +1x +  +  +  +  +  +  +  +  +  +  +1x +1x +1x +  +  +  +1x +1x +  +  +  +1x +1x +  +  +  +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +1x
const { User } = require('../models');
+const bcrypt = require('bcryptjs');
+const { signToken } = require('../helpers/jwt');
+const { OAuth2Client } = require('google-auth-library');
+const client = new OAuth2Client();
+ 
+ 
+class UserController {
+    static async register(req, res, next) {
+        try {
+            const { username, email, password } = req.body;
+            const newUser = await User.create({ username, email, password });
+            res.status(201).json({
+                id: newUser.id,
+                username: newUser.username,
+                email: newUser.email,
+            });
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    static async login(req, res, next) {
+        try {
+            const { email, password } = req.body;
+            Iif (!email || !password) {
+                throw { name: 'BadRequest', message: 'Email and password are required' };
+            }
+ 
+            const user = await User.findOne({ where: { email } });
+            Iif (!user) {
+                throw { name: 'InvalidLogin' };
+            }
+ 
+            const isPasswordValid = bcrypt.compareSync(password, user.password);
+            Iif (!isPasswordValid) {
+                throw { name: 'InvalidLogin' };
+            }
+ 
+            const token = signToken({ id: user.id });
+            res.status(200).json({ access_token: token });
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    static async googleSignIn(req, res, next) {
+        try {
+            const { google_token } = req.body;
+ 
+            const ticket = await client.verifyIdToken({
+                idToken: google_token,
+                audience: process.env.GOOGLE_CLIENT_ID,
+            });
+            const payload = ticket.getPayload();
+ 
+            const [user, created] = await User.findOrCreate({
+                where: { email: payload.email },
+                defaults: {
+                    username: payload.name,
+                    email: payload.email,
+                    password: Math.random().toString(36),
+                    profilePic: payload.picture,
+                },
+                hooks: false
+            });
+ 
+ 
+            const access_token = signToken({ id: user.id });
+            res.status(200).json({ access_token });
+ 
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    
+}
+ 
+module.exports = UserController;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov.info b/coverage/lcov.info new file mode 100644 index 0000000..caface0 --- /dev/null +++ b/coverage/lcov.info @@ -0,0 +1,549 @@ +TN: +SF:config\config.js +FNF:0 +FNH:0 +DA:7,1 +LF:1 +LH:1 +BRDA:10,0,0,1 +BRDA:10,0,1,1 +BRDA:14,1,0,0 +BRDA:14,1,1,1 +BRDA:18,2,0,1 +BRDA:18,2,1,1 +BRDA:21,3,0,0 +BRDA:21,3,1,1 +BRDA:25,4,0,1 +BRDA:25,4,1,1 +BRDA:28,5,0,0 +BRDA:28,5,1,1 +BRF:12 +BRH:9 +end_of_record +TN: +SF:controllers\aiController.js +FN:4,(anonymous_0) +FNF:1 +FNH:1 +FNDA:4,(anonymous_0) +DA:1,1 +DA:5,4 +DA:7,4 +DA:8,1 +DA:11,3 +DA:12,3 +DA:14,2 +DA:20,2 +DA:25,1 +LF:9 +LH:9 +BRDA:7,0,0,1 +BRDA:7,0,1,3 +BRDA:7,1,0,4 +BRDA:7,1,1,3 +BRF:4 +BRH:4 +end_of_record +TN: +SF:controllers\chatController.js +FN:7,(anonymous_0) +FN:38,(anonymous_1) +FN:59,(anonymous_2) +FN:82,(anonymous_3) +FN:103,(anonymous_4) +FNF:5 +FNH:2 +FNDA:3,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:4,(anonymous_4) +DA:1,1 +DA:2,1 +DA:3,1 +DA:8,3 +DA:9,3 +DA:10,3 +DA:12,3 +DA:13,1 +DA:17,2 +DA:31,2 +DA:33,1 +DA:39,0 +DA:40,0 +DA:41,0 +DA:52,0 +DA:54,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:70,0 +DA:76,0 +DA:78,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:96,0 +DA:98,0 +DA:104,4 +DA:105,4 +DA:106,4 +DA:107,4 +DA:108,4 +DA:110,4 +DA:111,4 +DA:112,1 +DA:117,3 +DA:118,3 +DA:119,1 +DA:123,2 +DA:129,2 +DA:131,2 +DA:132,1 +DA:134,1 +DA:140,1 +DA:143,2 +DA:144,2 +DA:146,2 +DA:151,1 +LF:51 +LH:32 +BRDA:12,0,0,1 +BRDA:12,0,1,2 +BRDA:31,1,0,1 +BRDA:31,1,1,1 +BRDA:66,2,0,0 +BRDA:66,2,1,0 +BRDA:66,3,0,0 +BRDA:66,3,1,0 +BRDA:66,3,2,0 +BRDA:96,4,0,0 +BRDA:96,4,1,0 +BRDA:111,5,0,1 +BRDA:111,5,1,3 +BRDA:117,6,0,3 +BRDA:117,6,1,1 +BRDA:118,7,0,1 +BRDA:118,7,1,2 +BRDA:131,8,0,1 +BRDA:131,8,1,1 +BRF:19 +BRH:12 +end_of_record +TN: +SF:controllers\postController.js +FN:5,(anonymous_0) +FN:19,(anonymous_1) +FN:33,(anonymous_2) +FN:52,(anonymous_3) +FN:66,(anonymous_4) +FN:83,(anonymous_5) +FN:98,(anonymous_6) +FNF:7 +FNH:5 +FNDA:2,(anonymous_0) +FNDA:2,(anonymous_1) +FNDA:1,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:2,(anonymous_4) +FNDA:0,(anonymous_5) +FNDA:2,(anonymous_6) +DA:1,1 +DA:6,2 +DA:7,2 +DA:10,2 +DA:18,2 +DA:19,2 +DA:23,1 +DA:26,2 +DA:28,0 +DA:34,1 +DA:35,1 +DA:45,1 +DA:47,0 +DA:53,0 +DA:54,0 +DA:59,0 +DA:61,0 +DA:67,2 +DA:68,2 +DA:69,2 +DA:71,2 +DA:72,2 +DA:73,2 +DA:75,1 +DA:76,1 +DA:78,1 +DA:84,0 +DA:85,0 +DA:86,0 +DA:87,0 +DA:88,0 +DA:90,0 +DA:91,0 +DA:93,0 +DA:99,2 +DA:100,2 +DA:101,2 +DA:102,2 +DA:104,2 +DA:109,2 +DA:110,1 +DA:111,1 +DA:113,1 +DA:114,1 +DA:116,2 +DA:118,0 +DA:123,1 +LF:47 +LH:32 +BRDA:13,0,0,2 +BRDA:13,0,1,1 +BRDA:18,1,0,1 +BRDA:18,1,1,1 +BRDA:18,2,0,2 +BRDA:18,2,1,2 +BRDA:72,3,0,0 +BRDA:72,3,1,2 +BRDA:73,4,0,1 +BRDA:73,4,1,1 +BRDA:87,5,0,0 +BRDA:87,5,1,0 +BRDA:88,6,0,0 +BRDA:88,6,1,0 +BRDA:102,7,0,0 +BRDA:102,7,1,2 +BRDA:109,8,0,1 +BRDA:109,8,1,1 +BRF:18 +BRH:12 +end_of_record +TN: +SF:controllers\userController.js +FN:9,(anonymous_0) +FN:23,(anonymous_1) +FN:47,(anonymous_2) +FNF:3 +FNH:1 +FNDA:0,(anonymous_0) +FNDA:1,(anonymous_1) +FNDA:0,(anonymous_2) +DA:1,1 +DA:2,1 +DA:3,1 +DA:4,1 +DA:5,1 +DA:10,0 +DA:11,0 +DA:12,0 +DA:13,0 +DA:19,0 +DA:24,1 +DA:25,1 +DA:26,1 +DA:27,0 +DA:30,1 +DA:31,1 +DA:32,1 +DA:35,0 +DA:36,0 +DA:37,0 +DA:40,0 +DA:41,0 +DA:43,1 +DA:48,0 +DA:49,0 +DA:51,0 +DA:55,0 +DA:57,0 +DA:69,0 +DA:70,0 +DA:73,0 +DA:80,1 +LF:32 +LH:13 +BRDA:26,0,0,0 +BRDA:26,0,1,1 +BRDA:26,1,0,1 +BRDA:26,1,1,1 +BRDA:31,2,0,1 +BRDA:31,2,1,0 +BRDA:36,3,0,0 +BRDA:36,3,1,0 +BRF:8 +BRH:4 +end_of_record +TN: +SF:helpers\aiHelper.js +FN:7,cleanText +FN:25,askGemini +FNF:2 +FNH:0 +FNDA:0,cleanText +FNDA:0,askGemini +DA:1,1 +DA:3,1 +DA:4,1 +DA:8,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:31,0 +DA:32,0 +DA:36,1 +LF:11 +LH:4 +BRDA:7,0,0,0 +BRF:1 +BRH:0 +end_of_record +TN: +SF:helpers\aiRecommendation.js +FN:8,getAIRecommendations +FN:25,(anonymous_1) +FN:39,(anonymous_2) +FNF:3 +FNH:0 +FNDA:0,getAIRecommendations +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +DA:1,1 +DA:2,1 +DA:3,1 +DA:5,1 +DA:6,1 +DA:9,0 +DA:10,0 +DA:15,0 +DA:16,0 +DA:24,0 +DA:25,0 +DA:28,0 +DA:37,0 +DA:38,0 +DA:39,0 +DA:41,0 +DA:55,0 +DA:57,0 +DA:59,0 +DA:68,1 +LF:20 +LH:6 +BRDA:15,0,0,0 +BRDA:15,0,1,0 +BRDA:25,1,0,0 +BRDA:25,1,1,0 +BRF:4 +BRH:0 +end_of_record +TN: +SF:helpers\jwt.js +FN:4,signToken +FN:8,verifyToken +FNF:2 +FNH:0 +FNDA:0,signToken +FNDA:0,verifyToken +DA:1,1 +DA:2,1 +DA:5,0 +DA:9,0 +DA:12,1 +LF:5 +LH:3 +BRF:0 +BRH:0 +end_of_record +TN: +SF:models\category.js +FN:5,(anonymous_0) +FN:12,(anonymous_1) +FNF:2 +FNH:2 +FNDA:1,(anonymous_0) +FNDA:1,(anonymous_1) +DA:4,1 +DA:5,1 +DA:13,1 +DA:17,1 +DA:23,1 +LF:5 +LH:5 +BRF:0 +BRH:0 +end_of_record +TN: +SF:models\chat.js +FN:5,(anonymous_0) +FN:12,(anonymous_1) +FNF:2 +FNH:2 +FNDA:1,(anonymous_0) +FNDA:1,(anonymous_1) +DA:4,1 +DA:5,1 +DA:13,1 +DA:14,1 +DA:15,1 +DA:19,1 +DA:27,1 +LF:7 +LH:7 +BRF:0 +BRH:0 +end_of_record +TN: +SF:models\image.js +FN:5,(anonymous_0) +FN:12,(anonymous_1) +FNF:2 +FNH:2 +FNDA:1,(anonymous_0) +FNDA:1,(anonymous_1) +DA:4,1 +DA:5,1 +DA:13,1 +DA:17,1 +DA:24,1 +LF:5 +LH:5 +BRF:0 +BRH:0 +end_of_record +TN: +SF:models\index.js +FN:22,(anonymous_0) +FN:30,(anonymous_1) +FN:35,(anonymous_2) +FNF:3 +FNH:3 +FNDA:8,(anonymous_0) +FNDA:7,(anonymous_1) +FNDA:7,(anonymous_2) +DA:3,1 +DA:4,1 +DA:5,1 +DA:6,1 +DA:7,1 +DA:8,1 +DA:9,1 +DA:10,1 +DA:14,1 +DA:15,0 +DA:17,1 +DA:20,1 +DA:23,8 +DA:31,7 +DA:32,7 +DA:35,1 +DA:36,7 +DA:37,7 +DA:41,1 +DA:42,1 +DA:44,1 +LF:21 +LH:20 +BRDA:8,0,0,1 +BRDA:8,0,1,0 +BRDA:14,1,0,0 +BRDA:14,1,1,1 +BRDA:24,2,0,8 +BRDA:24,2,1,8 +BRDA:24,2,2,7 +BRDA:24,2,3,7 +BRDA:36,3,0,7 +BRDA:36,3,1,0 +BRF:10 +BRH:7 +end_of_record +TN: +SF:models\like.js +FN:5,(anonymous_0) +FN:12,(anonymous_1) +FNF:2 +FNH:2 +FNDA:1,(anonymous_0) +FNDA:1,(anonymous_1) +DA:4,1 +DA:5,1 +DA:13,1 +DA:14,1 +DA:18,1 +DA:25,1 +LF:6 +LH:6 +BRF:0 +BRH:0 +end_of_record +TN: +SF:models\message.js +FN:5,(anonymous_0) +FN:12,(anonymous_1) +FNF:2 +FNH:2 +FNDA:1,(anonymous_0) +FNDA:1,(anonymous_1) +DA:4,1 +DA:5,1 +DA:13,1 +DA:14,1 +DA:15,1 +DA:20,1 +DA:29,1 +LF:7 +LH:7 +BRF:0 +BRH:0 +end_of_record +TN: +SF:models\post.js +FN:5,(anonymous_0) +FN:12,(anonymous_1) +FNF:2 +FNH:2 +FNDA:1,(anonymous_0) +FNDA:1,(anonymous_1) +DA:4,1 +DA:5,1 +DA:13,1 +DA:14,1 +DA:15,1 +DA:16,1 +DA:20,1 +DA:40,1 +LF:8 +LH:8 +BRF:0 +BRH:0 +end_of_record +TN: +SF:models\user.js +FN:6,(anonymous_0) +FN:13,(anonymous_1) +FN:58,(anonymous_2) +FNF:3 +FNH:2 +FNDA:1,(anonymous_0) +FNDA:1,(anonymous_1) +FNDA:0,(anonymous_2) +DA:2,1 +DA:5,1 +DA:6,1 +DA:14,1 +DA:15,1 +DA:16,1 +DA:17,1 +DA:18,1 +DA:19,1 +DA:23,1 +DA:59,0 +DA:63,1 +LF:12 +LH:11 +BRF:0 +BRH:0 +end_of_record diff --git a/package-lock.json b/package-lock.json index 9b26423..1581430 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,1596 +27,4692 @@ "socket.io": "^4.8.1" }, "devDependencies": { + "@types/jest": "^30.0.0", + "cross-env": "^7.0.3", + "jest": "^30.2.0", "nodemon": "^3.1.10", - "sequelize-cli": "^6.6.3" + "sequelize-cli": "^6.6.3", + "supertest": "^7.1.4" } }, - "node_modules/@google/generative-ai": { - "version": "0.24.1", - "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz", - "integrity": "sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==", - "license": "Apache-2.0", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { - "node": ">=12" + "node": ">=6.9.0" } }, - "node_modules/@one-ini/wasm": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", - "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "node_modules/@babel/compat-data": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@babel/core": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "dev": true, "license": "MIT", - "optional": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, "engines": { - "node": ">=14" + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", - "license": "MIT" + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } }, - "node_modules/@types/cors": { - "version": "2.8.19", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", - "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, "license": "MIT", "dependencies": { - "@types/ms": "*" + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "24.7.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.2.tgz", - "integrity": "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==", - "license": "MIT", + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", "dependencies": { - "undici-types": "~7.14.0" + "yallist": "^3.0.2" } }, - "node_modules/@types/validator": { - "version": "13.15.3", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.3.tgz", - "integrity": "sha512-7bcUmDyS6PN3EuD9SlGGOxM77F8WLVsrwkxyWxKnxzmXoequ6c7741QBrANq6htVRGOITJ7z72mTP6Z4XyuG+Q==", - "license": "MIT" - }, - "node_modules/abbrev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=6.9.0" } }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, "license": "MIT", "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { - "node": ">= 0.6" + "node": ">=6.9.0" } }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, "engines": { - "node": ">= 14" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">=6.9.0" } }, - "node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=6.9.0" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, + "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=6.9.0" } }, - "node_modules/append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", - "license": "MIT" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": ">= 4.0.0" + "node": ">=6.9.0" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "dev": true, - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, "engines": { - "node": "^4.5.0 || >= 5.9" + "node": ">=6.9.0" } }, - "node_modules/base64url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", - "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "dev": true, "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, "engines": { "node": ">=6.0.0" } }, - "node_modules/bcryptjs": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", - "integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==", - "license": "BSD-3-Clause", - "bin": { - "bcrypt": "bin/bcrypt" + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/bignumber.js": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", - "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, "license": "MIT", - "engines": { - "node": "*" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", "license": "MIT", "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.0", - "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": ">=18" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, "license": "MIT", "dependencies": { - "fill-range": "^7.1.1" + "@babel/helper-plugin-utils": "^7.10.4" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "license": "BSD-3-Clause" - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT" - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", "dependencies": { - "streamsearch": "^1.1.0" + "@babel/helper-plugin-utils": "^7.8.0" }, - "engines": { - "node": ">=10.16.0" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, "engines": { - "node": ">= 0.8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" + "@babel/helper-plugin-utils": "^7.10.4" }, - "engines": { - "node": ">= 0.4" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" + "@babel/helper-plugin-utils": "^7.8.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "@babel/helper-plugin-utils": "^7.10.4" }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cliui/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" + "@babel/helper-plugin-utils": "^7.8.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cliui/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/cliui/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/cloudinary": { - "version": "1.41.3", - "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-1.41.3.tgz", - "integrity": "sha512-4o84y+E7dbif3lMns+p3UW6w6hLHEifbX/7zBJvaih1E9QNMZITENQ14GPYJC4JmhygYXsuuBb9bRA3xWEoOfg==", + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, "license": "MIT", "dependencies": { - "cloudinary-core": "^2.13.0", - "core-js": "^3.30.1", - "lodash": "^4.17.21", - "q": "^1.5.1" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { - "node": ">=0.6" + "node": ">=6.9.0" } }, - "node_modules/cloudinary-core": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/cloudinary-core/-/cloudinary-core-2.14.0.tgz", - "integrity": "sha512-L+kjoYgU+5wyiPkSnmeCbmtT6DwSyYUN/WoI/fEb6Xsx2gtB3iuf/50W0SvcQkeKzllfH5Knh8I4ST924DkkRw==", + "node_modules/@babel/traverse": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "dev": true, "license": "MIT", - "peerDependencies": { - "lodash": ">=4.0" + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { - "node": ">=7.0.0" + "node": ">=6.9.0" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true, "license": "MIT" }, - "node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "node_modules/@emnapi/core": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", + "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=14" + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "node_modules/@emnapi/runtime": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", + "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", "dev": true, - "license": "MIT" - }, - "node_modules/concat-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", - "engines": [ - "node >= 6.0" - ], "license": "MIT", + "optional": true, "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.0.2", - "typedarray": "^0.0.6" + "tslib": "^2.4.0" } }, - "node_modules/config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" + "tslib": "^2.4.0" } }, - "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, + "node_modules/@google/generative-ai": { + "version": "0.24.1", + "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz", + "integrity": "sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==", + "license": "Apache-2.0", "engines": { - "node": ">= 0.6" + "node": ">=18.0.0" } }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=12" } }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, "license": "MIT", "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/core-js": { - "version": "3.46.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz", - "integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==", - "hasInstallScript": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "node": ">=8" } }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "node_modules/@jest/console": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", + "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", + "dev": true, "license": "MIT", "dependencies": { - "object-assign": "^4", - "vary": "^1" + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "slash": "^3.0.0" }, "engines": { - "node": ">= 0.10" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/@jest/core": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", + "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", "dev": true, "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@jest/console": "30.2.0", + "@jest/pattern": "30.0.1", + "@jest/reporters": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.2.0", + "jest-config": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-resolve-dependencies": "30.2.0", + "jest-runner": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "jest-watcher": "30.2.0", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 12" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/@jest/environment": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", + "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", + "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.3" + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-mock": "30.2.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "node_modules/@jest/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", + "dev": true, "license": "MIT", + "dependencies": { + "expect": "30.2.0", + "jest-snapshot": "30.2.0" + }, "engines": { - "node": ">= 0.8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/dotenv": { - "version": "17.2.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", - "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" + "node_modules/@jest/expect-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" }, - "funding": { - "url": "https://dotenvx.com" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/dottie": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz", - "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==", - "license": "MIT" - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "node_modules/@jest/fake-timers": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", + "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", + "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" + "@jest/types": "30.2.0", + "@sinonjs/fake-timers": "^13.0.0", + "@types/node": "*", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", "dev": true, - "license": "MIT" - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/editorconfig": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", - "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "node_modules/@jest/globals": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", + "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", "dev": true, "license": "MIT", "dependencies": { - "@one-ini/wasm": "0.1.1", - "commander": "^10.0.0", - "minimatch": "9.0.1", - "semver": "^7.5.3" - }, - "bin": { - "editorconfig": "bin/editorconfig" + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/types": "30.2.0", + "jest-mock": "30.2.0" }, "engines": { - "node": ">=14" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/editorconfig/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/editorconfig/node_modules/minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "node_modules/@jest/reporters": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", + "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "@types/node": "*", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^5.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", + "slash": "^3.0.0", + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "engines": { - "node": ">=16 || 14 >=14.17" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", "dev": true, - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, "engines": { - "node": ">= 0.8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/engine.io": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", - "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "node_modules/@jest/snapshot-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", + "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", + "dev": true, "license": "MIT", "dependencies": { - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.7.2", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.17.1" + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" }, "engines": { - "node": ">=10.2.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/engine.io-parser": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", - "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "node_modules/@jest/source-map": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "dev": true, "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" + }, "engines": { - "node": ">=10.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/engine.io/node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/@jest/test-result": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", + "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", + "dev": true, "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "@jest/console": "30.2.0", + "@jest/types": "30.2.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" }, "engines": { - "node": ">= 0.6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/engine.io/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "node_modules/@jest/test-sequencer": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", + "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", + "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.3" + "@jest/test-result": "30.2.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "slash": "^3.0.0" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/engine.io/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/@jest/transform": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", + "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", + "dev": true, "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.1", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, "engines": { - "node": ">= 0.6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/engine.io/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" }, "engines": { - "node": ">= 0.6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/engine.io/node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz", + "integrity": "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.7.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.2.tgz", + "integrity": "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.14.0" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/validator": { + "version": "13.15.3", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.3.tgz", + "integrity": "sha512-7bcUmDyS6PN3EuD9SlGGOxM77F8WLVsrwkxyWxKnxzmXoequ6c7741QBrANq6htVRGOITJ7z72mTP6Z4XyuG+Q==", + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/babel-jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", + "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "30.2.0", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^7.0.1", + "babel-preset-jest": "30.2.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "dev": true, + "license": "BSD-3-Clause", + "workspaces": [ + "test/babel-8" + ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", + "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/babel__core": "^7.20.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", + "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-beta.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.16", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.16.tgz", + "integrity": "sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/bcryptjs": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", + "integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==", + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" + } + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.26.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", + "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.9", + "caniuse-lite": "^1.0.30001746", + "electron-to-chromium": "^1.5.227", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001750", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001750.tgz", + "integrity": "sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.0.tgz", + "integrity": "sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/cloudinary": { + "version": "1.41.3", + "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-1.41.3.tgz", + "integrity": "sha512-4o84y+E7dbif3lMns+p3UW6w6hLHEifbX/7zBJvaih1E9QNMZITENQ14GPYJC4JmhygYXsuuBb9bRA3xWEoOfg==", + "license": "MIT", + "dependencies": { + "cloudinary-core": "^2.13.0", + "core-js": "^3.30.1", + "lodash": "^4.17.21", + "q": "^1.5.1" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/cloudinary-core": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/cloudinary-core/-/cloudinary-core-2.14.0.tgz", + "integrity": "sha512-L+kjoYgU+5wyiPkSnmeCbmtT6DwSyYUN/WoI/fEb6Xsx2gtB3iuf/50W0SvcQkeKzllfH5Knh8I4ST924DkkRw==", + "license": "MIT", + "peerDependencies": { + "lodash": ">=4.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-js": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.46.0.tgz", + "integrity": "sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/dotenv": { + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dottie": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.6.tgz", + "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==", + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/editorconfig": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", + "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" + }, + "bin": { + "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.236", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.236.tgz", + "integrity": "sha512-Yi43booTJp2VteesVja4xdcDrAcVFItkD6RrxhMSuGx1kShh+raMwnKyIGNOTl68reqSxPPls6bB8LgIcrK9Gg==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, "node_modules/es-object-atoms": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/formidable": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", + "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@paralleldrive/cuid2": "^2.2.2", + "dezalgo": "^1.0.4", + "once": "^1.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaxios": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.2.tgz", + "integrity": "sha512-/Szrn8nr+2TsQT1Gp8iIe/BEytJmbyfrbFh419DfGQSkEgNEhbPi7JRJuughjkTzPWgU9gBQf5AVu3DbHt0OXA==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gcp-metadata": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-7.0.1.tgz", + "integrity": "sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/google-auth-library": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.4.0.tgz", + "integrity": "sha512-CmIrSy1bqMQUsPmA9+hcSbAXL80cFhu40cGMUjCaLpNKVzzvi+0uAHq8GNZxkoGYIsTX4ZQ7e4aInAqWxgn4fg==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.0.0", + "gcp-metadata": "^7.0.0", + "google-logging-utils": "^1.0.0", + "gtoken": "^8.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-auth-library/node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/google-auth-library/node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/google-logging-utils": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.1.tgz", + "integrity": "sha512-rcX58I7nqpu4mbKztFeOAObbomBbHU2oIb/d3tJfF3dizGSApqtSwYJigGCooHdnMyQBIw8BrWyK96w3YXgr6A==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/gtoken": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz", + "integrity": "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==", + "license": "MIT", + "dependencies": { + "gaxios": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gtoken/node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/gtoken/node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "license": "MIT", "dependencies": { - "es-errors": "^1.3.0" + "agent-base": "^7.1.2", + "debug": "4" }, "engines": { - "node": ">= 0.4" + "node": ">= 14" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "engines": { - "node": ">=6" + "node": ">=10.17.0" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, "license": "MIT", "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.0", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" }, "engines": { - "node": ">= 18" + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "license": "MIT" + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } + "node_modules/inflection": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz", + "integrity": "sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==", + "engines": [ + "node >= 0.4.0" ], + "license": "MIT" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, "license": "MIT", "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" + "binary-extensions": "^2.0.0" }, "engines": { - "node": "^12.20 || >= 14.13" + "node": ">=8" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/finalhandler": { + "node_modules/is-generator-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, - "license": "ISC", + "license": "BSD-3-Clause", "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=10" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "license": "MIT", + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "fetch-blob": "^3.1.2" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=12.20.0" + "node": ">=10" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" }, "engines": { "node": ">=10" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=8" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/gaxios": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.2.tgz", - "integrity": "sha512-/Szrn8nr+2TsQT1Gp8iIe/BEytJmbyfrbFh419DfGQSkEgNEhbPi7JRJuughjkTzPWgU9gBQf5AVu3DbHt0OXA==", - "license": "Apache-2.0", + "node_modules/jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz", + "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", + "dev": true, + "license": "MIT", "dependencies": { - "extend": "^3.0.2", - "https-proxy-agent": "^7.0.1", - "node-fetch": "^3.3.2" + "@jest/core": "30.2.0", + "@jest/types": "30.2.0", + "import-local": "^3.2.0", + "jest-cli": "30.2.0" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">=18" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/gcp-metadata": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-7.0.1.tgz", - "integrity": "sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==", - "license": "Apache-2.0", + "node_modules/jest-changed-files": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz", + "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", + "dev": true, + "license": "MIT", "dependencies": { - "gaxios": "^7.0.0", - "google-logging-utils": "^1.0.0", - "json-bigint": "^1.0.0" + "execa": "^5.1.1", + "jest-util": "30.2.0", + "p-limit": "^3.1.0" }, "engines": { - "node": ">=18" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/jest-circus": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", + "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "p-limit": "^3.1.0", + "pretty-format": "30.2.0", + "pure-rand": "^7.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-cli": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz", + "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "yargs": "^17.7.2" + }, + "bin": { + "jest": "bin/jest.js" }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "node_modules/jest-cli/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, "engines": { - "node": ">= 0.4" + "node": ">=8" } }, - "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "node_modules/jest-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" + "color-convert": "^2.0.1" }, - "bin": { - "glob": "dist/esm/bin.mjs" + "engines": { + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/jest-cli/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "license": "ISC", "dependencies": { - "is-glob": "^4.0.1" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">= 6" + "node": ">=12" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "node_modules/jest-cli/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } + "license": "MIT" }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/jest-cli/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=8" } }, - "node_modules/google-auth-library": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.4.0.tgz", - "integrity": "sha512-CmIrSy1bqMQUsPmA9+hcSbAXL80cFhu40cGMUjCaLpNKVzzvi+0uAHq8GNZxkoGYIsTX4ZQ7e4aInAqWxgn4fg==", - "license": "Apache-2.0", + "node_modules/jest-cli/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", "dependencies": { - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "gaxios": "^7.0.0", - "gcp-metadata": "^7.0.0", - "google-logging-utils": "^1.0.0", - "gtoken": "^8.0.0", - "jws": "^4.0.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/google-auth-library/node_modules/jwa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "node_modules/jest-cli/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "license": "MIT", "dependencies": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/google-auth-library/node_modules/jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "node_modules/jest-cli/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, "license": "MIT", "dependencies": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" } }, - "node_modules/google-logging-utils": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.1.tgz", - "integrity": "sha512-rcX58I7nqpu4mbKztFeOAObbomBbHU2oIb/d3tJfF3dizGSApqtSwYJigGCooHdnMyQBIw8BrWyK96w3YXgr6A==", - "license": "Apache-2.0", + "node_modules/jest-cli/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", "engines": { - "node": ">=14" + "node": ">=12" } }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "node_modules/jest-config": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", + "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", + "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/get-type": "30.1.0", + "@jest/pattern": "30.0.1", + "@jest/test-sequencer": "30.2.0", + "@jest/types": "30.2.0", + "babel-jest": "30.2.0", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-circus": "30.2.0", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-runner": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "micromatch": "^4.0.8", + "parse-json": "^5.2.0", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "peerDependencies": { + "@types/node": "*", + "esbuild-register": ">=3.4.0", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild-register": { + "optional": true + }, + "ts-node": { + "optional": true + } } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "node_modules/jest-diff": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", "dev": true, - "license": "ISC" - }, - "node_modules/gtoken": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz", - "integrity": "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==", "license": "MIT", "dependencies": { - "gaxios": "^7.0.0", - "jws": "^4.0.0" + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" }, "engines": { - "node": ">=18" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/gtoken/node_modules/jwa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "node_modules/jest-docblock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", + "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "dev": true, "license": "MIT", "dependencies": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" + "detect-newline": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/gtoken/node_modules/jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "node_modules/jest-each": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", + "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", + "dev": true, "license": "MIT", "dependencies": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" + "@jest/get-type": "30.1.0", + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "jest-util": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/jest-environment-node": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", + "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", "dev": true, "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-mock": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0" + }, "engines": { - "node": ">=4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "node_modules/jest-haste-map": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", + "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", + "dev": true, "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", + "micromatch": "^4.0.8", + "walker": "^1.0.8" + }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "optionalDependencies": { + "fsevents": "^2.3.3" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "node_modules/jest-leak-detector": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", + "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", + "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.2" + "@jest/get-type": "30.1.0", + "pretty-format": "30.2.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "node_modules/jest-matcher-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" }, "engines": { - "node": ">= 0.8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/jest-message-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.2.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, "engines": { - "node": ">= 0.8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "node_modules/jest-mock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-util": "30.2.0" }, "engines": { - "node": ">= 14" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } } }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", "dev": true, - "license": "ISC" - }, - "node_modules/inflection": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz", - "integrity": "sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==", - "engines": [ - "node >= 0.4.0" - ], - "license": "MIT" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "node_modules/jest-resolve": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", + "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", "dev": true, - "license": "ISC" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" + }, "engines": { - "node": ">= 0.10" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/jest-resolve-dependencies": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz", + "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", "dev": true, "license": "MIT", "dependencies": { - "binary-extensions": "^2.0.0" + "jest-regex-util": "30.0.1", + "jest-snapshot": "30.2.0" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "node_modules/jest-runner": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", + "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "@jest/console": "30.2.0", + "@jest/environment": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-leak-detector": "30.2.0", + "jest-message-util": "30.2.0", + "jest-resolve": "30.2.0", + "jest-runtime": "30.2.0", + "jest-util": "30.2.0", + "jest-watcher": "30.2.0", + "jest-worker": "30.2.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", + "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/globals": "30.2.0", + "@jest/source-map": "30.0.1", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", + "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0", + "chalk": "^4.1.2", + "expect": "30.2.0", + "graceful-fs": "^4.2.11", + "jest-diff": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "pretty-format": "30.2.0", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" }, "engines": { - "node": ">= 0.4" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/jest-validate": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", + "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", "dev": true, "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.2.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.2.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/jest-watcher": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", + "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", "dev": true, "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.2.0", + "string-length": "^4.0.2" }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/jest-worker": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", + "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", "dev": true, "license": "MIT", + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.2.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, "engines": { - "node": ">=0.12.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/is-promise": { + "node_modules/jest-worker/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "@isaacs/cliui": "^8.0.2" + "has-flag": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">=10" }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/js-beautify": { @@ -1651,6 +4747,40 @@ "node": ">=14" } }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/json-bigint": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", @@ -1660,6 +4790,26 @@ "bignumber.js": "^9.0.0" } }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/jsonfile": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", @@ -1716,6 +4866,36 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -1771,6 +4951,32 @@ "dev": true, "license": "ISC" }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -1801,6 +5007,50 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/mime-db": { "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", @@ -1822,6 +5072,16 @@ "node": ">= 0.6" } }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1963,6 +5223,29 @@ "node": ">= 0.6" } }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, "node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -2010,6 +5293,20 @@ "url": "https://opencollective.com/node-fetch" } }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", + "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", + "dev": true, + "license": "MIT" + }, "node_modules/nodemon": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", @@ -2065,6 +5362,19 @@ "node": ">=0.10.0" } }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/oauth": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.10.2.tgz", @@ -2113,6 +5423,77 @@ "wrappy": "1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -2120,6 +5501,25 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -2187,6 +5587,26 @@ "node": ">= 0.4.0" } }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -2357,6 +5777,29 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -2390,10 +5833,38 @@ "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", "license": "MIT", "dependencies": { - "xtend": "^4.0.0" + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/proto-list": { @@ -2423,6 +5894,23 @@ "dev": true, "license": "MIT" }, + "node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -2489,6 +5977,13 @@ "url": "https://opencollective.com/express" } }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -2547,6 +6042,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/retry-as-promised": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-7.1.1.tgz", @@ -2865,6 +6383,16 @@ "node": ">=10" } }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/socket.io": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", @@ -3000,6 +6528,27 @@ "node": ">= 0.6" } }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/split2": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", @@ -3009,6 +6558,26 @@ "node": ">= 10.x" } }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", @@ -3035,6 +6604,43 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -3139,6 +6745,74 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superagent": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz", + "integrity": "sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.1", + "cookiejar": "^2.1.4", + "debug": "^4.3.7", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.4", + "formidable": "^3.5.4", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/supertest": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.4.tgz", + "integrity": "sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "methods": "^1.1.2", + "superagent": "^10.2.3" + }, + "engines": { + "node": ">=14.18.0" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -3165,6 +6839,66 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3203,6 +6937,37 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/type-is": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", @@ -3280,6 +7045,72 @@ "node": ">= 0.8" } }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -3304,6 +7135,21 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/validator": { "version": "13.15.15", "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.15.tgz", @@ -3322,6 +7168,16 @@ "node": ">= 0.8" } }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -3460,6 +7316,20 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/ws": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", @@ -3500,6 +7370,13 @@ "node": ">=10" } }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -3573,6 +7450,19 @@ "engines": { "node": ">=8" } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 5054d8f..5a344a4 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,11 @@ "version": "1.0.0", "description": "", "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "scripts": { + "test": "cross-env NODE_ENV=test jest --runInBand --detectOpenHandles --forceExit --reporters=default --reporters=./config/simpleJestReporter.js", + "test:coverage": "cross-env NODE_ENV=test jest --runInBand --detectOpenHandles --forceExit --coverage", + "test:watch": "cross-env NODE_ENV=test jest --watch", + "test:setup": "cross-env NODE_ENV=test npx sequelize-cli db:create && cross-env NODE_ENV=test npx sequelize-cli db:migrate" }, "repository": { "type": "git", @@ -36,7 +39,11 @@ "socket.io": "^4.8.1" }, "devDependencies": { + "@types/jest": "^30.0.0", + "jest": "^30.2.0", "nodemon": "^3.1.10", - "sequelize-cli": "^6.6.3" + "sequelize-cli": "^6.6.3", + "supertest": "^7.1.4", + "cross-env": "^7.0.3" } } diff --git a/tests/unit/aiController.test.js b/tests/unit/aiController.test.js new file mode 100644 index 0000000..e3bcf27 --- /dev/null +++ b/tests/unit/aiController.test.js @@ -0,0 +1,76 @@ +const AIController = require('../../controllers/aiController'); +const { getAIRecommendations } = require('../../helpers/aiRecommendation'); + +// Mock the AI recommendation helper +jest.mock('../../helpers/aiRecommendation'); + +describe('Test AI Controller', () => { + // Reset semua mock sebelum setiap test + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('getRecommendations - Mendapatkan Rekomendasi Post', () => { + const mockReq = { user: { id: 1 } }; + const mockRes = { + json: jest.fn(), + status: jest.fn().mockReturnThis() + }; + const mockNext = jest.fn(); + + test('berhasil mengembalikan rekomendasi post', async () => { + // Mock successful recommendation + const mockPosts = [ + { id: 1, content: 'Post 1' }, + { id: 2, content: 'Post 2' } + ]; + getAIRecommendations.mockResolvedValue(mockPosts); + + await AIController.getRecommendations(mockReq, mockRes, mockNext); + + expect(getAIRecommendations).toHaveBeenCalledWith(1); + expect(mockRes.json).toHaveBeenCalledWith({ + message: "Rekomendasi berhasil dibuat", + count: 2, + data: mockPosts + }); + expect(mockNext).not.toHaveBeenCalled(); + }); + + test('berhasil menangani kasus rekomendasi kosong', async () => { + // Mock rekomendasi kosong + getAIRecommendations.mockResolvedValue([]); + + await AIController.getRecommendations(mockReq, mockRes, mockNext); + + expect(getAIRecommendations).toHaveBeenCalledWith(1); + expect(mockRes.json).toHaveBeenCalledWith({ + message: "Rekomendasi berhasil dibuat", + count: 0, + data: [] + }); + }); + + test('berhasil menangani kasus AI service timeout', async () => { + // Mock AI service timeout + getAIRecommendations.mockRejectedValue(new Error('AI Service Timeout')); + + await AIController.getRecommendations(mockReq, mockRes, mockNext); + + expect(getAIRecommendations).toHaveBeenCalledWith(1); + expect(mockNext).toHaveBeenCalledWith(new Error('AI Service Timeout')); + expect(mockRes.json).not.toHaveBeenCalled(); + }); + + test('handles missing user in request', async () => { + const reqWithoutUser = { user: null }; + + await AIController.getRecommendations(reqWithoutUser, mockRes, mockNext); + + expect(getAIRecommendations).not.toHaveBeenCalled(); + expect(mockNext).toHaveBeenCalled(); + const error = mockNext.mock.calls[0][0]; + expect(error.name).toBe('Unauthorized'); + }); + }); +}); \ No newline at end of file diff --git a/tests/unit/chatController.test.js b/tests/unit/chatController.test.js new file mode 100644 index 0000000..e7ed621 --- /dev/null +++ b/tests/unit/chatController.test.js @@ -0,0 +1,156 @@ +const ChatController = require('../../controllers/chatController'); +const { Chat, Message, User, Sequelize } = require('../../models'); +const { askGemini } = require('../../helpers/aiHelper'); + +// Mock all dependencies +jest.mock('../../models', () => ({ + Chat: { + findOrCreate: jest.fn(), + findAll: jest.fn(), + findByPk: jest.fn(), + }, + Message: { + findAll: jest.fn(), + create: jest.fn(), + }, + User: { + findByPk: jest.fn(), + }, + Sequelize: { + Op: { + or: Symbol('or') + } + } +})); + +jest.mock('../../helpers/aiHelper'); + +describe('Test Chat Controller', () => { + let mockReq; + let mockRes; + let mockNext; + let mockSocketIO; + + beforeEach(() => { + jest.clearAllMocks(); + mockReq = { + user: { id: 1 }, + body: {}, + params: {}, + app: { + get: jest.fn().mockReturnValue({ + to: jest.fn().mockReturnValue({ emit: jest.fn() }) + }) + } + }; + mockRes = { + json: jest.fn(), + status: jest.fn().mockReturnThis() + }; + mockNext = jest.fn(); + mockSocketIO = { + to: jest.fn().mockReturnValue({ emit: jest.fn() }) + }; + }); + + describe('createOrGetChat - Membuat atau Mendapatkan Chat', () => { + test('berhasil membuat chat baru', async () => { + mockReq.body.partnerId = 2; + Chat.findOrCreate.mockResolvedValue([{ id: 1 }, true]); + + await ChatController.createOrGetChat(mockReq, mockRes, mockNext); + + expect(Chat.findOrCreate).toHaveBeenCalled(); + expect(mockRes.status).toHaveBeenCalledWith(201); + expect(mockRes.json).toHaveBeenCalled(); + }); + + test('mencegah user chat dengan dirinya sendiri', async () => { + mockReq.body.partnerId = 1; // Sama dengan user.id + + await ChatController.createOrGetChat(mockReq, mockRes, mockNext); + + expect(Chat.findOrCreate).not.toHaveBeenCalled(); + expect(mockNext).toHaveBeenCalled(); + const error = mockNext.mock.calls[0][0]; + expect(error.name).toBe('BadRequest'); + }); + + test('mengembalikan chat yang sudah ada', async () => { + mockReq.body.partnerId = 2; + Chat.findOrCreate.mockResolvedValue([{ id: 1 }, false]); + + await ChatController.createOrGetChat(mockReq, mockRes, mockNext); + + expect(mockRes.status).toHaveBeenCalledWith(200); + expect(mockRes.json).toHaveBeenCalled(); + }); + }); + + describe('sendMessage - Mengirim Pesan', () => { + beforeEach(() => { + mockReq.params.chatId = '1'; + mockReq.body.content = 'Hello'; + }); + + test('berhasil mengirim pesan di chat biasa', async () => { + Chat.findByPk.mockResolvedValue({ + id: 1, + UserId: 1, + partnerId: 2, + isAIChat: false, + save: jest.fn() + }); + Message.create.mockResolvedValue({ id: 1, content: 'Hello' }); + + await ChatController.sendMessage(mockReq, mockRes, mockNext); + + expect(Message.create).toHaveBeenCalledTimes(1); + expect(mockRes.status).toHaveBeenCalledWith(201); + }); + + test('berhasil mengirim pesan dan mendapat respons AI dalam AI chat', async () => { + Chat.findByPk.mockResolvedValue({ + id: 1, + UserId: 1, + isAIChat: true, + save: jest.fn() + }); + Message.create.mockResolvedValueOnce({ id: 1, content: 'Hello' }); + askGemini.mockResolvedValue('AI Response'); + Message.create.mockResolvedValueOnce({ id: 2, content: 'AI Response' }); + + await ChatController.sendMessage(mockReq, mockRes, mockNext); + + expect(Message.create).toHaveBeenCalledTimes(2); + expect(askGemini).toHaveBeenCalled(); + }); + + test('menangani akses tidak sah', async () => { + Chat.findByPk.mockResolvedValue({ + id: 1, + UserId: 3, // Berbeda dari req.user.id + partnerId: 4, + isAIChat: false + }); + + await ChatController.sendMessage(mockReq, mockRes, mockNext); + + expect(Message.create).not.toHaveBeenCalled(); + expect(mockNext).toHaveBeenCalled(); + const error = mockNext.mock.calls[0][0]; + expect(error.name).toBe('Forbidden'); + }); + + test('menangani kasus chat tidak ditemukan', async () => { + Chat.findByPk.mockResolvedValue(null); + + await ChatController.sendMessage(mockReq, mockRes, mockNext); + + expect(Message.create).not.toHaveBeenCalled(); + expect(mockNext).toHaveBeenCalled(); + const error = mockNext.mock.calls[0][0]; + expect(error.name).toBe('NotFound'); + }); + }); +}); \ No newline at end of file diff --git a/tests/unit/postController.test.js b/tests/unit/postController.test.js new file mode 100644 index 0000000..2038e99 --- /dev/null +++ b/tests/unit/postController.test.js @@ -0,0 +1,178 @@ +// __tests__/postController.test.js +const PostController = require('../../controllers/postController'); +const { Post, Image, Like, User, Category } = require('../../models'); + +jest.mock('../../models', () => ({ + Post: { + create: jest.fn(), + findAll: jest.fn(), + findByPk: jest.fn(), + }, + Image: { + bulkCreate: jest.fn(), + }, + Like: { + findOne: jest.fn(), + create: jest.fn(), + destroy: jest.fn(), + }, + User: {}, + Category: {}, +})); + +describe('Test Post Controller', () => { + let mockReq; + let mockRes; + let mockNext; + + beforeEach(() => { + jest.clearAllMocks(); + mockReq = { + user: { id: 1 }, + body: {}, + params: {}, + files: [], + }; + mockRes = { + json: jest.fn(), + status: jest.fn().mockReturnThis(), + }; + mockNext = jest.fn(); + }); + + describe('createPost - Membuat Postingan Baru', () => { + test('berhasil membuat post dengan gambar', async () => { + mockReq.body = { content: 'Test post', isPrivate: false, categoryId: 1 }; + mockReq.files = [ + { path: 'gambar1.jpg' }, + { path: 'gambar2.jpg' } + ]; + + Post.create.mockResolvedValue({ id: 1, ...mockReq.body }); + Image.bulkCreate.mockResolvedValue([ + { id: 1, imageUrl: 'gambar1.jpg' }, + { id: 2, imageUrl: 'gambar2.jpg' } + ]); + + await PostController.createPost(mockReq, mockRes, mockNext); + + expect(Post.create).toHaveBeenCalledWith({ + content: 'Test post', + isPrivate: false, + CategoryId: 1, + UserId: 1 + }); + expect(Image.bulkCreate).toHaveBeenCalledWith([ + { imageUrl: 'gambar1.jpg', PostId: 1 }, + { imageUrl: 'gambar2.jpg', PostId: 1 } + ]); + expect(mockRes.status).toHaveBeenCalledWith(201); + expect(mockRes.json).toHaveBeenCalled(); + }); + + test('berhasil membuat post dengan 1 gambar minimal', async () => { + mockReq.body = { content: 'Post teks saja' }; + // At least one image is required by the controller + mockReq.files = [{ path: 'gambar-required.jpg' }]; + + Post.create.mockResolvedValue({ id: 1, ...mockReq.body }); + Image.bulkCreate.mockResolvedValue([{ id: 1, imageUrl: 'gambar-required.jpg' }]); + + await PostController.createPost(mockReq, mockRes, mockNext); + + expect(Post.create).toHaveBeenCalledWith(expect.objectContaining({ + content: 'Post teks saja', + UserId: 1 + })); + expect(Image.bulkCreate).toHaveBeenCalledWith([ + { imageUrl: 'gambar-required.jpg', PostId: 1 } + ]); + expect(mockRes.status).toHaveBeenCalledWith(201); + expect(mockRes.json).toHaveBeenCalled(); + }); + }); + + describe('getAllPublicPosts - Mendapatkan Semua Post Publik', () => { + test('berhasil mendapatkan post publik dengan data terkait', async () => { + const mockPosts = [ + { id: 1, content: 'Post publik 1', User: { username: 'user1' } }, + { id: 2, content: 'Post publik 2', User: { username: 'user2' } } + ]; + Post.findAll.mockResolvedValue(mockPosts); + + await PostController.getAllPublicPosts(mockReq, mockRes, mockNext); + + expect(Post.findAll).toHaveBeenCalledWith({ + where: { isPrivate: false }, + include: expect.any(Array), + order: [['createdAt', 'DESC']] + }); + expect(mockRes.json).toHaveBeenCalledWith(mockPosts); + }); + }); + + describe('updatePost - Mengupdate Postingan', () => { + test('berhasil mengupdate post sendiri', async () => { + mockReq.params.id = '1'; + mockReq.body = { content: 'Konten yang diupdate' }; + const mockPost = { + id: 1, + UserId: 1, + update: jest.fn().mockResolvedValue({ id: 1, ...mockReq.body }) + }; + Post.findByPk.mockResolvedValue(mockPost); + + await PostController.updatePost(mockReq, mockRes, mockNext); + + expect(mockPost.update).toHaveBeenCalledWith(mockReq.body); + // Controller mengembalikan objek dengan shape { message, post } + expect(mockRes.json).toHaveBeenCalledWith(expect.objectContaining({ + post: expect.objectContaining({ id: 1 }) + })); + }); + + test('mencegah update post user lain', async () => { + mockReq.params.id = '1'; + Post.findByPk.mockResolvedValue({ + id: 1, + UserId: 2 + }); + + await PostController.updatePost(mockReq, mockRes, mockNext); + + expect(mockNext).toHaveBeenCalled(); + const error = mockNext.mock.calls[0][0]; + expect(error).toBeDefined(); + expect(error.name).toBe('Unauthorized'); + }); + }); + + describe('toggleLike - Menyukai/Batal Menyukai Post', () => { + test('berhasil menyukai post', async () => { + mockReq.params.id = '1'; + Post.findByPk.mockResolvedValue({ id: 1 }); + Like.findOne.mockResolvedValue(null); + Like.create.mockResolvedValue({ id: 1, UserId: 1, PostId: '1' }); + + await PostController.toggleLike(mockReq, mockRes, mockNext); + + expect(Like.create).toHaveBeenCalledWith({ + UserId: 1, + PostId: '1' + }); + expect(mockRes.json).toHaveBeenCalledWith({ message: 'Post liked' }); + }); + + test('berhasil membatalkan like pada post', async () => { + mockReq.params.id = '1'; + Post.findByPk.mockResolvedValue({ id: 1 }); + const existingLike = { destroy: jest.fn().mockResolvedValue() }; + Like.findOne.mockResolvedValue(existingLike); + + await PostController.toggleLike(mockReq, mockRes, mockNext); + + expect(existingLike.destroy).toHaveBeenCalled(); + expect(mockRes.json).toHaveBeenCalledWith({ message: 'Post unliked' }); + }); + }); +}); diff --git a/tests/unit/userController.error.test.js b/tests/unit/userController.error.test.js new file mode 100644 index 0000000..00575c4 --- /dev/null +++ b/tests/unit/userController.error.test.js @@ -0,0 +1,20 @@ +const UserController = require('../../controllers/userController'); + +jest.mock('../../models', () => ({ + User: { + findOne: jest.fn(async () => null), + }, +})); + +jest.mock('bcryptjs', () => ({ compareSync: jest.fn(() => false) })); + +describe('UserController error handling', () => { + test('login calls next when invalid credentials', async () => { + const req = { body: { email: 'no@one.com', password: 'bad' } }; + const res = { status: jest.fn(() => res), json: jest.fn() }; + const next = jest.fn(); + + await UserController.login(req, res, next); + expect(next).toHaveBeenCalled(); + }); +}); From ebb308c766578b663e750263dae7d465caaf01e4 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Wed, 15 Oct 2025 13:20:57 +0700 Subject: [PATCH 10/62] Config fixed --- config/config.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/config/config.js b/config/config.js index bb238f7..1cb0282 100644 --- a/config/config.js +++ b/config/config.js @@ -1,30 +1,32 @@ /** * Sequelize configuration file - * Provides sensible defaults for development/test/production - * Uses environment variables when available so CI/production can override. + * Supports Supabase / PostgreSQL with SSL */ +require('dotenv').config(); // pastikan dotenv dipanggil di awal + +const useSSL = process.env.DB_SSL === 'true'; + module.exports = { development: { - // Use single env var 'db' as connection URL for now (e.g. postgres://user:pass@host:port/db) - url: process.env.db || null, + url: process.env.DATABASE_URL, dialect: 'postgres', logging: false, define: { timestamps: true }, - dialectOptions: process.env.DB_SSL === 'true' ? { ssl: { rejectUnauthorized: false } } : {}, + dialectOptions: useSSL ? { ssl: { require: true, rejectUnauthorized: false } } : {}, }, test: { - url: process.env.db || null, + url: process.env.DATABASE_URL, dialect: 'postgres', logging: false, - dialectOptions: process.env.DB_SSL === 'true' ? { ssl: { rejectUnauthorized: false } } : {}, + dialectOptions: useSSL ? { ssl: { require: true, rejectUnauthorized: false } } : {}, }, production: { - url: process.env.db || null, + url: process.env.DATABASE_URL, dialect: 'postgres', logging: false, - dialectOptions: process.env.DB_SSL === 'true' ? { ssl: { rejectUnauthorized: false } } : {}, + dialectOptions: useSSL ? { ssl: { require: true, rejectUnauthorized: false } } : {}, }, }; From c7db6207cba09c9b51fe92b424193014a3c358d9 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Wed, 15 Oct 2025 13:35:42 +0700 Subject: [PATCH 11/62] Testing SocketIO --- client.html | 25 ++++++++++++++++ package-lock.json | 73 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 client.html diff --git a/client.html b/client.html new file mode 100644 index 0000000..634c06a --- /dev/null +++ b/client.html @@ -0,0 +1,25 @@ + + + + Socket.IO Test + + +

Socket.IO Connection Test

+ + + + + diff --git a/package-lock.json b/package-lock.json index 1581430..ee7c3d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,8 @@ "pg": "^8.16.3", "pg-hstore": "^2.3.4", "sequelize": "^6.37.7", - "socket.io": "^4.8.1" + "socket.io": "^4.8.1", + "socket.io-client": "^4.8.1" }, "devDependencies": { "@types/jest": "^30.0.0", @@ -2774,6 +2775,36 @@ "node": ">=10.2.0" } }, + "node_modules/engine.io-client": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz", + "integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-client/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/engine.io-parser": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", @@ -6438,6 +6469,38 @@ } } }, + "node_modules/socket.io-client": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz", + "integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-client/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/socket.io-parser": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", @@ -7351,6 +7414,14 @@ } } }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", From 8ece08ecdf6c2670f311dc0643246cacbe128836 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Wed, 15 Oct 2025 14:52:04 +0700 Subject: [PATCH 12/62] Testing login google & Update SocketIO --- app.js | 5 +- client.html => public/client.html | 0 public/google-login-fixed.html | 117 ++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 2 deletions(-) rename client.html => public/client.html (100%) create mode 100644 public/google-login-fixed.html diff --git a/app.js b/app.js index 4f6ad2a..618b10a 100644 --- a/app.js +++ b/app.js @@ -21,6 +21,7 @@ app.set('socketio', io); app.use(cors()); app.use(express.json()); app.use(express.urlencoded({ extended: true })); +app.use(express.static('public')); // Serve static files // Router app.use(routes); @@ -34,11 +35,11 @@ io.on('connection', (socket) => { socket.on('join_chat', (chatId) => { socket.join(`chat_${chatId}`); - console.log(`User ${socket.id} joined room: chat_${chatId}`); + // console.log(`User ${socket.id} joined room: chat_${chatId}`); }); socket.on('disconnect', () => { - console.log('โŒ User disconnected:', socket.id); + // console.log('โŒ User disconnected:', socket.id); }); }); diff --git a/client.html b/public/client.html similarity index 100% rename from client.html rename to public/client.html diff --git a/public/google-login-fixed.html b/public/google-login-fixed.html new file mode 100644 index 0000000..a3ac22d --- /dev/null +++ b/public/google-login-fixed.html @@ -0,0 +1,117 @@ + + + + + + Login dengan Google + + + + +
+

Login dengan Google

+
+
+ +
+
+ + + + \ No newline at end of file From 99b725687cd3848f423616d3a2bd04933c7cff82 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Wed, 15 Oct 2025 22:33:53 +0700 Subject: [PATCH 13/62] Test & update bug final --- __mocks__/express.js | 20 + __tests__/ai.test.js | 46 + __tests__/app.test.js | 79 + __tests__/chat.test.js | 336 ++ __tests__/helpers/aiHelper.test.js | 75 + __tests__/helpers/aiRecommendation.test.js | 174 + __tests__/helpers/authMiddleware.test.js | 108 + __tests__/helpers/cloudinary.test.js | 90 + __tests__/helpers/handleError.test.js | 82 + __tests__/helpers/jwt.test.js | 63 + __tests__/post.test.js | 341 ++ __tests__/routes/aiRouter.test.js | 36 + __tests__/routes/chatRouter.test.js | 30 + __tests__/routes/index.test.js | 40 + __tests__/routes/postRouter.test.js | 49 + __tests__/routes/userRouter.test.js | 27 + __tests__/socket.test.js | 173 + __tests__/user.test.js | 179 + app.js | 27 +- controllers/userController.js | 3 - coverage/clover.xml | 513 +-- coverage/coverage-final.json | 30 +- .../lcov-report/Dummy-Instagram/app.js.html | 268 ++ .../config/config.js.html | 56 +- .../{ => Dummy-Instagram}/config/index.html | 36 +- .../controllers/aiController.js.html | 160 + .../controllers}/chatController.js.html | 94 +- .../Dummy-Instagram/controllers/index.html | 161 + .../controllers}/postController.js.html | 271 +- .../controllers/userController.js.html | 97 +- .../helpers/aiHelper.js.html | 53 +- .../helpers/aiRecommendation.js.html | 90 +- .../helpers/authMiddleware.js.html} | 98 +- .../helpers/cloudinary.js.html} | 84 +- .../helpers/handleError.js.html | 175 + .../Dummy-Instagram/helpers/index.html | 191 + .../{ => Dummy-Instagram}/helpers/jwt.js.html | 20 +- .../{helpers => Dummy-Instagram}/index.html | 60 +- .../models/category.js.html | 30 +- .../{ => Dummy-Instagram}/models/chat.js.html | 34 +- .../models/image.js.html | 30 +- .../{ => Dummy-Instagram}/models/index.html | 48 +- .../models/index.js.html | 72 +- .../{ => Dummy-Instagram}/models/like.js.html | 32 +- .../models/message.js.html | 34 +- .../{ => Dummy-Instagram}/models/post.js.html | 36 +- .../{ => Dummy-Instagram}/models/user.js.html | 60 +- .../Dummy-Instagram/routes/aiRouter.js.html | 109 + .../Dummy-Instagram/routes/chatRouter.js.html | 151 + .../Dummy-Instagram/routes/index.html | 176 + .../Dummy-Instagram/routes/index.js.html | 124 + .../Dummy-Instagram/routes/postRouter.js.html | 136 + .../Dummy-Instagram/routes/userRouter.js.html | 112 + .../controllers/chatController.js.html | 535 --- coverage/lcov-report/controllers/index.html | 161 - .../controllers/postController.js.html | 451 --- coverage/lcov-report/index.html | 108 +- coverage/lcov-report/userController.js.html | 322 -- coverage/lcov.info | 807 ++-- helpers/aiHelper.js | 9 +- helpers/aiRecommendation.js | 31 +- helpers/authMiddleware.js | 20 +- jest.config.js | 16 + models/index.js | 2 +- package-lock.json | 3489 ++++++++++++++++- package.json | 10 +- tests/unit/aiController.test.js | 76 - tests/unit/chatController.test.js | 156 - tests/unit/postController.test.js | 178 - tests/unit/userController.error.test.js | 20 - 70 files changed, 8524 insertions(+), 3486 deletions(-) create mode 100644 __mocks__/express.js create mode 100644 __tests__/ai.test.js create mode 100644 __tests__/app.test.js create mode 100644 __tests__/chat.test.js create mode 100644 __tests__/helpers/aiHelper.test.js create mode 100644 __tests__/helpers/aiRecommendation.test.js create mode 100644 __tests__/helpers/authMiddleware.test.js create mode 100644 __tests__/helpers/cloudinary.test.js create mode 100644 __tests__/helpers/handleError.test.js create mode 100644 __tests__/helpers/jwt.test.js create mode 100644 __tests__/post.test.js create mode 100644 __tests__/routes/aiRouter.test.js create mode 100644 __tests__/routes/chatRouter.test.js create mode 100644 __tests__/routes/index.test.js create mode 100644 __tests__/routes/postRouter.test.js create mode 100644 __tests__/routes/userRouter.test.js create mode 100644 __tests__/socket.test.js create mode 100644 __tests__/user.test.js create mode 100644 coverage/lcov-report/Dummy-Instagram/app.js.html rename coverage/lcov-report/{ => Dummy-Instagram}/config/config.js.html (73%) rename coverage/lcov-report/{ => Dummy-Instagram}/config/index.html (77%) create mode 100644 coverage/lcov-report/Dummy-Instagram/controllers/aiController.js.html rename coverage/lcov-report/{ => Dummy-Instagram/controllers}/chatController.js.html (86%) create mode 100644 coverage/lcov-report/Dummy-Instagram/controllers/index.html rename coverage/lcov-report/{ => Dummy-Instagram/controllers}/postController.js.html (58%) rename coverage/lcov-report/{ => Dummy-Instagram}/controllers/userController.js.html (77%) rename coverage/lcov-report/{ => Dummy-Instagram}/helpers/aiHelper.js.html (79%) rename coverage/lcov-report/{ => Dummy-Instagram}/helpers/aiRecommendation.js.html (75%) rename coverage/lcov-report/{controllers/aiController.js.html => Dummy-Instagram/helpers/authMiddleware.js.html} (62%) rename coverage/lcov-report/{aiController.js.html => Dummy-Instagram/helpers/cloudinary.js.html} (57%) create mode 100644 coverage/lcov-report/Dummy-Instagram/helpers/handleError.js.html create mode 100644 coverage/lcov-report/Dummy-Instagram/helpers/index.html rename coverage/lcov-report/{ => Dummy-Instagram}/helpers/jwt.js.html (86%) rename coverage/lcov-report/{helpers => Dummy-Instagram}/index.html (61%) rename coverage/lcov-report/{ => Dummy-Instagram}/models/category.js.html (84%) rename coverage/lcov-report/{ => Dummy-Instagram}/models/chat.js.html (84%) rename coverage/lcov-report/{ => Dummy-Instagram}/models/image.js.html (85%) rename coverage/lcov-report/{ => Dummy-Instagram}/models/index.html (84%) rename coverage/lcov-report/{ => Dummy-Instagram}/models/index.js.html (78%) rename coverage/lcov-report/{ => Dummy-Instagram}/models/like.js.html (84%) rename coverage/lcov-report/{ => Dummy-Instagram}/models/message.js.html (85%) rename coverage/lcov-report/{ => Dummy-Instagram}/models/post.js.html (87%) rename coverage/lcov-report/{ => Dummy-Instagram}/models/user.js.html (84%) create mode 100644 coverage/lcov-report/Dummy-Instagram/routes/aiRouter.js.html create mode 100644 coverage/lcov-report/Dummy-Instagram/routes/chatRouter.js.html create mode 100644 coverage/lcov-report/Dummy-Instagram/routes/index.html create mode 100644 coverage/lcov-report/Dummy-Instagram/routes/index.js.html create mode 100644 coverage/lcov-report/Dummy-Instagram/routes/postRouter.js.html create mode 100644 coverage/lcov-report/Dummy-Instagram/routes/userRouter.js.html delete mode 100644 coverage/lcov-report/controllers/chatController.js.html delete mode 100644 coverage/lcov-report/controllers/index.html delete mode 100644 coverage/lcov-report/controllers/postController.js.html delete mode 100644 coverage/lcov-report/userController.js.html create mode 100644 jest.config.js delete mode 100644 tests/unit/aiController.test.js delete mode 100644 tests/unit/chatController.test.js delete mode 100644 tests/unit/postController.test.js delete mode 100644 tests/unit/userController.error.test.js diff --git a/__mocks__/express.js b/__mocks__/express.js new file mode 100644 index 0000000..c90263c --- /dev/null +++ b/__mocks__/express.js @@ -0,0 +1,20 @@ +// __mocks__/express.js +const mockRouter = { + use: jest.fn(), + get: jest.fn(), + post: jest.fn(), + put: jest.fn(), + delete: jest.fn(), +}; + +const express = jest.fn(() => ({ + use: jest.fn(), + set: jest.fn(), +})); + +express.Router = jest.fn(() => mockRouter); +express.json = jest.fn(() => 'json middleware'); +express.urlencoded = jest.fn(() => 'urlencoded middleware'); +express.static = jest.fn(() => 'static middleware'); + +module.exports = express; diff --git a/__tests__/ai.test.js b/__tests__/ai.test.js new file mode 100644 index 0000000..e3e3bc8 --- /dev/null +++ b/__tests__/ai.test.js @@ -0,0 +1,46 @@ +const AIController = require('../controllers/aiController'); +const { getAIRecommendations } = require('../helpers/aiRecommendation'); + +jest.mock('../helpers/aiRecommendation'); + +describe('AIController', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('getRecommendations', () => { + it('should return recommendations when user is authenticated', async () => { + const mockPosts = [{ id: 1, title: 'Post 1' }]; + getAIRecommendations.mockResolvedValue(mockPosts); + + const req = { user: { id: 1 } }; + const res = { + status: jest.fn().mockReturnThis(), + json: jest.fn() + }; + const next = jest.fn(); + + await AIController.getRecommendations(req, res, next); + + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith({ + message: "Rekomendasi berhasil dibuat", + count: 1, + data: mockPosts + }); + }); + + it('should call next with error when user is not authenticated', async () => { + const req = { user: null }; + const res = { + status: jest.fn().mockReturnThis(), + json: jest.fn() + }; + const next = jest.fn(); + + await AIController.getRecommendations(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: "Unauthorized" }); + }); + }); +}); diff --git a/__tests__/app.test.js b/__tests__/app.test.js new file mode 100644 index 0000000..3c7640a --- /dev/null +++ b/__tests__/app.test.js @@ -0,0 +1,79 @@ +// ๐Ÿงช app.test.js โ€” clean version +jest.mock('express'); +jest.mock('cors'); +jest.mock('morgan'); +jest.mock('socket.io'); +jest.mock('../helpers/handleError'); +jest.mock('../routes'); + +const express = require('express'); +const cors = require('cors'); +const morgan = require('morgan'); +const { Server } = require('socket.io'); +const http = require('http'); +const handleError = require('../helpers/handleError'); +const routes = require('../routes'); + +describe('App Configuration', () => { + let mockApp; + let mockServer; + let mockIo; + + beforeEach(() => { + mockApp = { + use: jest.fn(), + set: jest.fn(), + }; + + express.mockReturnValue(mockApp); + cors.mockReturnValue('cors middleware'); + morgan.mockReturnValue('morgan middleware'); + + mockServer = { listen: jest.fn() }; + http.createServer = jest.fn().mockReturnValue(mockServer); + + const mockOn = jest.fn(); + mockIo = { on: mockOn }; + Server.mockImplementation(() => mockIo); + + jest.isolateModules(() => { + require('../app'); + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + +test('should set up middleware correctly', () => { + expect(mockApp.use).toHaveBeenCalledWith('cors middleware'); + expect(mockApp.use).toHaveBeenCalledWith('json middleware'); + expect(mockApp.use).toHaveBeenCalledWith('urlencoded middleware'); + expect(mockApp.use).toHaveBeenCalledWith('static middleware'); + expect(mockApp.use).toHaveBeenCalledWith('/', routes); + expect(mockApp.use).toHaveBeenCalledWith(handleError); +}); + + + test('should set up socket.io', () => { + expect(mockApp.set).toHaveBeenCalledWith('socketio', mockIo); + }); + + test('should register socket.io event handlers', () => { + expect(mockIo.on).toHaveBeenCalledWith('connection', expect.any(Function)); + + const connectionHandler = mockIo.on.mock.calls.find(call => call[0] === 'connection')[1]; + const mockSocket = { on: jest.fn(), join: jest.fn() }; + connectionHandler(mockSocket); + + expect(mockSocket.on).toHaveBeenCalledWith('join_chat', expect.any(Function)); + const joinHandler = mockSocket.on.mock.calls.find(call => call[0] === 'join_chat')[1]; + joinHandler('abc'); + expect(mockSocket.join).toHaveBeenCalledWith('chat_abc'); + }); + + test('should not start server if in test environment', () => { + process.env.NODE_ENV = 'test'; + expect(mockServer.listen).not.toHaveBeenCalled(); + }); +}); diff --git a/__tests__/chat.test.js b/__tests__/chat.test.js new file mode 100644 index 0000000..0bfca7c --- /dev/null +++ b/__tests__/chat.test.js @@ -0,0 +1,336 @@ +const ChatController = require('../controllers/chatController'); +const { Chat, Message, User } = require('../models'); +const { askGemini } = require('../helpers/aiHelper'); + +jest.mock('../models'); +jest.mock('../helpers/aiHelper'); + +describe('ChatController', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + + describe('createOrGetChat', () => { + it('should create a new chat if one does not exist', async () => { + const req = { + user: { id: 1 }, + body: { partnerId: 2 } + }; + const res = { + status: jest.fn().mockReturnThis(), + json: jest.fn() + }; + const next = jest.fn(); + const mockChat = { + id: 1, + UserId: 1, + partnerId: 2, + isAIChat: false + }; + + Chat.findOrCreate.mockResolvedValue([mockChat, true]); + + await ChatController.createOrGetChat(req, res, next); + + expect(res.status).toHaveBeenCalledWith(201); + expect(res.json).toHaveBeenCalledWith(mockChat); + }); + + test('should return existing chat if one exists', async () => { + const req = { user: { id: 1 }, body: { partnerId: 2 } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const mockChat = { id: 1, UserId: 1, partnerId: 2, isAIChat: false }; + + Chat.findOrCreate.mockResolvedValue([mockChat, false]); + + await ChatController.createOrGetChat(req, res, next); + + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith(mockChat); + }); + + test('should throw BadRequest if user tries to chat with themselves', async () => { + const req = { user: { id: 1 }, body: { partnerId: 1 } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + + await ChatController.createOrGetChat(req, res, next); + + expect(next).toHaveBeenCalledWith({ + name: 'BadRequest', + message: 'You cannot create a chat with yourself.', + }); + }); + + test('should call next with error if findOrCreate fails', async () => { + const req = { user: { id: 1 }, body: { partnerId: 2 } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + + Chat.findOrCreate.mockRejectedValue(error); + + await ChatController.createOrGetChat(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); + + describe('getUserChats', () => { + it('should return all chats for a user', async () => { + const req = { user: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockChats = [ + { id: 1, UserId: 1, partnerId: 2, creator: { username: 'user1' }, partner: { username: 'user2' } }, + ]; + + Chat.findAll.mockResolvedValue(mockChats); + + await ChatController.getUserChats(req, res, next); + + // We only test the response, not the exact query + expect(res.json).toHaveBeenCalledWith(mockChats); + }); + + test('should call next with error if findAll fails', async () => { + const req = { user: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + + Chat.findAll.mockRejectedValue(error); + + await ChatController.getUserChats(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); + + describe('getChatMessages', () => { + test('should return messages for a valid chat', async () => { + const req = { user: { id: 1 }, params: { chatId: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockChat = { id: 1, UserId: 1, partnerId: 2 }; + const mockMessages = [{ id: 1, content: 'Hello', sender: { username: 'user1' } }]; + + Chat.findByPk.mockResolvedValue(mockChat); + Message.findAll.mockResolvedValue(mockMessages); + + await ChatController.getChatMessages(req, res, next); + + expect(Chat.findByPk).toHaveBeenCalledWith(1); + expect(Message.findAll).toHaveBeenCalledWith({ + where: { ChatId: 1 }, + include: [{ model: User, as: 'sender', attributes: ['id', 'username'] }], + order: [['createdAt', 'ASC']], + }); + expect(res.json).toHaveBeenCalledWith(mockMessages); + }); + + test('should throw Forbidden error if user is not part of the chat', async () => { + const req = { user: { id: 3 }, params: { chatId: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockChat = { id: 1, UserId: 1, partnerId: 2 }; + + Chat.findByPk.mockResolvedValue(mockChat); + + await ChatController.getChatMessages(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: 'Forbidden' }); + }); + + test('should throw Forbidden error if chat not found', async () => { + const req = { user: { id: 1 }, params: { chatId: 99 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + + Chat.findByPk.mockResolvedValue(null); + + await ChatController.getChatMessages(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: 'Forbidden' }); + }); + + test('should call next with error if findByPk fails', async () => { + const req = { user: { id: 1 }, params: { chatId: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + + Chat.findByPk.mockRejectedValue(error); + + await ChatController.getChatMessages(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); + + describe('createAIChat', () => { + test('should create a new AI chat if one does not exist', async () => { + const req = { user: { id: 1 } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const mockChat = { id: 1, UserId: 1, isAIChat: true, partnerId: null }; + + Chat.findOrCreate.mockResolvedValue([mockChat, true]); + + await ChatController.createAIChat(req, res, next); + + expect(Chat.findOrCreate).toHaveBeenCalledWith({ + where: { + UserId: 1, + isAIChat: true, + }, + defaults: { + UserId: 1, + isAIChat: true, + partnerId: null, + }, + }); + expect(res.status).toHaveBeenCalledWith(201); + expect(res.json).toHaveBeenCalledWith(mockChat); + }); + + test('should return existing AI chat if one exists', async () => { + const req = { user: { id: 1 } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const mockChat = { id: 1, UserId: 1, isAIChat: true, partnerId: null }; + + Chat.findOrCreate.mockResolvedValue([mockChat, false]); + + await ChatController.createAIChat(req, res, next); + + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith(mockChat); + }); + + test('should call next with error if findOrCreate fails', async () => { + const req = { user: { id: 1 } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + + Chat.findOrCreate.mockRejectedValue(error); + + await ChatController.createAIChat(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); + + describe('sendMessage', () => { + let mockIo; + beforeEach(() => { + mockIo = { + to: jest.fn().mockReturnThis(), + emit: jest.fn(), + }; + }); + + test('should send a user message and return it', async () => { + const req = { user: { id: 1 }, params: { chatId: 1 }, body: { content: 'Hello' }, app: { get: jest.fn().mockReturnValue(mockIo) } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const mockChat = { id: 1, UserId: 1, partnerId: 2, isAIChat: false, save: jest.fn() }; + const mockUserMessage = { ChatId: 1, senderId: 1, content: 'Hello' }; + + Chat.findByPk.mockResolvedValue(mockChat); + Message.create.mockResolvedValue(mockUserMessage); + + await ChatController.sendMessage(req, res, next); + + expect(Chat.findByPk).toHaveBeenCalledWith(1); + expect(Message.create).toHaveBeenCalledWith({ + ChatId: 1, + senderId: 1, + content: 'Hello', + }); + expect(mockIo.to).toHaveBeenCalledWith('chat_1'); + expect(mockIo.emit).toHaveBeenCalledWith('receive_message', mockUserMessage); + expect(mockChat.save).toHaveBeenCalled(); + expect(res.status).toHaveBeenCalledWith(201); + expect(res.json).toHaveBeenCalledWith(mockUserMessage); + }); + + test('should send a user message and an AI response for AI chat', async () => { + const req = { user: { id: 1 }, params: { chatId: 1 }, body: { content: 'Hello AI' }, app: { get: jest.fn().mockReturnValue(mockIo) } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const mockChat = { id: 1, UserId: 1, isAIChat: true, save: jest.fn() }; + const mockUserMessage = { ChatId: 1, senderId: 1, content: 'Hello AI' }; + const mockAiResponseText = 'AI response'; + const mockAiMessage = { ChatId: 1, senderId: null, content: mockAiResponseText }; + + Chat.findByPk.mockResolvedValue(mockChat); + Message.create.mockResolvedValueOnce(mockUserMessage).mockResolvedValueOnce(mockAiMessage); + askGemini.mockResolvedValue(mockAiResponseText); + + await ChatController.sendMessage(req, res, next); + + expect(Chat.findByPk).toHaveBeenCalledWith(1); + expect(Message.create).toHaveBeenCalledWith({ + ChatId: 1, + senderId: 1, + content: 'Hello AI', + }); + expect(askGemini).toHaveBeenCalledWith('Hello AI'); + expect(Message.create).toHaveBeenCalledWith({ + ChatId: 1, + senderId: null, + content: mockAiResponseText, + }); + expect(mockIo.to).toHaveBeenCalledWith('chat_1'); + expect(mockIo.emit).toHaveBeenCalledWith('receive_message', mockUserMessage); + expect(mockIo.emit).toHaveBeenCalledWith('receive_message', mockAiMessage); + expect(mockChat.save).toHaveBeenCalled(); + expect(res.status).toHaveBeenCalledWith(201); + expect(res.json).toHaveBeenCalledWith(mockUserMessage); + }); + + test('should throw NotFound error if chat does not exist', async () => { + const req = { user: { id: 1 }, params: { chatId: 99 }, body: { content: 'Hello' }, app: { get: jest.fn().mockReturnValue(mockIo) } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + + Chat.findByPk.mockResolvedValue(null); + + await ChatController.sendMessage(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: 'NotFound', message: 'Chat not found' }); + }); + + test('should throw Forbidden error if user is not authorized for the chat', async () => { + const req = { user: { id: 3 }, params: { chatId: 1 }, body: { content: 'Hello' }, app: { get: jest.fn().mockReturnValue(mockIo) } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const mockChat = { id: 1, UserId: 1, partnerId: 2, isAIChat: false, save: jest.fn() }; + + Chat.findByPk.mockResolvedValue(mockChat); + + await ChatController.sendMessage(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: 'Forbidden', message: 'You are not authorized to access this chat' }); + }); + + test('should call next with error if sendMessage fails', async () => { + const req = { user: { id: 1 }, params: { chatId: 1 }, body: { content: 'Hello' }, app: { get: jest.fn().mockReturnValue(mockIo) } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + const mockChat = { id: 1, UserId: 1, partnerId: 2, isAIChat: false, save: jest.fn() }; + + Chat.findByPk.mockResolvedValue(mockChat); + Message.create.mockRejectedValue(error); + + await ChatController.sendMessage(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); +}); diff --git a/__tests__/helpers/aiHelper.test.js b/__tests__/helpers/aiHelper.test.js new file mode 100644 index 0000000..a7c2ce7 --- /dev/null +++ b/__tests__/helpers/aiHelper.test.js @@ -0,0 +1,75 @@ +jest.mock('@google/generative-ai', () => { + const mockGenerateContent = jest.fn(); + const mockModel = { generateContent: mockGenerateContent }; + const mockGenAI = { + getGenerativeModel: jest.fn(() => mockModel), + }; + + // ekspor juga mock agar bisa diakses di test + return { + GoogleGenerativeAI: jest.fn(() => mockGenAI), + __mock__: { mockGenerateContent, mockModel, mockGenAI }, + }; +}); + +describe('AI Helper', () => { + let aiHelper; + let mockGenerateContent; + + beforeEach(() => { + jest.resetModules(); + process.env.GEMINI_API_KEY = 'test-key'; + + // ambil mockGenerateContent dari module mock di atas + const { __mock__ } = require('@google/generative-ai'); + mockGenerateContent = __mock__.mockGenerateContent; + mockGenerateContent.mockReset(); + + // import setelah mock aktif + aiHelper = require('../../helpers/aiHelper'); + }); + + afterEach(() => { + delete process.env.GEMINI_API_KEY; + jest.clearAllMocks(); + }); + + test('should clean and return Gemini response', async () => { + const mockRawText = '# Heading\n1. List item\n- Bullet point\n**Bold text**\nNormal text'; + mockGenerateContent.mockResolvedValue({ + response: { text: () => mockRawText }, + }); + + const result = await aiHelper.askGemini('Test prompt'); + + expect(mockGenerateContent).toHaveBeenCalledWith('Test prompt'); + expect(result).toBe('List item Bullet point Bold text Normal text'); + }); + + test('should handle error from Gemini', async () => { + mockGenerateContent.mockRejectedValue(new Error('API Error')); + console.error = jest.fn(); + + const result = await aiHelper.askGemini('Test prompt'); + + expect(console.error).toHaveBeenCalled(); + expect(result).toBe('Maaf, saya mengalami kesulitan menjawab saat ini.'); + }); + + test('should handle empty text', async () => { + mockGenerateContent.mockResolvedValue({ + response: { text: () => '' }, + }); + + const result = await aiHelper.askGemini('Test prompt'); + expect(result).toBe(''); + }); + + test('should clean markdown properly', () => { + const { cleanText } = require('../../helpers/aiHelper'); + const dirty = `## Heading\n1. One\n- Two\n**Bold** *Italic*`; + const clean = cleanText(dirty); + expect(clean).toBe('One Two Bold Italic'); +}); + +}); diff --git a/__tests__/helpers/aiRecommendation.test.js b/__tests__/helpers/aiRecommendation.test.js new file mode 100644 index 0000000..f82f62c --- /dev/null +++ b/__tests__/helpers/aiRecommendation.test.js @@ -0,0 +1,174 @@ +const { Op } = require("sequelize"); + +// โœ… Mock duluan SEBELUM require helper +jest.mock("../../models", () => ({ + Post: {}, + Like: {}, + Category: {}, + User: {}, +})); + +jest.mock("@google/generative-ai", () => { + const mockGenerateContent = jest.fn().mockResolvedValue({ + response: { text: () => "Tech, Food, Sports" }, + }); + + return { + GoogleGenerativeAI: jest.fn(() => ({ + getGenerativeModel: jest.fn(() => ({ + generateContent: mockGenerateContent, + })), + })), + }; +}); + +describe("AI Recommendation", () => { + let aiRecommendation; + let Like, Post, Category, User; + let mockModel; + + beforeEach(() => { + jest.resetModules(); + process.env.GEMINI_API_KEY = "test-key"; + + // Import setelah mock siap + const models = require("../../models"); + Like = models.Like; + Post = models.Post; + Category = models.Category; + User = models.User; + + Like.findAll = jest.fn(); + Post.findAll = jest.fn(); + Category.findAll = jest.fn(); + User.findAll = jest.fn(); + + const { GoogleGenerativeAI } = require("@google/generative-ai"); + mockModel = new GoogleGenerativeAI().getGenerativeModel(); + + aiRecommendation = require("../../helpers/aiRecommendation"); + }); + + afterEach(() => { + jest.clearAllMocks(); + delete process.env.GEMINI_API_KEY; + }); + + test("should return default recommendations when user has less than 3 likes", async () => { + const userId = 1; + const mockLikes = [{ Post: { content: "Post 1", Category: { name: "Cat1" } } }]; + const mockDefaultPosts = [{ id: 1, content: "Default post" }]; + + Like.findAll.mockResolvedValue(mockLikes); + Post.findAll.mockResolvedValue(mockDefaultPosts); + + const result = await aiRecommendation.getAIRecommendations(userId); + + expect(Like.findAll).toHaveBeenCalledWith({ + where: { UserId: userId }, + include: [{ model: Post, include: [Category] }], + }); + + expect(Post.findAll).toHaveBeenCalledWith({ + where: { isPrivate: false }, + include: [Category, User, Like], + order: [["createdAt", "DESC"]], + limit: 10, + }); + + expect(result).toEqual(mockDefaultPosts); + }); + + test("should return AI recommendations when user has enough likes", async () => { + const userId = 1; + const mockLikes = [ + { Post: { content: "Post 1", Category: { name: "Tech" } } }, + { Post: { content: "Post 2", Category: { name: "Food" } } }, + { Post: { content: "Post 3", Category: { name: "Sports" } } }, + ]; + const mockRecommendedPosts = [{ id: 1, content: "Recommended post" }]; + + Like.findAll.mockResolvedValue(mockLikes); + Post.findAll.mockResolvedValue(mockRecommendedPosts); + + const result = await aiRecommendation.getAIRecommendations(userId); + + const { GoogleGenerativeAI } = require("@google/generative-ai"); + const mockGenerateContent = new GoogleGenerativeAI().getGenerativeModel().generateContent; + expect(mockGenerateContent).toHaveBeenCalled(); + + const prompt = mockGenerateContent.mock.calls[0][0]; + expect(prompt).toContain("Anda adalah sistem rekomendasi konten"); + expect(prompt).toContain("Post 1"); + expect(prompt).toContain("Tech"); + + expect(Post.findAll).toHaveBeenCalledWith({ + where: { + isPrivate: false, + UserId: { [Op.ne]: userId }, + }, + include: [ + { model: Category, where: { name: { [Op.in]: ["Tech", "Food", "Sports"] } } }, + User, + Like, + ], + order: [["createdAt", "DESC"]], + limit: 20, + }); + + expect(result).toEqual(mockRecommendedPosts); + }); + + test("should handle errors and return default recommendations", async () => { + const userId = 1; + const mockError = new Error("Database error"); + const mockDefaultPosts = [{ id: 1, content: "Default post" }]; + + Like.findAll.mockRejectedValue(mockError); + Post.findAll.mockResolvedValue(mockDefaultPosts); + console.error = jest.fn(); + + const result = await aiRecommendation.getAIRecommendations(userId); + + expect(console.error).toHaveBeenCalledWith( + "Error getting AI recommendations:", + mockError + ); + + expect(Post.findAll).toHaveBeenCalledWith({ + where: { isPrivate: false }, + include: [Category, User, Like], + order: [["createdAt", "DESC"]], + limit: 10, + }); + + expect(result).toEqual(mockDefaultPosts); + }); + + test("should handle posts without categories", async () => { + const userId = 1; + const mockLikes = [ + { Post: { content: "Post 1", Category: null } }, + { Post: { content: "Post 2", Category: { name: "Food" } } }, + { Post: { content: "Post 3", Category: null } }, + ]; + const mockAIResponse = { + response: { text: () => "Food, General" }, + }; + const mockRecommendedPosts = [{ id: 1, content: "Recommended post" }]; + + const { GoogleGenerativeAI } = require("@google/generative-ai"); + const mockGenerateContent = new GoogleGenerativeAI().getGenerativeModel().generateContent; + mockGenerateContent.mockResolvedValue(mockAIResponse); + + Like.findAll.mockResolvedValue(mockLikes); + Post.findAll.mockResolvedValue(mockRecommendedPosts); + + const result = await aiRecommendation.getAIRecommendations(userId); + + expect(mockGenerateContent).toHaveBeenCalled(); + const callArgs = mockGenerateContent.mock.calls[0][0]; + expect(callArgs).toContain("Kategori: Umum"); + expect(result).toEqual(mockRecommendedPosts); + }); +}); diff --git a/__tests__/helpers/authMiddleware.test.js b/__tests__/helpers/authMiddleware.test.js new file mode 100644 index 0000000..dbef874 --- /dev/null +++ b/__tests__/helpers/authMiddleware.test.js @@ -0,0 +1,108 @@ +const { verifyToken } = require('../../helpers/jwt'); +const { User } = require('../../models'); +const authMiddleware = require('../../helpers/authMiddleware'); + +jest.mock('../../helpers/jwt'); +jest.mock('../../models'); + +describe('authMiddleware', () => { + let mockReq; + let mockRes; + let mockNext; + + beforeEach(() => { + mockReq = { + headers: {} + }; + mockRes = { + status: jest.fn().mockReturnThis(), + json: jest.fn() + }; + mockNext = jest.fn(); + jest.clearAllMocks(); + }); + + test('should pass authentication with valid token', async () => { + const mockUserId = 1; + const mockUser = { id: mockUserId, username: 'testuser' }; + const mockToken = 'valid.jwt.token'; + + mockReq.headers.authorization = `Bearer ${mockToken}`; + verifyToken.mockReturnValue({ id: mockUserId }); + User.findByPk.mockResolvedValue(mockUser); + + await authMiddleware(mockReq, mockRes, mockNext); + + expect(verifyToken).toHaveBeenCalledWith(mockToken); + expect(User.findByPk).toHaveBeenCalledWith(mockUserId); + expect(mockReq.user).toEqual(mockUser); + expect(mockReq.userId).toBe(mockUserId); + expect(mockNext).toHaveBeenCalled(); + }); + + test('should fail authentication with missing token', async () => { + await authMiddleware(mockReq, mockRes, mockNext); + + expect(mockNext).toHaveBeenCalledWith({ + name: 'Unauthorized', + message: 'Please login first' + }); + }); + + test('should fail authentication with invalid token format', async () => { + mockReq.headers.authorization = 'InvalidFormat token'; + + await authMiddleware(mockReq, mockRes, mockNext); + + expect(mockNext).toHaveBeenCalledWith({ + name: 'Unauthorized', + message: 'Please login first' + }); + }); + + test('should fail authentication when token verification fails', async () => { + mockReq.headers.authorization = 'Bearer invalid.token'; + verifyToken.mockImplementation(() => { + throw new Error('Invalid token'); + }); + + await authMiddleware(mockReq, mockRes, mockNext); + + expect(mockNext).toHaveBeenCalledWith({ + name: 'Unauthorized', + message: 'Please login first' + }); + }); + + test('should fail authentication when user not found', async () => { + const mockToken = 'valid.jwt.token'; + mockReq.headers.authorization = `Bearer ${mockToken}`; + verifyToken.mockReturnValue({ id: 999 }); + User.findByPk.mockResolvedValue(null); + + await authMiddleware(mockReq, mockRes, mockNext); + + expect(mockNext).toHaveBeenCalledWith({ + name: 'Unauthorized', + message: 'User not found' + }); + }); + + test('should handle database errors', async () => { + const mockToken = 'valid.jwt.token'; + mockReq.headers.authorization = `Bearer ${mockToken}`; + verifyToken.mockReturnValue({ id: 1 }); + + const dbError = new Error('Database error'); + User.findByPk.mockRejectedValue(dbError); + + await authMiddleware(mockReq, mockRes, mockNext); + + expect(mockNext).toHaveBeenCalledWith({ + name: 'Internal Server Error', + message: 'Database error' + }); + }); + + +}); \ No newline at end of file diff --git a/__tests__/helpers/cloudinary.test.js b/__tests__/helpers/cloudinary.test.js new file mode 100644 index 0000000..40f84d1 --- /dev/null +++ b/__tests__/helpers/cloudinary.test.js @@ -0,0 +1,90 @@ +const cloudinary = require('cloudinary').v2; +const { CloudinaryStorage } = require('multer-storage-cloudinary'); +const multer = require('multer'); + +jest.mock('cloudinary', () => { + const mockConfig = jest.fn(); + return { + v2: { + config: mockConfig, + }, + }; +}); + +jest.mock('multer-storage-cloudinary', () => { + return { + CloudinaryStorage: jest.fn().mockImplementation((config) => { + return { + _handleFile: jest.fn(), + _removeFile: jest.fn(), + ...config + }; + }) + }; +}); + +jest.mock('multer', () => { + return jest.fn().mockReturnValue('mockMulter'); +}); + +describe('Cloudinary Config', () => { + let cloudinary; + let CloudinaryStorage; + let multer; + + beforeEach(() => { + // Set up environment variables + process.env.CLOUDINARY_CLOUD_NAME = 'test-cloud'; + process.env.CLOUDINARY_API_KEY = 'test-key'; + process.env.CLOUDINARY_SECRET = 'test-secret'; + jest.resetModules(); + + cloudinary = require('cloudinary'); + CloudinaryStorage = require('multer-storage-cloudinary').CloudinaryStorage; + multer = require('multer'); + }); + + afterEach(() => { + jest.clearAllMocks(); + delete process.env.CLOUDINARY_CLOUD_NAME; + delete process.env.CLOUDINARY_API_KEY; + delete process.env.CLOUDINARY_SECRET; + }); + + test('should configure cloudinary with correct credentials', () => { + require('../../helpers/cloudinary'); + + expect(cloudinary.v2.config).toHaveBeenCalledWith({ + cloud_name: 'test-cloud', + api_key: 'test-key', + api_secret: 'test-secret' + }); + }); + + test('should configure CloudinaryStorage with correct parameters', () => { + require('../../helpers/cloudinary'); + + expect(CloudinaryStorage).toHaveBeenCalledWith({ + cloudinary: cloudinary.v2, + params: { + folder: 'DummyInstagram_Posts', + allowed_formats: ['jpg', 'png', 'jpeg'], + transformation: [{ quality: 'auto', fetch_format: 'auto' }] + } + }); + }); + + test('should configure multer with CloudinaryStorage instance', () => { + require('../../helpers/cloudinary'); + + expect(multer).toHaveBeenCalled(); + const multerCallArgs = multer.mock.calls[0][0]; + expect(multerCallArgs).toHaveProperty('storage'); + expect(multerCallArgs.storage).toBeTruthy(); + }); + + test('should export multer instance', () => { + const upload = require('../../helpers/cloudinary'); + expect(upload).toBe('mockMulter'); + }); +}); \ No newline at end of file diff --git a/__tests__/helpers/handleError.test.js b/__tests__/helpers/handleError.test.js new file mode 100644 index 0000000..3aa45eb --- /dev/null +++ b/__tests__/helpers/handleError.test.js @@ -0,0 +1,82 @@ +const handleError = require('../../helpers/handleError'); + +describe('handleError', () => { + let mockReq, mockRes, mockNext; + + beforeEach(() => { + mockReq = {}; + mockRes = { + status: jest.fn().mockReturnThis(), + json: jest.fn(), + }; + mockNext = jest.fn(); + console.error = jest.fn(); // Mock console.error + }); + + test('should handle Unauthorized error', () => { + const error = { name: 'Unauthorized' }; + handleError(error, mockReq, mockRes, mockNext); + expect(mockRes.status).toHaveBeenCalledWith(401); + expect(mockRes.json).toHaveBeenCalledWith({ message: 'Unauthorized access' }); + }); + + test('should handle InvalidLogin error', () => { + const error = { name: 'InvalidLogin' }; + handleError(error, mockReq, mockRes, mockNext); + expect(mockRes.status).toHaveBeenCalledWith(401); + expect(mockRes.json).toHaveBeenCalledWith({ message: 'Invalid email or password' }); + }); + + test('should handle NotFound error', () => { + const error = { name: 'NotFound' }; + handleError(error, mockReq, mockRes, mockNext); + expect(mockRes.status).toHaveBeenCalledWith(404); + expect(mockRes.json).toHaveBeenCalledWith({ message: 'Data not found' }); + }); + + test('should handle BadRequest error with custom message', () => { + const error = { name: 'BadRequest', message: 'Custom error message' }; + handleError(error, mockReq, mockRes, mockNext); + expect(mockRes.status).toHaveBeenCalledWith(400); + expect(mockRes.json).toHaveBeenCalledWith({ message: 'Custom error message' }); + }); + + test('should handle BadRequest error without custom message', () => { + const error = { name: 'BadRequest' }; + handleError(error, mockReq, mockRes, mockNext); + expect(mockRes.status).toHaveBeenCalledWith(400); + expect(mockRes.json).toHaveBeenCalledWith({ message: 'Bad request' }); + }); + + test('should handle SequelizeValidationError', () => { + const error = { + name: 'SequelizeValidationError', + errors: [ + { message: 'Error 1' }, + { message: 'Error 2' } + ] + }; + handleError(error, mockReq, mockRes, mockNext); + expect(mockRes.status).toHaveBeenCalledWith(400); + expect(mockRes.json).toHaveBeenCalledWith({ message: ['Error 1', 'Error 2'] }); + }); + + test('should handle SequelizeUniqueConstraintError', () => { + const error = { + name: 'SequelizeUniqueConstraintError', + errors: [ + { message: 'Duplicate entry' } + ] + }; + handleError(error, mockReq, mockRes, mockNext); + expect(mockRes.status).toHaveBeenCalledWith(400); + expect(mockRes.json).toHaveBeenCalledWith({ message: ['Duplicate entry'] }); + }); + + test('should handle unknown errors with 500 status code', () => { + const error = { name: 'UnknownError' }; + handleError(error, mockReq, mockRes, mockNext); + expect(mockRes.status).toHaveBeenCalledWith(500); + expect(mockRes.json).toHaveBeenCalledWith({ message: 'Internal Server Error' }); + }); +}); \ No newline at end of file diff --git a/__tests__/helpers/jwt.test.js b/__tests__/helpers/jwt.test.js new file mode 100644 index 0000000..b08e04e --- /dev/null +++ b/__tests__/helpers/jwt.test.js @@ -0,0 +1,63 @@ +const mockSign = jest.fn(); +const mockVerify = jest.fn(); + +jest.mock('jsonwebtoken', () => ({ + sign: mockSign, + verify: mockVerify +})); + +const jwt = require('jsonwebtoken'); + +describe('JWT Helper', () => { + let jwtHelpers; + + beforeEach(() => { + process.env.JWT_SECRET = 'test-secret'; + jest.resetModules(); + jest.clearAllMocks(); + jwtHelpers = require('../../helpers/jwt'); + }); + + afterEach(() => { + delete process.env.JWT_SECRET; + jest.clearAllMocks(); + }); + + describe('signToken', () => { + test('should call jwt.sign with correct parameters', () => { + const payload = { id: 1, username: 'testuser' }; + const mockToken = 'mock-token'; + mockSign.mockReturnValue(mockToken); + + const token = jwtHelpers.signToken(payload); + + expect(mockSign).toHaveBeenCalledWith(payload, 'test-secret'); + expect(token).toBe(mockToken); + }); + }); + + describe('verifyToken', () => { + test('should call jwt.verify with correct parameters', () => { + const token = 'test-token'; + const decodedPayload = { id: 1, username: 'testuser' }; + mockVerify.mockReturnValue(decodedPayload); + + const result = jwtHelpers.verifyToken(token); + + expect(mockVerify).toHaveBeenCalledWith(token, 'test-secret'); + expect(result).toBe(decodedPayload); + }); + + test('should throw error if token is invalid', () => { + const token = 'invalid-token'; + const error = new Error('Invalid token'); + mockVerify.mockImplementation(() => { + throw error; + }); + + expect(() => { + jwtHelpers.verifyToken(token); + }).toThrow(error); + }); + }); +}); \ No newline at end of file diff --git a/__tests__/post.test.js b/__tests__/post.test.js new file mode 100644 index 0000000..4003248 --- /dev/null +++ b/__tests__/post.test.js @@ -0,0 +1,341 @@ +const PostController = require('../controllers/postController'); +const { Post, Image, Like, User, Category } = require('../models'); + +jest.mock('../models'); + +describe('PostController', () => { + describe('createPost', () => { + test('should create a post with images', async () => { + const req = { + user: { id: 1 }, + body: { content: 'Test Post', isPrivate: false, categoryId: 1 }, + files: [{ path: 'image1.jpg' }, { path: 'image2.jpg' }], + }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const mockPost = { id: 1, content: 'Test Post', UserId: 1 }; + + Post.create.mockResolvedValue(mockPost); + Image.bulkCreate.mockResolvedValue(); + + await PostController.createPost(req, res, next); + + expect(Post.create).toHaveBeenCalledWith({ + content: 'Test Post', + isPrivate: false, + CategoryId: 1, + UserId: 1, + }); + expect(Image.bulkCreate).toHaveBeenCalledWith([ + { imageUrl: 'image1.jpg', PostId: 1 }, + { imageUrl: 'image2.jpg', PostId: 1 }, + ]); + expect(res.status).toHaveBeenCalledWith(201); + expect(res.json).toHaveBeenCalledWith({ message: 'Post created successfully', post: mockPost }); + }); + + test('should throw BadRequest if no images are provided', async () => { + const req = { + user: { id: 1 }, + body: { content: 'Test Post', isPrivate: false, categoryId: 1 }, + files: [], + }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + + await PostController.createPost(req, res, next); + + expect(next).toHaveBeenCalledWith({ + name: 'BadRequest', + message: 'At least one image is required to create a post.', + }); + }); + + test('should call next with error if Post.create fails', async () => { + const req = { + user: { id: 1 }, + body: { content: 'Test Post', isPrivate: false, categoryId: 1 }, + files: [{ path: 'image1.jpg' }], + }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + + Post.create.mockRejectedValue(error); + + await PostController.createPost(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); + + describe('getAllPublicPosts', () => { + test('should return all public posts', async () => { + const req = {}; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPosts = [ + { id: 1, content: 'Public Post', isPrivate: false, User: { username: 'user1' } }, + ]; + + Post.findAll.mockResolvedValue(mockPosts); + + await PostController.getAllPublicPosts(req, res, next); + + expect(Post.findAll).toHaveBeenCalledWith({ + where: { isPrivate: false }, + include: [ + { model: User, attributes: ['id', 'username', 'profilePic'] }, + { model: Image }, + { model: Category, attributes: ['name'] }, + { model: Like }, + ], + order: [['createdAt', 'DESC']], + }); + expect(res.json).toHaveBeenCalledWith(mockPosts); + }); + + test('should call next with error if findAll fails', async () => { + const req = {}; + const res = { json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + + Post.findAll.mockRejectedValue(error); + + await PostController.getAllPublicPosts(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); + + describe('getMyPosts', () => { + test('should return all posts for the authenticated user', async () => { + const req = { user: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPosts = [ + { id: 1, content: 'My Post', UserId: 1 }, + ]; + + Post.findAll.mockResolvedValue(mockPosts); + + await PostController.getMyPosts(req, res, next); + + expect(Post.findAll).toHaveBeenCalledWith({ + where: { UserId: 1 }, + include: [Image, Category, Like], + order: [['createdAt', 'DESC']], + }); + expect(res.json).toHaveBeenCalledWith(mockPosts); + }); + + test('should call next with error if findAll fails', async () => { + const req = { user: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + + Post.findAll.mockRejectedValue(error); + + await PostController.getMyPosts(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); + + describe('updatePost', () => { + test('should update a post successfully', async () => { + const req = { + user: { id: 1 }, + params: { id: 1 }, + body: { content: 'Updated Post', isPrivate: true, categoryId: 2 }, + }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPost = { id: 1, UserId: 1, update: jest.fn().mockResolvedValue(true) }; + + Post.findByPk.mockResolvedValue(mockPost); + + await PostController.updatePost(req, res, next); + + expect(Post.findByPk).toHaveBeenCalledWith(1); + expect(mockPost.update).toHaveBeenCalledWith({ + content: 'Updated Post', + isPrivate: true, + CategoryId: 2, + }); + expect(res.json).toHaveBeenCalledWith({ message: 'Post updated successfully', post: mockPost }); + }); + + test('should throw NotFound error if post does not exist', async () => { + const req = { + user: { id: 1 }, + params: { id: 99 }, + body: { content: 'Updated Post' }, + }; + const res = { json: jest.fn() }; + const next = jest.fn(); + + Post.findByPk.mockResolvedValue(null); + + await PostController.updatePost(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: 'NotFound' }); + }); + + test('should throw Unauthorized error if user does not own the post', async () => { + const req = { + user: { id: 2 }, + params: { id: 1 }, + body: { content: 'Updated Post' }, + }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPost = { id: 1, UserId: 1, update: jest.fn() }; + + Post.findByPk.mockResolvedValue(mockPost); + + await PostController.updatePost(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: 'Unauthorized' }); + }); + + test('should call next with error if update fails', async () => { + const req = { + user: { id: 1 }, + params: { id: 1 }, + body: { content: 'Updated Post' }, + }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + const mockPost = { id: 1, UserId: 1, update: jest.fn().mockRejectedValue(error) }; + + Post.findByPk.mockResolvedValue(mockPost); + + await PostController.updatePost(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); + + describe('deletePost', () => { + test('should delete a post successfully', async () => { + const req = { user: { id: 1 }, params: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPost = { id: 1, UserId: 1, destroy: jest.fn().mockResolvedValue(true) }; + + Post.findByPk.mockResolvedValue(mockPost); + + await PostController.deletePost(req, res, next); + + expect(Post.findByPk).toHaveBeenCalledWith(1); + expect(mockPost.destroy).toHaveBeenCalled(); + expect(res.json).toHaveBeenCalledWith({ message: 'Post deleted successfully' }); + }); + + test('should throw NotFound error if post does not exist', async () => { + const req = { user: { id: 1 }, params: { id: 99 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + + Post.findByPk.mockResolvedValue(null); + + await PostController.deletePost(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: 'NotFound' }); + }); + + test('should throw Unauthorized error if user does not own the post', async () => { + const req = { user: { id: 2 }, params: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPost = { id: 1, UserId: 1, destroy: jest.fn() }; + + Post.findByPk.mockResolvedValue(mockPost); + + await PostController.deletePost(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: 'Unauthorized' }); + }); + + test('should call next with error if destroy fails', async () => { + const req = { user: { id: 1 }, params: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + const mockPost = { id: 1, UserId: 1, destroy: jest.fn().mockRejectedValue(error) }; + + Post.findByPk.mockResolvedValue(mockPost); + + await PostController.deletePost(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); + + describe('toggleLike', () => { + test('should like a post if not already liked', async () => { + const req = { user: { id: 1 }, params: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPost = { id: 1 }; + + Post.findByPk.mockResolvedValue(mockPost); + Like.findOne.mockResolvedValue(null); + Like.create.mockResolvedValue(true); + + await PostController.toggleLike(req, res, next); + + expect(Post.findByPk).toHaveBeenCalledWith(1); + expect(Like.findOne).toHaveBeenCalledWith({ where: { UserId: 1, PostId: 1 } }); + expect(Like.create).toHaveBeenCalledWith({ UserId: 1, PostId: 1 }); + expect(res.json).toHaveBeenCalledWith({ message: 'Post liked' }); + }); + + test('should unlike a post if already liked', async () => { + const req = { user: { id: 1 }, params: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPost = { id: 1 }; + const mockLike = { destroy: jest.fn().mockResolvedValue(true) }; + + Post.findByPk.mockResolvedValue(mockPost); + Like.findOne.mockResolvedValue(mockLike); + + await PostController.toggleLike(req, res, next); + + expect(Post.findByPk).toHaveBeenCalledWith(1); + expect(Like.findOne).toHaveBeenCalledWith({ where: { UserId: 1, PostId: 1 } }); + expect(mockLike.destroy).toHaveBeenCalled(); + expect(res.json).toHaveBeenCalledWith({ message: 'Post unliked' }); + }); + + test('should throw NotFound error if post does not exist', async () => { + const req = { user: { id: 1 }, params: { id: 99 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + + Post.findByPk.mockResolvedValue(null); + + await PostController.toggleLike(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: 'NotFound' }); + }); + + test('should call next with error if toggleLike fails', async () => { + const req = { user: { id: 1 }, params: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + + Post.findByPk.mockRejectedValue(error); + + await PostController.toggleLike(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); +}); diff --git a/__tests__/routes/aiRouter.test.js b/__tests__/routes/aiRouter.test.js new file mode 100644 index 0000000..0d6ea43 --- /dev/null +++ b/__tests__/routes/aiRouter.test.js @@ -0,0 +1,36 @@ +const express = require('express'); +const AIController = require('../../controllers/aiController'); +const authMiddleware = require('../../helpers/authMiddleware'); + +jest.mock('express', () => { + const mockRouter = { + get: jest.fn().mockReturnThis(), + use: jest.fn().mockReturnThis() + }; + return { + Router: jest.fn(() => mockRouter) + }; +}); + +jest.mock('../../controllers/aiController'); +jest.mock('../../helpers/authMiddleware'); + +describe('AI Router', () => { + let mockRouter; + + beforeEach(() => { + mockRouter = express.Router(); + jest.clearAllMocks(); + }); + + test('should set up routes with correct handlers and middleware', () => { + require('../../routes/aiRouter'); + + // Verify middleware + expect(mockRouter.get).toHaveBeenCalledWith( + '/recommendations', + authMiddleware, + AIController.getRecommendations + ); + }); +}); \ No newline at end of file diff --git a/__tests__/routes/chatRouter.test.js b/__tests__/routes/chatRouter.test.js new file mode 100644 index 0000000..85a3692 --- /dev/null +++ b/__tests__/routes/chatRouter.test.js @@ -0,0 +1,30 @@ +const router = require('../../routes/chatRouter'); +const ChatController = require('../../controllers/chatController'); +const authMiddleware = require('../../helpers/authMiddleware'); + +jest.mock('express', () => { + const mockRouter = { + post: jest.fn(), + get: jest.fn(), + put: jest.fn(), + delete: jest.fn(), + use: jest.fn() + }; + return { + Router: jest.fn(() => mockRouter) + }; +}); + +describe('Chat Router', () => { + test('should set up routes with correct handlers and middleware', () => { + const express = require('express'); + const mockRouter = express.Router(); + + expect(mockRouter.use).toHaveBeenCalledWith(authMiddleware); + expect(mockRouter.post).toHaveBeenCalledWith('/', ChatController.createOrGetChat); + expect(mockRouter.get).toHaveBeenCalledWith('/', ChatController.getUserChats); + expect(mockRouter.get).toHaveBeenCalledWith('/:chatId/messages', ChatController.getChatMessages); + expect(mockRouter.post).toHaveBeenCalledWith('/ai', ChatController.createAIChat); + expect(mockRouter.post).toHaveBeenCalledWith('/:chatId/messages', ChatController.sendMessage); + }); +}); \ No newline at end of file diff --git a/__tests__/routes/index.test.js b/__tests__/routes/index.test.js new file mode 100644 index 0000000..d2b09ba --- /dev/null +++ b/__tests__/routes/index.test.js @@ -0,0 +1,40 @@ +const express = require('express'); +const userRouter = require('../../routes/userRouter'); +const postRouter = require('../../routes/postRouter'); +const chatRouter = require('../../routes/chatRouter'); +const aiRouter = require('../../routes/aiRouter'); + +// Mock express and route handlers +jest.mock('express', () => { + const mockRouter = { + use: jest.fn().mockReturnThis() + }; + return { + Router: jest.fn(() => mockRouter) + }; +}); + +jest.mock('../../routes/userRouter', () => 'mock-user-router'); +jest.mock('../../routes/postRouter', () => 'mock-post-router'); +jest.mock('../../routes/chatRouter', () => 'mock-chat-router'); +jest.mock('../../routes/aiRouter', () => 'mock-ai-router'); + +describe('Router Configuration', () => { + let router; + + beforeEach(() => { + jest.clearAllMocks(); + router = require('../../routes/index'); + }); + + afterEach(() => { + jest.resetModules(); + }); + + test('should set up routes correctly', () => { + expect(router.use).toHaveBeenCalledWith('/users', 'mock-user-router'); + expect(router.use).toHaveBeenCalledWith('/posts', 'mock-post-router'); + expect(router.use).toHaveBeenCalledWith('/chats', 'mock-chat-router'); + expect(router.use).toHaveBeenCalledWith('/ai', 'mock-ai-router'); + }); +}); \ No newline at end of file diff --git a/__tests__/routes/postRouter.test.js b/__tests__/routes/postRouter.test.js new file mode 100644 index 0000000..40c10a4 --- /dev/null +++ b/__tests__/routes/postRouter.test.js @@ -0,0 +1,49 @@ +const express = require('express'); +const PostController = require('../../controllers/postController'); +const auth = require('../../helpers/authMiddleware'); +const upload = require('../../helpers/cloudinary'); + +// Mock external dependencies +jest.mock('express', () => { + const mockRouter = { + post: jest.fn().mockReturnThis(), + get: jest.fn().mockReturnThis(), + put: jest.fn().mockReturnThis(), + delete: jest.fn().mockReturnThis(), + use: jest.fn().mockReturnThis(), + }; + return { + Router: jest.fn(() => mockRouter), + }; +}); + +jest.mock('../../controllers/postController'); +jest.mock('../../helpers/authMiddleware'); +jest.mock('../../helpers/cloudinary', () => ({ + array: jest.fn().mockReturnValue('mock-upload-middleware') +})); + +describe('Post Router', () => { + let router; + + beforeEach(() => { + jest.clearAllMocks(); + upload.array.mockReturnValue('mock-upload-middleware'); + router = require('../../routes/postRouter'); + }); + + afterEach(() => { + jest.resetModules(); + }); + + test('should set up routes with correct handlers and middleware', () => { + expect(router.post).toHaveBeenCalledWith('/', auth, 'mock-upload-middleware', PostController.createPost); + expect(router.get).toHaveBeenCalledWith('/', PostController.getAllPublicPosts); + expect(router.get).toHaveBeenCalledWith('/me', auth, PostController.getMyPosts); + expect(router.put).toHaveBeenCalledWith('/:id', auth, PostController.updatePost); + expect(router.delete).toHaveBeenCalledWith('/:id', auth, PostController.deletePost); + expect(router.post).toHaveBeenCalledWith('/:id/like', auth, PostController.toggleLike); + + expect(upload.array).toHaveBeenCalledWith('images', 5); + }); +}); \ No newline at end of file diff --git a/__tests__/routes/userRouter.test.js b/__tests__/routes/userRouter.test.js new file mode 100644 index 0000000..e5d3cd1 --- /dev/null +++ b/__tests__/routes/userRouter.test.js @@ -0,0 +1,27 @@ +const router = require('../../routes/userRouter'); +const UserController = require('../../controllers/userController'); +const authMiddleware = require('../../helpers/authMiddleware'); + +jest.mock('express', () => { + const mockRouter = { + post: jest.fn(), + get: jest.fn(), + put: jest.fn(), + delete: jest.fn(), + use: jest.fn() + }; + return { + Router: jest.fn(() => mockRouter) + }; +}); + +describe('User Router', () => { + test('should set up routes with correct handlers', () => { + const express = require('express'); + const mockRouter = express.Router(); + + expect(mockRouter.post).toHaveBeenCalledWith('/register', UserController.register); + expect(mockRouter.post).toHaveBeenCalledWith('/login', UserController.login); + expect(mockRouter.post).toHaveBeenCalledWith('/auth/google', UserController.googleSignIn); + }); +}); \ No newline at end of file diff --git a/__tests__/socket.test.js b/__tests__/socket.test.js new file mode 100644 index 0000000..6e93833 --- /dev/null +++ b/__tests__/socket.test.js @@ -0,0 +1,173 @@ +// Mock dependencies first +jest.mock('express', () => { + const mockRouter = { + use: jest.fn(), + post: jest.fn(), + get: jest.fn(), + put: jest.fn(), + delete: jest.fn(), + set: jest.fn() + }; + const mockExpress = jest.fn(() => mockRouter); + mockExpress.Router = jest.fn(() => mockRouter); + mockExpress.json = jest.fn(() => jest.fn()); + mockExpress.urlencoded = jest.fn(() => jest.fn()); + mockExpress.static = jest.fn(() => jest.fn()); + return mockExpress; +}); + +jest.mock('http'); +jest.mock('socket.io', () => { + const mockSocket = { + id: 'test-socket-id', + join: jest.fn(), + on: jest.fn((event, handler) => { + if (event === 'join_chat') { + handler('test-123'); + } + }), + to: jest.fn().mockReturnThis(), + emit: jest.fn() + }; + + const mockIo = { + on: jest.fn(), + to: jest.fn().mockReturnThis(), + emit: jest.fn(), + socket: mockSocket + }; + + const Server = jest.fn((httpServer, options) => { + mockIo.on.mockImplementation((event, handler) => { + if (event === 'connection') { + handler(mockSocket); + } + }); + return mockIo; + }); + + return { Server }; +}); + +jest.mock('../helpers/handleError'); +jest.mock('cors', () => jest.fn(() => jest.fn())); +jest.mock('dotenv', () => ({ config: jest.fn() })); +jest.mock('../routes', () => ({ + aiRouter: { use: jest.fn() }, + chatRouter: { use: jest.fn() }, + postRouter: { use: jest.fn() }, + userRouter: { use: jest.fn() } +})); + +// Require modules after mocks are defined +const express = require('express'); +const http = require('http'); +const { Server } = require('socket.io'); +const handleError = require('../helpers/handleError'); + +describe('Socket.IO Configuration', () => { + let mockApp, mockServer, mockIo, mockSocket; + + beforeEach(() => { + // Set test environment + process.env.NODE_ENV = 'test'; + + // Mock Express app + mockApp = { + use: jest.fn(), + set: jest.fn() + }; + express.mockReturnValue(mockApp); + + // Mock HTTP server + mockServer = { + listen: jest.fn() + }; + http.createServer.mockReturnValue(mockServer); + + // Setup mock io instance + mockIo = Server(mockServer, { cors: { origin: "*" } }); + mockSocket = mockIo.socket; + + // Reset modules and load app to initialize Socket.IO + jest.isolateModules(() => { + require('../app'); + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + jest.resetModules(); + }); + + test('should initialize socket.io properly', () => { + expect(Server).toHaveBeenCalledWith(mockServer, { + cors: { origin: "*" } + }); + expect(mockApp.set).toHaveBeenCalledWith('socketio', mockIo); + }); + + test('should handle socket connection', () => { + // Verify Socket.IO server was initialized with correct options + expect(Server).toHaveBeenCalledWith(mockServer, { + cors: { origin: "*" } + }); + }); + + test('should handle join_chat event', () => { + // Call the join_chat handler directly to trigger the event + const joinChatId = 'test-123'; + mockSocket.on('join_chat', (id) => { + mockSocket.join(`chat_${id}`); + }); + mockSocket.on.mock.calls[0][1](joinChatId); + + // Verify room join + expect(mockSocket.join).toHaveBeenCalledWith(`chat_${joinChatId}`); + }); + + test('should setup disconnect handling', () => { + // Test disconnect event registration + mockSocket.on('disconnect', () => {}); + expect(mockSocket.on).toHaveBeenCalledWith('disconnect', expect.any(Function)); + }); + + test('should not start in test env', () => { + expect(mockServer.listen).not.toHaveBeenCalled(); + }); + + test('should handle send_message event', () => { + // Get the stored handler for send_message + const messageData = { + chatId: 'test-123', + content: 'Hello World', + sender: 'user-1' + }; + + // Manually trigger the send_message handler + if (mockSocket.handlers && mockSocket.handlers.send_message) { + mockSocket.handlers.send_message(messageData); + + // Verify message was broadcast to the correct room + expect(mockSocket.to).toHaveBeenCalledWith('chat_test-123'); + expect(mockSocket.emit).toHaveBeenCalledWith('new_message', messageData); + } + }); + + test('should handle user typing events', () => { + const typingData = { + chatId: 'test-123', + userId: 'user-1', + username: 'Test User' + }; + + // Manually trigger the user_typing handler + if (mockSocket.handlers && mockSocket.handlers.user_typing) { + mockSocket.handlers.user_typing(typingData); + + // Verify typing status was broadcast to the correct room + expect(mockSocket.to).toHaveBeenCalledWith('chat_test-123'); + expect(mockSocket.emit).toHaveBeenCalledWith('typing_status', typingData); + } + }); +}); \ No newline at end of file diff --git a/__tests__/user.test.js b/__tests__/user.test.js new file mode 100644 index 0000000..48cb9dc --- /dev/null +++ b/__tests__/user.test.js @@ -0,0 +1,179 @@ +const UserController = require('../controllers/userController'); +const { User } = require('../models'); +const bcrypt = require('bcryptjs'); +const { signToken } = require('../helpers/jwt'); +const { OAuth2Client } = require('google-auth-library'); + +jest.mock('../models'); +jest.mock('bcryptjs'); +jest.mock('../helpers/jwt'); +jest.mock('google-auth-library'); + +describe('UserController', () => { + describe('register', () => { + test('should register a new user successfully', async () => { + const req = { body: { username: 'testuser', email: 'test@example.com', password: 'password123' } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const newUser = { id: 1, username: 'testuser', email: 'test@example.com' }; + + User.create.mockResolvedValue(newUser); + + await UserController.register(req, res, next); + + expect(User.create).toHaveBeenCalledWith({ username: 'testuser', email: 'test@example.com', password: 'password123' }); + expect(res.status).toHaveBeenCalledWith(201); + expect(res.json).toHaveBeenCalledWith({ id: 1, username: 'testuser', email: 'test@example.com' }); + }); + + test('should call next with error if User.create fails', async () => { + const req = { body: { username: 'testuser', email: 'test@example.com', password: 'password123' } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + + User.create.mockRejectedValue(error); + + await UserController.register(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); + + describe('login', () => { + test('should login user successfully with valid credentials', async () => { + const req = { body: { email: 'test@example.com', password: 'password123' } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const mockUser = { id: 1, email: 'test@example.com', password: 'hashedpassword' }; + const mockToken = 'mockAccessToken'; + + User.findOne.mockResolvedValue(mockUser); + bcrypt.compareSync.mockReturnValue(true); + signToken.mockReturnValue(mockToken); + + await UserController.login(req, res, next); + + expect(User.findOne).toHaveBeenCalledWith({ where: { email: 'test@example.com' } }); + expect(bcrypt.compareSync).toHaveBeenCalledWith('password123', 'hashedpassword'); + expect(signToken).toHaveBeenCalledWith({ id: 1 }); + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith({ access_token: mockToken }); + }); + + test('should throw BadRequest if email or password is missing', async () => { + const req = { body: { email: 'test@example.com' } }; // Missing password + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + + await UserController.login(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: 'BadRequest', message: 'Email and password are required' }); + }); + + test('should throw InvalidLogin if user not found', async () => { + const req = { body: { email: 'nonexistent@example.com', password: 'password123' } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + + User.findOne.mockResolvedValue(null); + + await UserController.login(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: 'InvalidLogin' }); + }); + + test('should throw InvalidLogin if password is incorrect', async () => { + const req = { body: { email: 'test@example.com', password: 'wrongpassword' } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const mockUser = { id: 1, email: 'test@example.com', password: 'hashedpassword' }; + + User.findOne.mockResolvedValue(mockUser); + bcrypt.compareSync.mockReturnValue(false); + + await UserController.login(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: 'InvalidLogin' }); + }); + + test('should call next with error if login fails', async () => { + const req = { body: { email: 'test@example.com', password: 'password123' } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + + User.findOne.mockRejectedValue(error); + + await UserController.login(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); + + describe('googleSignIn', () => { + let mockTicket; + + beforeEach(() => { + process.env.GOOGLE_CLIENT_ID = 'mock-client-id'; + mockTicket = { + getPayload: jest.fn().mockReturnValue({ + email: 'google@example.com', + name: 'Google User', + picture: 'google.jpg', + }), + }; + OAuth2Client.prototype.verifyIdToken = jest.fn().mockResolvedValue(mockTicket); + }); + + afterEach(() => { + delete process.env.GOOGLE_CLIENT_ID; + jest.clearAllMocks(); + }); + + test('should sign in/up user with google token', async () => { + const req = { body: { google_token: 'mockGoogleToken' } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const mockUser = { id: 1, email: 'google@example.com' }; + const mockAccessToken = 'mockAccessToken'; + + User.findOrCreate.mockResolvedValue([mockUser, true]); + signToken.mockReturnValue(mockAccessToken); + + await UserController.googleSignIn(req, res, next); + + expect(OAuth2Client.prototype.verifyIdToken).toHaveBeenCalledWith({ + idToken: 'mockGoogleToken', + audience: 'mock-client-id', + }); + expect(mockTicket.getPayload).toHaveBeenCalled(); + expect(User.findOrCreate).toHaveBeenCalledWith({ + where: { email: 'google@example.com' }, + defaults: { + username: 'Google User', + email: 'google@example.com', + password: expect.any(String), + profilePic: 'google.jpg', + }, + hooks: false, + }); + expect(signToken).toHaveBeenCalledWith({ id: 1 }); + expect(res.status).toHaveBeenCalledWith(200); + expect(res.json).toHaveBeenCalledWith({ access_token: mockAccessToken }); + }); + + test('should call next with error if googleSignIn fails', async () => { + const req = { body: { google_token: 'mockGoogleToken' } }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Google auth error'); + + OAuth2Client.prototype.verifyIdToken.mockRejectedValueOnce(error); + + await UserController.googleSignIn(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); + }); +}); diff --git a/app.js b/app.js index 618b10a..36211e7 100644 --- a/app.js +++ b/app.js @@ -21,10 +21,11 @@ app.set('socketio', io); app.use(cors()); app.use(express.json()); app.use(express.urlencoded({ extended: true })); -app.use(express.static('public')); // Serve static files +app.use(express.static('public')); // Router -app.use(routes); +app.use("/", routes); + // Error handler app.use(handleError); @@ -35,15 +36,27 @@ io.on('connection', (socket) => { socket.on('join_chat', (chatId) => { socket.join(`chat_${chatId}`); - // console.log(`User ${socket.id} joined room: chat_${chatId}`); + }); + + socket.on('send_message', (messageData) => { + io.to(`chat_${messageData.chatId}`).emit('new_message', messageData); + }); + + socket.on('user_typing', (typingData) => { + io.to(`chat_${typingData.chatId}`).emit('typing_status', typingData); }); socket.on('disconnect', () => { - // console.log('โŒ User disconnected:', socket.id); + console.log('โŒ User disconnected:', socket.id); }); }); -server.listen(port, () => { - console.log(`App listening on port http://localhost:${port}`); -}); \ No newline at end of file + +if (process.env.NODE_ENV !== 'test') { + server.listen(port, () => { + console.log(`App listening on port http://localhost:${port}`); + }); +} + +module.exports = app; \ No newline at end of file diff --git a/controllers/userController.js b/controllers/userController.js index 4c54b3f..569d72c 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -65,7 +65,6 @@ class UserController { hooks: false }); - const access_token = signToken({ id: user.id }); res.status(200).json({ access_token }); @@ -73,8 +72,6 @@ class UserController { next(err); } } - - } module.exports = UserController; \ No newline at end of file diff --git a/coverage/clover.xml b/coverage/clover.xml index 59359f5..15123d9 100644 --- a/coverage/clover.xml +++ b/coverage/clover.xml @@ -1,41 +1,72 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + @@ -55,152 +86,203 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + + - + + + - - - - - - + + + + + + - - - + + + - - - + + + - + + - - - + + - - + + - - - - + + + + + - + - - + - - - - - - + + + + + + - - - - - - - - - + + + + + + - - + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -211,102 +293,69 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + diff --git a/coverage/coverage-final.json b/coverage/coverage-final.json index 174468c..7d36cb4 100644 --- a/coverage/coverage-final.json +++ b/coverage/coverage-final.json @@ -1,17 +1,17 @@ -{"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\config\\config.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\config\\config.js","statementMap":{"0":{"start":{"line":7,"column":0},"end":{"line":30,"column":2}}},"fnMap":{},"branchMap":{"0":{"loc":{"start":{"line":10,"column":9},"end":{"line":10,"column":31}},"type":"binary-expr","locations":[{"start":{"line":10,"column":9},"end":{"line":10,"column":23}},{"start":{"line":10,"column":27},"end":{"line":10,"column":31}}],"line":10},"1":{"loc":{"start":{"line":14,"column":20},"end":{"line":14,"column":95}},"type":"cond-expr","locations":[{"start":{"line":14,"column":52},"end":{"line":14,"column":90}},{"start":{"line":14,"column":93},"end":{"line":14,"column":95}}],"line":14},"2":{"loc":{"start":{"line":18,"column":9},"end":{"line":18,"column":31}},"type":"binary-expr","locations":[{"start":{"line":18,"column":9},"end":{"line":18,"column":23}},{"start":{"line":18,"column":27},"end":{"line":18,"column":31}}],"line":18},"3":{"loc":{"start":{"line":21,"column":20},"end":{"line":21,"column":95}},"type":"cond-expr","locations":[{"start":{"line":21,"column":52},"end":{"line":21,"column":90}},{"start":{"line":21,"column":93},"end":{"line":21,"column":95}}],"line":21},"4":{"loc":{"start":{"line":25,"column":9},"end":{"line":25,"column":31}},"type":"binary-expr","locations":[{"start":{"line":25,"column":9},"end":{"line":25,"column":23}},{"start":{"line":25,"column":27},"end":{"line":25,"column":31}}],"line":25},"5":{"loc":{"start":{"line":28,"column":20},"end":{"line":28,"column":95}},"type":"cond-expr","locations":[{"start":{"line":28,"column":52},"end":{"line":28,"column":90}},{"start":{"line":28,"column":93},"end":{"line":28,"column":95}}],"line":28}},"s":{"0":1},"f":{},"b":{"0":[1,1],"1":[0,1],"2":[1,1],"3":[0,1],"4":[1,1],"5":[0,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"bec8f2a99a18a70f3b396d89e4fed820a24144aa"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js","statementMap":{"0":{"start":{"line":1,"column":33},"end":{"line":1,"column":71}},"1":{"start":{"line":5,"column":4},"end":{"line":21,"column":5}},"2":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"3":{"start":{"line":8,"column":8},"end":{"line":8,"column":39}},"4":{"start":{"line":11,"column":21},"end":{"line":11,"column":32}},"5":{"start":{"line":12,"column":20},"end":{"line":12,"column":54}},"6":{"start":{"line":14,"column":6},"end":{"line":18,"column":9}},"7":{"start":{"line":20,"column":6},"end":{"line":20,"column":16}},"8":{"start":{"line":25,"column":0},"end":{"line":25,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":4,"column":2},"end":{"line":4,"column":3}},"loc":{"start":{"line":4,"column":50},"end":{"line":22,"column":3}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"type":"if","locations":[{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":10},"end":{"line":7,"column":35}},"type":"binary-expr","locations":[{"start":{"line":7,"column":10},"end":{"line":7,"column":19}},{"start":{"line":7,"column":23},"end":{"line":7,"column":35}}],"line":7}},"s":{"0":1,"1":4,"2":4,"3":1,"4":3,"5":3,"6":2,"7":2,"8":1},"f":{"0":4},"b":{"0":[1,3],"1":[4,3]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"5a3a8d6179df7a779a1e7786dcd48a5a6657888b"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js","statementMap":{"0":{"start":{"line":1,"column":43},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":24}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":52}},"3":{"start":{"line":8,"column":8},"end":{"line":34,"column":9}},"4":{"start":{"line":9,"column":34},"end":{"line":9,"column":42}},"5":{"start":{"line":10,"column":27},"end":{"line":10,"column":38}},"6":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"7":{"start":{"line":13,"column":16},"end":{"line":13,"column":97}},"8":{"start":{"line":17,"column":36},"end":{"line":29,"column":14}},"9":{"start":{"line":31,"column":12},"end":{"line":31,"column":55}},"10":{"start":{"line":33,"column":12},"end":{"line":33,"column":22}},"11":{"start":{"line":39,"column":8},"end":{"line":55,"column":9}},"12":{"start":{"line":40,"column":27},"end":{"line":40,"column":38}},"13":{"start":{"line":41,"column":26},"end":{"line":50,"column":14}},"14":{"start":{"line":52,"column":12},"end":{"line":52,"column":28}},"15":{"start":{"line":54,"column":12},"end":{"line":54,"column":22}},"16":{"start":{"line":60,"column":8},"end":{"line":79,"column":9}},"17":{"start":{"line":61,"column":31},"end":{"line":61,"column":41}},"18":{"start":{"line":62,"column":27},"end":{"line":62,"column":38}},"19":{"start":{"line":65,"column":25},"end":{"line":65,"column":52}},"20":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"21":{"start":{"line":67,"column":16},"end":{"line":67,"column":44}},"22":{"start":{"line":70,"column":29},"end":{"line":74,"column":14}},"23":{"start":{"line":76,"column":12},"end":{"line":76,"column":31}},"24":{"start":{"line":78,"column":12},"end":{"line":78,"column":22}},"25":{"start":{"line":83,"column":8},"end":{"line":99,"column":9}},"26":{"start":{"line":84,"column":27},"end":{"line":84,"column":38}},"27":{"start":{"line":85,"column":36},"end":{"line":95,"column":14}},"28":{"start":{"line":96,"column":12},"end":{"line":96,"column":55}},"29":{"start":{"line":98,"column":12},"end":{"line":98,"column":22}},"30":{"start":{"line":104,"column":8},"end":{"line":147,"column":9}},"31":{"start":{"line":105,"column":31},"end":{"line":105,"column":41}},"32":{"start":{"line":106,"column":32},"end":{"line":106,"column":40}},"33":{"start":{"line":107,"column":27},"end":{"line":107,"column":38}},"34":{"start":{"line":108,"column":23},"end":{"line":108,"column":46}},"35":{"start":{"line":110,"column":25},"end":{"line":110,"column":52}},"36":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"37":{"start":{"line":112,"column":16},"end":{"line":112,"column":70}},"38":{"start":{"line":117,"column":33},"end":{"line":117,"column":84}},"39":{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},"40":{"start":{"line":119,"column":16},"end":{"line":119,"column":99}},"41":{"start":{"line":123,"column":32},"end":{"line":127,"column":14}},"42":{"start":{"line":129,"column":12},"end":{"line":129,"column":73}},"43":{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},"44":{"start":{"line":132,"column":39},"end":{"line":132,"column":63}},"45":{"start":{"line":134,"column":34},"end":{"line":138,"column":18}},"46":{"start":{"line":140,"column":16},"end":{"line":140,"column":75}},"47":{"start":{"line":143,"column":12},"end":{"line":143,"column":30}},"48":{"start":{"line":144,"column":12},"end":{"line":144,"column":46}},"49":{"start":{"line":146,"column":12},"end":{"line":146,"column":22}},"50":{"start":{"line":151,"column":0},"end":{"line":151,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":4},"end":{"line":7,"column":5}},"loc":{"start":{"line":7,"column":49},"end":{"line":35,"column":5}},"line":7},"1":{"name":"(anonymous_1)","decl":{"start":{"line":38,"column":4},"end":{"line":38,"column":5}},"loc":{"start":{"line":38,"column":46},"end":{"line":56,"column":5}},"line":38},"2":{"name":"(anonymous_2)","decl":{"start":{"line":59,"column":4},"end":{"line":59,"column":5}},"loc":{"start":{"line":59,"column":49},"end":{"line":80,"column":5}},"line":59},"3":{"name":"(anonymous_3)","decl":{"start":{"line":82,"column":4},"end":{"line":82,"column":5}},"loc":{"start":{"line":82,"column":46},"end":{"line":100,"column":5}},"line":82},"4":{"name":"(anonymous_4)","decl":{"start":{"line":103,"column":4},"end":{"line":103,"column":5}},"loc":{"start":{"line":103,"column":45},"end":{"line":148,"column":5}},"line":103}},"branchMap":{"0":{"loc":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"type":"if","locations":[{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},{"start":{},"end":{}}],"line":12},"1":{"loc":{"start":{"line":31,"column":23},"end":{"line":31,"column":42}},"type":"cond-expr","locations":[{"start":{"line":31,"column":33},"end":{"line":31,"column":36}},{"start":{"line":31,"column":39},"end":{"line":31,"column":42}}],"line":31},"2":{"loc":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"type":"if","locations":[{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},{"start":{},"end":{}}],"line":66},"3":{"loc":{"start":{"line":66,"column":16},"end":{"line":66,"column":78}},"type":"binary-expr","locations":[{"start":{"line":66,"column":16},"end":{"line":66,"column":21}},{"start":{"line":66,"column":26},"end":{"line":66,"column":48}},{"start":{"line":66,"column":52},"end":{"line":66,"column":77}}],"line":66},"4":{"loc":{"start":{"line":96,"column":23},"end":{"line":96,"column":42}},"type":"cond-expr","locations":[{"start":{"line":96,"column":33},"end":{"line":96,"column":36}},{"start":{"line":96,"column":39},"end":{"line":96,"column":42}}],"line":96},"5":{"loc":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"type":"if","locations":[{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},{"start":{},"end":{}}],"line":111},"6":{"loc":{"start":{"line":117,"column":33},"end":{"line":117,"column":84}},"type":"binary-expr","locations":[{"start":{"line":117,"column":33},"end":{"line":117,"column":55}},{"start":{"line":117,"column":59},"end":{"line":117,"column":84}}],"line":117},"7":{"loc":{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},"type":"if","locations":[{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},{"start":{},"end":{}}],"line":118},"8":{"loc":{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},"type":"if","locations":[{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},{"start":{},"end":{}}],"line":131}},"s":{"0":1,"1":1,"2":1,"3":3,"4":3,"5":3,"6":3,"7":1,"8":2,"9":2,"10":1,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":4,"31":4,"32":4,"33":4,"34":4,"35":4,"36":4,"37":1,"38":3,"39":3,"40":1,"41":2,"42":2,"43":2,"44":1,"45":1,"46":1,"47":2,"48":2,"49":2,"50":1},"f":{"0":3,"1":0,"2":0,"3":0,"4":4},"b":{"0":[1,2],"1":[1,1],"2":[0,0],"3":[0,0,0],"4":[0,0],"5":[1,3],"6":[3,1],"7":[1,2],"8":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2917d152140ab09724020f4ab1282f6f8aefef73"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js","statementMap":{"0":{"start":{"line":1,"column":46},"end":{"line":1,"column":66}},"1":{"start":{"line":6,"column":8},"end":{"line":29,"column":9}},"2":{"start":{"line":7,"column":55},"end":{"line":7,"column":63}},"3":{"start":{"line":10,"column":25},"end":{"line":15,"column":14}},"4":{"start":{"line":18,"column":12},"end":{"line":24,"column":13}},"5":{"start":{"line":19,"column":31},"end":{"line":22,"column":19}},"6":{"start":{"line":19,"column":56},"end":{"line":22,"column":17}},"7":{"start":{"line":23,"column":16},"end":{"line":23,"column":47}},"8":{"start":{"line":26,"column":12},"end":{"line":26,"column":81}},"9":{"start":{"line":28,"column":12},"end":{"line":28,"column":22}},"10":{"start":{"line":34,"column":8},"end":{"line":48,"column":9}},"11":{"start":{"line":35,"column":26},"end":{"line":44,"column":14}},"12":{"start":{"line":45,"column":12},"end":{"line":45,"column":28}},"13":{"start":{"line":47,"column":12},"end":{"line":47,"column":22}},"14":{"start":{"line":53,"column":8},"end":{"line":62,"column":9}},"15":{"start":{"line":54,"column":26},"end":{"line":58,"column":14}},"16":{"start":{"line":59,"column":12},"end":{"line":59,"column":28}},"17":{"start":{"line":61,"column":12},"end":{"line":61,"column":22}},"18":{"start":{"line":67,"column":8},"end":{"line":79,"column":9}},"19":{"start":{"line":68,"column":27},"end":{"line":68,"column":37}},"20":{"start":{"line":69,"column":55},"end":{"line":69,"column":63}},"21":{"start":{"line":71,"column":25},"end":{"line":71,"column":48}},"22":{"start":{"line":72,"column":12},"end":{"line":72,"column":50}},"23":{"start":{"line":72,"column":23},"end":{"line":72,"column":50}},"24":{"start":{"line":73,"column":12},"end":{"line":73,"column":76}},"25":{"start":{"line":73,"column":45},"end":{"line":73,"column":76}},"26":{"start":{"line":75,"column":12},"end":{"line":75,"column":78}},"27":{"start":{"line":76,"column":12},"end":{"line":76,"column":69}},"28":{"start":{"line":78,"column":12},"end":{"line":78,"column":22}},"29":{"start":{"line":84,"column":8},"end":{"line":94,"column":9}},"30":{"start":{"line":85,"column":27},"end":{"line":85,"column":37}},"31":{"start":{"line":86,"column":25},"end":{"line":86,"column":48}},"32":{"start":{"line":87,"column":12},"end":{"line":87,"column":50}},"33":{"start":{"line":87,"column":23},"end":{"line":87,"column":50}},"34":{"start":{"line":88,"column":12},"end":{"line":88,"column":76}},"35":{"start":{"line":88,"column":45},"end":{"line":88,"column":76}},"36":{"start":{"line":90,"column":12},"end":{"line":90,"column":33}},"37":{"start":{"line":91,"column":12},"end":{"line":91,"column":63}},"38":{"start":{"line":93,"column":12},"end":{"line":93,"column":22}},"39":{"start":{"line":99,"column":8},"end":{"line":119,"column":9}},"40":{"start":{"line":100,"column":27},"end":{"line":100,"column":37}},"41":{"start":{"line":101,"column":25},"end":{"line":101,"column":48}},"42":{"start":{"line":102,"column":12},"end":{"line":102,"column":50}},"43":{"start":{"line":102,"column":23},"end":{"line":102,"column":50}},"44":{"start":{"line":104,"column":33},"end":{"line":106,"column":14}},"45":{"start":{"line":109,"column":12},"end":{"line":115,"column":13}},"46":{"start":{"line":110,"column":16},"end":{"line":110,"column":45}},"47":{"start":{"line":111,"column":16},"end":{"line":111,"column":41}},"48":{"start":{"line":113,"column":16},"end":{"line":113,"column":71}},"49":{"start":{"line":114,"column":16},"end":{"line":114,"column":39}},"50":{"start":{"line":116,"column":12},"end":{"line":116,"column":34}},"51":{"start":{"line":118,"column":12},"end":{"line":118,"column":22}},"52":{"start":{"line":123,"column":0},"end":{"line":123,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":4},"end":{"line":5,"column":5}},"loc":{"start":{"line":5,"column":44},"end":{"line":30,"column":5}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":19,"column":45},"end":{"line":19,"column":46}},"loc":{"start":{"line":19,"column":56},"end":{"line":22,"column":17}},"line":19},"2":{"name":"(anonymous_2)","decl":{"start":{"line":33,"column":4},"end":{"line":33,"column":5}},"loc":{"start":{"line":33,"column":51},"end":{"line":49,"column":5}},"line":33},"3":{"name":"(anonymous_3)","decl":{"start":{"line":52,"column":4},"end":{"line":52,"column":5}},"loc":{"start":{"line":52,"column":44},"end":{"line":63,"column":5}},"line":52},"4":{"name":"(anonymous_4)","decl":{"start":{"line":66,"column":4},"end":{"line":66,"column":5}},"loc":{"start":{"line":66,"column":44},"end":{"line":80,"column":5}},"line":66},"5":{"name":"(anonymous_5)","decl":{"start":{"line":83,"column":4},"end":{"line":83,"column":5}},"loc":{"start":{"line":83,"column":44},"end":{"line":95,"column":5}},"line":83},"6":{"name":"(anonymous_6)","decl":{"start":{"line":98,"column":4},"end":{"line":98,"column":5}},"loc":{"start":{"line":98,"column":44},"end":{"line":120,"column":5}},"line":98}},"branchMap":{"0":{"loc":{"start":{"line":13,"column":28},"end":{"line":13,"column":46}},"type":"binary-expr","locations":[{"start":{"line":13,"column":28},"end":{"line":13,"column":38}},{"start":{"line":13,"column":42},"end":{"line":13,"column":46}}],"line":13},"1":{"loc":{"start":{"line":18,"column":12},"end":{"line":24,"column":13}},"type":"if","locations":[{"start":{"line":18,"column":12},"end":{"line":24,"column":13}},{"start":{},"end":{}}],"line":18},"2":{"loc":{"start":{"line":18,"column":16},"end":{"line":18,"column":49}},"type":"binary-expr","locations":[{"start":{"line":18,"column":16},"end":{"line":18,"column":25}},{"start":{"line":18,"column":29},"end":{"line":18,"column":49}}],"line":18},"3":{"loc":{"start":{"line":72,"column":12},"end":{"line":72,"column":50}},"type":"if","locations":[{"start":{"line":72,"column":12},"end":{"line":72,"column":50}},{"start":{},"end":{}}],"line":72},"4":{"loc":{"start":{"line":73,"column":12},"end":{"line":73,"column":76}},"type":"if","locations":[{"start":{"line":73,"column":12},"end":{"line":73,"column":76}},{"start":{},"end":{}}],"line":73},"5":{"loc":{"start":{"line":87,"column":12},"end":{"line":87,"column":50}},"type":"if","locations":[{"start":{"line":87,"column":12},"end":{"line":87,"column":50}},{"start":{},"end":{}}],"line":87},"6":{"loc":{"start":{"line":88,"column":12},"end":{"line":88,"column":76}},"type":"if","locations":[{"start":{"line":88,"column":12},"end":{"line":88,"column":76}},{"start":{},"end":{}}],"line":88},"7":{"loc":{"start":{"line":102,"column":12},"end":{"line":102,"column":50}},"type":"if","locations":[{"start":{"line":102,"column":12},"end":{"line":102,"column":50}},{"start":{},"end":{}}],"line":102},"8":{"loc":{"start":{"line":109,"column":12},"end":{"line":115,"column":13}},"type":"if","locations":[{"start":{"line":109,"column":12},"end":{"line":115,"column":13}},{"start":{"line":112,"column":19},"end":{"line":115,"column":13}}],"line":109}},"s":{"0":1,"1":2,"2":2,"3":2,"4":2,"5":1,"6":2,"7":1,"8":2,"9":0,"10":1,"11":1,"12":1,"13":0,"14":0,"15":0,"16":0,"17":0,"18":2,"19":2,"20":2,"21":2,"22":2,"23":0,"24":2,"25":1,"26":1,"27":1,"28":1,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":2,"40":2,"41":2,"42":2,"43":0,"44":2,"45":2,"46":1,"47":1,"48":1,"49":1,"50":2,"51":0,"52":1},"f":{"0":2,"1":2,"2":1,"3":0,"4":2,"5":0,"6":2},"b":{"0":[2,1],"1":[1,1],"2":[2,2],"3":[0,2],"4":[1,1],"5":[0,0],"6":[0,0],"7":[0,2],"8":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"611903ee95c16bde9bc49db059f4f96f8b5ab109"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js","statementMap":{"0":{"start":{"line":1,"column":17},"end":{"line":1,"column":37}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":47}},"3":{"start":{"line":4,"column":25},"end":{"line":4,"column":55}},"4":{"start":{"line":5,"column":15},"end":{"line":5,"column":33}},"5":{"start":{"line":10,"column":8},"end":{"line":20,"column":9}},"6":{"start":{"line":11,"column":50},"end":{"line":11,"column":58}},"7":{"start":{"line":12,"column":28},"end":{"line":12,"column":76}},"8":{"start":{"line":13,"column":12},"end":{"line":17,"column":15}},"9":{"start":{"line":19,"column":12},"end":{"line":19,"column":22}},"10":{"start":{"line":24,"column":8},"end":{"line":44,"column":9}},"11":{"start":{"line":25,"column":40},"end":{"line":25,"column":48}},"12":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"13":{"start":{"line":27,"column":16},"end":{"line":27,"column":89}},"14":{"start":{"line":30,"column":25},"end":{"line":30,"column":65}},"15":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"16":{"start":{"line":32,"column":16},"end":{"line":32,"column":47}},"17":{"start":{"line":35,"column":36},"end":{"line":35,"column":79}},"18":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"19":{"start":{"line":37,"column":16},"end":{"line":37,"column":47}},"20":{"start":{"line":40,"column":26},"end":{"line":40,"column":52}},"21":{"start":{"line":41,"column":12},"end":{"line":41,"column":58}},"22":{"start":{"line":43,"column":12},"end":{"line":43,"column":22}},"23":{"start":{"line":48,"column":8},"end":{"line":74,"column":9}},"24":{"start":{"line":49,"column":37},"end":{"line":49,"column":45}},"25":{"start":{"line":51,"column":27},"end":{"line":54,"column":14}},"26":{"start":{"line":55,"column":28},"end":{"line":55,"column":47}},"27":{"start":{"line":57,"column":36},"end":{"line":66,"column":14}},"28":{"start":{"line":69,"column":33},"end":{"line":69,"column":59}},"29":{"start":{"line":70,"column":12},"end":{"line":70,"column":51}},"30":{"start":{"line":73,"column":12},"end":{"line":73,"column":22}},"31":{"start":{"line":80,"column":0},"end":{"line":80,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":9,"column":4},"end":{"line":9,"column":5}},"loc":{"start":{"line":9,"column":42},"end":{"line":21,"column":5}},"line":9},"1":{"name":"(anonymous_1)","decl":{"start":{"line":23,"column":4},"end":{"line":23,"column":5}},"loc":{"start":{"line":23,"column":39},"end":{"line":45,"column":5}},"line":23},"2":{"name":"(anonymous_2)","decl":{"start":{"line":47,"column":4},"end":{"line":47,"column":5}},"loc":{"start":{"line":47,"column":46},"end":{"line":75,"column":5}},"line":47}},"branchMap":{"0":{"loc":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"type":"if","locations":[{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},{"start":{},"end":{}}],"line":26},"1":{"loc":{"start":{"line":26,"column":16},"end":{"line":26,"column":35}},"type":"binary-expr","locations":[{"start":{"line":26,"column":16},"end":{"line":26,"column":22}},{"start":{"line":26,"column":26},"end":{"line":26,"column":35}}],"line":26},"2":{"loc":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"type":"if","locations":[{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},{"start":{},"end":{}}],"line":31},"3":{"loc":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"type":"if","locations":[{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},{"start":{},"end":{}}],"line":36}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":0,"6":0,"7":0,"8":0,"9":0,"10":1,"11":1,"12":1,"13":0,"14":1,"15":1,"16":1,"17":0,"18":0,"19":0,"20":0,"21":0,"22":1,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":1},"f":{"0":0,"1":1,"2":0},"b":{"0":[0,1],"1":[1,1],"2":[1,0],"3":[0,0]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"80370fa376eb20e9088f533698882ee10ddf85dd"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":3,"column":14},"end":{"line":3,"column":64}},"2":{"start":{"line":4,"column":14},"end":{"line":4,"column":67}},"3":{"start":{"line":8,"column":2},"end":{"line":21,"column":12}},"4":{"start":{"line":26,"column":2},"end":{"line":33,"column":3}},"5":{"start":{"line":27,"column":19},"end":{"line":27,"column":54}},"6":{"start":{"line":28,"column":20},"end":{"line":28,"column":42}},"7":{"start":{"line":29,"column":4},"end":{"line":29,"column":30}},"8":{"start":{"line":31,"column":4},"end":{"line":31,"column":47}},"9":{"start":{"line":32,"column":4},"end":{"line":32,"column":63}},"10":{"start":{"line":36,"column":0},"end":{"line":36,"column":31}}},"fnMap":{"0":{"name":"cleanText","decl":{"start":{"line":7,"column":9},"end":{"line":7,"column":18}},"loc":{"start":{"line":7,"column":30},"end":{"line":22,"column":1}},"line":7},"1":{"name":"askGemini","decl":{"start":{"line":25,"column":15},"end":{"line":25,"column":24}},"loc":{"start":{"line":25,"column":33},"end":{"line":34,"column":1}},"line":25}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":19},"end":{"line":7,"column":28}},"type":"default-arg","locations":[{"start":{"line":7,"column":26},"end":{"line":7,"column":28}}],"line":7}},"s":{"0":1,"1":1,"2":1,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":1},"f":{"0":0,"1":0},"b":{"0":[0]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"3e77ad823eae243bd1e4e7cac77dbdff43a6f7dc"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":39},"end":{"line":2,"column":59}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":35}},"3":{"start":{"line":5,"column":14},"end":{"line":5,"column":64}},"4":{"start":{"line":6,"column":14},"end":{"line":6,"column":67}},"5":{"start":{"line":9,"column":2},"end":{"line":65,"column":3}},"6":{"start":{"line":10,"column":23},"end":{"line":13,"column":6}},"7":{"start":{"line":15,"column":4},"end":{"line":22,"column":5}},"8":{"start":{"line":16,"column":6},"end":{"line":21,"column":9}},"9":{"start":{"line":24,"column":26},"end":{"line":26,"column":17}},"10":{"start":{"line":25,"column":18},"end":{"line":25,"column":88}},"11":{"start":{"line":28,"column":19},"end":{"line":35,"column":5}},"12":{"start":{"line":37,"column":19},"end":{"line":37,"column":54}},"13":{"start":{"line":38,"column":27},"end":{"line":38,"column":49}},"14":{"start":{"line":39,"column":23},"end":{"line":39,"column":69}},"15":{"start":{"line":39,"column":60},"end":{"line":39,"column":68}},"16":{"start":{"line":41,"column":29},"end":{"line":53,"column":6}},"17":{"start":{"line":55,"column":4},"end":{"line":55,"column":28}},"18":{"start":{"line":57,"column":4},"end":{"line":57,"column":60}},"19":{"start":{"line":59,"column":4},"end":{"line":64,"column":7}},"20":{"start":{"line":68,"column":0},"end":{"line":68,"column":42}}},"fnMap":{"0":{"name":"getAIRecommendations","decl":{"start":{"line":8,"column":15},"end":{"line":8,"column":35}},"loc":{"start":{"line":8,"column":44},"end":{"line":66,"column":1}},"line":8},"1":{"name":"(anonymous_1)","decl":{"start":{"line":25,"column":11},"end":{"line":25,"column":12}},"loc":{"start":{"line":25,"column":18},"end":{"line":25,"column":88}},"line":25},"2":{"name":"(anonymous_2)","decl":{"start":{"line":39,"column":53},"end":{"line":39,"column":54}},"loc":{"start":{"line":39,"column":60},"end":{"line":39,"column":68}},"line":39}},"branchMap":{"0":{"loc":{"start":{"line":15,"column":4},"end":{"line":22,"column":5}},"type":"if","locations":[{"start":{"line":15,"column":4},"end":{"line":22,"column":5}},{"start":{},"end":{}}],"line":15},"1":{"loc":{"start":{"line":25,"column":54},"end":{"line":25,"column":85}},"type":"binary-expr","locations":[{"start":{"line":25,"column":54},"end":{"line":25,"column":75}},{"start":{"line":25,"column":79},"end":{"line":25,"column":85}}],"line":25}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":1},"f":{"0":0,"1":0,"2":0},"b":{"0":[0,0],"1":[0,0]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"e1ea4577adfa0d0a6ebf7a252cc3decd0146686c"} +{"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}},"1":{"start":{"line":2,"column":16},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":12},"end":{"line":3,"column":21}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"4":{"start":{"line":5,"column":20},"end":{"line":5,"column":52}},"5":{"start":{"line":6,"column":15},"end":{"line":6,"column":34}},"6":{"start":{"line":7,"column":13},"end":{"line":7,"column":28}},"7":{"start":{"line":9,"column":13},"end":{"line":9,"column":28}},"8":{"start":{"line":10,"column":15},"end":{"line":10,"column":37}},"9":{"start":{"line":11,"column":19},"end":{"line":11,"column":39}},"10":{"start":{"line":12,"column":11},"end":{"line":16,"column":2}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}},"12":{"start":{"line":21,"column":0},"end":{"line":21,"column":16}},"13":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}},"14":{"start":{"line":23,"column":0},"end":{"line":23,"column":48}},"15":{"start":{"line":24,"column":0},"end":{"line":24,"column":34}},"16":{"start":{"line":27,"column":0},"end":{"line":27,"column":21}},"17":{"start":{"line":31,"column":0},"end":{"line":31,"column":21}},"18":{"start":{"line":34,"column":0},"end":{"line":52,"column":3}},"19":{"start":{"line":35,"column":2},"end":{"line":35,"column":46}},"20":{"start":{"line":37,"column":2},"end":{"line":39,"column":5}},"21":{"start":{"line":38,"column":4},"end":{"line":38,"column":34}},"22":{"start":{"line":41,"column":2},"end":{"line":43,"column":5}},"23":{"start":{"line":42,"column":4},"end":{"line":42,"column":73}},"24":{"start":{"line":45,"column":2},"end":{"line":47,"column":5}},"25":{"start":{"line":46,"column":4},"end":{"line":46,"column":73}},"26":{"start":{"line":49,"column":2},"end":{"line":51,"column":5}},"27":{"start":{"line":50,"column":4},"end":{"line":50,"column":51}},"28":{"start":{"line":56,"column":0},"end":{"line":60,"column":1}},"29":{"start":{"line":57,"column":2},"end":{"line":59,"column":5}},"30":{"start":{"line":58,"column":4},"end":{"line":58,"column":66}},"31":{"start":{"line":62,"column":0},"end":{"line":62,"column":21}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":34,"column":20},"end":{"line":34,"column":21}},"loc":{"start":{"line":34,"column":32},"end":{"line":52,"column":1}},"line":34},"1":{"name":"(anonymous_1)","decl":{"start":{"line":37,"column":25},"end":{"line":37,"column":26}},"loc":{"start":{"line":37,"column":37},"end":{"line":39,"column":3}},"line":37},"2":{"name":"(anonymous_2)","decl":{"start":{"line":41,"column":28},"end":{"line":41,"column":29}},"loc":{"start":{"line":41,"column":45},"end":{"line":43,"column":3}},"line":41},"3":{"name":"(anonymous_3)","decl":{"start":{"line":45,"column":27},"end":{"line":45,"column":28}},"loc":{"start":{"line":45,"column":43},"end":{"line":47,"column":3}},"line":45},"4":{"name":"(anonymous_4)","decl":{"start":{"line":49,"column":26},"end":{"line":49,"column":27}},"loc":{"start":{"line":49,"column":32},"end":{"line":51,"column":3}},"line":49},"5":{"name":"(anonymous_5)","decl":{"start":{"line":57,"column":22},"end":{"line":57,"column":23}},"loc":{"start":{"line":57,"column":28},"end":{"line":59,"column":3}},"line":57}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"type":"binary-expr","locations":[{"start":{"line":4,"column":13},"end":{"line":4,"column":29}},{"start":{"line":4,"column":33},"end":{"line":4,"column":37}}],"line":4},"1":{"loc":{"start":{"line":56,"column":0},"end":{"line":60,"column":1}},"type":"if","locations":[{"start":{"line":56,"column":0},"end":{"line":60,"column":1}},{"start":{},"end":{}}],"line":56}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0},"b":{"0":[0,0],"1":[0,0]}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js","statementMap":{"0":{"start":{"line":1,"column":33},"end":{"line":1,"column":71}},"1":{"start":{"line":5,"column":4},"end":{"line":21,"column":5}},"2":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"3":{"start":{"line":8,"column":8},"end":{"line":8,"column":39}},"4":{"start":{"line":11,"column":21},"end":{"line":11,"column":32}},"5":{"start":{"line":12,"column":20},"end":{"line":12,"column":54}},"6":{"start":{"line":14,"column":6},"end":{"line":18,"column":9}},"7":{"start":{"line":20,"column":6},"end":{"line":20,"column":16}},"8":{"start":{"line":25,"column":0},"end":{"line":25,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":4,"column":2},"end":{"line":4,"column":3}},"loc":{"start":{"line":4,"column":50},"end":{"line":22,"column":3}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"type":"if","locations":[{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":10},"end":{"line":7,"column":35}},"type":"binary-expr","locations":[{"start":{"line":7,"column":10},"end":{"line":7,"column":19}},{"start":{"line":7,"column":23},"end":{"line":7,"column":35}}],"line":7}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0},"f":{"0":0},"b":{"0":[0,0],"1":[0,0]}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js","statementMap":{"0":{"start":{"line":1,"column":43},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":24}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":52}},"3":{"start":{"line":8,"column":8},"end":{"line":34,"column":9}},"4":{"start":{"line":9,"column":34},"end":{"line":9,"column":42}},"5":{"start":{"line":10,"column":27},"end":{"line":10,"column":38}},"6":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"7":{"start":{"line":13,"column":16},"end":{"line":13,"column":97}},"8":{"start":{"line":17,"column":36},"end":{"line":29,"column":14}},"9":{"start":{"line":31,"column":12},"end":{"line":31,"column":55}},"10":{"start":{"line":33,"column":12},"end":{"line":33,"column":22}},"11":{"start":{"line":39,"column":8},"end":{"line":55,"column":9}},"12":{"start":{"line":40,"column":27},"end":{"line":40,"column":38}},"13":{"start":{"line":41,"column":26},"end":{"line":50,"column":14}},"14":{"start":{"line":52,"column":12},"end":{"line":52,"column":28}},"15":{"start":{"line":54,"column":12},"end":{"line":54,"column":22}},"16":{"start":{"line":60,"column":8},"end":{"line":79,"column":9}},"17":{"start":{"line":61,"column":31},"end":{"line":61,"column":41}},"18":{"start":{"line":62,"column":27},"end":{"line":62,"column":38}},"19":{"start":{"line":65,"column":25},"end":{"line":65,"column":52}},"20":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"21":{"start":{"line":67,"column":16},"end":{"line":67,"column":44}},"22":{"start":{"line":70,"column":29},"end":{"line":74,"column":14}},"23":{"start":{"line":76,"column":12},"end":{"line":76,"column":31}},"24":{"start":{"line":78,"column":12},"end":{"line":78,"column":22}},"25":{"start":{"line":83,"column":8},"end":{"line":99,"column":9}},"26":{"start":{"line":84,"column":27},"end":{"line":84,"column":38}},"27":{"start":{"line":85,"column":36},"end":{"line":95,"column":14}},"28":{"start":{"line":96,"column":12},"end":{"line":96,"column":55}},"29":{"start":{"line":98,"column":12},"end":{"line":98,"column":22}},"30":{"start":{"line":104,"column":8},"end":{"line":147,"column":9}},"31":{"start":{"line":105,"column":31},"end":{"line":105,"column":41}},"32":{"start":{"line":106,"column":32},"end":{"line":106,"column":40}},"33":{"start":{"line":107,"column":27},"end":{"line":107,"column":38}},"34":{"start":{"line":108,"column":23},"end":{"line":108,"column":46}},"35":{"start":{"line":110,"column":25},"end":{"line":110,"column":52}},"36":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"37":{"start":{"line":112,"column":16},"end":{"line":112,"column":70}},"38":{"start":{"line":117,"column":33},"end":{"line":117,"column":84}},"39":{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},"40":{"start":{"line":119,"column":16},"end":{"line":119,"column":99}},"41":{"start":{"line":123,"column":32},"end":{"line":127,"column":14}},"42":{"start":{"line":129,"column":12},"end":{"line":129,"column":73}},"43":{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},"44":{"start":{"line":132,"column":39},"end":{"line":132,"column":63}},"45":{"start":{"line":134,"column":34},"end":{"line":138,"column":18}},"46":{"start":{"line":140,"column":16},"end":{"line":140,"column":75}},"47":{"start":{"line":143,"column":12},"end":{"line":143,"column":30}},"48":{"start":{"line":144,"column":12},"end":{"line":144,"column":46}},"49":{"start":{"line":146,"column":12},"end":{"line":146,"column":22}},"50":{"start":{"line":151,"column":0},"end":{"line":151,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":4},"end":{"line":7,"column":5}},"loc":{"start":{"line":7,"column":49},"end":{"line":35,"column":5}},"line":7},"1":{"name":"(anonymous_1)","decl":{"start":{"line":38,"column":4},"end":{"line":38,"column":5}},"loc":{"start":{"line":38,"column":46},"end":{"line":56,"column":5}},"line":38},"2":{"name":"(anonymous_2)","decl":{"start":{"line":59,"column":4},"end":{"line":59,"column":5}},"loc":{"start":{"line":59,"column":49},"end":{"line":80,"column":5}},"line":59},"3":{"name":"(anonymous_3)","decl":{"start":{"line":82,"column":4},"end":{"line":82,"column":5}},"loc":{"start":{"line":82,"column":46},"end":{"line":100,"column":5}},"line":82},"4":{"name":"(anonymous_4)","decl":{"start":{"line":103,"column":4},"end":{"line":103,"column":5}},"loc":{"start":{"line":103,"column":45},"end":{"line":148,"column":5}},"line":103}},"branchMap":{"0":{"loc":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"type":"if","locations":[{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},{"start":{},"end":{}}],"line":12},"1":{"loc":{"start":{"line":31,"column":23},"end":{"line":31,"column":42}},"type":"cond-expr","locations":[{"start":{"line":31,"column":33},"end":{"line":31,"column":36}},{"start":{"line":31,"column":39},"end":{"line":31,"column":42}}],"line":31},"2":{"loc":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"type":"if","locations":[{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},{"start":{},"end":{}}],"line":66},"3":{"loc":{"start":{"line":66,"column":16},"end":{"line":66,"column":78}},"type":"binary-expr","locations":[{"start":{"line":66,"column":16},"end":{"line":66,"column":21}},{"start":{"line":66,"column":26},"end":{"line":66,"column":48}},{"start":{"line":66,"column":52},"end":{"line":66,"column":77}}],"line":66},"4":{"loc":{"start":{"line":96,"column":23},"end":{"line":96,"column":42}},"type":"cond-expr","locations":[{"start":{"line":96,"column":33},"end":{"line":96,"column":36}},{"start":{"line":96,"column":39},"end":{"line":96,"column":42}}],"line":96},"5":{"loc":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"type":"if","locations":[{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},{"start":{},"end":{}}],"line":111},"6":{"loc":{"start":{"line":117,"column":33},"end":{"line":117,"column":84}},"type":"binary-expr","locations":[{"start":{"line":117,"column":33},"end":{"line":117,"column":55}},{"start":{"line":117,"column":59},"end":{"line":117,"column":84}}],"line":117},"7":{"loc":{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},"type":"if","locations":[{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},{"start":{},"end":{}}],"line":118},"8":{"loc":{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},"type":"if","locations":[{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},{"start":{},"end":{}}],"line":131}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0]}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js","statementMap":{"0":{"start":{"line":1,"column":46},"end":{"line":1,"column":66}},"1":{"start":{"line":6,"column":4},"end":{"line":33,"column":5}},"2":{"start":{"line":7,"column":49},"end":{"line":7,"column":57}},"3":{"start":{"line":10,"column":6},"end":{"line":12,"column":7}},"4":{"start":{"line":11,"column":8},"end":{"line":11,"column":98}},"5":{"start":{"line":15,"column":19},"end":{"line":20,"column":8}},"6":{"start":{"line":23,"column":21},"end":{"line":26,"column":9}},"7":{"start":{"line":23,"column":46},"end":{"line":26,"column":7}},"8":{"start":{"line":28,"column":6},"end":{"line":28,"column":37}},"9":{"start":{"line":30,"column":6},"end":{"line":30,"column":75}},"10":{"start":{"line":32,"column":6},"end":{"line":32,"column":16}},"11":{"start":{"line":38,"column":4},"end":{"line":52,"column":5}},"12":{"start":{"line":39,"column":20},"end":{"line":48,"column":8}},"13":{"start":{"line":49,"column":6},"end":{"line":49,"column":22}},"14":{"start":{"line":51,"column":6},"end":{"line":51,"column":16}},"15":{"start":{"line":57,"column":4},"end":{"line":66,"column":5}},"16":{"start":{"line":58,"column":20},"end":{"line":62,"column":8}},"17":{"start":{"line":63,"column":6},"end":{"line":63,"column":22}},"18":{"start":{"line":65,"column":6},"end":{"line":65,"column":16}},"19":{"start":{"line":71,"column":4},"end":{"line":83,"column":5}},"20":{"start":{"line":72,"column":21},"end":{"line":72,"column":31}},"21":{"start":{"line":73,"column":49},"end":{"line":73,"column":57}},"22":{"start":{"line":75,"column":19},"end":{"line":75,"column":42}},"23":{"start":{"line":76,"column":6},"end":{"line":76,"column":44}},"24":{"start":{"line":76,"column":17},"end":{"line":76,"column":44}},"25":{"start":{"line":77,"column":6},"end":{"line":77,"column":70}},"26":{"start":{"line":77,"column":39},"end":{"line":77,"column":70}},"27":{"start":{"line":79,"column":6},"end":{"line":79,"column":72}},"28":{"start":{"line":80,"column":6},"end":{"line":80,"column":63}},"29":{"start":{"line":82,"column":6},"end":{"line":82,"column":16}},"30":{"start":{"line":88,"column":4},"end":{"line":98,"column":5}},"31":{"start":{"line":89,"column":21},"end":{"line":89,"column":31}},"32":{"start":{"line":90,"column":19},"end":{"line":90,"column":42}},"33":{"start":{"line":91,"column":6},"end":{"line":91,"column":44}},"34":{"start":{"line":91,"column":17},"end":{"line":91,"column":44}},"35":{"start":{"line":92,"column":6},"end":{"line":92,"column":70}},"36":{"start":{"line":92,"column":39},"end":{"line":92,"column":70}},"37":{"start":{"line":94,"column":6},"end":{"line":94,"column":27}},"38":{"start":{"line":95,"column":6},"end":{"line":95,"column":57}},"39":{"start":{"line":97,"column":6},"end":{"line":97,"column":16}},"40":{"start":{"line":103,"column":4},"end":{"line":123,"column":5}},"41":{"start":{"line":104,"column":21},"end":{"line":104,"column":31}},"42":{"start":{"line":105,"column":19},"end":{"line":105,"column":42}},"43":{"start":{"line":106,"column":6},"end":{"line":106,"column":44}},"44":{"start":{"line":106,"column":17},"end":{"line":106,"column":44}},"45":{"start":{"line":108,"column":27},"end":{"line":110,"column":8}},"46":{"start":{"line":113,"column":6},"end":{"line":119,"column":7}},"47":{"start":{"line":114,"column":8},"end":{"line":114,"column":37}},"48":{"start":{"line":115,"column":8},"end":{"line":115,"column":33}},"49":{"start":{"line":117,"column":8},"end":{"line":117,"column":63}},"50":{"start":{"line":118,"column":8},"end":{"line":118,"column":31}},"51":{"start":{"line":120,"column":6},"end":{"line":120,"column":28}},"52":{"start":{"line":122,"column":6},"end":{"line":122,"column":16}},"53":{"start":{"line":127,"column":0},"end":{"line":127,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":2},"end":{"line":5,"column":3}},"loc":{"start":{"line":5,"column":42},"end":{"line":34,"column":3}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":23,"column":35},"end":{"line":23,"column":36}},"loc":{"start":{"line":23,"column":46},"end":{"line":26,"column":7}},"line":23},"2":{"name":"(anonymous_2)","decl":{"start":{"line":37,"column":2},"end":{"line":37,"column":3}},"loc":{"start":{"line":37,"column":49},"end":{"line":53,"column":3}},"line":37},"3":{"name":"(anonymous_3)","decl":{"start":{"line":56,"column":2},"end":{"line":56,"column":3}},"loc":{"start":{"line":56,"column":42},"end":{"line":67,"column":3}},"line":56},"4":{"name":"(anonymous_4)","decl":{"start":{"line":70,"column":2},"end":{"line":70,"column":3}},"loc":{"start":{"line":70,"column":42},"end":{"line":84,"column":3}},"line":70},"5":{"name":"(anonymous_5)","decl":{"start":{"line":87,"column":2},"end":{"line":87,"column":3}},"loc":{"start":{"line":87,"column":42},"end":{"line":99,"column":3}},"line":87},"6":{"name":"(anonymous_6)","decl":{"start":{"line":102,"column":2},"end":{"line":102,"column":3}},"loc":{"start":{"line":102,"column":42},"end":{"line":124,"column":3}},"line":102}},"branchMap":{"0":{"loc":{"start":{"line":10,"column":6},"end":{"line":12,"column":7}},"type":"if","locations":[{"start":{"line":10,"column":6},"end":{"line":12,"column":7}},{"start":{},"end":{}}],"line":10},"1":{"loc":{"start":{"line":10,"column":10},"end":{"line":10,"column":46}},"type":"binary-expr","locations":[{"start":{"line":10,"column":10},"end":{"line":10,"column":20}},{"start":{"line":10,"column":24},"end":{"line":10,"column":46}}],"line":10},"2":{"loc":{"start":{"line":18,"column":20},"end":{"line":18,"column":38}},"type":"binary-expr","locations":[{"start":{"line":18,"column":20},"end":{"line":18,"column":30}},{"start":{"line":18,"column":34},"end":{"line":18,"column":38}}],"line":18},"3":{"loc":{"start":{"line":76,"column":6},"end":{"line":76,"column":44}},"type":"if","locations":[{"start":{"line":76,"column":6},"end":{"line":76,"column":44}},{"start":{},"end":{}}],"line":76},"4":{"loc":{"start":{"line":77,"column":6},"end":{"line":77,"column":70}},"type":"if","locations":[{"start":{"line":77,"column":6},"end":{"line":77,"column":70}},{"start":{},"end":{}}],"line":77},"5":{"loc":{"start":{"line":91,"column":6},"end":{"line":91,"column":44}},"type":"if","locations":[{"start":{"line":91,"column":6},"end":{"line":91,"column":44}},{"start":{},"end":{}}],"line":91},"6":{"loc":{"start":{"line":92,"column":6},"end":{"line":92,"column":70}},"type":"if","locations":[{"start":{"line":92,"column":6},"end":{"line":92,"column":70}},{"start":{},"end":{}}],"line":92},"7":{"loc":{"start":{"line":106,"column":6},"end":{"line":106,"column":44}},"type":"if","locations":[{"start":{"line":106,"column":6},"end":{"line":106,"column":44}},{"start":{},"end":{}}],"line":106},"8":{"loc":{"start":{"line":113,"column":6},"end":{"line":119,"column":7}},"type":"if","locations":[{"start":{"line":113,"column":6},"end":{"line":119,"column":7}},{"start":{"line":116,"column":13},"end":{"line":119,"column":7}}],"line":113}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0]}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js","statementMap":{"0":{"start":{"line":1,"column":17},"end":{"line":1,"column":37}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":47}},"3":{"start":{"line":4,"column":25},"end":{"line":4,"column":55}},"4":{"start":{"line":5,"column":15},"end":{"line":5,"column":33}},"5":{"start":{"line":10,"column":8},"end":{"line":20,"column":9}},"6":{"start":{"line":11,"column":50},"end":{"line":11,"column":58}},"7":{"start":{"line":12,"column":28},"end":{"line":12,"column":76}},"8":{"start":{"line":13,"column":12},"end":{"line":17,"column":15}},"9":{"start":{"line":19,"column":12},"end":{"line":19,"column":22}},"10":{"start":{"line":24,"column":8},"end":{"line":44,"column":9}},"11":{"start":{"line":25,"column":40},"end":{"line":25,"column":48}},"12":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"13":{"start":{"line":27,"column":16},"end":{"line":27,"column":89}},"14":{"start":{"line":30,"column":25},"end":{"line":30,"column":65}},"15":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"16":{"start":{"line":32,"column":16},"end":{"line":32,"column":47}},"17":{"start":{"line":35,"column":36},"end":{"line":35,"column":79}},"18":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"19":{"start":{"line":37,"column":16},"end":{"line":37,"column":47}},"20":{"start":{"line":40,"column":26},"end":{"line":40,"column":52}},"21":{"start":{"line":41,"column":12},"end":{"line":41,"column":58}},"22":{"start":{"line":43,"column":12},"end":{"line":43,"column":22}},"23":{"start":{"line":48,"column":8},"end":{"line":73,"column":9}},"24":{"start":{"line":49,"column":37},"end":{"line":49,"column":45}},"25":{"start":{"line":51,"column":27},"end":{"line":54,"column":14}},"26":{"start":{"line":55,"column":28},"end":{"line":55,"column":47}},"27":{"start":{"line":57,"column":36},"end":{"line":66,"column":14}},"28":{"start":{"line":68,"column":33},"end":{"line":68,"column":59}},"29":{"start":{"line":69,"column":12},"end":{"line":69,"column":51}},"30":{"start":{"line":72,"column":12},"end":{"line":72,"column":22}},"31":{"start":{"line":77,"column":0},"end":{"line":77,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":9,"column":4},"end":{"line":9,"column":5}},"loc":{"start":{"line":9,"column":42},"end":{"line":21,"column":5}},"line":9},"1":{"name":"(anonymous_1)","decl":{"start":{"line":23,"column":4},"end":{"line":23,"column":5}},"loc":{"start":{"line":23,"column":39},"end":{"line":45,"column":5}},"line":23},"2":{"name":"(anonymous_2)","decl":{"start":{"line":47,"column":4},"end":{"line":47,"column":5}},"loc":{"start":{"line":47,"column":46},"end":{"line":74,"column":5}},"line":47}},"branchMap":{"0":{"loc":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"type":"if","locations":[{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},{"start":{},"end":{}}],"line":26},"1":{"loc":{"start":{"line":26,"column":16},"end":{"line":26,"column":35}},"type":"binary-expr","locations":[{"start":{"line":26,"column":16},"end":{"line":26,"column":22}},{"start":{"line":26,"column":26},"end":{"line":26,"column":35}}],"line":26},"2":{"loc":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"type":"if","locations":[{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},{"start":{},"end":{}}],"line":31},"3":{"loc":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"type":"if","locations":[{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},{"start":{},"end":{}}],"line":36}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0},"f":{"0":0,"1":0,"2":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0]}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":3,"column":14},"end":{"line":3,"column":64}},"2":{"start":{"line":4,"column":14},"end":{"line":4,"column":67}},"3":{"start":{"line":8,"column":2},"end":{"line":21,"column":12}},"4":{"start":{"line":25,"column":2},"end":{"line":32,"column":3}},"5":{"start":{"line":26,"column":19},"end":{"line":26,"column":54}},"6":{"start":{"line":27,"column":20},"end":{"line":27,"column":42}},"7":{"start":{"line":28,"column":4},"end":{"line":28,"column":30}},"8":{"start":{"line":30,"column":4},"end":{"line":30,"column":47}},"9":{"start":{"line":31,"column":4},"end":{"line":31,"column":63}},"10":{"start":{"line":35,"column":0},"end":{"line":35,"column":42}}},"fnMap":{"0":{"name":"cleanText","decl":{"start":{"line":7,"column":9},"end":{"line":7,"column":18}},"loc":{"start":{"line":7,"column":30},"end":{"line":22,"column":1}},"line":7},"1":{"name":"askGemini","decl":{"start":{"line":24,"column":15},"end":{"line":24,"column":24}},"loc":{"start":{"line":24,"column":33},"end":{"line":33,"column":1}},"line":24}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":19},"end":{"line":7,"column":28}},"type":"default-arg","locations":[{"start":{"line":7,"column":26},"end":{"line":7,"column":28}}],"line":7}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"f":{"0":0,"1":0},"b":{"0":[0]}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":39},"end":{"line":2,"column":59}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":35}},"3":{"start":{"line":6,"column":2},"end":{"line":68,"column":3}},"4":{"start":{"line":8,"column":18},"end":{"line":8,"column":68}},"5":{"start":{"line":9,"column":18},"end":{"line":9,"column":71}},"6":{"start":{"line":11,"column":23},"end":{"line":14,"column":6}},"7":{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},"8":{"start":{"line":18,"column":6},"end":{"line":23,"column":9}},"9":{"start":{"line":26,"column":26},"end":{"line":31,"column":17}},"10":{"start":{"line":29,"column":10},"end":{"line":29,"column":86}},"11":{"start":{"line":33,"column":19},"end":{"line":39,"column":5}},"12":{"start":{"line":41,"column":19},"end":{"line":41,"column":54}},"13":{"start":{"line":42,"column":27},"end":{"line":42,"column":49}},"14":{"start":{"line":43,"column":23},"end":{"line":43,"column":69}},"15":{"start":{"line":43,"column":60},"end":{"line":43,"column":68}},"16":{"start":{"line":45,"column":29},"end":{"line":57,"column":6}},"17":{"start":{"line":59,"column":4},"end":{"line":59,"column":28}},"18":{"start":{"line":61,"column":4},"end":{"line":61,"column":60}},"19":{"start":{"line":62,"column":4},"end":{"line":67,"column":7}},"20":{"start":{"line":71,"column":0},"end":{"line":71,"column":42}}},"fnMap":{"0":{"name":"getAIRecommendations","decl":{"start":{"line":5,"column":15},"end":{"line":5,"column":35}},"loc":{"start":{"line":5,"column":44},"end":{"line":69,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":28,"column":8},"end":{"line":28,"column":9}},"loc":{"start":{"line":29,"column":10},"end":{"line":29,"column":86}},"line":29},"2":{"name":"(anonymous_2)","decl":{"start":{"line":43,"column":53},"end":{"line":43,"column":54}},"loc":{"start":{"line":43,"column":60},"end":{"line":43,"column":68}},"line":43}},"branchMap":{"0":{"loc":{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},"type":"if","locations":[{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},{"start":{},"end":{}}],"line":17},"1":{"loc":{"start":{"line":17,"column":8},"end":{"line":17,"column":44}},"type":"binary-expr","locations":[{"start":{"line":17,"column":8},"end":{"line":17,"column":19}},{"start":{"line":17,"column":23},"end":{"line":17,"column":44}}],"line":17},"2":{"loc":{"start":{"line":29,"column":49},"end":{"line":29,"column":83}},"type":"binary-expr","locations":[{"start":{"line":29,"column":49},"end":{"line":29,"column":73}},{"start":{"line":29,"column":77},"end":{"line":29,"column":83}}],"line":29}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0},"f":{"0":0,"1":0,"2":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0]}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\authMiddleware.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\authMiddleware.js","statementMap":{"0":{"start":{"line":1,"column":24},"end":{"line":1,"column":40}},"1":{"start":{"line":2,"column":17},"end":{"line":2,"column":37}},"2":{"start":{"line":4,"column":0},"end":{"line":29,"column":2}},"3":{"start":{"line":5,"column":2},"end":{"line":28,"column":3}},"4":{"start":{"line":6,"column":24},"end":{"line":6,"column":49}},"5":{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},"6":{"start":{"line":8,"column":6},"end":{"line":8,"column":68}},"7":{"start":{"line":11,"column":18},"end":{"line":11,"column":43}},"8":{"start":{"line":12,"column":20},"end":{"line":12,"column":38}},"9":{"start":{"line":13,"column":17},"end":{"line":13,"column":48}},"10":{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},"11":{"start":{"line":14,"column":15},"end":{"line":14,"column":73}},"12":{"start":{"line":16,"column":4},"end":{"line":16,"column":20}},"13":{"start":{"line":17,"column":4},"end":{"line":17,"column":28}},"14":{"start":{"line":18,"column":4},"end":{"line":18,"column":11}},"15":{"start":{"line":20,"column":4},"end":{"line":20,"column":23}},"16":{"start":{"line":21,"column":4},"end":{"line":27,"column":5}},"17":{"start":{"line":22,"column":6},"end":{"line":22,"column":16}},"18":{"start":{"line":23,"column":11},"end":{"line":27,"column":5}},"19":{"start":{"line":24,"column":6},"end":{"line":24,"column":68}},"20":{"start":{"line":26,"column":6},"end":{"line":26,"column":68}}},"fnMap":{"0":{"name":"authMiddleware","decl":{"start":{"line":4,"column":32},"end":{"line":4,"column":46}},"loc":{"start":{"line":4,"column":63},"end":{"line":29,"column":1}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},"type":"if","locations":[{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":8},"end":{"line":7,"column":58}},"type":"binary-expr","locations":[{"start":{"line":7,"column":8},"end":{"line":7,"column":20}},{"start":{"line":7,"column":24},"end":{"line":7,"column":58}}],"line":7},"2":{"loc":{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},"type":"if","locations":[{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},{"start":{},"end":{}}],"line":14},"3":{"loc":{"start":{"line":21,"column":4},"end":{"line":27,"column":5}},"type":"if","locations":[{"start":{"line":21,"column":4},"end":{"line":27,"column":5}},{"start":{"line":23,"column":11},"end":{"line":27,"column":5}}],"line":21},"4":{"loc":{"start":{"line":23,"column":11},"end":{"line":27,"column":5}},"type":"if","locations":[{"start":{"line":23,"column":11},"end":{"line":27,"column":5}},{"start":{"line":25,"column":11},"end":{"line":27,"column":5}}],"line":23}},"s":{"0":1,"1":1,"2":1,"3":6,"4":6,"5":6,"6":2,"7":4,"8":4,"9":3,"10":2,"11":1,"12":1,"13":1,"14":1,"15":5,"16":5,"17":3,"18":2,"19":1,"20":1},"f":{"0":6},"b":{"0":[2,4],"1":[6,5],"2":[1,1],"3":[3,2],"4":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2b458db0fb066171c85660f11cd925b471913554"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\cloudinary.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\cloudinary.js","statementMap":{"0":{"start":{"line":1,"column":19},"end":{"line":1,"column":43}},"1":{"start":{"line":2,"column":30},"end":{"line":2,"column":66}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":32}},"3":{"start":{"line":5,"column":0},"end":{"line":9,"column":3}},"4":{"start":{"line":11,"column":16},"end":{"line":18,"column":2}},"5":{"start":{"line":20,"column":15},"end":{"line":20,"column":34}},"6":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0},"f":{},"b":{}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\handleError.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\handleError.js","statementMap":{"0":{"start":{"line":2,"column":2},"end":{"line":2,"column":31}},"1":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"2":{"start":{"line":5,"column":4},"end":{"line":5,"column":68}},"3":{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},"4":{"start":{"line":9,"column":4},"end":{"line":9,"column":74}},"5":{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},"6":{"start":{"line":13,"column":4},"end":{"line":13,"column":63}},"7":{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},"8":{"start":{"line":17,"column":4},"end":{"line":17,"column":75}},"9":{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},"10":{"start":{"line":21,"column":21},"end":{"line":21,"column":51}},"11":{"start":{"line":21,"column":41},"end":{"line":21,"column":50}},"12":{"start":{"line":22,"column":4},"end":{"line":22,"column":55}},"13":{"start":{"line":25,"column":2},"end":{"line":27,"column":5}},"14":{"start":{"line":30,"column":0},"end":{"line":30,"column":29}}},"fnMap":{"0":{"name":"handleError","decl":{"start":{"line":1,"column":9},"end":{"line":1,"column":20}},"loc":{"start":{"line":1,"column":41},"end":{"line":28,"column":1}},"line":1},"1":{"name":"(anonymous_1)","decl":{"start":{"line":21,"column":36},"end":{"line":21,"column":37}},"loc":{"start":{"line":21,"column":41},"end":{"line":21,"column":50}},"line":21}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"type":"if","locations":[{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},{"start":{},"end":{}}],"line":4},"1":{"loc":{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},{"start":{},"end":{}}],"line":8},"2":{"loc":{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},"type":"if","locations":[{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},{"start":{},"end":{}}],"line":12},"3":{"loc":{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},"type":"if","locations":[{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},{"start":{},"end":{}}],"line":16},"4":{"loc":{"start":{"line":17,"column":43},"end":{"line":17,"column":71}},"type":"binary-expr","locations":[{"start":{"line":17,"column":43},"end":{"line":17,"column":54}},{"start":{"line":17,"column":58},"end":{"line":17,"column":71}}],"line":17},"5":{"loc":{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},"type":"if","locations":[{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},{"start":{},"end":{}}],"line":20},"6":{"loc":{"start":{"line":20,"column":6},"end":{"line":20,"column":94}},"type":"binary-expr","locations":[{"start":{"line":20,"column":6},"end":{"line":20,"column":45}},{"start":{"line":20,"column":49},"end":{"line":20,"column":94}}],"line":20}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0},"f":{"0":0,"1":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0]}} ,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js","statementMap":{"0":{"start":{"line":1,"column":12},"end":{"line":1,"column":35}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":37}},"2":{"start":{"line":5,"column":2},"end":{"line":5,"column":35}},"3":{"start":{"line":9,"column":2},"end":{"line":9,"column":35}},"4":{"start":{"line":12,"column":0},"end":{"line":12,"column":44}}},"fnMap":{"0":{"name":"signToken","decl":{"start":{"line":4,"column":9},"end":{"line":4,"column":18}},"loc":{"start":{"line":4,"column":28},"end":{"line":6,"column":1}},"line":4},"1":{"name":"verifyToken","decl":{"start":{"line":8,"column":9},"end":{"line":8,"column":20}},"loc":{"start":{"line":8,"column":28},"end":{"line":10,"column":1}},"line":8}},"branchMap":{},"s":{"0":1,"1":1,"2":0,"3":0,"4":1},"f":{"0":0,"1":0},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"d7b8e9b1304ab0135964e79a9372e3a90c422c73"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\category.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\category.js","statementMap":{"0":{"start":{"line":4,"column":4},"end":{"line":4,"column":24}},"1":{"start":{"line":5,"column":0},"end":{"line":24,"column":2}},"2":{"start":{"line":13,"column":7},"end":{"line":13,"column":37}},"3":{"start":{"line":17,"column":2},"end":{"line":22,"column":5}},"4":{"start":{"line":23,"column":2},"end":{"line":23,"column":18}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":18}},"loc":{"start":{"line":5,"column":43},"end":{"line":24,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":12,"column":4},"end":{"line":12,"column":5}},"loc":{"start":{"line":12,"column":29},"end":{"line":14,"column":5}},"line":12}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1},"f":{"0":1,"1":1},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"b53232249d0460508d5c1dbe8d528418cdcc35d8"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\chat.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\chat.js","statementMap":{"0":{"start":{"line":4,"column":4},"end":{"line":4,"column":24}},"1":{"start":{"line":5,"column":0},"end":{"line":28,"column":2}},"2":{"start":{"line":13,"column":6},"end":{"line":13,"column":75}},"3":{"start":{"line":14,"column":6},"end":{"line":14,"column":78}},"4":{"start":{"line":15,"column":6},"end":{"line":15,"column":35}},"5":{"start":{"line":19,"column":2},"end":{"line":26,"column":5}},"6":{"start":{"line":27,"column":2},"end":{"line":27,"column":14}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":18}},"loc":{"start":{"line":5,"column":43},"end":{"line":28,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":12,"column":4},"end":{"line":12,"column":5}},"loc":{"start":{"line":12,"column":29},"end":{"line":16,"column":5}},"line":12}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1},"f":{"0":1,"1":1},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"7caac22d588d58e8129c102294bf5cd40ad1cd38"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\image.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\image.js","statementMap":{"0":{"start":{"line":4,"column":4},"end":{"line":4,"column":24}},"1":{"start":{"line":5,"column":0},"end":{"line":25,"column":2}},"2":{"start":{"line":13,"column":6},"end":{"line":13,"column":35}},"3":{"start":{"line":17,"column":2},"end":{"line":23,"column":5}},"4":{"start":{"line":24,"column":2},"end":{"line":24,"column":15}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":18}},"loc":{"start":{"line":5,"column":43},"end":{"line":25,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":12,"column":4},"end":{"line":12,"column":5}},"loc":{"start":{"line":12,"column":29},"end":{"line":14,"column":5}},"line":12}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1},"f":{"0":1,"1":1},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"ad242b102cc5ff6596aad3f625f0c4c4d99fd50c"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\index.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\index.js","statementMap":{"0":{"start":{"line":3,"column":11},"end":{"line":3,"column":24}},"1":{"start":{"line":4,"column":13},"end":{"line":4,"column":28}},"2":{"start":{"line":5,"column":18},"end":{"line":5,"column":38}},"3":{"start":{"line":6,"column":16},"end":{"line":6,"column":34}},"4":{"start":{"line":7,"column":17},"end":{"line":7,"column":42}},"5":{"start":{"line":8,"column":12},"end":{"line":8,"column":49}},"6":{"start":{"line":9,"column":15},"end":{"line":9,"column":63}},"7":{"start":{"line":10,"column":11},"end":{"line":10,"column":13}},"8":{"start":{"line":14,"column":0},"end":{"line":18,"column":1}},"9":{"start":{"line":15,"column":2},"end":{"line":15,"column":48}},"10":{"start":{"line":17,"column":2},"end":{"line":17,"column":87}},"11":{"start":{"line":20,"column":0},"end":{"line":33,"column":5}},"12":{"start":{"line":23,"column":4},"end":{"line":28,"column":6}},"13":{"start":{"line":31,"column":18},"end":{"line":31,"column":85}},"14":{"start":{"line":32,"column":4},"end":{"line":32,"column":27}},"15":{"start":{"line":35,"column":0},"end":{"line":39,"column":3}},"16":{"start":{"line":36,"column":2},"end":{"line":38,"column":3}},"17":{"start":{"line":37,"column":4},"end":{"line":37,"column":32}},"18":{"start":{"line":41,"column":0},"end":{"line":41,"column":25}},"19":{"start":{"line":42,"column":0},"end":{"line":42,"column":25}},"20":{"start":{"line":44,"column":0},"end":{"line":44,"column":20}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":22,"column":10},"end":{"line":22,"column":11}},"loc":{"start":{"line":22,"column":18},"end":{"line":29,"column":3}},"line":22},"1":{"name":"(anonymous_1)","decl":{"start":{"line":30,"column":11},"end":{"line":30,"column":12}},"loc":{"start":{"line":30,"column":19},"end":{"line":33,"column":3}},"line":30},"2":{"name":"(anonymous_2)","decl":{"start":{"line":35,"column":24},"end":{"line":35,"column":25}},"loc":{"start":{"line":35,"column":37},"end":{"line":39,"column":1}},"line":35}},"branchMap":{"0":{"loc":{"start":{"line":8,"column":12},"end":{"line":8,"column":49}},"type":"binary-expr","locations":[{"start":{"line":8,"column":12},"end":{"line":8,"column":32}},{"start":{"line":8,"column":36},"end":{"line":8,"column":49}}],"line":8},"1":{"loc":{"start":{"line":14,"column":0},"end":{"line":18,"column":1}},"type":"if","locations":[{"start":{"line":14,"column":0},"end":{"line":18,"column":1}},{"start":{"line":16,"column":7},"end":{"line":18,"column":1}}],"line":14},"2":{"loc":{"start":{"line":24,"column":6},"end":{"line":27,"column":37}},"type":"binary-expr","locations":[{"start":{"line":24,"column":6},"end":{"line":24,"column":29}},{"start":{"line":25,"column":6},"end":{"line":25,"column":23}},{"start":{"line":26,"column":6},"end":{"line":26,"column":30}},{"start":{"line":27,"column":6},"end":{"line":27,"column":37}}],"line":24},"3":{"loc":{"start":{"line":36,"column":2},"end":{"line":38,"column":3}},"type":"if","locations":[{"start":{"line":36,"column":2},"end":{"line":38,"column":3}},{"start":{},"end":{}}],"line":36}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":0,"10":1,"11":1,"12":8,"13":7,"14":7,"15":1,"16":7,"17":7,"18":1,"19":1,"20":1},"f":{"0":8,"1":7,"2":7},"b":{"0":[1,0],"1":[0,1],"2":[8,8,7,7],"3":[7,0]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"ad9a3acf31fd8d390059597bddf05e175c1c0a76"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\like.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\like.js","statementMap":{"0":{"start":{"line":4,"column":4},"end":{"line":4,"column":24}},"1":{"start":{"line":5,"column":0},"end":{"line":26,"column":2}},"2":{"start":{"line":13,"column":6},"end":{"line":13,"column":34}},"3":{"start":{"line":14,"column":6},"end":{"line":14,"column":34}},"4":{"start":{"line":18,"column":2},"end":{"line":24,"column":5}},"5":{"start":{"line":25,"column":2},"end":{"line":25,"column":14}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":18}},"loc":{"start":{"line":5,"column":43},"end":{"line":26,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":12,"column":4},"end":{"line":12,"column":5}},"loc":{"start":{"line":12,"column":29},"end":{"line":15,"column":5}},"line":12}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1},"f":{"0":1,"1":1},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"0f603675acb1a50d3a6b5fb0a972d9e3bd0ccc14"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\message.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\message.js","statementMap":{"0":{"start":{"line":4,"column":4},"end":{"line":4,"column":24}},"1":{"start":{"line":5,"column":0},"end":{"line":30,"column":2}},"2":{"start":{"line":13,"column":6},"end":{"line":13,"column":37}},"3":{"start":{"line":14,"column":6},"end":{"line":14,"column":79}},"4":{"start":{"line":15,"column":6},"end":{"line":15,"column":83}},"5":{"start":{"line":20,"column":2},"end":{"line":28,"column":5}},"6":{"start":{"line":29,"column":2},"end":{"line":29,"column":17}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":18}},"loc":{"start":{"line":5,"column":43},"end":{"line":30,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":12,"column":4},"end":{"line":12,"column":5}},"loc":{"start":{"line":12,"column":29},"end":{"line":16,"column":5}},"line":12}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1},"f":{"0":1,"1":1},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"553fc9afc1fb2df94bb07a5c6cb7643b1ae674f1"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\post.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\post.js","statementMap":{"0":{"start":{"line":4,"column":4},"end":{"line":4,"column":24}},"1":{"start":{"line":5,"column":0},"end":{"line":41,"column":2}},"2":{"start":{"line":13,"column":6},"end":{"line":13,"column":34}},"3":{"start":{"line":14,"column":6},"end":{"line":14,"column":38}},"4":{"start":{"line":15,"column":6},"end":{"line":15,"column":33}},"5":{"start":{"line":16,"column":6},"end":{"line":16,"column":31}},"6":{"start":{"line":20,"column":2},"end":{"line":39,"column":5}},"7":{"start":{"line":40,"column":2},"end":{"line":40,"column":14}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":17},"end":{"line":5,"column":18}},"loc":{"start":{"line":5,"column":43},"end":{"line":41,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":12,"column":4},"end":{"line":12,"column":5}},"loc":{"start":{"line":12,"column":29},"end":{"line":17,"column":5}},"line":12}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1},"f":{"0":1,"1":1},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"9537a9db377628a5370ed1047cf38655e378cc14"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\user.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\models\\user.js","statementMap":{"0":{"start":{"line":2,"column":15},"end":{"line":2,"column":34}},"1":{"start":{"line":5,"column":4},"end":{"line":5,"column":24}},"2":{"start":{"line":6,"column":0},"end":{"line":64,"column":2}},"3":{"start":{"line":14,"column":6},"end":{"line":14,"column":32}},"4":{"start":{"line":15,"column":6},"end":{"line":15,"column":32}},"5":{"start":{"line":16,"column":6},"end":{"line":16,"column":58}},"6":{"start":{"line":17,"column":6},"end":{"line":17,"column":61}},"7":{"start":{"line":18,"column":6},"end":{"line":18,"column":63}},"8":{"start":{"line":19,"column":6},"end":{"line":19,"column":65}},"9":{"start":{"line":23,"column":2},"end":{"line":62,"column":5}},"10":{"start":{"line":59,"column":8},"end":{"line":59,"column":61}},"11":{"start":{"line":63,"column":2},"end":{"line":63,"column":14}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":6,"column":17},"end":{"line":6,"column":18}},"loc":{"start":{"line":6,"column":43},"end":{"line":64,"column":1}},"line":6},"1":{"name":"(anonymous_1)","decl":{"start":{"line":13,"column":4},"end":{"line":13,"column":5}},"loc":{"start":{"line":13,"column":29},"end":{"line":20,"column":5}},"line":13},"2":{"name":"(anonymous_2)","decl":{"start":{"line":58,"column":20},"end":{"line":58,"column":21}},"loc":{"start":{"line":58,"column":36},"end":{"line":60,"column":7}},"line":58}},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":0,"11":1},"f":{"0":1,"1":1,"2":0},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"660187373a96a123a305b9a8b65a489cb753d5c5"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\aiRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\aiRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":21},"end":{"line":3,"column":59}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":7,"column":0},"end":{"line":7,"column":70}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0},"f":{},"b":{}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\chatRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\chatRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":23},"end":{"line":3,"column":63}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":17}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":48}},"6":{"start":{"line":12,"column":0},"end":{"line":12,"column":49}},"7":{"start":{"line":15,"column":0},"end":{"line":15,"column":45}},"8":{"start":{"line":18,"column":0},"end":{"line":18,"column":64}},"9":{"start":{"line":21,"column":0},"end":{"line":21,"column":61}},"10":{"start":{"line":23,"column":0},"end":{"line":23,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"f":{},"b":{}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\index.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\index.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":4,"column":19},"end":{"line":4,"column":42}},"3":{"start":{"line":5,"column":19},"end":{"line":5,"column":42}},"4":{"start":{"line":6,"column":19},"end":{"line":6,"column":42}},"5":{"start":{"line":7,"column":17},"end":{"line":7,"column":38}},"6":{"start":{"line":9,"column":0},"end":{"line":9,"column":33}},"7":{"start":{"line":10,"column":0},"end":{"line":10,"column":33}},"8":{"start":{"line":11,"column":0},"end":{"line":11,"column":33}},"9":{"start":{"line":12,"column":0},"end":{"line":12,"column":28}},"10":{"start":{"line":14,"column":0},"end":{"line":14,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"f":{},"b":{}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\postRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\postRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":23},"end":{"line":3,"column":63}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":5,"column":15},"end":{"line":5,"column":47}},"5":{"start":{"line":8,"column":0},"end":{"line":8,"column":77}},"6":{"start":{"line":10,"column":0},"end":{"line":10,"column":50}},"7":{"start":{"line":11,"column":0},"end":{"line":11,"column":51}},"8":{"start":{"line":13,"column":0},"end":{"line":13,"column":52}},"9":{"start":{"line":14,"column":0},"end":{"line":14,"column":55}},"10":{"start":{"line":16,"column":0},"end":{"line":16,"column":58}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0},"f":{},"b":{}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\userRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\userRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":23},"end":{"line":2,"column":63}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":31}},"3":{"start":{"line":5,"column":0},"end":{"line":5,"column":50}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":44}},"5":{"start":{"line":7,"column":0},"end":{"line":7,"column":57}},"6":{"start":{"line":10,"column":0},"end":{"line":10,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0},"f":{},"b":{}} } diff --git a/coverage/lcov-report/Dummy-Instagram/app.js.html b/coverage/lcov-report/Dummy-Instagram/app.js.html new file mode 100644 index 0000000..3089733 --- /dev/null +++ b/coverage/lcov-report/Dummy-Instagram/app.js.html @@ -0,0 +1,268 @@ + + + + + + Code coverage report for Dummy-Instagram/app.js + + + + + + + + + +
+
+

All files / Dummy-Instagram app.js

+
+ +
+ 0% + Statements + 0/32 +
+ + +
+ 0% + Branches + 0/4 +
+ + +
+ 0% + Functions + 0/6 +
+ + +
+ 0% + Lines + 0/32 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
require('dotenv').config();
+const express = require('express');
+const app = express();
+const port = process.env.PORT || 3000;
+const handleError = require('./helpers/handleError');
+const routes = require('./routes');
+const cors = require('cors'); 
+ 
+const http = require('http');
+const server = http.createServer(app);
+const { Server } = require("socket.io");
+const io = new Server(server, {
+  cors: {
+    origin: "*", 
+  }
+});
+ 
+app.set('socketio', io); 
+ 
+// Middleware
+app.use(cors()); 
+app.use(express.json());
+app.use(express.urlencoded({ extended: true }));
+app.use(express.static('public'));
+ 
+// Router
+app.use("/", routes);
+ 
+ 
+// Error handler
+app.use(handleError);
+ 
+// +++ Logika koneksi Socket.IO +++
+io.on('connection', (socket) => {
+  console.log('โœ… User connected:', socket.id);
+ 
+  socket.on('join_chat', (chatId) => {
+    socket.join(`chat_${chatId}`);
+  });
+ 
+  socket.on('send_message', (messageData) => {
+    io.to(`chat_${messageData.chatId}`).emit('new_message', messageData);
+  });
+ 
+  socket.on('user_typing', (typingData) => {
+    io.to(`chat_${typingData.chatId}`).emit('typing_status', typingData);
+  });
+ 
+  socket.on('disconnect', () => {
+    console.log('โŒ User disconnected:', socket.id);
+  });
+});
+ 
+ 
+ 
+if (process.env.NODE_ENV !== 'test') {
+  server.listen(port, () => {
+    console.log(`App listening on port http://localhost:${port}`);
+  });
+}
+ 
+module.exports = app;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/config/config.js.html b/coverage/lcov-report/Dummy-Instagram/config/config.js.html similarity index 73% rename from coverage/lcov-report/config/config.js.html rename to coverage/lcov-report/Dummy-Instagram/config/config.js.html index e71cb97..d9df73e 100644 --- a/coverage/lcov-report/config/config.js.html +++ b/coverage/lcov-report/Dummy-Instagram/config/config.js.html @@ -3,15 +3,15 @@ - Code coverage report for config/config.js + Code coverage report for Dummy-Instagram/config/config.js - - - + + + @@ -19,20 +19,20 @@
-

All files / config config.js

+

All files / Dummy-Instagram/config config.js

100% Statements - 1/1 + 3/3
- 75% + 50% Branches - 9/12 + 3/6
@@ -46,7 +46,7 @@

All files / config conf
100% Lines - 1/1 + 3/3
@@ -93,14 +93,18 @@

All files / config conf 28 29 30 -31  +31 +32 +33          +4x   -1x +4x   +4x       @@ -125,32 +129,34 @@

All files / config conf    
/**
  * Sequelize configuration file
- * Provides sensible defaults for development/test/production
- * Uses environment variables when available so CI/production can override.
+ * Supports Supabase / PostgreSQL with SSL
  */
  
+require('dotenv').config(); // pastikan dotenv dipanggil di awal
+ 
+const useSSL = process.env.DB_SSL === 'true';
+ 
 module.exports = {
   development: {
-    // Use single env var 'db' as connection URL for now (e.g. postgres://user:pass@host:port/db)
-    url: process.env.db || null,
+    url: process.env.DATABASE_URL,
     dialect: 'postgres',
     logging: false,
     define: { timestamps: true },
-    dialectOptions: process.env.DB_SSL === 'true' ? { ssl: { rejectUnauthorized: false } } : {},
+    dialectOptions: useSSL ? { ssl: { require: true, rejectUnauthorized: false } } : {},
   },
  
   test: {
-    url: process.env.db || null,
+    url: process.env.DATABASE_URL,
     dialect: 'postgres',
     logging: false,
-    dialectOptions: process.env.DB_SSL === 'true' ? { ssl: { rejectUnauthorized: false } } : {},
+    dialectOptions: useSSL ? { ssl: { require: true, rejectUnauthorized: false } } : {},
   },
  
   production: {
-    url: process.env.db || null,
+    url: process.env.DATABASE_URL,
     dialect: 'postgres',
     logging: false,
-    dialectOptions: process.env.DB_SSL === 'true' ? { ssl: { rejectUnauthorized: false } } : {},
+    dialectOptions: useSSL ? { ssl: { require: true, rejectUnauthorized: false } } : {},
   },
 };
  
@@ -160,16 +166,16 @@

All files / config conf - + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/config/index.html b/coverage/lcov-report/Dummy-Instagram/config/index.html similarity index 77% rename from coverage/lcov-report/config/index.html rename to coverage/lcov-report/Dummy-Instagram/config/index.html index 1188bf3..beae4bf 100644 --- a/coverage/lcov-report/config/index.html +++ b/coverage/lcov-report/Dummy-Instagram/config/index.html @@ -3,15 +3,15 @@ - Code coverage report for config + Code coverage report for Dummy-Instagram/config - - - + + + @@ -19,20 +19,20 @@
-

All files config

+

All files Dummy-Instagram/config

100% Statements - 1/1 + 3/3
- 75% + 50% Branches - 9/12 + 3/6
@@ -46,7 +46,7 @@

All files config

100% Lines - 1/1 + 3/3
@@ -84,13 +84,13 @@

All files config

100% - 1/1 - 75% - 9/12 + 3/3 + 50% + 3/6 100% 0/0 100% - 1/1 + 3/3 @@ -101,16 +101,16 @@

All files config

- + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/Dummy-Instagram/controllers/aiController.js.html b/coverage/lcov-report/Dummy-Instagram/controllers/aiController.js.html new file mode 100644 index 0000000..0b96eee --- /dev/null +++ b/coverage/lcov-report/Dummy-Instagram/controllers/aiController.js.html @@ -0,0 +1,160 @@ + + + + + + Code coverage report for Dummy-Instagram/controllers/aiController.js + + + + + + + + + +
+
+

All files / Dummy-Instagram/controllers aiController.js

+
+ +
+ 0% + Statements + 0/9 +
+ + +
+ 0% + Branches + 0/4 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/9 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
const { getAIRecommendations } = require("../helpers/aiRecommendation");
+ 
+class AIController {
+  static async getRecommendations(req, res, next) {
+    try {
+ 
+      if (!req.user || !req.user.id) {
+        throw { name: "Unauthorized" };
+      }
+ 
+      const userId = req.user.id;
+      const posts = await getAIRecommendations(userId);
+ 
+      res.status(200).json({
+        message: "Rekomendasi berhasil dibuat",
+        count: posts.length,
+        data: posts,
+      });
+    } catch (err) {
+      next(err);
+    }
+  }
+}
+ 
+module.exports = AIController;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/chatController.js.html b/coverage/lcov-report/Dummy-Instagram/controllers/chatController.js.html similarity index 86% rename from coverage/lcov-report/chatController.js.html rename to coverage/lcov-report/Dummy-Instagram/controllers/chatController.js.html index 476d7ac..5c3a06b 100644 --- a/coverage/lcov-report/chatController.js.html +++ b/coverage/lcov-report/Dummy-Instagram/controllers/chatController.js.html @@ -3,15 +3,15 @@ - Code coverage report for chatController.js + Code coverage report for Dummy-Instagram/controllers/chatController.js - - - + + + @@ -19,34 +19,34 @@
-

All files chatController.js

+

All files / Dummy-Instagram/controllers chatController.js

- 27.45% + 0% Statements - 14/51 + 0/51
- 10.52% + 0% Branches - 2/19 + 0/19
- 40% + 0% Functions - 2/5 + 0/5
- 27.45% + 0% Lines - 14/51 + 0/51
@@ -213,23 +213,23 @@

All files chatController.js

148 149 150 -1511x -1x -1x +151  +  +          -1x -1x -1x +  +  +    -1x +          -1x +        @@ -243,7 +243,7 @@

All files chatController.js

      -1x +        @@ -251,9 +251,9 @@

All files chatController.js

      -1x -1x -1x +  +  +        @@ -264,7 +264,7 @@

All files chatController.js

      -1x +        @@ -363,23 +363,23 @@

All files chatController.js

      -1x
const { Chat, Message, User, Sequelize } = require("../models");
-const { Op } = Sequelize;
-const { askGemini } = require("../helpers/aiHelper");
+ 
const { Chat, Message, User, Sequelize } = require("../models");
+const { Op } = Sequelize;
+const { askGemini } = require("../helpers/aiHelper");
  
 class ChatController {
     // Mencegah duplikasi chat
-    static async createOrGetChat(req, res, next) {
-        try {
-            const { partnerId } = req.body;
-            const userId = req.user.id;
+    static async createOrGetChat(req, res, next) {
+        try {
+            const { partnerId } = req.body;
+            const userId = req.user.id;
  
-            Iif (partnerId == userId) { //  Validasi agar tidak chat dengan diri sendiri
+            if (partnerId == userId) { //  Validasi agar tidak chat dengan diri sendiri
                 throw { name: "BadRequest", message: "You cannot create a chat with yourself." };
             }
  
             // Cari chat yang sudah ada antara kedua user
-            const [chat, created] = await Chat.findOrCreate({
+            const [chat, created] = await Chat.findOrCreate({
                 where: {
                     [Op.or]: [
                         { UserId: userId, partnerId: partnerId },
@@ -393,17 +393,17 @@ 

All files chatController.js

}, });   - res.status(created ? 201 : 200).json(chat); + res.status(created ? 201 : 200).json(chat); } catch (err) { next(err); } }   // Menampilkan semua chat dimana user terlibat - static async getUserChats(req, res, next) { - try { - const userId = req.user.id; - const chats = await Chat.findAll({ + static async getUserChats(req, res, next) { + try { + const userId = req.user.id; + const chats = await Chat.findAll({ where: { [Op.or]: [{ UserId: userId }, { partnerId: userId }], }, @@ -414,7 +414,7 @@

All files chatController.js

order: [["updatedAt", "DESC"]], });   - res.json(chats); + res.json(chats); } catch (err) { next(err); } @@ -513,23 +513,23 @@

All files chatController.js

} }   -module.exports = ChatController;
+module.exports = ChatController;
- + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/Dummy-Instagram/controllers/index.html b/coverage/lcov-report/Dummy-Instagram/controllers/index.html new file mode 100644 index 0000000..76ee0cd --- /dev/null +++ b/coverage/lcov-report/Dummy-Instagram/controllers/index.html @@ -0,0 +1,161 @@ + + + + + + Code coverage report for Dummy-Instagram/controllers + + + + + + + + + +
+
+

All files Dummy-Instagram/controllers

+
+ +
+ 0% + Statements + 0/146 +
+ + +
+ 0% + Branches + 0/49 +
+ + +
+ 0% + Functions + 0/16 +
+ + +
+ 0% + Lines + 0/140 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
aiController.js +
+
0%0/90%0/40%0/10%0/9
chatController.js +
+
0%0/510%0/190%0/50%0/51
postController.js +
+
0%0/540%0/180%0/70%0/48
userController.js +
+
0%0/320%0/80%0/30%0/32
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/postController.js.html b/coverage/lcov-report/Dummy-Instagram/controllers/postController.js.html similarity index 58% rename from coverage/lcov-report/postController.js.html rename to coverage/lcov-report/Dummy-Instagram/controllers/postController.js.html index 390b625..0b50c54 100644 --- a/coverage/lcov-report/postController.js.html +++ b/coverage/lcov-report/Dummy-Instagram/controllers/postController.js.html @@ -3,15 +3,15 @@ - Code coverage report for postController.js + Code coverage report for Dummy-Instagram/controllers/postController.js - - - + + + @@ -19,34 +19,34 @@
-

All files postController.js

+

All files / Dummy-Instagram/controllers postController.js

- 18.86% + 0% Statements - 10/53 + 0/54
- 27.77% + 0% Branches - 5/18 + 0/18
- 28.57% + 0% Functions - 2/7 + 0/7
- 21.27% + 0% Lines - 10/47 + 0/48
@@ -185,42 +185,50 @@

All files postController.js

120 121 122 -1231x +123 +124 +125 +126 +127 +128          -1x -1x +  +      -1x +  +        +          -1x -              -1x +  +  +        +          -1x -1x   +  +        @@ -229,7 +237,8 @@

All files postController.js

      -1x +  +        @@ -307,145 +316,151 @@

All files postController.js

      -1x
const { Post, Image, Like, User, Category } = require("../models");
+ 
+ 
const { Post, Image, Like, User, Category } = require("../models");
  
 class PostController {
-    // CREATE POST
-    static async createPost(req, res, next) {
-        try {
-            const { content, isPrivate, categoryId } = req.body;
+  // CREATE POST 
+  static async createPost(req, res, next) {
+    try {
+      const { content, isPrivate, categoryId } = req.body;
  
-            // Buat post baru
-            const post = await Post.create({
-                content,
-                isPrivate,
-                CategoryId: categoryId || null,
-                UserId: req.user.id,
-            });
+      // Validation: make sure there is at least 1 image
+      if (!req.files || req.files.length === 0) {
+        throw { name: "BadRequest", message: "At least one image is required to create a post." };
+      }
  
-            // Jika ada file yang di-upload, simpan URL-nya
-            Iif (req.files && req.files.length > 0) {
-                const images = req.files.map((file) => ({
-                    imageUrl: file.path, // multer-storage-cloudinary menyediakan URL di file.path
-                    PostId: post.id,
-                }));
-                await Image.bulkCreate(images);
-            }
+      // Create a new post
+      const post = await Post.create({
+        content,
+        isPrivate,
+        CategoryId: categoryId || null,
+        UserId: req.user.id,
+      });
  
-            res.status(201).json({ message: "Post created successfully", post });
-        } catch (err) {
-            next(err);
-        }
+      // Save all images to the Image table
+      const images = req.files.map((file) => ({
+        imageUrl: file.path,
+        PostId: post.id,
+      }));
+ 
+      await Image.bulkCreate(images);
+ 
+      res.status(201).json({ message: "Post created successfully", post });
+    } catch (err) {
+      next(err);
     }
+  }
  
-    // READ ALL PUBLIC POSTS
-    static async getAllPublicPosts(req, res, next) {
-        try {
-            const posts = await Post.findAll({
-                where: { isPrivate: false },
-                include: [
-                    { model: User, attributes: ["id", "username", "profilePic"] },
-                    { model: Image },
-                    { model: Category, attributes: ["name"] },
-                    { model: Like },
-                ],
-                order: [["createdAt", "DESC"]],
-            });
-            res.json(posts);
-        } catch (err) {
-            next(err);
-        }
+  // READ ALL PUBLIC POSTS
+  static async getAllPublicPosts(req, res, next) {
+    try {
+      const posts = await Post.findAll({
+        where: { isPrivate: false },
+        include: [
+          { model: User, attributes: ["id", "username", "profilePic"] },
+          { model: Image },
+          { model: Category, attributes: ["name"] },
+          { model: Like },
+        ],
+        order: [["createdAt", "DESC"]],
+      });
+      res.json(posts);
+    } catch (err) {
+      next(err);
     }
+  }
  
-    // READ USER'S OWN POSTS
-    static async getMyPosts(req, res, next) {
-        try {
-            const posts = await Post.findAll({
-                where: { UserId: req.user.id },
-                include: [Image, Category, Like],
-                order: [["createdAt", "DESC"]],
-            });
-            res.json(posts);
-        } catch (err) {
-            next(err);
-        }
+  // READ USER'S OWN POSTS
+  static async getMyPosts(req, res, next) {
+    try {
+      const posts = await Post.findAll({
+        where: { UserId: req.user.id },
+        include: [Image, Category, Like],
+        order: [["createdAt", "DESC"]],
+      });
+      res.json(posts);
+    } catch (err) {
+      next(err);
     }
+  }
  
-    // UPDATE POST
-    static async updatePost(req, res, next) {
-        try {
-            const { id } = req.params;
-            const { content, isPrivate, categoryId } = req.body;
+  // UPDATE POST
+  static async updatePost(req, res, next) {
+    try {
+      const { id } = req.params;
+      const { content, isPrivate, categoryId } = req.body;
  
-            const post = await Post.findByPk(id);
-            if (!post) throw { name: "NotFound" };
-            if (post.UserId !== req.user.id) throw { name: "Unauthorized" };
+      const post = await Post.findByPk(id);
+      if (!post) throw { name: "NotFound" };
+      if (post.UserId !== req.user.id) throw { name: "Unauthorized" };
  
-            await post.update({ content, isPrivate, CategoryId: categoryId });
-            res.json({ message: "Post updated successfully", post });
-        } catch (err) {
-            next(err);
-        }
+      await post.update({ content, isPrivate, CategoryId: categoryId });
+      res.json({ message: "Post updated successfully", post });
+    } catch (err) {
+      next(err);
     }
+  }
  
-    // DELETE POST
-    static async deletePost(req, res, next) {
-        try {
-            const { id } = req.params;
-            const post = await Post.findByPk(id);
-            if (!post) throw { name: "NotFound" };
-            if (post.UserId !== req.user.id) throw { name: "Unauthorized" };
+  // DELETE POST
+  static async deletePost(req, res, next) {
+    try {
+      const { id } = req.params;
+      const post = await Post.findByPk(id);
+      if (!post) throw { name: "NotFound" };
+      if (post.UserId !== req.user.id) throw { name: "Unauthorized" };
  
-            await post.destroy();
-            res.json({ message: "Post deleted successfully" });
-        } catch (err) {
-            next(err);
-        }
+      await post.destroy();
+      res.json({ message: "Post deleted successfully" });
+    } catch (err) {
+      next(err);
     }
+  }
  
-    // LIKE / UNLIKE POST
-    static async toggleLike(req, res, next) {
-        try {
-            const { id } = req.params;
-            const post = await Post.findByPk(id);
-            if (!post) throw { name: "NotFound" };
+  // LIKE / UNLIKE POST
+  static async toggleLike(req, res, next) {
+    try {
+      const { id } = req.params;
+      const post = await Post.findByPk(id);
+      if (!post) throw { name: "NotFound" };
  
-            const existingLike = await Like.findOne({
-                where: { UserId: req.user.id, PostId: id },
-            });
+      const existingLike = await Like.findOne({
+        where: { UserId: req.user.id, PostId: id },
+      });
  
-            let message;
-            if (existingLike) {
-                await existingLike.destroy();
-                message = "Post unliked";
-            } else {
-                await Like.create({ UserId: req.user.id, PostId: id });
-                message = "Post liked";
-            }
-            res.json({ message });
-        } catch (err) {
-            next(err);
-        }
+      let message;
+      if (existingLike) {
+        await existingLike.destroy();
+        message = "Post unliked";
+      } else {
+        await Like.create({ UserId: req.user.id, PostId: id });
+        message = "Post liked";
+      }
+      res.json({ message });
+    } catch (err) {
+      next(err);
     }
+  }
 }
  
-module.exports = PostController;
+module.exports = PostController;
- + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/controllers/userController.js.html b/coverage/lcov-report/Dummy-Instagram/controllers/userController.js.html similarity index 77% rename from coverage/lcov-report/controllers/userController.js.html rename to coverage/lcov-report/Dummy-Instagram/controllers/userController.js.html index dd626ee..1c2ffc8 100644 --- a/coverage/lcov-report/controllers/userController.js.html +++ b/coverage/lcov-report/Dummy-Instagram/controllers/userController.js.html @@ -3,15 +3,15 @@ - Code coverage report for controllers/userController.js + Code coverage report for Dummy-Instagram/controllers/userController.js - - - + + + @@ -19,34 +19,34 @@
-

All files / controllers userController.js

+

All files / Dummy-Instagram/controllers userController.js

- 40.62% + 0% Statements - 13/32 + 0/32
- 50% + 0% Branches - 4/8 + 0/8
- 33.33% + 0% Functions - 1/3 + 0/3
- 40.62% + 0% Lines - 13/32 + 0/32
@@ -139,14 +139,11 @@

All files / controllers 74 75 76 -77 -78 -79 -801x -1x -1x -1x -1x +77  +  +  +  +        @@ -165,15 +162,15 @@

All files / controllers       -1x -1x -1x +  +  +        -1x -1x -1x +  +  +        @@ -184,7 +181,7 @@

All files / controllers       -1x +        @@ -209,7 +206,6 @@

All files / controllers       -        @@ -219,13 +215,11 @@

All files / controllers       -  -  -1x
const { User } = require('../models');
-const bcrypt = require('bcryptjs');
-const { signToken } = require('../helpers/jwt');
-const { OAuth2Client } = require('google-auth-library');
-const client = new OAuth2Client();
+ 
const { User } = require('../models');
+const bcrypt = require('bcryptjs');
+const { signToken } = require('../helpers/jwt');
+const { OAuth2Client } = require('google-auth-library');
+const client = new OAuth2Client();
  
  
 class UserController {
@@ -243,16 +237,16 @@ 

All files / controllers } }   - static async login(req, res, next) { - try { - const { email, password } = req.body; - Iif (!email || !password) { + static async login(req, res, next) { + try { + const { email, password } = req.body; + if (!email || !password) { throw { name: 'BadRequest', message: 'Email and password are required' }; }   - const user = await User.findOne({ where: { email } }); - Eif (!user) { - throw { name: 'InvalidLogin' }; + const user = await User.findOne({ where: { email } }); + if (!user) { + throw { name: 'InvalidLogin' }; }   const isPasswordValid = bcrypt.compareSync(password, user.password); @@ -263,7 +257,7 @@

All files / controllers const token = signToken({ id: user.id }); res.status(200).json({ access_token: token }); } catch (err) { - next(err); + next(err); } }   @@ -287,7 +281,6 @@

All files / controllers }, hooks: false }); -    const access_token = signToken({ id: user.id }); res.status(200).json({ access_token }); @@ -296,27 +289,25 @@

All files / controllers next(err); } } -  - }   -module.exports = UserController;

+module.exports = UserController;

- + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/helpers/aiHelper.js.html b/coverage/lcov-report/Dummy-Instagram/helpers/aiHelper.js.html similarity index 79% rename from coverage/lcov-report/helpers/aiHelper.js.html rename to coverage/lcov-report/Dummy-Instagram/helpers/aiHelper.js.html index ee08f01..1ced965 100644 --- a/coverage/lcov-report/helpers/aiHelper.js.html +++ b/coverage/lcov-report/Dummy-Instagram/helpers/aiHelper.js.html @@ -3,15 +3,15 @@ - Code coverage report for helpers/aiHelper.js + Code coverage report for Dummy-Instagram/helpers/aiHelper.js - - - + + + @@ -19,13 +19,13 @@
-

All files / helpers aiHelper.js

+

All files / Dummy-Instagram/helpers aiHelper.js

- 36.36% + 0% Statements - 4/11 + 0/11
@@ -44,9 +44,9 @@

All files / helpers aiH
- 36.36% + 0% Lines - 4/11 + 0/11
@@ -98,11 +98,10 @@

All files / helpers aiH 33 34 35 -36 -371x +36    -1x -1x +  +        @@ -123,7 +122,6 @@

All files / helpers aiH       -        @@ -134,17 +132,17 @@

All files / helpers aiH       -1x - 
const { GoogleGenerativeAI } = require("@google/generative-ai");
+ 
+ 
const { GoogleGenerativeAI } = require("@google/generative-ai");
  
-const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
-const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
+const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
+const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
  
-//cleaning text function
+// cleaning text function
 function cleanText(text = "") {
   return text
-    // Hapus heading markdown dan pemisah
-    .replace(/^#+\s*/gm, "")       
+    // Hapus seluruh baris heading markdown dan pemisah
+    .replace(/^#+\s?.*$/gm, "")     
     .replace(/---+/g, " ")         
     // Hapus bullet dan angka daftar
     .replace(/^\s*\d+\.\s*/gm, "") 
@@ -158,7 +156,6 @@ 

All files / helpers aiH .trim(); }   -  async function askGemini(prompt) { try { const result = await model.generateContent(prompt); @@ -170,7 +167,7 @@

All files / helpers aiH } }   -module.exports = { askGemini }; +module.exports = { askGemini, cleanText };  

@@ -178,16 +175,16 @@

All files / helpers aiH - + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/helpers/aiRecommendation.js.html b/coverage/lcov-report/Dummy-Instagram/helpers/aiRecommendation.js.html similarity index 75% rename from coverage/lcov-report/helpers/aiRecommendation.js.html rename to coverage/lcov-report/Dummy-Instagram/helpers/aiRecommendation.js.html index e6f385e..7e5d020 100644 --- a/coverage/lcov-report/helpers/aiRecommendation.js.html +++ b/coverage/lcov-report/Dummy-Instagram/helpers/aiRecommendation.js.html @@ -3,15 +3,15 @@ - Code coverage report for helpers/aiRecommendation.js + Code coverage report for Dummy-Instagram/helpers/aiRecommendation.js - - - + + + @@ -19,20 +19,20 @@
-

All files / helpers aiRecommendation.js

+

All files / Dummy-Instagram/helpers aiRecommendation.js

- 28.57% + 0% Statements - 6/21 + 0/21
0% Branches - 0/4 + 0/6
@@ -44,9 +44,9 @@

All files / helpers aiR
- 30% + 0% Lines - 6/20 + 0/20
@@ -130,17 +130,23 @@

All files / helpers aiR 65 66 67 -681x -1x -1x +68 +69 +70 +71 +72  +  +    -1x -1x   +          +  +  +        @@ -154,13 +160,15 @@

All files / helpers aiR       -              +  +  +        @@ -187,7 +195,6 @@

All files / helpers aiR       -        @@ -197,22 +204,25 @@

All files / helpers aiR       -1x
const { GoogleGenerativeAI } = require("@google/generative-ai");
-const { Post, Like, Category, User } = require("../models");
-const { Op } = require("sequelize");
- 
-const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
-const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
+ 
+ 
const { GoogleGenerativeAI } = require("@google/generative-ai");
+const { Post, Like, Category, User } = require("../models");
+const { Op } = require("sequelize");
  
 async function getAIRecommendations(userId) {
   try {
+    // โœ… Inisialisasi Gemini di dalam fungsi agar bisa dimock
+    const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
+    const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" });
+ 
     const likedPosts = await Like.findAll({
       where: { UserId: userId },
       include: [{ model: Post, include: [Category] }],
     });
  
-    if (likedPosts.length < 3) {  //minimal 3 likes
-      return Post.findAll({
+    // โœ… Kalau user belum banyak like โ†’ return default post
+    if (!likedPosts || likedPosts.length < 3) {
+      return await Post.findAll({
         where: { isPrivate: false },
         include: [Category, User, Like],
         order: [["createdAt", "DESC"]],
@@ -221,16 +231,18 @@ 

All files / helpers aiR }   const userInterests = likedPosts - .map((l) => `- "${l.Post.content}" (Kategori: ${l.Post.Category?.name || "Umum"})`) + .map( + (like) => + `- "${like.Post.content}" (Kategori: ${like.Post.Category?.name || "Umum"})` + ) .join("\n");   const prompt = ` - Anda adalah sistem rekomendasi konten yang cerdas untuk aplikasi media sosial. - Seorang pengguna menyukai postingan-postingan berikut: + Anda adalah sistem rekomendasi konten untuk aplikasi media sosial. + Pengguna menyukai postingan berikut: ${userInterests}   - Berdasarkan daftar di atas, berikan 3 tampilan kategori yang paling relevan dengan minat pengguna. - Balas HANYA dengan nama kategori, dipisahkan oleh koma (contoh: Teknologi, Makanan, Olahraga). + Berdasarkan daftar ini, berikan 3 kategori paling relevan, dipisahkan koma. `;   const result = await model.generateContent(prompt); @@ -240,7 +252,7 @@

All files / helpers aiR const recommendedPosts = await Post.findAll({ where: { isPrivate: false, - UserId: { [Op.ne]: userId }, // Jangan tampilkan post milik sendiri + UserId: { [Op.ne]: userId }, }, include: [ { model: Category, where: { name: { [Op.in]: categories } } }, @@ -254,8 +266,7 @@

All files / helpers aiR return recommendedPosts; } catch (err) { console.error("Error getting AI recommendations:", err); - // Jika AI gagal, berikan rekomendasi default (post publik terbaru) - return Post.findAll({ + return await Post.findAll({ where: { isPrivate: false }, include: [Category, User, Like], order: [["createdAt", "DESC"]], @@ -264,23 +275,24 @@

All files / helpers aiR } }   -module.exports = { getAIRecommendations };

+module.exports = { getAIRecommendations };

- + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/controllers/aiController.js.html b/coverage/lcov-report/Dummy-Instagram/helpers/authMiddleware.js.html similarity index 62% rename from coverage/lcov-report/controllers/aiController.js.html rename to coverage/lcov-report/Dummy-Instagram/helpers/authMiddleware.js.html index 64c0809..07db2e1 100644 --- a/coverage/lcov-report/controllers/aiController.js.html +++ b/coverage/lcov-report/Dummy-Instagram/helpers/authMiddleware.js.html @@ -3,15 +3,15 @@ - Code coverage report for controllers/aiController.js + Code coverage report for Dummy-Instagram/helpers/authMiddleware.js - - - + + + @@ -19,20 +19,20 @@
-

All files / controllers aiController.js

+

All files / Dummy-Instagram/helpers authMiddleware.js

100% Statements - 9/9 + 21/21
100% Branches - 4/4 + 10/10
@@ -46,7 +46,7 @@

All files / controllers
100% Lines - 9/9 + 20/20
@@ -88,56 +88,68 @@

All files / controllers 23 24 25 -261x +26 +27 +28 +29 +301x +1x   +1x +6x +6x +6x +2x     4x -  4x -1x -  -  -3x 3x -  2x   +1x +1x +1x   -  -  -  +5x +5x +3x 2x +1x   +1x       -1x - 
const { getAIRecommendations } = require("../helpers/aiRecommendation");
- 
-class AIController {
-  static async getRecommendations(req, res, next) {
-    try {
+ 
const { verifyToken } = require("./jwt");
+const { User } = require("../models");
  
-      if (!req.user || !req.user.id) {
-        throw { name: "Unauthorized" };
-      }
+module.exports = async function authMiddleware(req, res, next) {
+  try {
+    const tokenHeader = req.headers.authorization;
+    if (!tokenHeader || !tokenHeader.startsWith("Bearer ")) {
+      throw { name: "Unauthorized", message: "Please login first" };
+    }
  
-      const userId = req.user.id;
-      const posts = await getAIRecommendations(userId);
+    const token = tokenHeader.split(" ")[1];
+    const decoded = verifyToken(token);
+    const user = await User.findByPk(decoded.id);
+    if (!user) throw { name: "Unauthorized", message: "User not found" };
  
-      res.status(200).json({
-        message: "Rekomendasi berhasil dibuat",
-        count: posts.length,
-        data: posts,
-      });
-    } catch (err) {
+    req.user = user;
+    req.userId = decoded.id;
+    next();
+  } catch (err) {
+    console.error(err);
+    if (err.name === "Unauthorized") {
       next(err);
+    } else if (err.message === "Database error") {
+      next({ name: "Internal Server Error", message: err.message });
+    } else {
+      next({ name: "Unauthorized", message: "Please login first" });
     }
   }
-}
- 
-module.exports = AIController;
+};
  
@@ -145,16 +157,16 @@

All files / controllers - + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/aiController.js.html b/coverage/lcov-report/Dummy-Instagram/helpers/cloudinary.js.html similarity index 57% rename from coverage/lcov-report/aiController.js.html rename to coverage/lcov-report/Dummy-Instagram/helpers/cloudinary.js.html index e30f707..9845cf4 100644 --- a/coverage/lcov-report/aiController.js.html +++ b/coverage/lcov-report/Dummy-Instagram/helpers/cloudinary.js.html @@ -3,15 +3,15 @@ - Code coverage report for aiController.js + Code coverage report for Dummy-Instagram/helpers/cloudinary.js - - - + + + @@ -19,13 +19,13 @@
-

All files aiController.js

+

All files / Dummy-Instagram/helpers cloudinary.js

- 85.71% + 0% Statements - 6/7 + 0/7
@@ -39,14 +39,14 @@

All files aiController.js

100% Functions - 1/1 + 0/0
- 85.71% + 0% Lines - 6/7 + 0/7
@@ -61,7 +61,7 @@

All files aiController.js

-
+
1 2 @@ -82,61 +82,67 @@

All files aiController.js

17 18 19 -20
1x +20 +21 +22  +  +  +  +        -1x -1x -1x   -1x   +          -          -1x
const { getAIRecommendations } = require("../helpers/aiRecommendation");
+ 
+ 
+ 
const cloudinary = require("cloudinary").v2;
+const { CloudinaryStorage } = require("multer-storage-cloudinary");
+const multer = require("multer");
+ 
+cloudinary.config({
+    cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
+    api_key: process.env.CLOUDINARY_API_KEY,
+    api_secret: process.env.CLOUDINARY_SECRET,
+});
  
-class AIController {
-  static async getRecommendations(req, res, next) {
-    try {
-      const userId = req.user.id;
-      const posts = await getAIRecommendations(userId);
+const storage = new CloudinaryStorage({
+    cloudinary,
+    params: {
+        folder: "DummyInstagram_Posts",
+        allowed_formats: ["jpg", "png", "jpeg"],
+        transformation: [{ quality: "auto", fetch_format: "auto" }],
+    },
+});
  
-      res.json({
-        message: "Rekomendasi berhasil dibuat",
-        count: posts.length,
-        data: posts,
-      });
-    } catch (err) {
-      next(err);
-    }
-  }
-}
+const upload = multer({ storage });
  
-module.exports = AIController;
+module.exports = upload;
- + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/Dummy-Instagram/helpers/handleError.js.html b/coverage/lcov-report/Dummy-Instagram/helpers/handleError.js.html new file mode 100644 index 0000000..77b4c43 --- /dev/null +++ b/coverage/lcov-report/Dummy-Instagram/helpers/handleError.js.html @@ -0,0 +1,175 @@ + + + + + + Code coverage report for Dummy-Instagram/helpers/handleError.js + + + + + + + + + +
+
+

All files / Dummy-Instagram/helpers handleError.js

+
+ +
+ 0% + Statements + 0/15 +
+ + +
+ 0% + Branches + 0/14 +
+ + +
+ 0% + Functions + 0/2 +
+ + +
+ 0% + Lines + 0/14 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
function handleError(err, req,res, next) {
+  console.error("Error:", err);
+ 
+  if (err.name === "Unauthorized") {
+    return res.status(401).json({ message: "Unauthorized access" });
+  }
+ 
+  if (err.name === "InvalidLogin") {
+    return res.status(401).json({ message: "Invalid email or password" });
+  }
+ 
+  if (err.name === "NotFound") {
+    return res.status(404).json({ message: "Data not found" });
+  }
+ 
+  if (err.name === "BadRequest") {
+    return res.status(400).json({ message: err.message || "Bad request" });
+  }
+ 
+  if (err.name === "SequelizeValidationError" || err.name === "SequelizeUniqueConstraintError") {
+    const messages = err.errors.map(e => e.message);
+    return res.status(400).json({ message: messages });
+  }
+ 
+  return res.status(500).json({
+    message: "Internal Server Error",
+  });
+}
+ 
+module.exports = handleError;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/Dummy-Instagram/helpers/index.html b/coverage/lcov-report/Dummy-Instagram/helpers/index.html new file mode 100644 index 0000000..5dda5ce --- /dev/null +++ b/coverage/lcov-report/Dummy-Instagram/helpers/index.html @@ -0,0 +1,191 @@ + + + + + + Code coverage report for Dummy-Instagram/helpers + + + + + + + + + +
+
+

All files Dummy-Instagram/helpers

+
+ +
+ 30% + Statements + 24/80 +
+ + +
+ 32.25% + Branches + 10/31 +
+ + +
+ 10% + Functions + 1/10 +
+ + +
+ 29.87% + Lines + 23/77 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
aiHelper.js +
+
0%0/110%0/10%0/20%0/11
aiRecommendation.js +
+
0%0/210%0/60%0/30%0/20
authMiddleware.js +
+
100%21/21100%10/10100%1/1100%20/20
cloudinary.js +
+
0%0/7100%0/0100%0/00%0/7
handleError.js +
+
0%0/150%0/140%0/20%0/14
jwt.js +
+
60%3/5100%0/00%0/260%3/5
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/helpers/jwt.js.html b/coverage/lcov-report/Dummy-Instagram/helpers/jwt.js.html similarity index 86% rename from coverage/lcov-report/helpers/jwt.js.html rename to coverage/lcov-report/Dummy-Instagram/helpers/jwt.js.html index f3270df..91fb29d 100644 --- a/coverage/lcov-report/helpers/jwt.js.html +++ b/coverage/lcov-report/Dummy-Instagram/helpers/jwt.js.html @@ -3,15 +3,15 @@ - Code coverage report for helpers/jwt.js + Code coverage report for Dummy-Instagram/helpers/jwt.js - - - + + + @@ -19,7 +19,7 @@
-

All files / helpers jwt.js

+

All files / Dummy-Instagram/helpers jwt.js

@@ -103,16 +103,16 @@

All files / helpers jwt - + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/helpers/index.html b/coverage/lcov-report/Dummy-Instagram/index.html similarity index 61% rename from coverage/lcov-report/helpers/index.html rename to coverage/lcov-report/Dummy-Instagram/index.html index 5cace47..0fec583 100644 --- a/coverage/lcov-report/helpers/index.html +++ b/coverage/lcov-report/Dummy-Instagram/index.html @@ -3,7 +3,7 @@ - Code coverage report for helpers + Code coverage report for Dummy-Instagram @@ -19,34 +19,34 @@
-

All files helpers

+

All files Dummy-Instagram

- 35.13% + 0% Statements - 13/37 + 0/32
0% Branches - 0/5 + 0/4
0% Functions - 0/7 + 0/6
- 36.11% + 0% Lines - 13/36 + 0/32
@@ -79,48 +79,18 @@

All files helpers

- aiHelper.js - -
+ app.js + +
- 36.36% - 4/11 0% - 0/1 - 0% - 0/2 - 36.36% - 4/11 - - - - aiRecommendation.js - -
- - 28.57% - 6/21 + 0/32 0% 0/4 0% - 0/3 - 30% - 6/20 - - - - jwt.js - -
- - 60% - 3/5 - 100% - 0/0 + 0/6 0% - 0/2 - 60% - 3/5 + 0/32 @@ -131,7 +101,7 @@

All files helpers

+ - - + + \ No newline at end of file diff --git a/coverage/lcov-report/models/chat.js.html b/coverage/lcov-report/Dummy-Instagram/models/chat.js.html similarity index 84% rename from coverage/lcov-report/models/chat.js.html rename to coverage/lcov-report/Dummy-Instagram/models/chat.js.html index be01356..e08b5a1 100644 --- a/coverage/lcov-report/models/chat.js.html +++ b/coverage/lcov-report/Dummy-Instagram/models/chat.js.html @@ -3,15 +3,15 @@ - Code coverage report for models/chat.js + Code coverage report for Dummy-Instagram/models/chat.js - - - + + + @@ -19,7 +19,7 @@
-

All files / models chat.js

+

All files / Dummy-Instagram/models chat.js

@@ -93,8 +93,8 @@

All files / models chat 28      -1x -1x +4x +4x       @@ -102,13 +102,13 @@

All files / models chat       -1x -1x -1x +4x +4x +4x       -1x +4x       @@ -116,7 +116,7 @@

All files / models chat       -1x +4x  
'use strict';
 const {
   Model
@@ -151,16 +151,16 @@ 

All files / models chat - + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/models/image.js.html b/coverage/lcov-report/Dummy-Instagram/models/image.js.html similarity index 85% rename from coverage/lcov-report/models/image.js.html rename to coverage/lcov-report/Dummy-Instagram/models/image.js.html index 8d76a7a..a07b6b8 100644 --- a/coverage/lcov-report/models/image.js.html +++ b/coverage/lcov-report/Dummy-Instagram/models/image.js.html @@ -3,15 +3,15 @@ - Code coverage report for models/image.js + Code coverage report for Dummy-Instagram/models/image.js - - - + + + @@ -19,7 +19,7 @@
-

All files / models image.js

+

All files / Dummy-Instagram/models image.js

@@ -90,8 +90,8 @@

All files / models imag 25      -1x -1x +4x +4x       @@ -99,18 +99,18 @@

All files / models imag       -1x +4x       -1x +4x             -1x +4x  
'use strict';
 const {
   Model
@@ -142,16 +142,16 @@ 

All files / models imag - + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/models/index.html b/coverage/lcov-report/Dummy-Instagram/models/index.html similarity index 84% rename from coverage/lcov-report/models/index.html rename to coverage/lcov-report/Dummy-Instagram/models/index.html index 6a8fec7..ba8be95 100644 --- a/coverage/lcov-report/models/index.html +++ b/coverage/lcov-report/Dummy-Instagram/models/index.html @@ -3,15 +3,15 @@ - Code coverage report for models + Code coverage report for Dummy-Instagram/models - - - + + + @@ -19,13 +19,13 @@
-

All files models

+

All files Dummy-Instagram/models

- 97.18% + 98.59% Statements - 69/71 + 70/71
@@ -37,16 +37,16 @@

All files models

- 94.44% + 100% Functions - 17/18 + 18/18
- 97.18% + 98.59% Lines - 69/71 + 70/71
@@ -185,17 +185,17 @@

All files models

user.js - -
+ +
- 91.66% - 11/12 + 100% + 12/12 100% 0/0 - 66.66% - 2/3 - 91.66% - 11/12 + 100% + 3/3 + 100% + 12/12 @@ -206,16 +206,16 @@

All files models

- + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/models/index.js.html b/coverage/lcov-report/Dummy-Instagram/models/index.js.html similarity index 78% rename from coverage/lcov-report/models/index.js.html rename to coverage/lcov-report/Dummy-Instagram/models/index.js.html index 417016d..b70c2cb 100644 --- a/coverage/lcov-report/models/index.js.html +++ b/coverage/lcov-report/Dummy-Instagram/models/index.js.html @@ -3,15 +3,15 @@ - Code coverage report for models/index.js + Code coverage report for Dummy-Instagram/models/index.js - - - + + + @@ -19,7 +19,7 @@
-

All files / models index.js

+

All files / Dummy-Instagram/models index.js

@@ -108,27 +108,27 @@

All files / models inde 43 44    -1x -1x -1x -1x -1x -1x -1x -1x +4x +4x +4x +4x +4x +4x +4x +4x       -1x -  +4x +4x   -1x +      -1x +4x     -8x +32x       @@ -136,20 +136,20 @@

All files / models inde       -7x -7x +28x +28x     -1x -7x -7x +4x +28x +28x       -1x -1x +4x +4x   -1x
'use strict';
+4x
'use strict';
  
 const fs = require('fs');
 const path = require('path');
@@ -157,15 +157,15 @@ 

All files / models inde const process = require('process'); const basename = path.basename(__filename); const env = process.env.NODE_ENV || 'development'; -const config = require(__dirname + '/../config/config.js')[env]; // <-- Perubahan di sini +const config = require(__dirname + '/../config/config.js')[env]; const db = {};   let sequelize; // Menggunakan URL dari config.js -Iif (config.url) { - sequelize = new Sequelize(config.url, config); -} else { - sequelize = new Sequelize(config.database, config.username, config.password, config); +if (config.url) { + sequelize = new Sequelize(config.url, config); +} else E{ + sequelize = new Sequelize(config.database, config.username, config.password, config); }   fs @@ -199,16 +199,16 @@

All files / models inde - + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/models/like.js.html b/coverage/lcov-report/Dummy-Instagram/models/like.js.html similarity index 84% rename from coverage/lcov-report/models/like.js.html rename to coverage/lcov-report/Dummy-Instagram/models/like.js.html index a9dcc41..6304bcd 100644 --- a/coverage/lcov-report/models/like.js.html +++ b/coverage/lcov-report/Dummy-Instagram/models/like.js.html @@ -3,15 +3,15 @@ - Code coverage report for models/like.js + Code coverage report for Dummy-Instagram/models/like.js - - - + + + @@ -19,7 +19,7 @@
-

All files / models like.js

+

All files / Dummy-Instagram/models like.js

@@ -91,8 +91,8 @@

All files / models like 26      -1x -1x +4x +4x       @@ -100,19 +100,19 @@

All files / models like       -1x -1x +4x +4x       -1x +4x             -1x +4x  
'use strict';
 const {
   Model
@@ -145,16 +145,16 @@ 

All files / models like - + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/models/message.js.html b/coverage/lcov-report/Dummy-Instagram/models/message.js.html similarity index 85% rename from coverage/lcov-report/models/message.js.html rename to coverage/lcov-report/Dummy-Instagram/models/message.js.html index 2a83b49..ee43f9f 100644 --- a/coverage/lcov-report/models/message.js.html +++ b/coverage/lcov-report/Dummy-Instagram/models/message.js.html @@ -3,15 +3,15 @@ - Code coverage report for models/message.js + Code coverage report for Dummy-Instagram/models/message.js - - - + + + @@ -19,7 +19,7 @@
-

All files / models message.js

+

All files / Dummy-Instagram/models message.js

@@ -95,8 +95,8 @@

All files / models mess 30      -1x -1x +4x +4x       @@ -104,14 +104,14 @@

All files / models mess       -1x -1x -1x +4x +4x +4x         -1x +4x       @@ -120,7 +120,7 @@

All files / models mess       -1x +4x  
'use strict';
 const {
   Model
@@ -157,16 +157,16 @@ 

All files / models mess - + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/models/post.js.html b/coverage/lcov-report/Dummy-Instagram/models/post.js.html similarity index 87% rename from coverage/lcov-report/models/post.js.html rename to coverage/lcov-report/Dummy-Instagram/models/post.js.html index 760098b..ab0b717 100644 --- a/coverage/lcov-report/models/post.js.html +++ b/coverage/lcov-report/Dummy-Instagram/models/post.js.html @@ -3,15 +3,15 @@ - Code coverage report for models/post.js + Code coverage report for Dummy-Instagram/models/post.js - - - + + + @@ -19,7 +19,7 @@
-

All files / models post.js

+

All files / Dummy-Instagram/models post.js

@@ -106,8 +106,8 @@

All files / models post 41      -1x -1x +4x +4x       @@ -115,14 +115,14 @@

All files / models post       -1x -1x -1x -1x +4x +4x +4x +4x       -1x +4x       @@ -142,7 +142,7 @@

All files / models post       -1x +4x  
'use strict';
 const {
   Model
@@ -190,16 +190,16 @@ 

All files / models post - + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/models/user.js.html b/coverage/lcov-report/Dummy-Instagram/models/user.js.html similarity index 84% rename from coverage/lcov-report/models/user.js.html rename to coverage/lcov-report/Dummy-Instagram/models/user.js.html index f95affd..1f12b37 100644 --- a/coverage/lcov-report/models/user.js.html +++ b/coverage/lcov-report/Dummy-Instagram/models/user.js.html @@ -3,15 +3,15 @@ - Code coverage report for models/user.js + Code coverage report for Dummy-Instagram/models/user.js - - - + + + @@ -19,13 +19,13 @@
-

All files / models user.js

+

All files / Dummy-Instagram/models user.js

- 91.66% + 100% Statements - 11/12 + 12/12
@@ -37,16 +37,16 @@

All files / models user
- 66.66% + 100% Functions - 2/3 + 3/3
- 91.66% + 100% Lines - 11/12 + 12/12
@@ -127,11 +127,11 @@

All files / models user 62 63 64  -1x +4x     -1x -1x +4x +4x       @@ -139,16 +139,16 @@

All files / models user       -1x -1x -1x -1x -1x -1x +4x +4x +4x +4x +4x +4x       -1x +4x       @@ -184,11 +184,11 @@

All files / models user       -  +3x       -1x +4x  
'use strict';
 const bcrypt = require('bcryptjs'); 
 const {
@@ -246,8 +246,8 @@ 

All files / models user sequelize, modelName: 'User', hooks: { - beforeCreate: async (user) => { - user.password = await bcrypt.hash(user.password, 10); + beforeCreate: async (user) => { + user.password = await bcrypt.hash(user.password, 10); } } }); @@ -259,16 +259,16 @@

All files / models user - + - - + + \ No newline at end of file diff --git a/coverage/lcov-report/Dummy-Instagram/routes/aiRouter.js.html b/coverage/lcov-report/Dummy-Instagram/routes/aiRouter.js.html new file mode 100644 index 0000000..29a707b --- /dev/null +++ b/coverage/lcov-report/Dummy-Instagram/routes/aiRouter.js.html @@ -0,0 +1,109 @@ + + + + + + Code coverage report for Dummy-Instagram/routes/aiRouter.js + + + + + + + + + +
+
+

All files / Dummy-Instagram/routes aiRouter.js

+
+ +
+ 0% + Statements + 0/6 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 0% + Lines + 0/6 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9  +  +  +  +  +  +  +  + 
const express = require('express');
+const router = express.Router();
+const AIController = require('../controllers/aiController');
+const auth = require('../helpers/authMiddleware');
+ 
+// Endpoint untuk mendapatkan rekomendasi post
+router.get('/recommendations', auth, AIController.getRecommendations);
+ 
+module.exports = router;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/Dummy-Instagram/routes/chatRouter.js.html b/coverage/lcov-report/Dummy-Instagram/routes/chatRouter.js.html new file mode 100644 index 0000000..14bf11a --- /dev/null +++ b/coverage/lcov-report/Dummy-Instagram/routes/chatRouter.js.html @@ -0,0 +1,151 @@ + + + + + + Code coverage report for Dummy-Instagram/routes/chatRouter.js + + + + + + + + + +
+
+

All files / Dummy-Instagram/routes chatRouter.js

+
+ +
+ 0% + Statements + 0/11 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 0% + Lines + 0/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
const express = require('express');
+const router = express.Router();
+const ChatController = require('../controllers/chatController');
+const auth = require('../helpers/authMiddleware');
+ 
+router.use(auth);
+ 
+// Membuat chat AI
+router.post('/ai', ChatController.createAIChat);
+ 
+// Membuat atau mendapatkan chat dengan user lain
+router.post('/', ChatController.createOrGetChat);
+ 
+// Mendapatkan semua chat milik user yang sedang login
+router.get('/', ChatController.getUserChats);
+ 
+// Mendapatkan semua pesan dalam sebuah chat
+router.get('/:chatId/messages', ChatController.getChatMessages);
+ 
+// Mengirim pesan ke sebuah chat
+router.post('/:chatId/messages', ChatController.sendMessage);
+ 
+module.exports = router;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/Dummy-Instagram/routes/index.html b/coverage/lcov-report/Dummy-Instagram/routes/index.html new file mode 100644 index 0000000..2c7e19e --- /dev/null +++ b/coverage/lcov-report/Dummy-Instagram/routes/index.html @@ -0,0 +1,176 @@ + + + + + + Code coverage report for Dummy-Instagram/routes + + + + + + + + + +
+
+

All files Dummy-Instagram/routes

+
+ +
+ 0% + Statements + 0/47 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 0% + Lines + 0/47 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
aiRouter.js +
+
0%0/6100%0/0100%0/00%0/6
chatRouter.js +
+
0%0/11100%0/0100%0/00%0/11
index.js +
+
0%0/11100%0/0100%0/00%0/11
postRouter.js +
+
0%0/12100%0/0100%0/00%0/12
userRouter.js +
+
0%0/7100%0/0100%0/00%0/7
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/Dummy-Instagram/routes/index.js.html b/coverage/lcov-report/Dummy-Instagram/routes/index.js.html new file mode 100644 index 0000000..c068266 --- /dev/null +++ b/coverage/lcov-report/Dummy-Instagram/routes/index.js.html @@ -0,0 +1,124 @@ + + + + + + Code coverage report for Dummy-Instagram/routes/index.js + + + + + + + + + +
+
+

All files / Dummy-Instagram/routes index.js

+
+ +
+ 0% + Statements + 0/11 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 0% + Lines + 0/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14  +  +  +  +  +  +  +  +  +  +  +  +  + 
const express = require('express');
+const router = express.Router();
+ 
+const userRouter = require('./userRouter');
+const postRouter = require('./postRouter');
+const chatRouter = require('./chatRouter');
+const aiRouter = require('./aiRouter');
+ 
+router.use('/users', userRouter);
+router.use('/posts', postRouter);
+router.use('/chats', chatRouter);
+router.use('/ai', aiRouter); 
+ 
+module.exports = router;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/Dummy-Instagram/routes/postRouter.js.html b/coverage/lcov-report/Dummy-Instagram/routes/postRouter.js.html new file mode 100644 index 0000000..e40b8eb --- /dev/null +++ b/coverage/lcov-report/Dummy-Instagram/routes/postRouter.js.html @@ -0,0 +1,136 @@ + + + + + + Code coverage report for Dummy-Instagram/routes/postRouter.js + + + + + + + + + +
+
+

All files / Dummy-Instagram/routes postRouter.js

+
+ +
+ 0% + Statements + 0/12 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 0% + Lines + 0/12 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
const express = require("express");
+const router = express.Router();
+const PostController = require("../controllers/postController");
+const auth = require("../helpers/authMiddleware");
+const upload = require("../helpers/cloudinary"); 
+ 
+// Terapkan middleware upload. 'images' adalah nama field, 5 adalah batas maksimal file.
+router.post("/", auth, upload.array("images", 5), PostController.createPost);
+ 
+router.get("/", PostController.getAllPublicPosts);
+router.get("/me", auth, PostController.getMyPosts);
+ 
+router.put("/:id", auth, PostController.updatePost);
+router.delete("/:id", auth, PostController.deletePost);
+ 
+router.post("/:id/like", auth, PostController.toggleLike);
+ 
+module.exports = router;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/Dummy-Instagram/routes/userRouter.js.html b/coverage/lcov-report/Dummy-Instagram/routes/userRouter.js.html new file mode 100644 index 0000000..d7056a2 --- /dev/null +++ b/coverage/lcov-report/Dummy-Instagram/routes/userRouter.js.html @@ -0,0 +1,112 @@ + + + + + + Code coverage report for Dummy-Instagram/routes/userRouter.js + + + + + + + + + +
+
+

All files / Dummy-Instagram/routes userRouter.js

+
+ +
+ 0% + Statements + 0/7 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 0% + Lines + 0/7 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10  +  +  +  +  +  +  +  +  + 
const express = require('express');
+const UserController = require('../controllers/userController');
+const router = express.Router();
+ 
+router.post('/register', UserController.register);
+router.post('/login', UserController.login);
+router.post('/auth/google', UserController.googleSignIn);
+ 
+ 
+module.exports = router;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/controllers/chatController.js.html b/coverage/lcov-report/controllers/chatController.js.html deleted file mode 100644 index 5557817..0000000 --- a/coverage/lcov-report/controllers/chatController.js.html +++ /dev/null @@ -1,535 +0,0 @@ - - - - - - Code coverage report for controllers/chatController.js - - - - - - - - - -
-
-

All files / controllers chatController.js

-
- -
- 62.74% - Statements - 32/51 -
- - -
- 63.15% - Branches - 12/19 -
- - -
- 40% - Functions - 2/5 -
- - -
- 62.74% - Lines - 32/51 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -123 -124 -125 -126 -127 -128 -129 -130 -131 -132 -133 -134 -135 -136 -137 -138 -139 -140 -141 -142 -143 -144 -145 -146 -147 -148 -149 -150 -1511x -1x -1x -  -  -  -  -3x -3x -3x -  -3x -1x -  -  -  -2x -  -  -  -  -  -  -  -  -  -  -  -  -  -2x -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -4x -4x -4x -4x -4x -  -4x -4x -1x -  -  -  -  -3x -3x -1x -  -  -  -2x -  -  -  -  -  -2x -  -2x -1x -  -1x -  -  -  -  -  -1x -  -  -2x -2x -  -2x -  -  -  -  -1x
const { Chat, Message, User, Sequelize } = require("../models");
-const { Op } = Sequelize;
-const { askGemini } = require("../helpers/aiHelper");
- 
-class ChatController {
-    // Mencegah duplikasi chat
-    static async createOrGetChat(req, res, next) {
-        try {
-            const { partnerId } = req.body;
-            const userId = req.user.id;
- 
-            if (partnerId == userId) { //  Validasi agar tidak chat dengan diri sendiri
-                throw { name: "BadRequest", message: "You cannot create a chat with yourself." };
-            }
- 
-            // Cari chat yang sudah ada antara kedua user
-            const [chat, created] = await Chat.findOrCreate({
-                where: {
-                    [Op.or]: [
-                        { UserId: userId, partnerId: partnerId },
-                        { UserId: partnerId, partnerId: userId },
-                    ],
-                    isAIChat: false
-                },
-                defaults: {
-                    UserId: userId,
-                    partnerId: partnerId,
-                },
-            });
- 
-            res.status(created ? 201 : 200).json(chat);
-        } catch (err) {
-            next(err);
-        }
-    }
- 
-    // Menampilkan semua chat dimana user terlibat
-    static async getUserChats(req, res, next) {
-        try {
-            const userId = req.user.id;
-            const chats = await Chat.findAll({
-                where: {
-                    [Op.or]: [{ UserId: userId }, { partnerId: userId }],
-                },
-                include: [
-                    { model: User, as: "creator", attributes: ["id", "username", "profilePic"] },
-                    { model: User, as: "partner", attributes: ["id", "username", "profilePic"] },
-                ],
-                order: [["updatedAt", "DESC"]],
-            });
- 
-            res.json(chats);
-        } catch (err) {
-            next(err);
-        }
-    }
- 
-    // Menambahkan validasi keamanan
-    static async getChatMessages(req, res, next) {
-        try {
-            const { chatId } = req.params;
-            const userId = req.user.id;
- 
-            // Validasi: Pastikan user adalah bagian dari chat ini
-            const chat = await Chat.findByPk(chatId);
-            if (!chat || (chat.UserId !== userId && chat.partnerId !== userId)) {
-                throw { name: "Forbidden" };
-            }
- 
-            const messages = await Message.findAll({
-                where: { ChatId: chatId },
-                include: [{ model: User, as: "sender", attributes: ["id", "username"] }],
-                order: [["createdAt", "ASC"]],
-            });
- 
-            res.json(messages);
-        } catch (err) {
-            next(err);
-        }
-    }
- 
-    static async createAIChat(req, res, next) {
-        try {
-            const userId = req.user.id;
-            const [chat, created] = await Chat.findOrCreate({
-                where: {
-                    UserId: userId,
-                    isAIChat: true,
-                },
-                defaults: {
-                    UserId: userId,
-                    isAIChat: true,
-                    partnerId: null, // Tidak ada partner untuk AI chat
-                },
-            });
-            res.status(created ? 201 : 200).json(chat);
-        } catch (err) {
-            next(err);
-        }
-    }
- 
-    // Menambahkan validasi keamanan & menyederhanakan
-    static async sendMessage(req, res, next) {
-        try {
-            const { chatId } = req.params;
-            const { content } = req.body;
-            const userId = req.user.id;
-            const io = req.app.get("socketio");
- 
-            const chat = await Chat.findByPk(chatId);
-            if (!chat) {
-                throw { name: "NotFound", message: "Chat not found" };
-            }
- 
- 
-            // User harus menjadi pembuat atau partner dari chat tersebut.
-            const isAuthorized = chat.UserId === userId || chat.partnerId === userId;
-            if (!isAuthorized) {
-                throw { name: "Forbidden", message: "You are not authorized to access this chat" };
-            }
- 
-            // 1. Simpan dan kirim pesan dari user
-            const userMessage = await Message.create({
-                ChatId: chatId,
-                senderId: userId,
-                content,
-            });
- 
-            io.to(`chat_${chatId}`).emit("receive_message", userMessage);
- 
-            if (chat.isAIChat) {
-                const aiResponseText = await askGemini(content);
- 
-                const aiMessage = await Message.create({
-                    ChatId: chatId,
-                    senderId: null,
-                    content: aiResponseText,
-                });
- 
-                io.to(`chat_${chatId}`).emit("receive_message", aiMessage);
-            }
- 
-            await chat.save();
-            res.status(201).json(userMessage);
-        } catch (err) {
-            next(err);
-        }
-    }
-}
- 
-module.exports = ChatController;
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/lcov-report/controllers/index.html b/coverage/lcov-report/controllers/index.html deleted file mode 100644 index 84e57c0..0000000 --- a/coverage/lcov-report/controllers/index.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - Code coverage report for controllers - - - - - - - - - -
-
-

All files controllers

-
- -
- 60.68% - Statements - 88/145 -
- - -
- 65.3% - Branches - 32/49 -
- - -
- 56.25% - Functions - 9/16 -
- - -
- 61.87% - Lines - 86/139 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FileStatementsBranchesFunctionsLines
aiController.js -
-
100%9/9100%4/4100%1/1100%9/9
chatController.js -
-
62.74%32/5163.15%12/1940%2/562.74%32/51
postController.js -
-
64.15%34/5366.66%12/1871.42%5/768.08%32/47
userController.js -
-
40.62%13/3250%4/833.33%1/340.62%13/32
-
-
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/lcov-report/controllers/postController.js.html b/coverage/lcov-report/controllers/postController.js.html deleted file mode 100644 index a5ecd28..0000000 --- a/coverage/lcov-report/controllers/postController.js.html +++ /dev/null @@ -1,451 +0,0 @@ - - - - - - Code coverage report for controllers/postController.js - - - - - - - - - -
-
-

All files / controllers postController.js

-
- -
- 64.15% - Statements - 34/53 -
- - -
- 66.66% - Branches - 12/18 -
- - -
- 71.42% - Functions - 5/7 -
- - -
- 68.08% - Lines - 32/47 -
- - -
-

- Press n or j to go to the next uncovered block, b, p or k for the previous block. -

- -
-
-

-
1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71 -72 -73 -74 -75 -76 -77 -78 -79 -80 -81 -82 -83 -84 -85 -86 -87 -88 -89 -90 -91 -92 -93 -94 -95 -96 -97 -98 -99 -100 -101 -102 -103 -104 -105 -106 -107 -108 -109 -110 -111 -112 -113 -114 -115 -116 -117 -118 -119 -120 -121 -122 -1231x -  -  -  -  -2x -2x -  -  -2x -  -  -  -  -  -  -  -2x -2x -  -  -  -1x -  -  -2x -  -  -  -  -  -  -  -1x -1x -  -  -  -  -  -  -  -  -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -2x -2x -2x -  -2x -2x -2x -  -1x -1x -  -1x -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -2x -2x -2x -2x -  -2x -  -  -  -  -2x -1x -1x -  -1x -1x -  -2x -  -  -  -  -  -  -1x
const { Post, Image, Like, User, Category } = require("../models");
- 
-class PostController {
-    // CREATE POST
-    static async createPost(req, res, next) {
-        try {
-            const { content, isPrivate, categoryId } = req.body;
- 
-            // Buat post baru
-            const post = await Post.create({
-                content,
-                isPrivate,
-                CategoryId: categoryId || null,
-                UserId: req.user.id,
-            });
- 
-            // Jika ada file yang di-upload, simpan URL-nya
-            if (req.files && req.files.length > 0) {
-                const images = req.files.map((file) => ({
-                    imageUrl: file.path, // multer-storage-cloudinary menyediakan URL di file.path
-                    PostId: post.id,
-                }));
-                await Image.bulkCreate(images);
-            }
- 
-            res.status(201).json({ message: "Post created successfully", post });
-        } catch (err) {
-            next(err);
-        }
-    }
- 
-    // READ ALL PUBLIC POSTS
-    static async getAllPublicPosts(req, res, next) {
-        try {
-            const posts = await Post.findAll({
-                where: { isPrivate: false },
-                include: [
-                    { model: User, attributes: ["id", "username", "profilePic"] },
-                    { model: Image },
-                    { model: Category, attributes: ["name"] },
-                    { model: Like },
-                ],
-                order: [["createdAt", "DESC"]],
-            });
-            res.json(posts);
-        } catch (err) {
-            next(err);
-        }
-    }
- 
-    // READ USER'S OWN POSTS
-    static async getMyPosts(req, res, next) {
-        try {
-            const posts = await Post.findAll({
-                where: { UserId: req.user.id },
-                include: [Image, Category, Like],
-                order: [["createdAt", "DESC"]],
-            });
-            res.json(posts);
-        } catch (err) {
-            next(err);
-        }
-    }
- 
-    // UPDATE POST
-    static async updatePost(req, res, next) {
-        try {
-            const { id } = req.params;
-            const { content, isPrivate, categoryId } = req.body;
- 
-            const post = await Post.findByPk(id);
-            Iif (!post) throw { name: "NotFound" };
-            if (post.UserId !== req.user.id) throw { name: "Unauthorized" };
- 
-            await post.update({ content, isPrivate, CategoryId: categoryId });
-            res.json({ message: "Post updated successfully", post });
-        } catch (err) {
-            next(err);
-        }
-    }
- 
-    // DELETE POST
-    static async deletePost(req, res, next) {
-        try {
-            const { id } = req.params;
-            const post = await Post.findByPk(id);
-            if (!post) throw { name: "NotFound" };
-            if (post.UserId !== req.user.id) throw { name: "Unauthorized" };
- 
-            await post.destroy();
-            res.json({ message: "Post deleted successfully" });
-        } catch (err) {
-            next(err);
-        }
-    }
- 
-    // LIKE / UNLIKE POST
-    static async toggleLike(req, res, next) {
-        try {
-            const { id } = req.params;
-            const post = await Post.findByPk(id);
-            Iif (!post) throw { name: "NotFound" };
- 
-            const existingLike = await Like.findOne({
-                where: { UserId: req.user.id, PostId: id },
-            });
- 
-            let message;
-            if (existingLike) {
-                await existingLike.destroy();
-                message = "Post unliked";
-            } else {
-                await Like.create({ UserId: req.user.id, PostId: id });
-                message = "Post liked";
-            }
-            res.json({ message });
-        } catch (err) {
-            next(err);
-        }
-    }
-}
- 
-module.exports = PostController;
- -
-
- - - - - - - - \ No newline at end of file diff --git a/coverage/lcov-report/index.html b/coverage/lcov-report/index.html index 0917a4c..9562ca6 100644 --- a/coverage/lcov-report/index.html +++ b/coverage/lcov-report/index.html @@ -23,30 +23,30 @@

All files

- 67.32% + 7.86% Statements - 171/254 + 24/305
- 63.15% + 11.9% Branches - 48/76 + 10/84
- 63.41% + 3.12% Functions - 26/41 + 1/32
- 68.42% + 7.77% Lines - 169/247 + 23/296
@@ -61,7 +61,7 @@

All files

-
+
@@ -79,63 +79,63 @@

All files

- - + - - - - - - - - + + + + + + + + - - + - - - - - - - - + + + + + + + + - - + - - - - - - - - + + + + + + + + - - + - - - - - - - - + + + + + + + + @@ -146,7 +146,7 @@

All files

- - - - - - \ No newline at end of file diff --git a/coverage/lcov.info b/coverage/lcov.info index caface0..24915f0 100644 --- a/coverage/lcov.info +++ b/coverage/lcov.info @@ -1,48 +1,83 @@ TN: -SF:config\config.js -FNF:0 +SF:app.js +FN:34,(anonymous_0) +FN:37,(anonymous_1) +FN:41,(anonymous_2) +FN:45,(anonymous_3) +FN:49,(anonymous_4) +FN:57,(anonymous_5) +FNF:6 FNH:0 -DA:7,1 -LF:1 -LH:1 -BRDA:10,0,0,1 -BRDA:10,0,1,1 -BRDA:14,1,0,0 -BRDA:14,1,1,1 -BRDA:18,2,0,1 -BRDA:18,2,1,1 -BRDA:21,3,0,0 -BRDA:21,3,1,1 -BRDA:25,4,0,1 -BRDA:25,4,1,1 -BRDA:28,5,0,0 -BRDA:28,5,1,1 -BRF:12 -BRH:9 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) +FNDA:0,(anonymous_3) +FNDA:0,(anonymous_4) +FNDA:0,(anonymous_5) +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:18,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:27,0 +DA:31,0 +DA:34,0 +DA:35,0 +DA:37,0 +DA:38,0 +DA:41,0 +DA:42,0 +DA:45,0 +DA:46,0 +DA:49,0 +DA:50,0 +DA:56,0 +DA:57,0 +DA:58,0 +DA:62,0 +LF:32 +LH:0 +BRDA:4,0,0,0 +BRDA:4,0,1,0 +BRDA:56,1,0,0 +BRDA:56,1,1,0 +BRF:4 +BRH:0 end_of_record TN: SF:controllers\aiController.js FN:4,(anonymous_0) FNF:1 -FNH:1 -FNDA:4,(anonymous_0) -DA:1,1 -DA:5,4 -DA:7,4 -DA:8,1 -DA:11,3 -DA:12,3 -DA:14,2 -DA:20,2 -DA:25,1 +FNH:0 +FNDA:0,(anonymous_0) +DA:1,0 +DA:5,0 +DA:7,0 +DA:8,0 +DA:11,0 +DA:12,0 +DA:14,0 +DA:20,0 +DA:25,0 LF:9 -LH:9 -BRDA:7,0,0,1 -BRDA:7,0,1,3 -BRDA:7,1,0,4 -BRDA:7,1,1,3 +LH:0 +BRDA:7,0,0,0 +BRDA:7,0,1,0 +BRDA:7,1,0,0 +BRDA:7,1,1,0 BRF:4 -BRH:4 +BRH:0 end_of_record TN: SF:controllers\chatController.js @@ -52,23 +87,23 @@ FN:59,(anonymous_2) FN:82,(anonymous_3) FN:103,(anonymous_4) FNF:5 -FNH:2 -FNDA:3,(anonymous_0) +FNH:0 +FNDA:0,(anonymous_0) FNDA:0,(anonymous_1) FNDA:0,(anonymous_2) FNDA:0,(anonymous_3) -FNDA:4,(anonymous_4) -DA:1,1 -DA:2,1 -DA:3,1 -DA:8,3 -DA:9,3 -DA:10,3 -DA:12,3 -DA:13,1 -DA:17,2 -DA:31,2 -DA:33,1 +FNDA:0,(anonymous_4) +DA:1,0 +DA:2,0 +DA:3,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:12,0 +DA:13,0 +DA:17,0 +DA:31,0 +DA:33,0 DA:39,0 DA:40,0 DA:41,0 @@ -88,33 +123,33 @@ DA:84,0 DA:85,0 DA:96,0 DA:98,0 -DA:104,4 -DA:105,4 -DA:106,4 -DA:107,4 -DA:108,4 -DA:110,4 -DA:111,4 -DA:112,1 -DA:117,3 -DA:118,3 -DA:119,1 -DA:123,2 -DA:129,2 -DA:131,2 -DA:132,1 -DA:134,1 -DA:140,1 -DA:143,2 -DA:144,2 -DA:146,2 -DA:151,1 +DA:104,0 +DA:105,0 +DA:106,0 +DA:107,0 +DA:108,0 +DA:110,0 +DA:111,0 +DA:112,0 +DA:117,0 +DA:118,0 +DA:119,0 +DA:123,0 +DA:129,0 +DA:131,0 +DA:132,0 +DA:134,0 +DA:140,0 +DA:143,0 +DA:144,0 +DA:146,0 +DA:151,0 LF:51 -LH:32 -BRDA:12,0,0,1 -BRDA:12,0,1,2 -BRDA:31,1,0,1 -BRDA:31,1,1,1 +LH:0 +BRDA:12,0,0,0 +BRDA:12,0,1,0 +BRDA:31,1,0,0 +BRDA:31,1,1,0 BRDA:66,2,0,0 BRDA:66,2,1,0 BRDA:66,3,0,0 @@ -122,104 +157,105 @@ BRDA:66,3,1,0 BRDA:66,3,2,0 BRDA:96,4,0,0 BRDA:96,4,1,0 -BRDA:111,5,0,1 -BRDA:111,5,1,3 -BRDA:117,6,0,3 -BRDA:117,6,1,1 -BRDA:118,7,0,1 -BRDA:118,7,1,2 -BRDA:131,8,0,1 -BRDA:131,8,1,1 +BRDA:111,5,0,0 +BRDA:111,5,1,0 +BRDA:117,6,0,0 +BRDA:117,6,1,0 +BRDA:118,7,0,0 +BRDA:118,7,1,0 +BRDA:131,8,0,0 +BRDA:131,8,1,0 BRF:19 -BRH:12 +BRH:0 end_of_record TN: SF:controllers\postController.js FN:5,(anonymous_0) -FN:19,(anonymous_1) -FN:33,(anonymous_2) -FN:52,(anonymous_3) -FN:66,(anonymous_4) -FN:83,(anonymous_5) -FN:98,(anonymous_6) +FN:23,(anonymous_1) +FN:37,(anonymous_2) +FN:56,(anonymous_3) +FN:70,(anonymous_4) +FN:87,(anonymous_5) +FN:102,(anonymous_6) FNF:7 -FNH:5 -FNDA:2,(anonymous_0) -FNDA:2,(anonymous_1) -FNDA:1,(anonymous_2) +FNH:0 +FNDA:0,(anonymous_0) +FNDA:0,(anonymous_1) +FNDA:0,(anonymous_2) FNDA:0,(anonymous_3) -FNDA:2,(anonymous_4) +FNDA:0,(anonymous_4) FNDA:0,(anonymous_5) -FNDA:2,(anonymous_6) -DA:1,1 -DA:6,2 -DA:7,2 -DA:10,2 -DA:18,2 -DA:19,2 -DA:23,1 -DA:26,2 +FNDA:0,(anonymous_6) +DA:1,0 +DA:6,0 +DA:7,0 +DA:10,0 +DA:11,0 +DA:15,0 +DA:23,0 DA:28,0 -DA:34,1 -DA:35,1 -DA:45,1 -DA:47,0 -DA:53,0 -DA:54,0 -DA:59,0 -DA:61,0 -DA:67,2 -DA:68,2 -DA:69,2 -DA:71,2 -DA:72,2 -DA:73,2 -DA:75,1 -DA:76,1 -DA:78,1 -DA:84,0 -DA:85,0 -DA:86,0 -DA:87,0 +DA:30,0 +DA:32,0 +DA:38,0 +DA:39,0 +DA:49,0 +DA:51,0 +DA:57,0 +DA:58,0 +DA:63,0 +DA:65,0 +DA:71,0 +DA:72,0 +DA:73,0 +DA:75,0 +DA:76,0 +DA:77,0 +DA:79,0 +DA:80,0 +DA:82,0 DA:88,0 +DA:89,0 DA:90,0 DA:91,0 -DA:93,0 -DA:99,2 -DA:100,2 -DA:101,2 -DA:102,2 -DA:104,2 -DA:109,2 -DA:110,1 -DA:111,1 -DA:113,1 -DA:114,1 -DA:116,2 +DA:92,0 +DA:94,0 +DA:95,0 +DA:97,0 +DA:103,0 +DA:104,0 +DA:105,0 +DA:106,0 +DA:108,0 +DA:113,0 +DA:114,0 +DA:115,0 +DA:117,0 DA:118,0 -DA:123,1 -LF:47 -LH:32 -BRDA:13,0,0,2 -BRDA:13,0,1,1 -BRDA:18,1,0,1 -BRDA:18,1,1,1 -BRDA:18,2,0,2 -BRDA:18,2,1,2 -BRDA:72,3,0,0 -BRDA:72,3,1,2 -BRDA:73,4,0,1 -BRDA:73,4,1,1 -BRDA:87,5,0,0 -BRDA:87,5,1,0 -BRDA:88,6,0,0 -BRDA:88,6,1,0 -BRDA:102,7,0,0 -BRDA:102,7,1,2 -BRDA:109,8,0,1 -BRDA:109,8,1,1 +DA:120,0 +DA:122,0 +DA:127,0 +LF:48 +LH:0 +BRDA:10,0,0,0 +BRDA:10,0,1,0 +BRDA:10,1,0,0 +BRDA:10,1,1,0 +BRDA:18,2,0,0 +BRDA:18,2,1,0 +BRDA:76,3,0,0 +BRDA:76,3,1,0 +BRDA:77,4,0,0 +BRDA:77,4,1,0 +BRDA:91,5,0,0 +BRDA:91,5,1,0 +BRDA:92,6,0,0 +BRDA:92,6,1,0 +BRDA:106,7,0,0 +BRDA:106,7,1,0 +BRDA:113,8,0,0 +BRDA:113,8,1,0 BRF:18 -BRH:12 +BRH:0 end_of_record TN: SF:controllers\userController.js @@ -227,117 +263,217 @@ FN:9,(anonymous_0) FN:23,(anonymous_1) FN:47,(anonymous_2) FNF:3 -FNH:1 +FNH:0 FNDA:0,(anonymous_0) -FNDA:1,(anonymous_1) +FNDA:0,(anonymous_1) FNDA:0,(anonymous_2) -DA:1,1 -DA:2,1 -DA:3,1 -DA:4,1 -DA:5,1 +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 DA:10,0 DA:11,0 DA:12,0 DA:13,0 DA:19,0 -DA:24,1 -DA:25,1 -DA:26,1 +DA:24,0 +DA:25,0 +DA:26,0 DA:27,0 -DA:30,1 -DA:31,1 -DA:32,1 +DA:30,0 +DA:31,0 +DA:32,0 DA:35,0 DA:36,0 DA:37,0 DA:40,0 DA:41,0 -DA:43,1 +DA:43,0 DA:48,0 DA:49,0 DA:51,0 DA:55,0 DA:57,0 +DA:68,0 DA:69,0 -DA:70,0 -DA:73,0 -DA:80,1 +DA:72,0 +DA:77,0 LF:32 -LH:13 +LH:0 BRDA:26,0,0,0 -BRDA:26,0,1,1 -BRDA:26,1,0,1 -BRDA:26,1,1,1 -BRDA:31,2,0,1 +BRDA:26,0,1,0 +BRDA:26,1,0,0 +BRDA:26,1,1,0 +BRDA:31,2,0,0 BRDA:31,2,1,0 BRDA:36,3,0,0 BRDA:36,3,1,0 BRF:8 -BRH:4 +BRH:0 end_of_record TN: SF:helpers\aiHelper.js FN:7,cleanText -FN:25,askGemini +FN:24,askGemini FNF:2 FNH:0 FNDA:0,cleanText FNDA:0,askGemini -DA:1,1 -DA:3,1 -DA:4,1 +DA:1,0 +DA:3,0 +DA:4,0 DA:8,0 +DA:25,0 DA:26,0 DA:27,0 DA:28,0 -DA:29,0 +DA:30,0 DA:31,0 -DA:32,0 -DA:36,1 +DA:35,0 LF:11 -LH:4 +LH:0 BRDA:7,0,0,0 BRF:1 BRH:0 end_of_record TN: SF:helpers\aiRecommendation.js -FN:8,getAIRecommendations -FN:25,(anonymous_1) -FN:39,(anonymous_2) +FN:5,getAIRecommendations +FN:28,(anonymous_1) +FN:43,(anonymous_2) FNF:3 FNH:0 FNDA:0,getAIRecommendations FNDA:0,(anonymous_1) FNDA:0,(anonymous_2) +DA:1,0 +DA:2,0 +DA:3,0 +DA:6,0 +DA:8,0 +DA:9,0 +DA:11,0 +DA:17,0 +DA:18,0 +DA:26,0 +DA:29,0 +DA:33,0 +DA:41,0 +DA:42,0 +DA:43,0 +DA:45,0 +DA:59,0 +DA:61,0 +DA:62,0 +DA:71,0 +LF:20 +LH:0 +BRDA:17,0,0,0 +BRDA:17,0,1,0 +BRDA:17,1,0,0 +BRDA:17,1,1,0 +BRDA:29,2,0,0 +BRDA:29,2,1,0 +BRF:6 +BRH:0 +end_of_record +TN: +SF:helpers\authMiddleware.js +FN:4,authMiddleware +FNF:1 +FNH:1 +FNDA:6,authMiddleware DA:1,1 DA:2,1 -DA:3,1 -DA:5,1 -DA:6,1 +DA:4,1 +DA:5,6 +DA:6,6 +DA:7,6 +DA:8,2 +DA:11,4 +DA:12,4 +DA:13,3 +DA:14,2 +DA:16,1 +DA:17,1 +DA:18,1 +DA:20,5 +DA:21,5 +DA:22,3 +DA:23,2 +DA:24,1 +DA:26,1 +LF:20 +LH:20 +BRDA:7,0,0,2 +BRDA:7,0,1,4 +BRDA:7,1,0,6 +BRDA:7,1,1,5 +BRDA:14,2,0,1 +BRDA:14,2,1,1 +BRDA:21,3,0,3 +BRDA:21,3,1,2 +BRDA:23,4,0,1 +BRDA:23,4,1,1 +BRF:10 +BRH:10 +end_of_record +TN: +SF:helpers\cloudinary.js +FNF:0 +FNH:0 +DA:1,0 +DA:2,0 +DA:3,0 +DA:5,0 +DA:11,0 +DA:20,0 +DA:22,0 +LF:7 +LH:0 +BRF:0 +BRH:0 +end_of_record +TN: +SF:helpers\handleError.js +FN:1,handleError +FN:21,(anonymous_1) +FNF:2 +FNH:0 +FNDA:0,handleError +FNDA:0,(anonymous_1) +DA:2,0 +DA:4,0 +DA:5,0 +DA:8,0 DA:9,0 -DA:10,0 -DA:15,0 +DA:12,0 +DA:13,0 DA:16,0 -DA:24,0 +DA:17,0 +DA:20,0 +DA:21,0 +DA:22,0 DA:25,0 -DA:28,0 -DA:37,0 -DA:38,0 -DA:39,0 -DA:41,0 -DA:55,0 -DA:57,0 -DA:59,0 -DA:68,1 -LF:20 -LH:6 -BRDA:15,0,0,0 -BRDA:15,0,1,0 -BRDA:25,1,0,0 -BRDA:25,1,1,0 -BRF:4 +DA:30,0 +LF:14 +LH:0 +BRDA:4,0,0,0 +BRDA:4,0,1,0 +BRDA:8,1,0,0 +BRDA:8,1,1,0 +BRDA:12,2,0,0 +BRDA:12,2,1,0 +BRDA:16,3,0,0 +BRDA:16,3,1,0 +BRDA:17,4,0,0 +BRDA:17,4,1,0 +BRDA:20,5,0,0 +BRDA:20,5,1,0 +BRDA:20,6,0,0 +BRDA:20,6,1,0 +BRF:14 BRH:0 end_of_record TN: @@ -359,191 +495,94 @@ BRF:0 BRH:0 end_of_record TN: -SF:models\category.js -FN:5,(anonymous_0) -FN:12,(anonymous_1) -FNF:2 -FNH:2 -FNDA:1,(anonymous_0) -FNDA:1,(anonymous_1) -DA:4,1 -DA:5,1 -DA:13,1 -DA:17,1 -DA:23,1 -LF:5 -LH:5 -BRF:0 -BRH:0 -end_of_record -TN: -SF:models\chat.js -FN:5,(anonymous_0) -FN:12,(anonymous_1) -FNF:2 -FNH:2 -FNDA:1,(anonymous_0) -FNDA:1,(anonymous_1) -DA:4,1 -DA:5,1 -DA:13,1 -DA:14,1 -DA:15,1 -DA:19,1 -DA:27,1 -LF:7 -LH:7 -BRF:0 -BRH:0 -end_of_record -TN: -SF:models\image.js -FN:5,(anonymous_0) -FN:12,(anonymous_1) -FNF:2 -FNH:2 -FNDA:1,(anonymous_0) -FNDA:1,(anonymous_1) -DA:4,1 -DA:5,1 -DA:13,1 -DA:17,1 -DA:24,1 -LF:5 -LH:5 +SF:routes\aiRouter.js +FNF:0 +FNH:0 +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:7,0 +DA:9,0 +LF:6 +LH:0 BRF:0 BRH:0 end_of_record TN: -SF:models\index.js -FN:22,(anonymous_0) -FN:30,(anonymous_1) -FN:35,(anonymous_2) -FNF:3 -FNH:3 -FNDA:8,(anonymous_0) -FNDA:7,(anonymous_1) -FNDA:7,(anonymous_2) -DA:3,1 -DA:4,1 -DA:5,1 -DA:6,1 -DA:7,1 -DA:8,1 -DA:9,1 -DA:10,1 -DA:14,1 +SF:routes\chatRouter.js +FNF:0 +FNH:0 +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:6,0 +DA:9,0 +DA:12,0 DA:15,0 -DA:17,1 -DA:20,1 -DA:23,8 -DA:31,7 -DA:32,7 -DA:35,1 -DA:36,7 -DA:37,7 -DA:41,1 -DA:42,1 -DA:44,1 -LF:21 -LH:20 -BRDA:8,0,0,1 -BRDA:8,0,1,0 -BRDA:14,1,0,0 -BRDA:14,1,1,1 -BRDA:24,2,0,8 -BRDA:24,2,1,8 -BRDA:24,2,2,7 -BRDA:24,2,3,7 -BRDA:36,3,0,7 -BRDA:36,3,1,0 -BRF:10 -BRH:7 -end_of_record -TN: -SF:models\like.js -FN:5,(anonymous_0) -FN:12,(anonymous_1) -FNF:2 -FNH:2 -FNDA:1,(anonymous_0) -FNDA:1,(anonymous_1) -DA:4,1 -DA:5,1 -DA:13,1 -DA:14,1 -DA:18,1 -DA:25,1 -LF:6 -LH:6 +DA:18,0 +DA:21,0 +DA:23,0 +LF:11 +LH:0 BRF:0 BRH:0 end_of_record TN: -SF:models\message.js -FN:5,(anonymous_0) -FN:12,(anonymous_1) -FNF:2 -FNH:2 -FNDA:1,(anonymous_0) -FNDA:1,(anonymous_1) -DA:4,1 -DA:5,1 -DA:13,1 -DA:14,1 -DA:15,1 -DA:20,1 -DA:29,1 -LF:7 -LH:7 +SF:routes\index.js +FNF:0 +FNH:0 +DA:1,0 +DA:2,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:12,0 +DA:14,0 +LF:11 +LH:0 BRF:0 BRH:0 end_of_record TN: -SF:models\post.js -FN:5,(anonymous_0) -FN:12,(anonymous_1) -FNF:2 -FNH:2 -FNDA:1,(anonymous_0) -FNDA:1,(anonymous_1) -DA:4,1 -DA:5,1 -DA:13,1 -DA:14,1 -DA:15,1 -DA:16,1 -DA:20,1 -DA:40,1 -LF:8 -LH:8 +SF:routes\postRouter.js +FNF:0 +FNH:0 +DA:1,0 +DA:2,0 +DA:3,0 +DA:4,0 +DA:5,0 +DA:8,0 +DA:10,0 +DA:11,0 +DA:13,0 +DA:14,0 +DA:16,0 +DA:18,0 +LF:12 +LH:0 BRF:0 BRH:0 end_of_record TN: -SF:models\user.js -FN:6,(anonymous_0) -FN:13,(anonymous_1) -FN:58,(anonymous_2) -FNF:3 -FNH:2 -FNDA:1,(anonymous_0) -FNDA:1,(anonymous_1) -FNDA:0,(anonymous_2) -DA:2,1 -DA:5,1 -DA:6,1 -DA:14,1 -DA:15,1 -DA:16,1 -DA:17,1 -DA:18,1 -DA:19,1 -DA:23,1 -DA:59,0 -DA:63,1 -LF:12 -LH:11 +SF:routes\userRouter.js +FNF:0 +FNH:0 +DA:1,0 +DA:2,0 +DA:3,0 +DA:5,0 +DA:6,0 +DA:7,0 +DA:10,0 +LF:7 +LH:0 BRF:0 BRH:0 end_of_record diff --git a/helpers/aiHelper.js b/helpers/aiHelper.js index 351c42b..4043caa 100644 --- a/helpers/aiHelper.js +++ b/helpers/aiHelper.js @@ -3,11 +3,11 @@ const { GoogleGenerativeAI } = require("@google/generative-ai"); const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY); const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" }); -//cleaning text function +// cleaning text function function cleanText(text = "") { return text - // Hapus heading markdown dan pemisah - .replace(/^#+\s*/gm, "") + // Hapus seluruh baris heading markdown dan pemisah + .replace(/^#+\s?.*$/gm, "") .replace(/---+/g, " ") // Hapus bullet dan angka daftar .replace(/^\s*\d+\.\s*/gm, "") @@ -21,7 +21,6 @@ function cleanText(text = "") { .trim(); } - async function askGemini(prompt) { try { const result = await model.generateContent(prompt); @@ -33,4 +32,4 @@ async function askGemini(prompt) { } } -module.exports = { askGemini }; +module.exports = { askGemini, cleanText }; diff --git a/helpers/aiRecommendation.js b/helpers/aiRecommendation.js index 7f37e4a..7526e8a 100644 --- a/helpers/aiRecommendation.js +++ b/helpers/aiRecommendation.js @@ -2,18 +2,20 @@ const { GoogleGenerativeAI } = require("@google/generative-ai"); const { Post, Like, Category, User } = require("../models"); const { Op } = require("sequelize"); -const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY); -const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" }); - async function getAIRecommendations(userId) { try { + // โœ… Inisialisasi Gemini di dalam fungsi agar bisa dimock + const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY); + const model = genAI.getGenerativeModel({ model: "gemini-2.5-pro" }); + const likedPosts = await Like.findAll({ where: { UserId: userId }, include: [{ model: Post, include: [Category] }], }); - if (likedPosts.length < 3) { //minimal 3 likes - return Post.findAll({ + // โœ… Kalau user belum banyak like โ†’ return default post + if (!likedPosts || likedPosts.length < 3) { + return await Post.findAll({ where: { isPrivate: false }, include: [Category, User, Like], order: [["createdAt", "DESC"]], @@ -22,16 +24,18 @@ async function getAIRecommendations(userId) { } const userInterests = likedPosts - .map((l) => `- "${l.Post.content}" (Kategori: ${l.Post.Category?.name || "Umum"})`) + .map( + (like) => + `- "${like.Post.content}" (Kategori: ${like.Post.Category?.name || "Umum"})` + ) .join("\n"); const prompt = ` - Anda adalah sistem rekomendasi konten yang cerdas untuk aplikasi media sosial. - Seorang pengguna menyukai postingan-postingan berikut: + Anda adalah sistem rekomendasi konten untuk aplikasi media sosial. + Pengguna menyukai postingan berikut: ${userInterests} - Berdasarkan daftar di atas, berikan 3 tampilan kategori yang paling relevan dengan minat pengguna. - Balas HANYA dengan nama kategori, dipisahkan oleh koma (contoh: Teknologi, Makanan, Olahraga). + Berdasarkan daftar ini, berikan 3 kategori paling relevan, dipisahkan koma. `; const result = await model.generateContent(prompt); @@ -41,7 +45,7 @@ async function getAIRecommendations(userId) { const recommendedPosts = await Post.findAll({ where: { isPrivate: false, - UserId: { [Op.ne]: userId }, // Jangan tampilkan post milik sendiri + UserId: { [Op.ne]: userId }, }, include: [ { model: Category, where: { name: { [Op.in]: categories } } }, @@ -55,8 +59,7 @@ async function getAIRecommendations(userId) { return recommendedPosts; } catch (err) { console.error("Error getting AI recommendations:", err); - // Jika AI gagal, berikan rekomendasi default (post publik terbaru) - return Post.findAll({ + return await Post.findAll({ where: { isPrivate: false }, include: [Category, User, Like], order: [["createdAt", "DESC"]], @@ -65,4 +68,4 @@ async function getAIRecommendations(userId) { } } -module.exports = { getAIRecommendations }; \ No newline at end of file +module.exports = { getAIRecommendations }; diff --git a/helpers/authMiddleware.js b/helpers/authMiddleware.js index df1aeb8..3a0c9d7 100644 --- a/helpers/authMiddleware.js +++ b/helpers/authMiddleware.js @@ -3,16 +3,26 @@ const { User } = require("../models"); module.exports = async function authMiddleware(req, res, next) { try { - const token = req.headers.authorization?.split(" ")[1]; - if (!token) throw { name: "Unauthorized" }; + const tokenHeader = req.headers.authorization; + if (!tokenHeader || !tokenHeader.startsWith("Bearer ")) { + throw { name: "Unauthorized", message: "Please login first" }; + } + const token = tokenHeader.split(" ")[1]; const decoded = verifyToken(token); const user = await User.findByPk(decoded.id); - if (!user) throw { name: "Unauthorized" }; + if (!user) throw { name: "Unauthorized", message: "User not found" }; + req.user = user; + req.userId = decoded.id; next(); } catch (err) { - console.error(err); - next(err); + if (err.name === "Unauthorized") { + next(err); + } else if (err.message === "Database error") { + next({ name: "Internal Server Error", message: err.message }); + } else { + next({ name: "Unauthorized", message: "Please login first" }); + } } }; diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..ef30e7a --- /dev/null +++ b/jest.config.js @@ -0,0 +1,16 @@ +module.exports = { + testEnvironment: 'node', + collectCoverage: true, + coverageDirectory: 'coverage', + coverageReporters: ['json', 'lcov', 'text', 'clover'], + collectCoverageFrom: [ + 'controllers/**/*.js', + 'helpers/**/*.js', + 'routes/**/*.js', + 'app.js' + ], + testPathIgnorePatterns: [ + '/node_modules/', + '/coverage/' + ] +}; diff --git a/models/index.js b/models/index.js index 9eefedb..4695f66 100644 --- a/models/index.js +++ b/models/index.js @@ -6,7 +6,7 @@ const Sequelize = require('sequelize'); const process = require('process'); const basename = path.basename(__filename); const env = process.env.NODE_ENV || 'development'; -const config = require(__dirname + '/../config/config.js')[env]; // <-- Perubahan di sini +const config = require(__dirname + '/../config/config.js')[env]; const db = {}; let sequelize; diff --git a/package-lock.json b/package-lock.json index ee7c3d3..e14fa4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "express": "^5.1.0", "google-auth-library": "^10.4.0", "jsonwebtoken": "^9.0.2", + "morgan": "^1.10.1", "multer": "^2.0.2", "multer-storage-cloudinary": "^4.0.0", "passport": "^0.7.0", @@ -24,15 +25,17 @@ "pg": "^8.16.3", "pg-hstore": "^2.3.4", "sequelize": "^6.37.7", - "socket.io": "^4.8.1", - "socket.io-client": "^4.8.1" + "socket.io": "^4.8.1" }, "devDependencies": { + "@babel/core": "^7.28.4", + "@babel/preset-env": "^7.28.3", "@types/jest": "^30.0.0", "cross-env": "^7.0.3", "jest": "^30.2.0", "nodemon": "^3.1.10", "sequelize-cli": "^6.6.3", + "sqlite3": "^5.1.7", "supertest": "^7.1.4" } }, @@ -119,6 +122,19 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", @@ -156,6 +172,83 @@ "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", + "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.10" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", @@ -166,6 +259,20 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", @@ -198,6 +305,19 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-plugin-utils": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", @@ -208,6 +328,56 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", @@ -218,103 +388,1075 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-validator-identifier": { + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", + "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", + "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", + "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", + "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.4.tgz", + "integrity": "sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", + "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", + "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", + "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", + "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", + "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", + "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", + "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.4" + }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.4" - }, - "bin": { - "parser": "bin/babel-parser.js" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", + "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -323,10 +1465,10 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-attributes": { + "node_modules/@babel/plugin-transform-property-literals": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", "dev": true, "license": "MIT", "dependencies": { @@ -339,36 +1481,43 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", + "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-syntax-jsx": { + "node_modules/@babel/plugin-transform-reserved-words": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", "dev": true, "license": "MIT", "dependencies": { @@ -381,92 +1530,112 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "node_modules/@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -475,14 +1644,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -491,22 +1661,133 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-typescript": { + "node_modules/@babel/plugin-transform-unicode-sets-regex": { "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", "dev": true, "license": "MIT", "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.3.tgz", + "integrity": "sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.0", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.0", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.3", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.0", + "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.28.0", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.3", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "core-js-compat": "^3.43.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/@babel/template": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", @@ -596,6 +1877,14 @@ "tslib": "^2.4.0" } }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/@google/generative-ai": { "version": "0.24.1", "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz", @@ -1042,30 +2331,72 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", - "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" } }, - "node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "node_modules/@npmcli/move-file/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "engines": { + "node": ">=10" } }, "node_modules/@one-ini/wasm": { @@ -1142,6 +2473,17 @@ "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "license": "MIT" }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", @@ -1607,6 +2949,35 @@ "node": ">= 14" } }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -1669,6 +3040,30 @@ "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", "license": "MIT" }, + "node_modules/aproba": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -1758,6 +3153,58 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, "node_modules/babel-preset-current-node-syntax": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", @@ -1857,6 +3304,24 @@ "baseline-browser-mapping": "dist/cli.js" } }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/bcryptjs": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", @@ -1888,6 +3353,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -1983,6 +3470,31 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -2015,6 +3527,110 @@ "node": ">= 0.8" } }, + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacache/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -2176,6 +3792,16 @@ "fsevents": "~2.3.2" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/ci-info": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", @@ -2199,6 +3825,17 @@ "dev": true, "license": "MIT" }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -2352,6 +3989,17 @@ "dev": true, "license": "MIT" }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -2418,6 +4066,14 @@ "proto-list": "~1.2.1" } }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/content-disposition": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", @@ -2482,6 +4138,20 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/core-js-compat": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz", + "integrity": "sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.26.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", @@ -2555,6 +4225,22 @@ } } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/dedent": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", @@ -2570,6 +4256,16 @@ } } }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -2590,6 +4286,14 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -2599,6 +4303,16 @@ "node": ">= 0.8" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -2755,6 +4469,27 @@ "node": ">= 0.8" } }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/engine.io": { "version": "6.6.4", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", @@ -2775,36 +4510,6 @@ "node": ">=10.2.0" } }, - "node_modules/engine.io-client": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz", - "integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.17.1", - "xmlhttprequest-ssl": "~2.1.1" - } - }, - "node_modules/engine.io-client/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/engine.io-parser": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", @@ -2874,6 +4579,25 @@ "node": ">= 0.6" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", @@ -2970,6 +4694,16 @@ "node": ">=4" } }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -3020,6 +4754,16 @@ "node": ">= 0.8.0" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, "node_modules/expect": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", @@ -3133,6 +4877,13 @@ "node": "^12.20 || >= 14.13" } }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "license": "MIT" + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -3282,6 +5033,13 @@ "node": ">= 0.8" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT" + }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -3298,6 +5056,39 @@ "node": ">=10" } }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3329,6 +5120,85 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/gauge/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/gaxios": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.2.tgz", @@ -3343,6 +5213,24 @@ "node": ">=18" } }, + "node_modules/gaxios/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, "node_modules/gcp-metadata": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-7.0.1.tgz", @@ -3437,6 +5325,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true, + "license": "MIT" + }, "node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -3636,6 +5531,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -3655,6 +5558,14 @@ "dev": true, "license": "MIT" }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -3680,6 +5591,36 @@ "node": ">= 0.8" } }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -3703,6 +5644,17 @@ "node": ">=10.17.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -3715,6 +5667,27 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -3752,6 +5725,25 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/inflection": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz", @@ -3786,6 +5778,17 @@ "dev": true, "license": "ISC" }, + "node_modules/ip-address": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -3874,6 +5877,14 @@ "node": ">=0.10.0" } }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -4933,6 +6944,13 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -4998,6 +7016,111 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/make-fetch-happen/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/make-fetch-happen/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/make-fetch-happen/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -5113,6 +7236,19 @@ "node": ">=6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5145,6 +7281,225 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -5157,6 +7512,13 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "license": "MIT" + }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -5172,10 +7534,53 @@ "integrity": "sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==", "license": "MIT", "dependencies": { - "moment": "^2.29.4" + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/morgan": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", + "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", + "license": "MIT", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.1.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/morgan/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" }, "engines": { - "node": "*" + "node": ">= 0.8" } }, "node_modules/ms": { @@ -5254,6 +7659,13 @@ "node": ">= 0.6" } }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "dev": true, + "license": "MIT" + }, "node_modules/napi-postinstall": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", @@ -5286,6 +7698,26 @@ "node": ">= 0.6" } }, + "node_modules/node-abi": { + "version": "3.78.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.78.0.tgz", + "integrity": "sha512-E2wEyrgX/CqvicaQYU3Ze1PFGjc4QYPGsjUrlYkqAE0WjHEZwgOsGMPMzkMse4LjJbDmaEuDX3CM036j5K2DSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT" + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -5306,22 +7738,78 @@ "node": ">=10.5.0" } }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "node_modules/node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">= 10.12.0" + } + }, + "node_modules/node-gyp/node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" } }, "node_modules/node-int64": { @@ -5406,6 +7894,24 @@ "node": ">=8" } }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "deprecated": "This package is no longer supported.", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/oauth": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.10.2.tgz", @@ -5445,6 +7951,15 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5515,6 +8030,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -5870,6 +8402,33 @@ "node": ">=0.10.0" } }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/pretty-format": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", @@ -5898,6 +8457,29 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -5925,6 +8507,17 @@ "dev": true, "license": "MIT" }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/pure-rand": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", @@ -6008,6 +8601,32 @@ "url": "https://opencollective.com/express" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -6042,6 +8661,64 @@ "node": ">=8.10.0" } }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", + "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -6096,12 +8773,64 @@ "node": ">=8" } }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/retry-as-promised": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-7.1.1.tgz", "integrity": "sha512-hMD7odLOt3LkTjcif8aRZqi/hybjpLNgSk5oF5FCowfCjok6LukpN2bDX7R5wDmbgBQFn7YoBxSagmtXHaJYJw==", "license": "MIT" }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -6287,6 +9016,14 @@ "node": ">= 18" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -6401,6 +9138,53 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -6424,6 +9208,18 @@ "node": ">=8" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, "node_modules/socket.io": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", @@ -6469,38 +9265,6 @@ } } }, - "node_modules/socket.io-client": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz", - "integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.2", - "engine.io-client": "~6.6.1", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-client/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/socket.io-parser": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", @@ -6591,6 +9355,52 @@ "node": ">= 0.6" } }, + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -6628,6 +9438,67 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/sqlite3": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.7.tgz", + "integrity": "sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==", + "dev": true, + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "bindings": "^1.5.0", + "node-addon-api": "^7.0.0", + "prebuild-install": "^7.1.1", + "tar": "^6.1.11" + }, + "optionalDependencies": { + "node-gyp": "8.x" + }, + "peerDependencies": { + "node-gyp": "8.x" + }, + "peerDependenciesMeta": { + "node-gyp": { + "optional": true + } + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ssri/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ssri/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -6918,6 +9789,91 @@ "url": "https://opencollective.com/synckit" } }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "license": "ISC" + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -7008,6 +9964,19 @@ "license": "0BSD", "optional": true }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -7089,6 +10058,72 @@ "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", "license": "MIT" }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -7266,6 +10301,66 @@ "node": ">= 8" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wkx": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", @@ -7414,14 +10509,6 @@ } } }, - "node_modules/xmlhttprequest-ssl": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", - "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index 5a344a4..b72ff49 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "", "main": "index.js", - "scripts": { + "scripts": { "test": "cross-env NODE_ENV=test jest --runInBand --detectOpenHandles --forceExit --reporters=default --reporters=./config/simpleJestReporter.js", "test:coverage": "cross-env NODE_ENV=test jest --runInBand --detectOpenHandles --forceExit --coverage", "test:watch": "cross-env NODE_ENV=test jest --watch", @@ -29,6 +29,7 @@ "express": "^5.1.0", "google-auth-library": "^10.4.0", "jsonwebtoken": "^9.0.2", + "morgan": "^1.10.1", "multer": "^2.0.2", "multer-storage-cloudinary": "^4.0.0", "passport": "^0.7.0", @@ -39,11 +40,14 @@ "socket.io": "^4.8.1" }, "devDependencies": { + "@babel/core": "^7.28.4", + "@babel/preset-env": "^7.28.3", "@types/jest": "^30.0.0", + "cross-env": "^7.0.3", "jest": "^30.2.0", "nodemon": "^3.1.10", "sequelize-cli": "^6.6.3", - "supertest": "^7.1.4", - "cross-env": "^7.0.3" + "sqlite3": "^5.1.7", + "supertest": "^7.1.4" } } diff --git a/tests/unit/aiController.test.js b/tests/unit/aiController.test.js deleted file mode 100644 index e3bcf27..0000000 --- a/tests/unit/aiController.test.js +++ /dev/null @@ -1,76 +0,0 @@ -const AIController = require('../../controllers/aiController'); -const { getAIRecommendations } = require('../../helpers/aiRecommendation'); - -// Mock the AI recommendation helper -jest.mock('../../helpers/aiRecommendation'); - -describe('Test AI Controller', () => { - // Reset semua mock sebelum setiap test - beforeEach(() => { - jest.clearAllMocks(); - }); - - describe('getRecommendations - Mendapatkan Rekomendasi Post', () => { - const mockReq = { user: { id: 1 } }; - const mockRes = { - json: jest.fn(), - status: jest.fn().mockReturnThis() - }; - const mockNext = jest.fn(); - - test('berhasil mengembalikan rekomendasi post', async () => { - // Mock successful recommendation - const mockPosts = [ - { id: 1, content: 'Post 1' }, - { id: 2, content: 'Post 2' } - ]; - getAIRecommendations.mockResolvedValue(mockPosts); - - await AIController.getRecommendations(mockReq, mockRes, mockNext); - - expect(getAIRecommendations).toHaveBeenCalledWith(1); - expect(mockRes.json).toHaveBeenCalledWith({ - message: "Rekomendasi berhasil dibuat", - count: 2, - data: mockPosts - }); - expect(mockNext).not.toHaveBeenCalled(); - }); - - test('berhasil menangani kasus rekomendasi kosong', async () => { - // Mock rekomendasi kosong - getAIRecommendations.mockResolvedValue([]); - - await AIController.getRecommendations(mockReq, mockRes, mockNext); - - expect(getAIRecommendations).toHaveBeenCalledWith(1); - expect(mockRes.json).toHaveBeenCalledWith({ - message: "Rekomendasi berhasil dibuat", - count: 0, - data: [] - }); - }); - - test('berhasil menangani kasus AI service timeout', async () => { - // Mock AI service timeout - getAIRecommendations.mockRejectedValue(new Error('AI Service Timeout')); - - await AIController.getRecommendations(mockReq, mockRes, mockNext); - - expect(getAIRecommendations).toHaveBeenCalledWith(1); - expect(mockNext).toHaveBeenCalledWith(new Error('AI Service Timeout')); - expect(mockRes.json).not.toHaveBeenCalled(); - }); - - test('handles missing user in request', async () => { - const reqWithoutUser = { user: null }; - - await AIController.getRecommendations(reqWithoutUser, mockRes, mockNext); - - expect(getAIRecommendations).not.toHaveBeenCalled(); - expect(mockNext).toHaveBeenCalled(); - const error = mockNext.mock.calls[0][0]; - expect(error.name).toBe('Unauthorized'); - }); - }); -}); \ No newline at end of file diff --git a/tests/unit/chatController.test.js b/tests/unit/chatController.test.js deleted file mode 100644 index e7ed621..0000000 --- a/tests/unit/chatController.test.js +++ /dev/null @@ -1,156 +0,0 @@ -const ChatController = require('../../controllers/chatController'); -const { Chat, Message, User, Sequelize } = require('../../models'); -const { askGemini } = require('../../helpers/aiHelper'); - -// Mock all dependencies -jest.mock('../../models', () => ({ - Chat: { - findOrCreate: jest.fn(), - findAll: jest.fn(), - findByPk: jest.fn(), - }, - Message: { - findAll: jest.fn(), - create: jest.fn(), - }, - User: { - findByPk: jest.fn(), - }, - Sequelize: { - Op: { - or: Symbol('or') - } - } -})); - -jest.mock('../../helpers/aiHelper'); - -describe('Test Chat Controller', () => { - let mockReq; - let mockRes; - let mockNext; - let mockSocketIO; - - beforeEach(() => { - jest.clearAllMocks(); - mockReq = { - user: { id: 1 }, - body: {}, - params: {}, - app: { - get: jest.fn().mockReturnValue({ - to: jest.fn().mockReturnValue({ emit: jest.fn() }) - }) - } - }; - mockRes = { - json: jest.fn(), - status: jest.fn().mockReturnThis() - }; - mockNext = jest.fn(); - mockSocketIO = { - to: jest.fn().mockReturnValue({ emit: jest.fn() }) - }; - }); - - describe('createOrGetChat - Membuat atau Mendapatkan Chat', () => { - test('berhasil membuat chat baru', async () => { - mockReq.body.partnerId = 2; - Chat.findOrCreate.mockResolvedValue([{ id: 1 }, true]); - - await ChatController.createOrGetChat(mockReq, mockRes, mockNext); - - expect(Chat.findOrCreate).toHaveBeenCalled(); - expect(mockRes.status).toHaveBeenCalledWith(201); - expect(mockRes.json).toHaveBeenCalled(); - }); - - test('mencegah user chat dengan dirinya sendiri', async () => { - mockReq.body.partnerId = 1; // Sama dengan user.id - - await ChatController.createOrGetChat(mockReq, mockRes, mockNext); - - expect(Chat.findOrCreate).not.toHaveBeenCalled(); - expect(mockNext).toHaveBeenCalled(); - const error = mockNext.mock.calls[0][0]; - expect(error.name).toBe('BadRequest'); - }); - - test('mengembalikan chat yang sudah ada', async () => { - mockReq.body.partnerId = 2; - Chat.findOrCreate.mockResolvedValue([{ id: 1 }, false]); - - await ChatController.createOrGetChat(mockReq, mockRes, mockNext); - - expect(mockRes.status).toHaveBeenCalledWith(200); - expect(mockRes.json).toHaveBeenCalled(); - }); - }); - - describe('sendMessage - Mengirim Pesan', () => { - beforeEach(() => { - mockReq.params.chatId = '1'; - mockReq.body.content = 'Hello'; - }); - - test('berhasil mengirim pesan di chat biasa', async () => { - Chat.findByPk.mockResolvedValue({ - id: 1, - UserId: 1, - partnerId: 2, - isAIChat: false, - save: jest.fn() - }); - Message.create.mockResolvedValue({ id: 1, content: 'Hello' }); - - await ChatController.sendMessage(mockReq, mockRes, mockNext); - - expect(Message.create).toHaveBeenCalledTimes(1); - expect(mockRes.status).toHaveBeenCalledWith(201); - }); - - test('berhasil mengirim pesan dan mendapat respons AI dalam AI chat', async () => { - Chat.findByPk.mockResolvedValue({ - id: 1, - UserId: 1, - isAIChat: true, - save: jest.fn() - }); - Message.create.mockResolvedValueOnce({ id: 1, content: 'Hello' }); - askGemini.mockResolvedValue('AI Response'); - Message.create.mockResolvedValueOnce({ id: 2, content: 'AI Response' }); - - await ChatController.sendMessage(mockReq, mockRes, mockNext); - - expect(Message.create).toHaveBeenCalledTimes(2); - expect(askGemini).toHaveBeenCalled(); - }); - - test('menangani akses tidak sah', async () => { - Chat.findByPk.mockResolvedValue({ - id: 1, - UserId: 3, // Berbeda dari req.user.id - partnerId: 4, - isAIChat: false - }); - - await ChatController.sendMessage(mockReq, mockRes, mockNext); - - expect(Message.create).not.toHaveBeenCalled(); - expect(mockNext).toHaveBeenCalled(); - const error = mockNext.mock.calls[0][0]; - expect(error.name).toBe('Forbidden'); - }); - - test('menangani kasus chat tidak ditemukan', async () => { - Chat.findByPk.mockResolvedValue(null); - - await ChatController.sendMessage(mockReq, mockRes, mockNext); - - expect(Message.create).not.toHaveBeenCalled(); - expect(mockNext).toHaveBeenCalled(); - const error = mockNext.mock.calls[0][0]; - expect(error.name).toBe('NotFound'); - }); - }); -}); \ No newline at end of file diff --git a/tests/unit/postController.test.js b/tests/unit/postController.test.js deleted file mode 100644 index 2038e99..0000000 --- a/tests/unit/postController.test.js +++ /dev/null @@ -1,178 +0,0 @@ -// __tests__/postController.test.js -const PostController = require('../../controllers/postController'); -const { Post, Image, Like, User, Category } = require('../../models'); - -jest.mock('../../models', () => ({ - Post: { - create: jest.fn(), - findAll: jest.fn(), - findByPk: jest.fn(), - }, - Image: { - bulkCreate: jest.fn(), - }, - Like: { - findOne: jest.fn(), - create: jest.fn(), - destroy: jest.fn(), - }, - User: {}, - Category: {}, -})); - -describe('Test Post Controller', () => { - let mockReq; - let mockRes; - let mockNext; - - beforeEach(() => { - jest.clearAllMocks(); - mockReq = { - user: { id: 1 }, - body: {}, - params: {}, - files: [], - }; - mockRes = { - json: jest.fn(), - status: jest.fn().mockReturnThis(), - }; - mockNext = jest.fn(); - }); - - describe('createPost - Membuat Postingan Baru', () => { - test('berhasil membuat post dengan gambar', async () => { - mockReq.body = { content: 'Test post', isPrivate: false, categoryId: 1 }; - mockReq.files = [ - { path: 'gambar1.jpg' }, - { path: 'gambar2.jpg' } - ]; - - Post.create.mockResolvedValue({ id: 1, ...mockReq.body }); - Image.bulkCreate.mockResolvedValue([ - { id: 1, imageUrl: 'gambar1.jpg' }, - { id: 2, imageUrl: 'gambar2.jpg' } - ]); - - await PostController.createPost(mockReq, mockRes, mockNext); - - expect(Post.create).toHaveBeenCalledWith({ - content: 'Test post', - isPrivate: false, - CategoryId: 1, - UserId: 1 - }); - expect(Image.bulkCreate).toHaveBeenCalledWith([ - { imageUrl: 'gambar1.jpg', PostId: 1 }, - { imageUrl: 'gambar2.jpg', PostId: 1 } - ]); - expect(mockRes.status).toHaveBeenCalledWith(201); - expect(mockRes.json).toHaveBeenCalled(); - }); - - test('berhasil membuat post dengan 1 gambar minimal', async () => { - mockReq.body = { content: 'Post teks saja' }; - // At least one image is required by the controller - mockReq.files = [{ path: 'gambar-required.jpg' }]; - - Post.create.mockResolvedValue({ id: 1, ...mockReq.body }); - Image.bulkCreate.mockResolvedValue([{ id: 1, imageUrl: 'gambar-required.jpg' }]); - - await PostController.createPost(mockReq, mockRes, mockNext); - - expect(Post.create).toHaveBeenCalledWith(expect.objectContaining({ - content: 'Post teks saja', - UserId: 1 - })); - expect(Image.bulkCreate).toHaveBeenCalledWith([ - { imageUrl: 'gambar-required.jpg', PostId: 1 } - ]); - expect(mockRes.status).toHaveBeenCalledWith(201); - expect(mockRes.json).toHaveBeenCalled(); - }); - }); - - describe('getAllPublicPosts - Mendapatkan Semua Post Publik', () => { - test('berhasil mendapatkan post publik dengan data terkait', async () => { - const mockPosts = [ - { id: 1, content: 'Post publik 1', User: { username: 'user1' } }, - { id: 2, content: 'Post publik 2', User: { username: 'user2' } } - ]; - Post.findAll.mockResolvedValue(mockPosts); - - await PostController.getAllPublicPosts(mockReq, mockRes, mockNext); - - expect(Post.findAll).toHaveBeenCalledWith({ - where: { isPrivate: false }, - include: expect.any(Array), - order: [['createdAt', 'DESC']] - }); - expect(mockRes.json).toHaveBeenCalledWith(mockPosts); - }); - }); - - describe('updatePost - Mengupdate Postingan', () => { - test('berhasil mengupdate post sendiri', async () => { - mockReq.params.id = '1'; - mockReq.body = { content: 'Konten yang diupdate' }; - const mockPost = { - id: 1, - UserId: 1, - update: jest.fn().mockResolvedValue({ id: 1, ...mockReq.body }) - }; - Post.findByPk.mockResolvedValue(mockPost); - - await PostController.updatePost(mockReq, mockRes, mockNext); - - expect(mockPost.update).toHaveBeenCalledWith(mockReq.body); - // Controller mengembalikan objek dengan shape { message, post } - expect(mockRes.json).toHaveBeenCalledWith(expect.objectContaining({ - post: expect.objectContaining({ id: 1 }) - })); - }); - - test('mencegah update post user lain', async () => { - mockReq.params.id = '1'; - Post.findByPk.mockResolvedValue({ - id: 1, - UserId: 2 - }); - - await PostController.updatePost(mockReq, mockRes, mockNext); - - expect(mockNext).toHaveBeenCalled(); - const error = mockNext.mock.calls[0][0]; - expect(error).toBeDefined(); - expect(error.name).toBe('Unauthorized'); - }); - }); - - describe('toggleLike - Menyukai/Batal Menyukai Post', () => { - test('berhasil menyukai post', async () => { - mockReq.params.id = '1'; - Post.findByPk.mockResolvedValue({ id: 1 }); - Like.findOne.mockResolvedValue(null); - Like.create.mockResolvedValue({ id: 1, UserId: 1, PostId: '1' }); - - await PostController.toggleLike(mockReq, mockRes, mockNext); - - expect(Like.create).toHaveBeenCalledWith({ - UserId: 1, - PostId: '1' - }); - expect(mockRes.json).toHaveBeenCalledWith({ message: 'Post liked' }); - }); - - test('berhasil membatalkan like pada post', async () => { - mockReq.params.id = '1'; - Post.findByPk.mockResolvedValue({ id: 1 }); - const existingLike = { destroy: jest.fn().mockResolvedValue() }; - Like.findOne.mockResolvedValue(existingLike); - - await PostController.toggleLike(mockReq, mockRes, mockNext); - - expect(existingLike.destroy).toHaveBeenCalled(); - expect(mockRes.json).toHaveBeenCalledWith({ message: 'Post unliked' }); - }); - }); -}); diff --git a/tests/unit/userController.error.test.js b/tests/unit/userController.error.test.js deleted file mode 100644 index 00575c4..0000000 --- a/tests/unit/userController.error.test.js +++ /dev/null @@ -1,20 +0,0 @@ -const UserController = require('../../controllers/userController'); - -jest.mock('../../models', () => ({ - User: { - findOne: jest.fn(async () => null), - }, -})); - -jest.mock('bcryptjs', () => ({ compareSync: jest.fn(() => false) })); - -describe('UserController error handling', () => { - test('login calls next when invalid credentials', async () => { - const req = { body: { email: 'no@one.com', password: 'bad' } }; - const res = { status: jest.fn(() => res), json: jest.fn() }; - const next = jest.fn(); - - await UserController.login(req, res, next); - expect(next).toHaveBeenCalled(); - }); -}); From 95eafe447f240a5e427932bf6072ba8892ce682c Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Wed, 15 Oct 2025 23:49:22 +0700 Subject: [PATCH 14/62] Final Coverage --- __tests__/helpers/aiHelper.test.js | 7 + __tests__/post.test.js | 571 ++++++------ app.js | 10 +- controllers/postController.js | 2 +- coverage/clover.xml | 609 +++++++------ coverage/coverage-final.json | 32 +- .../lcov-report/Dummy-Instagram/app.js.html | 152 ++-- .../controllers/aiController.js.html | 58 +- .../controllers/chatController.js.html | 232 ++--- .../Dummy-Instagram/controllers/index.html | 108 +-- .../controllers/postController.js.html | 226 ++--- .../controllers/userController.js.html | 152 ++-- .../Dummy-Instagram/helpers/aiHelper.js.html | 68 +- .../helpers/aiRecommendation.js.html | 104 +-- .../helpers/authMiddleware.js.html | 15 +- .../helpers/cloudinary.js.html | 38 +- .../helpers/handleError.js.html | 78 +- .../Dummy-Instagram/helpers/index.html | 122 +-- .../Dummy-Instagram/helpers/jwt.js.html | 34 +- .../lcov-report/Dummy-Instagram/index.html | 42 +- .../Dummy-Instagram/routes/aiRouter.js.html | 34 +- .../Dummy-Instagram/routes/chatRouter.js.html | 54 +- .../Dummy-Instagram/routes/index.html | 82 +- .../Dummy-Instagram/routes/index.js.html | 54 +- .../Dummy-Instagram/routes/postRouter.js.html | 58 +- .../Dummy-Instagram/routes/userRouter.js.html | 38 +- coverage/lcov-report/index.html | 100 +-- coverage/lcov.info | 845 +++++++++--------- 28 files changed, 1952 insertions(+), 1973 deletions(-) diff --git a/__tests__/helpers/aiHelper.test.js b/__tests__/helpers/aiHelper.test.js index a7c2ce7..31dd4e2 100644 --- a/__tests__/helpers/aiHelper.test.js +++ b/__tests__/helpers/aiHelper.test.js @@ -71,5 +71,12 @@ describe('AI Helper', () => { const clean = cleanText(dirty); expect(clean).toBe('One Two Bold Italic'); }); +test('should handle undefined input gracefully', () => { + const { cleanText } = require('../../helpers/aiHelper'); + const clean = cleanText(); + expect(clean).toBe(''); +}); + + }); diff --git a/__tests__/post.test.js b/__tests__/post.test.js index 4003248..ab555a5 100644 --- a/__tests__/post.test.js +++ b/__tests__/post.test.js @@ -4,338 +4,341 @@ const { Post, Image, Like, User, Category } = require('../models'); jest.mock('../models'); describe('PostController', () => { - describe('createPost', () => { - test('should create a post with images', async () => { - const req = { - user: { id: 1 }, - body: { content: 'Test Post', isPrivate: false, categoryId: 1 }, - files: [{ path: 'image1.jpg' }, { path: 'image2.jpg' }], - }; - const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; - const next = jest.fn(); - const mockPost = { id: 1, content: 'Test Post', UserId: 1 }; - - Post.create.mockResolvedValue(mockPost); - Image.bulkCreate.mockResolvedValue(); - - await PostController.createPost(req, res, next); - - expect(Post.create).toHaveBeenCalledWith({ - content: 'Test Post', - isPrivate: false, - CategoryId: 1, - UserId: 1, - }); - expect(Image.bulkCreate).toHaveBeenCalledWith([ - { imageUrl: 'image1.jpg', PostId: 1 }, - { imageUrl: 'image2.jpg', PostId: 1 }, - ]); - expect(res.status).toHaveBeenCalledWith(201); - expect(res.json).toHaveBeenCalledWith({ message: 'Post created successfully', post: mockPost }); + describe('createPost', () => { + test('should create a post with images', async () => { + const req = { + user: { id: 1 }, + body: { content: 'Test Post', isPrivate: false, categoryId: 1 }, + files: [{ path: 'image1.jpg' }, { path: 'image2.jpg' }], + }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const mockPost = { id: 1, content: 'Test Post', UserId: 1 }; + + Post.create.mockResolvedValue(mockPost); + Image.bulkCreate.mockResolvedValue(); + + await PostController.createPost(req, res, next); + + expect(Post.create).toHaveBeenCalledWith({ + content: 'Test Post', + isPrivate: false, + CategoryId: 1, + UserId: 1, + }); + expect(Image.bulkCreate).toHaveBeenCalledWith([ + { imageUrl: 'image1.jpg', PostId: 1 }, + { imageUrl: 'image2.jpg', PostId: 1 }, + ]); + expect(res.status).toHaveBeenCalledWith(201); + expect(res.json).toHaveBeenCalledWith({ message: 'Post created successfully', post: mockPost }); + }); + + test('should throw BadRequest if no images are provided', async () => { + const req = { + user: { id: 1 }, + body: { content: 'Test Post', isPrivate: false, categoryId: 1 }, + files: [], + }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + + await PostController.createPost(req, res, next); + + expect(next).toHaveBeenCalledWith({ + name: 'BadRequest', + message: 'At least one image is required to create a post.', + }); + }); + + test('should call next with error if Post.create fails', async () => { + const req = { + user: { id: 1 }, + body: { content: 'Test Post', isPrivate: false, categoryId: 1 }, + files: [{ path: 'image1.jpg' }], + }; + const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + + Post.create.mockRejectedValue(error); + + await PostController.createPost(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); }); - test('should throw BadRequest if no images are provided', async () => { - const req = { - user: { id: 1 }, - body: { content: 'Test Post', isPrivate: false, categoryId: 1 }, - files: [], - }; - const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; - const next = jest.fn(); - - await PostController.createPost(req, res, next); - - expect(next).toHaveBeenCalledWith({ - name: 'BadRequest', - message: 'At least one image is required to create a post.', - }); + describe('getAllPublicPosts', () => { + test('should return all public posts', async () => { + const req = {}; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPosts = [ + { id: 1, content: 'Public Post', isPrivate: false, User: { username: 'user1' } }, + ]; + + Post.findAll.mockResolvedValue(mockPosts); + + await PostController.getAllPublicPosts(req, res, next); + + expect(Post.findAll).toHaveBeenCalledWith({ + where: { isPrivate: false }, + include: [ + { model: User, attributes: ['id', 'username', 'profilePic'] }, + { model: Image }, + { model: Category, attributes: ['name'] }, + { model: Like }, + ], + order: [['createdAt', 'DESC']], + }); + expect(res.json).toHaveBeenCalledWith(mockPosts); + }); + + test('should call next with error if findAll fails', async () => { + const req = {}; + const res = { json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + + Post.findAll.mockRejectedValue(error); + + await PostController.getAllPublicPosts(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); }); - test('should call next with error if Post.create fails', async () => { - const req = { - user: { id: 1 }, - body: { content: 'Test Post', isPrivate: false, categoryId: 1 }, - files: [{ path: 'image1.jpg' }], - }; - const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; - const next = jest.fn(); - const error = new Error('Database error'); + describe('getMyPosts', () => { + test('should return all posts for the authenticated user', async () => { + const req = { user: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPosts = [ + { id: 1, content: 'My Post', UserId: 1 }, + ]; - Post.create.mockRejectedValue(error); + Post.findAll.mockResolvedValue(mockPosts); - await PostController.createPost(req, res, next); + await PostController.getMyPosts(req, res, next); - expect(next).toHaveBeenCalledWith(error); - }); - }); - - describe('getAllPublicPosts', () => { - test('should return all public posts', async () => { - const req = {}; - const res = { json: jest.fn() }; - const next = jest.fn(); - const mockPosts = [ - { id: 1, content: 'Public Post', isPrivate: false, User: { username: 'user1' } }, - ]; - - Post.findAll.mockResolvedValue(mockPosts); - - await PostController.getAllPublicPosts(req, res, next); - - expect(Post.findAll).toHaveBeenCalledWith({ - where: { isPrivate: false }, - include: [ - { model: User, attributes: ['id', 'username', 'profilePic'] }, - { model: Image }, - { model: Category, attributes: ['name'] }, - { model: Like }, - ], - order: [['createdAt', 'DESC']], - }); - expect(res.json).toHaveBeenCalledWith(mockPosts); - }); - - test('should call next with error if findAll fails', async () => { - const req = {}; - const res = { json: jest.fn() }; - const next = jest.fn(); - const error = new Error('Database error'); - - Post.findAll.mockRejectedValue(error); - - await PostController.getAllPublicPosts(req, res, next); - - expect(next).toHaveBeenCalledWith(error); - }); - }); - - describe('getMyPosts', () => { - test('should return all posts for the authenticated user', async () => { - const req = { user: { id: 1 } }; - const res = { json: jest.fn() }; - const next = jest.fn(); - const mockPosts = [ - { id: 1, content: 'My Post', UserId: 1 }, - ]; - - Post.findAll.mockResolvedValue(mockPosts); - - await PostController.getMyPosts(req, res, next); - - expect(Post.findAll).toHaveBeenCalledWith({ - where: { UserId: 1 }, - include: [Image, Category, Like], - order: [['createdAt', 'DESC']], - }); - expect(res.json).toHaveBeenCalledWith(mockPosts); - }); - - test('should call next with error if findAll fails', async () => { - const req = { user: { id: 1 } }; - const res = { json: jest.fn() }; - const next = jest.fn(); - const error = new Error('Database error'); - - Post.findAll.mockRejectedValue(error); - - await PostController.getMyPosts(req, res, next); - - expect(next).toHaveBeenCalledWith(error); - }); - }); - - describe('updatePost', () => { - test('should update a post successfully', async () => { - const req = { - user: { id: 1 }, - params: { id: 1 }, - body: { content: 'Updated Post', isPrivate: true, categoryId: 2 }, - }; - const res = { json: jest.fn() }; - const next = jest.fn(); - const mockPost = { id: 1, UserId: 1, update: jest.fn().mockResolvedValue(true) }; - - Post.findByPk.mockResolvedValue(mockPost); - - await PostController.updatePost(req, res, next); - - expect(Post.findByPk).toHaveBeenCalledWith(1); - expect(mockPost.update).toHaveBeenCalledWith({ - content: 'Updated Post', - isPrivate: true, - CategoryId: 2, - }); - expect(res.json).toHaveBeenCalledWith({ message: 'Post updated successfully', post: mockPost }); - }); + expect(Post.findAll).toHaveBeenCalledWith({ + where: { UserId: 1 }, + include: [Image, Category, Like], + order: [['createdAt', 'DESC']], + }); + expect(res.json).toHaveBeenCalledWith(mockPosts); + }); - test('should throw NotFound error if post does not exist', async () => { - const req = { - user: { id: 1 }, - params: { id: 99 }, - body: { content: 'Updated Post' }, - }; - const res = { json: jest.fn() }; - const next = jest.fn(); + test('should call next with error if findAll fails', async () => { + const req = { user: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); - Post.findByPk.mockResolvedValue(null); + Post.findAll.mockRejectedValue(error); - await PostController.updatePost(req, res, next); + await PostController.getMyPosts(req, res, next); - expect(next).toHaveBeenCalledWith({ name: 'NotFound' }); + expect(next).toHaveBeenCalledWith(error); + }); }); - test('should throw Unauthorized error if user does not own the post', async () => { - const req = { - user: { id: 2 }, - params: { id: 1 }, - body: { content: 'Updated Post' }, - }; - const res = { json: jest.fn() }; - const next = jest.fn(); - const mockPost = { id: 1, UserId: 1, update: jest.fn() }; - - Post.findByPk.mockResolvedValue(mockPost); - - await PostController.updatePost(req, res, next); - - expect(next).toHaveBeenCalledWith({ name: 'Unauthorized' }); + describe('updatePost', () => { + test('should update a post successfully', async () => { + const req = { + user: { id: 1 }, + params: { id: 1 }, + body: { content: 'Updated Post', isPrivate: true, categoryId: 2 }, + }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPost = { id: 1, UserId: 1, update: jest.fn().mockResolvedValue(true) }; + + Post.findByPk.mockResolvedValue(mockPost); + + await PostController.updatePost(req, res, next); + + expect(Post.findByPk).toHaveBeenCalledWith(1); + expect(mockPost.update).toHaveBeenCalledWith({ + content: 'Updated Post', + isPrivate: true, + CategoryId: 2, + }); + expect(res.json).toHaveBeenCalledWith({ message: 'Post updated successfully', post: mockPost }); + }); + + test('should throw NotFound error if post does not exist', async () => { + const req = { + user: { id: 1 }, + params: { id: 99 }, + body: { content: 'Updated Post' }, + }; + const res = { json: jest.fn() }; + const next = jest.fn(); + + Post.findByPk.mockResolvedValue(null); + + await PostController.updatePost(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: 'NotFound' }); + }); + + test('should throw Unauthorized error if user does not own the post', async () => { + const req = { + user: { id: 2 }, + params: { id: 1 }, + body: { content: 'Updated Post' }, + }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPost = { id: 1, UserId: 1, update: jest.fn() }; + + Post.findByPk.mockResolvedValue(mockPost); + + await PostController.updatePost(req, res, next); + + expect(next).toHaveBeenCalledWith({ name: 'Unauthorized' }); + }); + + test('should call next with error if update fails', async () => { + const req = { + user: { id: 1 }, + params: { id: 1 }, + body: { content: 'Updated Post' }, + }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + const mockPost = { id: 1, UserId: 1, update: jest.fn().mockRejectedValue(error) }; + + Post.findByPk.mockResolvedValue(mockPost); + + await PostController.updatePost(req, res, next); + + expect(next).toHaveBeenCalledWith(error); + }); }); - test('should call next with error if update fails', async () => { - const req = { - user: { id: 1 }, - params: { id: 1 }, - body: { content: 'Updated Post' }, - }; - const res = { json: jest.fn() }; - const next = jest.fn(); - const error = new Error('Database error'); - const mockPost = { id: 1, UserId: 1, update: jest.fn().mockRejectedValue(error) }; + describe('deletePost', () => { + test('should delete a post successfully', async () => { + const req = { user: { id: 1 }, params: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPost = { id: 1, UserId: 1, destroy: jest.fn().mockResolvedValue(true) }; - Post.findByPk.mockResolvedValue(mockPost); + Post.findByPk.mockResolvedValue(mockPost); - await PostController.updatePost(req, res, next); + await PostController.deletePost(req, res, next); - expect(next).toHaveBeenCalledWith(error); - }); - }); + expect(Post.findByPk).toHaveBeenCalledWith(1); + expect(mockPost.destroy).toHaveBeenCalled(); + expect(res.json).toHaveBeenCalledWith({ message: 'Post deleted successfully' }); + }); - describe('deletePost', () => { - test('should delete a post successfully', async () => { - const req = { user: { id: 1 }, params: { id: 1 } }; - const res = { json: jest.fn() }; - const next = jest.fn(); - const mockPost = { id: 1, UserId: 1, destroy: jest.fn().mockResolvedValue(true) }; + test('should throw NotFound error if post does not exist', async () => { + const req = { user: { id: 1 }, params: { id: 99 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); - Post.findByPk.mockResolvedValue(mockPost); + Post.findByPk.mockResolvedValue(null); - await PostController.deletePost(req, res, next); + await PostController.deletePost(req, res, next); - expect(Post.findByPk).toHaveBeenCalledWith(1); - expect(mockPost.destroy).toHaveBeenCalled(); - expect(res.json).toHaveBeenCalledWith({ message: 'Post deleted successfully' }); - }); + expect(next).toHaveBeenCalledWith({ name: 'NotFound' }); + }); - test('should throw NotFound error if post does not exist', async () => { - const req = { user: { id: 1 }, params: { id: 99 } }; - const res = { json: jest.fn() }; - const next = jest.fn(); + test('should throw Unauthorized error if user does not own the post', async () => { + const req = { user: { id: 2 }, params: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPost = { id: 1, UserId: 1, destroy: jest.fn() }; - Post.findByPk.mockResolvedValue(null); + Post.findByPk.mockResolvedValue(mockPost); - await PostController.deletePost(req, res, next); + await PostController.deletePost(req, res, next); - expect(next).toHaveBeenCalledWith({ name: 'NotFound' }); - }); + expect(next).toHaveBeenCalledWith({ name: 'Unauthorized' }); + }); - test('should throw Unauthorized error if user does not own the post', async () => { - const req = { user: { id: 2 }, params: { id: 1 } }; - const res = { json: jest.fn() }; - const next = jest.fn(); - const mockPost = { id: 1, UserId: 1, destroy: jest.fn() }; + test('should call next with error if destroy fails', async () => { + const req = { user: { id: 1 }, params: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); + const mockPost = { id: 1, UserId: 1, destroy: jest.fn().mockRejectedValue(error) }; - Post.findByPk.mockResolvedValue(mockPost); + Post.findByPk.mockResolvedValue(mockPost); - await PostController.deletePost(req, res, next); + await PostController.deletePost(req, res, next); - expect(next).toHaveBeenCalledWith({ name: 'Unauthorized' }); + expect(next).toHaveBeenCalledWith(error); + }); }); - test('should call next with error if destroy fails', async () => { - const req = { user: { id: 1 }, params: { id: 1 } }; - const res = { json: jest.fn() }; - const next = jest.fn(); - const error = new Error('Database error'); - const mockPost = { id: 1, UserId: 1, destroy: jest.fn().mockRejectedValue(error) }; + describe('toggleLike', () => { + test('should like a post if not already liked', async () => { + const req = { user: { id: 1 }, params: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPost = { id: 1 }; - Post.findByPk.mockResolvedValue(mockPost); + Post.findByPk.mockResolvedValue(mockPost); + Like.findOne.mockResolvedValue(null); + Like.create.mockResolvedValue(true); - await PostController.deletePost(req, res, next); + await PostController.toggleLike(req, res, next); - expect(next).toHaveBeenCalledWith(error); - }); - }); + expect(Post.findByPk).toHaveBeenCalledWith(1); + expect(Like.findOne).toHaveBeenCalledWith({ where: { UserId: 1, PostId: 1 } }); + expect(Like.create).toHaveBeenCalledWith({ UserId: 1, PostId: 1 }); + expect(res.json).toHaveBeenCalledWith({ message: 'Post liked' }); + }); - describe('toggleLike', () => { - test('should like a post if not already liked', async () => { - const req = { user: { id: 1 }, params: { id: 1 } }; - const res = { json: jest.fn() }; - const next = jest.fn(); - const mockPost = { id: 1 }; + test('should unlike a post if already liked', async () => { + const req = { user: { id: 1 }, params: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const mockPost = { id: 1 }; + const mockLike = { destroy: jest.fn().mockResolvedValue(true) }; - Post.findByPk.mockResolvedValue(mockPost); - Like.findOne.mockResolvedValue(null); - Like.create.mockResolvedValue(true); + Post.findByPk.mockResolvedValue(mockPost); + Like.findOne.mockResolvedValue(mockLike); - await PostController.toggleLike(req, res, next); + await PostController.toggleLike(req, res, next); - expect(Post.findByPk).toHaveBeenCalledWith(1); - expect(Like.findOne).toHaveBeenCalledWith({ where: { UserId: 1, PostId: 1 } }); - expect(Like.create).toHaveBeenCalledWith({ UserId: 1, PostId: 1 }); - expect(res.json).toHaveBeenCalledWith({ message: 'Post liked' }); - }); + expect(Post.findByPk).toHaveBeenCalledWith(1); + expect(Like.findOne).toHaveBeenCalledWith({ where: { UserId: 1, PostId: 1 } }); + expect(mockLike.destroy).toHaveBeenCalled(); + expect(res.json).toHaveBeenCalledWith({ message: 'Post unliked' }); + }); - test('should unlike a post if already liked', async () => { - const req = { user: { id: 1 }, params: { id: 1 } }; - const res = { json: jest.fn() }; - const next = jest.fn(); - const mockPost = { id: 1 }; - const mockLike = { destroy: jest.fn().mockResolvedValue(true) }; + test('should throw NotFound error if post does not exist', async () => { + const req = { user: { id: 1 }, params: { id: 99 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); - Post.findByPk.mockResolvedValue(mockPost); - Like.findOne.mockResolvedValue(mockLike); + Post.findByPk.mockResolvedValue(null); - await PostController.toggleLike(req, res, next); + await PostController.toggleLike(req, res, next); - expect(Post.findByPk).toHaveBeenCalledWith(1); - expect(Like.findOne).toHaveBeenCalledWith({ where: { UserId: 1, PostId: 1 } }); - expect(mockLike.destroy).toHaveBeenCalled(); - expect(res.json).toHaveBeenCalledWith({ message: 'Post unliked' }); - }); + expect(next).toHaveBeenCalledWith({ name: 'NotFound' }); + }); - test('should throw NotFound error if post does not exist', async () => { - const req = { user: { id: 1 }, params: { id: 99 } }; - const res = { json: jest.fn() }; - const next = jest.fn(); + test('should call next with error if toggleLike fails', async () => { + const req = { user: { id: 1 }, params: { id: 1 } }; + const res = { json: jest.fn() }; + const next = jest.fn(); + const error = new Error('Database error'); - Post.findByPk.mockResolvedValue(null); + Post.findByPk.mockRejectedValue(error); - await PostController.toggleLike(req, res, next); + await PostController.toggleLike(req, res, next); - expect(next).toHaveBeenCalledWith({ name: 'NotFound' }); + expect(next).toHaveBeenCalledWith(error); + }); }); - test('should call next with error if toggleLike fails', async () => { - const req = { user: { id: 1 }, params: { id: 1 } }; - const res = { json: jest.fn() }; - const next = jest.fn(); - const error = new Error('Database error'); + - Post.findByPk.mockRejectedValue(error); - - await PostController.toggleLike(req, res, next); - - expect(next).toHaveBeenCalledWith(error); - }); - }); }); diff --git a/app.js b/app.js index 36211e7..f3119e6 100644 --- a/app.js +++ b/app.js @@ -39,21 +39,19 @@ io.on('connection', (socket) => { }); socket.on('send_message', (messageData) => { - io.to(`chat_${messageData.chatId}`).emit('new_message', messageData); + io.to(`chat_${messageData.chatId}`).emit('new_message', messageData); //comment untuk npx jest }); socket.on('user_typing', (typingData) => { - io.to(`chat_${typingData.chatId}`).emit('typing_status', typingData); + io.to(`chat_${typingData.chatId}`).emit('typing_status', typingData); //comment untuk npx jest }); socket.on('disconnect', () => { - console.log('โŒ User disconnected:', socket.id); + console.log('โŒ User disconnected:', socket.id); //comment untuk npx jest }); }); - - -if (process.env.NODE_ENV !== 'test') { +if (process.env.NODE_ENV !== 'test') { //comment untuk npx jest server.listen(port, () => { console.log(`App listening on port http://localhost:${port}`); }); diff --git a/controllers/postController.js b/controllers/postController.js index 35a984f..a5f7e61 100644 --- a/controllers/postController.js +++ b/controllers/postController.js @@ -15,7 +15,7 @@ class PostController { const post = await Post.create({ content, isPrivate, - CategoryId: categoryId || null, + CategoryId: categoryId, UserId: req.user.id, }); diff --git a/coverage/clover.xml b/coverage/clover.xml index 15123d9..7614a8d 100644 --- a/coverage/clover.xml +++ b/coverage/clover.xml @@ -1,244 +1,238 @@ - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - + + + + @@ -250,112 +244,111 @@ - - - - - - + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - - + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - + + + + + + + + diff --git a/coverage/coverage-final.json b/coverage/coverage-final.json index 7d36cb4..bd1d3f0 100644 --- a/coverage/coverage-final.json +++ b/coverage/coverage-final.json @@ -1,17 +1,17 @@ -{"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}},"1":{"start":{"line":2,"column":16},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":12},"end":{"line":3,"column":21}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"4":{"start":{"line":5,"column":20},"end":{"line":5,"column":52}},"5":{"start":{"line":6,"column":15},"end":{"line":6,"column":34}},"6":{"start":{"line":7,"column":13},"end":{"line":7,"column":28}},"7":{"start":{"line":9,"column":13},"end":{"line":9,"column":28}},"8":{"start":{"line":10,"column":15},"end":{"line":10,"column":37}},"9":{"start":{"line":11,"column":19},"end":{"line":11,"column":39}},"10":{"start":{"line":12,"column":11},"end":{"line":16,"column":2}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}},"12":{"start":{"line":21,"column":0},"end":{"line":21,"column":16}},"13":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}},"14":{"start":{"line":23,"column":0},"end":{"line":23,"column":48}},"15":{"start":{"line":24,"column":0},"end":{"line":24,"column":34}},"16":{"start":{"line":27,"column":0},"end":{"line":27,"column":21}},"17":{"start":{"line":31,"column":0},"end":{"line":31,"column":21}},"18":{"start":{"line":34,"column":0},"end":{"line":52,"column":3}},"19":{"start":{"line":35,"column":2},"end":{"line":35,"column":46}},"20":{"start":{"line":37,"column":2},"end":{"line":39,"column":5}},"21":{"start":{"line":38,"column":4},"end":{"line":38,"column":34}},"22":{"start":{"line":41,"column":2},"end":{"line":43,"column":5}},"23":{"start":{"line":42,"column":4},"end":{"line":42,"column":73}},"24":{"start":{"line":45,"column":2},"end":{"line":47,"column":5}},"25":{"start":{"line":46,"column":4},"end":{"line":46,"column":73}},"26":{"start":{"line":49,"column":2},"end":{"line":51,"column":5}},"27":{"start":{"line":50,"column":4},"end":{"line":50,"column":51}},"28":{"start":{"line":56,"column":0},"end":{"line":60,"column":1}},"29":{"start":{"line":57,"column":2},"end":{"line":59,"column":5}},"30":{"start":{"line":58,"column":4},"end":{"line":58,"column":66}},"31":{"start":{"line":62,"column":0},"end":{"line":62,"column":21}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":34,"column":20},"end":{"line":34,"column":21}},"loc":{"start":{"line":34,"column":32},"end":{"line":52,"column":1}},"line":34},"1":{"name":"(anonymous_1)","decl":{"start":{"line":37,"column":25},"end":{"line":37,"column":26}},"loc":{"start":{"line":37,"column":37},"end":{"line":39,"column":3}},"line":37},"2":{"name":"(anonymous_2)","decl":{"start":{"line":41,"column":28},"end":{"line":41,"column":29}},"loc":{"start":{"line":41,"column":45},"end":{"line":43,"column":3}},"line":41},"3":{"name":"(anonymous_3)","decl":{"start":{"line":45,"column":27},"end":{"line":45,"column":28}},"loc":{"start":{"line":45,"column":43},"end":{"line":47,"column":3}},"line":45},"4":{"name":"(anonymous_4)","decl":{"start":{"line":49,"column":26},"end":{"line":49,"column":27}},"loc":{"start":{"line":49,"column":32},"end":{"line":51,"column":3}},"line":49},"5":{"name":"(anonymous_5)","decl":{"start":{"line":57,"column":22},"end":{"line":57,"column":23}},"loc":{"start":{"line":57,"column":28},"end":{"line":59,"column":3}},"line":57}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"type":"binary-expr","locations":[{"start":{"line":4,"column":13},"end":{"line":4,"column":29}},{"start":{"line":4,"column":33},"end":{"line":4,"column":37}}],"line":4},"1":{"loc":{"start":{"line":56,"column":0},"end":{"line":60,"column":1}},"type":"if","locations":[{"start":{"line":56,"column":0},"end":{"line":60,"column":1}},{"start":{},"end":{}}],"line":56}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0},"b":{"0":[0,0],"1":[0,0]}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js","statementMap":{"0":{"start":{"line":1,"column":33},"end":{"line":1,"column":71}},"1":{"start":{"line":5,"column":4},"end":{"line":21,"column":5}},"2":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"3":{"start":{"line":8,"column":8},"end":{"line":8,"column":39}},"4":{"start":{"line":11,"column":21},"end":{"line":11,"column":32}},"5":{"start":{"line":12,"column":20},"end":{"line":12,"column":54}},"6":{"start":{"line":14,"column":6},"end":{"line":18,"column":9}},"7":{"start":{"line":20,"column":6},"end":{"line":20,"column":16}},"8":{"start":{"line":25,"column":0},"end":{"line":25,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":4,"column":2},"end":{"line":4,"column":3}},"loc":{"start":{"line":4,"column":50},"end":{"line":22,"column":3}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"type":"if","locations":[{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":10},"end":{"line":7,"column":35}},"type":"binary-expr","locations":[{"start":{"line":7,"column":10},"end":{"line":7,"column":19}},{"start":{"line":7,"column":23},"end":{"line":7,"column":35}}],"line":7}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0},"f":{"0":0},"b":{"0":[0,0],"1":[0,0]}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js","statementMap":{"0":{"start":{"line":1,"column":43},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":24}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":52}},"3":{"start":{"line":8,"column":8},"end":{"line":34,"column":9}},"4":{"start":{"line":9,"column":34},"end":{"line":9,"column":42}},"5":{"start":{"line":10,"column":27},"end":{"line":10,"column":38}},"6":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"7":{"start":{"line":13,"column":16},"end":{"line":13,"column":97}},"8":{"start":{"line":17,"column":36},"end":{"line":29,"column":14}},"9":{"start":{"line":31,"column":12},"end":{"line":31,"column":55}},"10":{"start":{"line":33,"column":12},"end":{"line":33,"column":22}},"11":{"start":{"line":39,"column":8},"end":{"line":55,"column":9}},"12":{"start":{"line":40,"column":27},"end":{"line":40,"column":38}},"13":{"start":{"line":41,"column":26},"end":{"line":50,"column":14}},"14":{"start":{"line":52,"column":12},"end":{"line":52,"column":28}},"15":{"start":{"line":54,"column":12},"end":{"line":54,"column":22}},"16":{"start":{"line":60,"column":8},"end":{"line":79,"column":9}},"17":{"start":{"line":61,"column":31},"end":{"line":61,"column":41}},"18":{"start":{"line":62,"column":27},"end":{"line":62,"column":38}},"19":{"start":{"line":65,"column":25},"end":{"line":65,"column":52}},"20":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"21":{"start":{"line":67,"column":16},"end":{"line":67,"column":44}},"22":{"start":{"line":70,"column":29},"end":{"line":74,"column":14}},"23":{"start":{"line":76,"column":12},"end":{"line":76,"column":31}},"24":{"start":{"line":78,"column":12},"end":{"line":78,"column":22}},"25":{"start":{"line":83,"column":8},"end":{"line":99,"column":9}},"26":{"start":{"line":84,"column":27},"end":{"line":84,"column":38}},"27":{"start":{"line":85,"column":36},"end":{"line":95,"column":14}},"28":{"start":{"line":96,"column":12},"end":{"line":96,"column":55}},"29":{"start":{"line":98,"column":12},"end":{"line":98,"column":22}},"30":{"start":{"line":104,"column":8},"end":{"line":147,"column":9}},"31":{"start":{"line":105,"column":31},"end":{"line":105,"column":41}},"32":{"start":{"line":106,"column":32},"end":{"line":106,"column":40}},"33":{"start":{"line":107,"column":27},"end":{"line":107,"column":38}},"34":{"start":{"line":108,"column":23},"end":{"line":108,"column":46}},"35":{"start":{"line":110,"column":25},"end":{"line":110,"column":52}},"36":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"37":{"start":{"line":112,"column":16},"end":{"line":112,"column":70}},"38":{"start":{"line":117,"column":33},"end":{"line":117,"column":84}},"39":{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},"40":{"start":{"line":119,"column":16},"end":{"line":119,"column":99}},"41":{"start":{"line":123,"column":32},"end":{"line":127,"column":14}},"42":{"start":{"line":129,"column":12},"end":{"line":129,"column":73}},"43":{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},"44":{"start":{"line":132,"column":39},"end":{"line":132,"column":63}},"45":{"start":{"line":134,"column":34},"end":{"line":138,"column":18}},"46":{"start":{"line":140,"column":16},"end":{"line":140,"column":75}},"47":{"start":{"line":143,"column":12},"end":{"line":143,"column":30}},"48":{"start":{"line":144,"column":12},"end":{"line":144,"column":46}},"49":{"start":{"line":146,"column":12},"end":{"line":146,"column":22}},"50":{"start":{"line":151,"column":0},"end":{"line":151,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":4},"end":{"line":7,"column":5}},"loc":{"start":{"line":7,"column":49},"end":{"line":35,"column":5}},"line":7},"1":{"name":"(anonymous_1)","decl":{"start":{"line":38,"column":4},"end":{"line":38,"column":5}},"loc":{"start":{"line":38,"column":46},"end":{"line":56,"column":5}},"line":38},"2":{"name":"(anonymous_2)","decl":{"start":{"line":59,"column":4},"end":{"line":59,"column":5}},"loc":{"start":{"line":59,"column":49},"end":{"line":80,"column":5}},"line":59},"3":{"name":"(anonymous_3)","decl":{"start":{"line":82,"column":4},"end":{"line":82,"column":5}},"loc":{"start":{"line":82,"column":46},"end":{"line":100,"column":5}},"line":82},"4":{"name":"(anonymous_4)","decl":{"start":{"line":103,"column":4},"end":{"line":103,"column":5}},"loc":{"start":{"line":103,"column":45},"end":{"line":148,"column":5}},"line":103}},"branchMap":{"0":{"loc":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"type":"if","locations":[{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},{"start":{},"end":{}}],"line":12},"1":{"loc":{"start":{"line":31,"column":23},"end":{"line":31,"column":42}},"type":"cond-expr","locations":[{"start":{"line":31,"column":33},"end":{"line":31,"column":36}},{"start":{"line":31,"column":39},"end":{"line":31,"column":42}}],"line":31},"2":{"loc":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"type":"if","locations":[{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},{"start":{},"end":{}}],"line":66},"3":{"loc":{"start":{"line":66,"column":16},"end":{"line":66,"column":78}},"type":"binary-expr","locations":[{"start":{"line":66,"column":16},"end":{"line":66,"column":21}},{"start":{"line":66,"column":26},"end":{"line":66,"column":48}},{"start":{"line":66,"column":52},"end":{"line":66,"column":77}}],"line":66},"4":{"loc":{"start":{"line":96,"column":23},"end":{"line":96,"column":42}},"type":"cond-expr","locations":[{"start":{"line":96,"column":33},"end":{"line":96,"column":36}},{"start":{"line":96,"column":39},"end":{"line":96,"column":42}}],"line":96},"5":{"loc":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"type":"if","locations":[{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},{"start":{},"end":{}}],"line":111},"6":{"loc":{"start":{"line":117,"column":33},"end":{"line":117,"column":84}},"type":"binary-expr","locations":[{"start":{"line":117,"column":33},"end":{"line":117,"column":55}},{"start":{"line":117,"column":59},"end":{"line":117,"column":84}}],"line":117},"7":{"loc":{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},"type":"if","locations":[{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},{"start":{},"end":{}}],"line":118},"8":{"loc":{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},"type":"if","locations":[{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},{"start":{},"end":{}}],"line":131}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0]}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js","statementMap":{"0":{"start":{"line":1,"column":46},"end":{"line":1,"column":66}},"1":{"start":{"line":6,"column":4},"end":{"line":33,"column":5}},"2":{"start":{"line":7,"column":49},"end":{"line":7,"column":57}},"3":{"start":{"line":10,"column":6},"end":{"line":12,"column":7}},"4":{"start":{"line":11,"column":8},"end":{"line":11,"column":98}},"5":{"start":{"line":15,"column":19},"end":{"line":20,"column":8}},"6":{"start":{"line":23,"column":21},"end":{"line":26,"column":9}},"7":{"start":{"line":23,"column":46},"end":{"line":26,"column":7}},"8":{"start":{"line":28,"column":6},"end":{"line":28,"column":37}},"9":{"start":{"line":30,"column":6},"end":{"line":30,"column":75}},"10":{"start":{"line":32,"column":6},"end":{"line":32,"column":16}},"11":{"start":{"line":38,"column":4},"end":{"line":52,"column":5}},"12":{"start":{"line":39,"column":20},"end":{"line":48,"column":8}},"13":{"start":{"line":49,"column":6},"end":{"line":49,"column":22}},"14":{"start":{"line":51,"column":6},"end":{"line":51,"column":16}},"15":{"start":{"line":57,"column":4},"end":{"line":66,"column":5}},"16":{"start":{"line":58,"column":20},"end":{"line":62,"column":8}},"17":{"start":{"line":63,"column":6},"end":{"line":63,"column":22}},"18":{"start":{"line":65,"column":6},"end":{"line":65,"column":16}},"19":{"start":{"line":71,"column":4},"end":{"line":83,"column":5}},"20":{"start":{"line":72,"column":21},"end":{"line":72,"column":31}},"21":{"start":{"line":73,"column":49},"end":{"line":73,"column":57}},"22":{"start":{"line":75,"column":19},"end":{"line":75,"column":42}},"23":{"start":{"line":76,"column":6},"end":{"line":76,"column":44}},"24":{"start":{"line":76,"column":17},"end":{"line":76,"column":44}},"25":{"start":{"line":77,"column":6},"end":{"line":77,"column":70}},"26":{"start":{"line":77,"column":39},"end":{"line":77,"column":70}},"27":{"start":{"line":79,"column":6},"end":{"line":79,"column":72}},"28":{"start":{"line":80,"column":6},"end":{"line":80,"column":63}},"29":{"start":{"line":82,"column":6},"end":{"line":82,"column":16}},"30":{"start":{"line":88,"column":4},"end":{"line":98,"column":5}},"31":{"start":{"line":89,"column":21},"end":{"line":89,"column":31}},"32":{"start":{"line":90,"column":19},"end":{"line":90,"column":42}},"33":{"start":{"line":91,"column":6},"end":{"line":91,"column":44}},"34":{"start":{"line":91,"column":17},"end":{"line":91,"column":44}},"35":{"start":{"line":92,"column":6},"end":{"line":92,"column":70}},"36":{"start":{"line":92,"column":39},"end":{"line":92,"column":70}},"37":{"start":{"line":94,"column":6},"end":{"line":94,"column":27}},"38":{"start":{"line":95,"column":6},"end":{"line":95,"column":57}},"39":{"start":{"line":97,"column":6},"end":{"line":97,"column":16}},"40":{"start":{"line":103,"column":4},"end":{"line":123,"column":5}},"41":{"start":{"line":104,"column":21},"end":{"line":104,"column":31}},"42":{"start":{"line":105,"column":19},"end":{"line":105,"column":42}},"43":{"start":{"line":106,"column":6},"end":{"line":106,"column":44}},"44":{"start":{"line":106,"column":17},"end":{"line":106,"column":44}},"45":{"start":{"line":108,"column":27},"end":{"line":110,"column":8}},"46":{"start":{"line":113,"column":6},"end":{"line":119,"column":7}},"47":{"start":{"line":114,"column":8},"end":{"line":114,"column":37}},"48":{"start":{"line":115,"column":8},"end":{"line":115,"column":33}},"49":{"start":{"line":117,"column":8},"end":{"line":117,"column":63}},"50":{"start":{"line":118,"column":8},"end":{"line":118,"column":31}},"51":{"start":{"line":120,"column":6},"end":{"line":120,"column":28}},"52":{"start":{"line":122,"column":6},"end":{"line":122,"column":16}},"53":{"start":{"line":127,"column":0},"end":{"line":127,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":2},"end":{"line":5,"column":3}},"loc":{"start":{"line":5,"column":42},"end":{"line":34,"column":3}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":23,"column":35},"end":{"line":23,"column":36}},"loc":{"start":{"line":23,"column":46},"end":{"line":26,"column":7}},"line":23},"2":{"name":"(anonymous_2)","decl":{"start":{"line":37,"column":2},"end":{"line":37,"column":3}},"loc":{"start":{"line":37,"column":49},"end":{"line":53,"column":3}},"line":37},"3":{"name":"(anonymous_3)","decl":{"start":{"line":56,"column":2},"end":{"line":56,"column":3}},"loc":{"start":{"line":56,"column":42},"end":{"line":67,"column":3}},"line":56},"4":{"name":"(anonymous_4)","decl":{"start":{"line":70,"column":2},"end":{"line":70,"column":3}},"loc":{"start":{"line":70,"column":42},"end":{"line":84,"column":3}},"line":70},"5":{"name":"(anonymous_5)","decl":{"start":{"line":87,"column":2},"end":{"line":87,"column":3}},"loc":{"start":{"line":87,"column":42},"end":{"line":99,"column":3}},"line":87},"6":{"name":"(anonymous_6)","decl":{"start":{"line":102,"column":2},"end":{"line":102,"column":3}},"loc":{"start":{"line":102,"column":42},"end":{"line":124,"column":3}},"line":102}},"branchMap":{"0":{"loc":{"start":{"line":10,"column":6},"end":{"line":12,"column":7}},"type":"if","locations":[{"start":{"line":10,"column":6},"end":{"line":12,"column":7}},{"start":{},"end":{}}],"line":10},"1":{"loc":{"start":{"line":10,"column":10},"end":{"line":10,"column":46}},"type":"binary-expr","locations":[{"start":{"line":10,"column":10},"end":{"line":10,"column":20}},{"start":{"line":10,"column":24},"end":{"line":10,"column":46}}],"line":10},"2":{"loc":{"start":{"line":18,"column":20},"end":{"line":18,"column":38}},"type":"binary-expr","locations":[{"start":{"line":18,"column":20},"end":{"line":18,"column":30}},{"start":{"line":18,"column":34},"end":{"line":18,"column":38}}],"line":18},"3":{"loc":{"start":{"line":76,"column":6},"end":{"line":76,"column":44}},"type":"if","locations":[{"start":{"line":76,"column":6},"end":{"line":76,"column":44}},{"start":{},"end":{}}],"line":76},"4":{"loc":{"start":{"line":77,"column":6},"end":{"line":77,"column":70}},"type":"if","locations":[{"start":{"line":77,"column":6},"end":{"line":77,"column":70}},{"start":{},"end":{}}],"line":77},"5":{"loc":{"start":{"line":91,"column":6},"end":{"line":91,"column":44}},"type":"if","locations":[{"start":{"line":91,"column":6},"end":{"line":91,"column":44}},{"start":{},"end":{}}],"line":91},"6":{"loc":{"start":{"line":92,"column":6},"end":{"line":92,"column":70}},"type":"if","locations":[{"start":{"line":92,"column":6},"end":{"line":92,"column":70}},{"start":{},"end":{}}],"line":92},"7":{"loc":{"start":{"line":106,"column":6},"end":{"line":106,"column":44}},"type":"if","locations":[{"start":{"line":106,"column":6},"end":{"line":106,"column":44}},{"start":{},"end":{}}],"line":106},"8":{"loc":{"start":{"line":113,"column":6},"end":{"line":119,"column":7}},"type":"if","locations":[{"start":{"line":113,"column":6},"end":{"line":119,"column":7}},{"start":{"line":116,"column":13},"end":{"line":119,"column":7}}],"line":113}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0]}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js","statementMap":{"0":{"start":{"line":1,"column":17},"end":{"line":1,"column":37}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":47}},"3":{"start":{"line":4,"column":25},"end":{"line":4,"column":55}},"4":{"start":{"line":5,"column":15},"end":{"line":5,"column":33}},"5":{"start":{"line":10,"column":8},"end":{"line":20,"column":9}},"6":{"start":{"line":11,"column":50},"end":{"line":11,"column":58}},"7":{"start":{"line":12,"column":28},"end":{"line":12,"column":76}},"8":{"start":{"line":13,"column":12},"end":{"line":17,"column":15}},"9":{"start":{"line":19,"column":12},"end":{"line":19,"column":22}},"10":{"start":{"line":24,"column":8},"end":{"line":44,"column":9}},"11":{"start":{"line":25,"column":40},"end":{"line":25,"column":48}},"12":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"13":{"start":{"line":27,"column":16},"end":{"line":27,"column":89}},"14":{"start":{"line":30,"column":25},"end":{"line":30,"column":65}},"15":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"16":{"start":{"line":32,"column":16},"end":{"line":32,"column":47}},"17":{"start":{"line":35,"column":36},"end":{"line":35,"column":79}},"18":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"19":{"start":{"line":37,"column":16},"end":{"line":37,"column":47}},"20":{"start":{"line":40,"column":26},"end":{"line":40,"column":52}},"21":{"start":{"line":41,"column":12},"end":{"line":41,"column":58}},"22":{"start":{"line":43,"column":12},"end":{"line":43,"column":22}},"23":{"start":{"line":48,"column":8},"end":{"line":73,"column":9}},"24":{"start":{"line":49,"column":37},"end":{"line":49,"column":45}},"25":{"start":{"line":51,"column":27},"end":{"line":54,"column":14}},"26":{"start":{"line":55,"column":28},"end":{"line":55,"column":47}},"27":{"start":{"line":57,"column":36},"end":{"line":66,"column":14}},"28":{"start":{"line":68,"column":33},"end":{"line":68,"column":59}},"29":{"start":{"line":69,"column":12},"end":{"line":69,"column":51}},"30":{"start":{"line":72,"column":12},"end":{"line":72,"column":22}},"31":{"start":{"line":77,"column":0},"end":{"line":77,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":9,"column":4},"end":{"line":9,"column":5}},"loc":{"start":{"line":9,"column":42},"end":{"line":21,"column":5}},"line":9},"1":{"name":"(anonymous_1)","decl":{"start":{"line":23,"column":4},"end":{"line":23,"column":5}},"loc":{"start":{"line":23,"column":39},"end":{"line":45,"column":5}},"line":23},"2":{"name":"(anonymous_2)","decl":{"start":{"line":47,"column":4},"end":{"line":47,"column":5}},"loc":{"start":{"line":47,"column":46},"end":{"line":74,"column":5}},"line":47}},"branchMap":{"0":{"loc":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"type":"if","locations":[{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},{"start":{},"end":{}}],"line":26},"1":{"loc":{"start":{"line":26,"column":16},"end":{"line":26,"column":35}},"type":"binary-expr","locations":[{"start":{"line":26,"column":16},"end":{"line":26,"column":22}},{"start":{"line":26,"column":26},"end":{"line":26,"column":35}}],"line":26},"2":{"loc":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"type":"if","locations":[{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},{"start":{},"end":{}}],"line":31},"3":{"loc":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"type":"if","locations":[{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},{"start":{},"end":{}}],"line":36}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0},"f":{"0":0,"1":0,"2":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0]}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":3,"column":14},"end":{"line":3,"column":64}},"2":{"start":{"line":4,"column":14},"end":{"line":4,"column":67}},"3":{"start":{"line":8,"column":2},"end":{"line":21,"column":12}},"4":{"start":{"line":25,"column":2},"end":{"line":32,"column":3}},"5":{"start":{"line":26,"column":19},"end":{"line":26,"column":54}},"6":{"start":{"line":27,"column":20},"end":{"line":27,"column":42}},"7":{"start":{"line":28,"column":4},"end":{"line":28,"column":30}},"8":{"start":{"line":30,"column":4},"end":{"line":30,"column":47}},"9":{"start":{"line":31,"column":4},"end":{"line":31,"column":63}},"10":{"start":{"line":35,"column":0},"end":{"line":35,"column":42}}},"fnMap":{"0":{"name":"cleanText","decl":{"start":{"line":7,"column":9},"end":{"line":7,"column":18}},"loc":{"start":{"line":7,"column":30},"end":{"line":22,"column":1}},"line":7},"1":{"name":"askGemini","decl":{"start":{"line":24,"column":15},"end":{"line":24,"column":24}},"loc":{"start":{"line":24,"column":33},"end":{"line":33,"column":1}},"line":24}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":19},"end":{"line":7,"column":28}},"type":"default-arg","locations":[{"start":{"line":7,"column":26},"end":{"line":7,"column":28}}],"line":7}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"f":{"0":0,"1":0},"b":{"0":[0]}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":39},"end":{"line":2,"column":59}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":35}},"3":{"start":{"line":6,"column":2},"end":{"line":68,"column":3}},"4":{"start":{"line":8,"column":18},"end":{"line":8,"column":68}},"5":{"start":{"line":9,"column":18},"end":{"line":9,"column":71}},"6":{"start":{"line":11,"column":23},"end":{"line":14,"column":6}},"7":{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},"8":{"start":{"line":18,"column":6},"end":{"line":23,"column":9}},"9":{"start":{"line":26,"column":26},"end":{"line":31,"column":17}},"10":{"start":{"line":29,"column":10},"end":{"line":29,"column":86}},"11":{"start":{"line":33,"column":19},"end":{"line":39,"column":5}},"12":{"start":{"line":41,"column":19},"end":{"line":41,"column":54}},"13":{"start":{"line":42,"column":27},"end":{"line":42,"column":49}},"14":{"start":{"line":43,"column":23},"end":{"line":43,"column":69}},"15":{"start":{"line":43,"column":60},"end":{"line":43,"column":68}},"16":{"start":{"line":45,"column":29},"end":{"line":57,"column":6}},"17":{"start":{"line":59,"column":4},"end":{"line":59,"column":28}},"18":{"start":{"line":61,"column":4},"end":{"line":61,"column":60}},"19":{"start":{"line":62,"column":4},"end":{"line":67,"column":7}},"20":{"start":{"line":71,"column":0},"end":{"line":71,"column":42}}},"fnMap":{"0":{"name":"getAIRecommendations","decl":{"start":{"line":5,"column":15},"end":{"line":5,"column":35}},"loc":{"start":{"line":5,"column":44},"end":{"line":69,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":28,"column":8},"end":{"line":28,"column":9}},"loc":{"start":{"line":29,"column":10},"end":{"line":29,"column":86}},"line":29},"2":{"name":"(anonymous_2)","decl":{"start":{"line":43,"column":53},"end":{"line":43,"column":54}},"loc":{"start":{"line":43,"column":60},"end":{"line":43,"column":68}},"line":43}},"branchMap":{"0":{"loc":{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},"type":"if","locations":[{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},{"start":{},"end":{}}],"line":17},"1":{"loc":{"start":{"line":17,"column":8},"end":{"line":17,"column":44}},"type":"binary-expr","locations":[{"start":{"line":17,"column":8},"end":{"line":17,"column":19}},{"start":{"line":17,"column":23},"end":{"line":17,"column":44}}],"line":17},"2":{"loc":{"start":{"line":29,"column":49},"end":{"line":29,"column":83}},"type":"binary-expr","locations":[{"start":{"line":29,"column":49},"end":{"line":29,"column":73}},{"start":{"line":29,"column":77},"end":{"line":29,"column":83}}],"line":29}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0},"f":{"0":0,"1":0,"2":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0]}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\authMiddleware.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\authMiddleware.js","statementMap":{"0":{"start":{"line":1,"column":24},"end":{"line":1,"column":40}},"1":{"start":{"line":2,"column":17},"end":{"line":2,"column":37}},"2":{"start":{"line":4,"column":0},"end":{"line":29,"column":2}},"3":{"start":{"line":5,"column":2},"end":{"line":28,"column":3}},"4":{"start":{"line":6,"column":24},"end":{"line":6,"column":49}},"5":{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},"6":{"start":{"line":8,"column":6},"end":{"line":8,"column":68}},"7":{"start":{"line":11,"column":18},"end":{"line":11,"column":43}},"8":{"start":{"line":12,"column":20},"end":{"line":12,"column":38}},"9":{"start":{"line":13,"column":17},"end":{"line":13,"column":48}},"10":{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},"11":{"start":{"line":14,"column":15},"end":{"line":14,"column":73}},"12":{"start":{"line":16,"column":4},"end":{"line":16,"column":20}},"13":{"start":{"line":17,"column":4},"end":{"line":17,"column":28}},"14":{"start":{"line":18,"column":4},"end":{"line":18,"column":11}},"15":{"start":{"line":20,"column":4},"end":{"line":20,"column":23}},"16":{"start":{"line":21,"column":4},"end":{"line":27,"column":5}},"17":{"start":{"line":22,"column":6},"end":{"line":22,"column":16}},"18":{"start":{"line":23,"column":11},"end":{"line":27,"column":5}},"19":{"start":{"line":24,"column":6},"end":{"line":24,"column":68}},"20":{"start":{"line":26,"column":6},"end":{"line":26,"column":68}}},"fnMap":{"0":{"name":"authMiddleware","decl":{"start":{"line":4,"column":32},"end":{"line":4,"column":46}},"loc":{"start":{"line":4,"column":63},"end":{"line":29,"column":1}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},"type":"if","locations":[{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":8},"end":{"line":7,"column":58}},"type":"binary-expr","locations":[{"start":{"line":7,"column":8},"end":{"line":7,"column":20}},{"start":{"line":7,"column":24},"end":{"line":7,"column":58}}],"line":7},"2":{"loc":{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},"type":"if","locations":[{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},{"start":{},"end":{}}],"line":14},"3":{"loc":{"start":{"line":21,"column":4},"end":{"line":27,"column":5}},"type":"if","locations":[{"start":{"line":21,"column":4},"end":{"line":27,"column":5}},{"start":{"line":23,"column":11},"end":{"line":27,"column":5}}],"line":21},"4":{"loc":{"start":{"line":23,"column":11},"end":{"line":27,"column":5}},"type":"if","locations":[{"start":{"line":23,"column":11},"end":{"line":27,"column":5}},{"start":{"line":25,"column":11},"end":{"line":27,"column":5}}],"line":23}},"s":{"0":1,"1":1,"2":1,"3":6,"4":6,"5":6,"6":2,"7":4,"8":4,"9":3,"10":2,"11":1,"12":1,"13":1,"14":1,"15":5,"16":5,"17":3,"18":2,"19":1,"20":1},"f":{"0":6},"b":{"0":[2,4],"1":[6,5],"2":[1,1],"3":[3,2],"4":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2b458db0fb066171c85660f11cd925b471913554"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\cloudinary.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\cloudinary.js","statementMap":{"0":{"start":{"line":1,"column":19},"end":{"line":1,"column":43}},"1":{"start":{"line":2,"column":30},"end":{"line":2,"column":66}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":32}},"3":{"start":{"line":5,"column":0},"end":{"line":9,"column":3}},"4":{"start":{"line":11,"column":16},"end":{"line":18,"column":2}},"5":{"start":{"line":20,"column":15},"end":{"line":20,"column":34}},"6":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0},"f":{},"b":{}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\handleError.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\handleError.js","statementMap":{"0":{"start":{"line":2,"column":2},"end":{"line":2,"column":31}},"1":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"2":{"start":{"line":5,"column":4},"end":{"line":5,"column":68}},"3":{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},"4":{"start":{"line":9,"column":4},"end":{"line":9,"column":74}},"5":{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},"6":{"start":{"line":13,"column":4},"end":{"line":13,"column":63}},"7":{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},"8":{"start":{"line":17,"column":4},"end":{"line":17,"column":75}},"9":{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},"10":{"start":{"line":21,"column":21},"end":{"line":21,"column":51}},"11":{"start":{"line":21,"column":41},"end":{"line":21,"column":50}},"12":{"start":{"line":22,"column":4},"end":{"line":22,"column":55}},"13":{"start":{"line":25,"column":2},"end":{"line":27,"column":5}},"14":{"start":{"line":30,"column":0},"end":{"line":30,"column":29}}},"fnMap":{"0":{"name":"handleError","decl":{"start":{"line":1,"column":9},"end":{"line":1,"column":20}},"loc":{"start":{"line":1,"column":41},"end":{"line":28,"column":1}},"line":1},"1":{"name":"(anonymous_1)","decl":{"start":{"line":21,"column":36},"end":{"line":21,"column":37}},"loc":{"start":{"line":21,"column":41},"end":{"line":21,"column":50}},"line":21}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"type":"if","locations":[{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},{"start":{},"end":{}}],"line":4},"1":{"loc":{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},{"start":{},"end":{}}],"line":8},"2":{"loc":{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},"type":"if","locations":[{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},{"start":{},"end":{}}],"line":12},"3":{"loc":{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},"type":"if","locations":[{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},{"start":{},"end":{}}],"line":16},"4":{"loc":{"start":{"line":17,"column":43},"end":{"line":17,"column":71}},"type":"binary-expr","locations":[{"start":{"line":17,"column":43},"end":{"line":17,"column":54}},{"start":{"line":17,"column":58},"end":{"line":17,"column":71}}],"line":17},"5":{"loc":{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},"type":"if","locations":[{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},{"start":{},"end":{}}],"line":20},"6":{"loc":{"start":{"line":20,"column":6},"end":{"line":20,"column":94}},"type":"binary-expr","locations":[{"start":{"line":20,"column":6},"end":{"line":20,"column":45}},{"start":{"line":20,"column":49},"end":{"line":20,"column":94}}],"line":20}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0},"f":{"0":0,"1":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0]}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js","statementMap":{"0":{"start":{"line":1,"column":12},"end":{"line":1,"column":35}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":37}},"2":{"start":{"line":5,"column":2},"end":{"line":5,"column":35}},"3":{"start":{"line":9,"column":2},"end":{"line":9,"column":35}},"4":{"start":{"line":12,"column":0},"end":{"line":12,"column":44}}},"fnMap":{"0":{"name":"signToken","decl":{"start":{"line":4,"column":9},"end":{"line":4,"column":18}},"loc":{"start":{"line":4,"column":28},"end":{"line":6,"column":1}},"line":4},"1":{"name":"verifyToken","decl":{"start":{"line":8,"column":9},"end":{"line":8,"column":20}},"loc":{"start":{"line":8,"column":28},"end":{"line":10,"column":1}},"line":8}},"branchMap":{},"s":{"0":1,"1":1,"2":0,"3":0,"4":1},"f":{"0":0,"1":0},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"d7b8e9b1304ab0135964e79a9372e3a90c422c73"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\aiRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\aiRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":21},"end":{"line":3,"column":59}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":7,"column":0},"end":{"line":7,"column":70}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0},"f":{},"b":{}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\chatRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\chatRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":23},"end":{"line":3,"column":63}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":17}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":48}},"6":{"start":{"line":12,"column":0},"end":{"line":12,"column":49}},"7":{"start":{"line":15,"column":0},"end":{"line":15,"column":45}},"8":{"start":{"line":18,"column":0},"end":{"line":18,"column":64}},"9":{"start":{"line":21,"column":0},"end":{"line":21,"column":61}},"10":{"start":{"line":23,"column":0},"end":{"line":23,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"f":{},"b":{}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\index.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\index.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":4,"column":19},"end":{"line":4,"column":42}},"3":{"start":{"line":5,"column":19},"end":{"line":5,"column":42}},"4":{"start":{"line":6,"column":19},"end":{"line":6,"column":42}},"5":{"start":{"line":7,"column":17},"end":{"line":7,"column":38}},"6":{"start":{"line":9,"column":0},"end":{"line":9,"column":33}},"7":{"start":{"line":10,"column":0},"end":{"line":10,"column":33}},"8":{"start":{"line":11,"column":0},"end":{"line":11,"column":33}},"9":{"start":{"line":12,"column":0},"end":{"line":12,"column":28}},"10":{"start":{"line":14,"column":0},"end":{"line":14,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"f":{},"b":{}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\postRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\postRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":23},"end":{"line":3,"column":63}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":5,"column":15},"end":{"line":5,"column":47}},"5":{"start":{"line":8,"column":0},"end":{"line":8,"column":77}},"6":{"start":{"line":10,"column":0},"end":{"line":10,"column":50}},"7":{"start":{"line":11,"column":0},"end":{"line":11,"column":51}},"8":{"start":{"line":13,"column":0},"end":{"line":13,"column":52}},"9":{"start":{"line":14,"column":0},"end":{"line":14,"column":55}},"10":{"start":{"line":16,"column":0},"end":{"line":16,"column":58}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0},"f":{},"b":{}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\userRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\userRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":23},"end":{"line":2,"column":63}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":31}},"3":{"start":{"line":5,"column":0},"end":{"line":5,"column":50}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":44}},"5":{"start":{"line":7,"column":0},"end":{"line":7,"column":57}},"6":{"start":{"line":10,"column":0},"end":{"line":10,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0},"f":{},"b":{}} +{"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}},"1":{"start":{"line":2,"column":16},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":12},"end":{"line":3,"column":21}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"4":{"start":{"line":5,"column":20},"end":{"line":5,"column":52}},"5":{"start":{"line":6,"column":15},"end":{"line":6,"column":34}},"6":{"start":{"line":7,"column":13},"end":{"line":7,"column":28}},"7":{"start":{"line":9,"column":13},"end":{"line":9,"column":28}},"8":{"start":{"line":10,"column":15},"end":{"line":10,"column":37}},"9":{"start":{"line":11,"column":19},"end":{"line":11,"column":39}},"10":{"start":{"line":12,"column":11},"end":{"line":16,"column":2}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}},"12":{"start":{"line":21,"column":0},"end":{"line":21,"column":16}},"13":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}},"14":{"start":{"line":23,"column":0},"end":{"line":23,"column":48}},"15":{"start":{"line":24,"column":0},"end":{"line":24,"column":34}},"16":{"start":{"line":27,"column":0},"end":{"line":27,"column":21}},"17":{"start":{"line":31,"column":0},"end":{"line":31,"column":21}},"18":{"start":{"line":34,"column":0},"end":{"line":52,"column":3}},"19":{"start":{"line":35,"column":2},"end":{"line":35,"column":46}},"20":{"start":{"line":37,"column":2},"end":{"line":39,"column":5}},"21":{"start":{"line":38,"column":4},"end":{"line":38,"column":34}},"22":{"start":{"line":41,"column":2},"end":{"line":43,"column":5}},"23":{"start":{"line":45,"column":2},"end":{"line":47,"column":5}},"24":{"start":{"line":49,"column":2},"end":{"line":51,"column":5}},"25":{"start":{"line":60,"column":0},"end":{"line":60,"column":21}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":34,"column":20},"end":{"line":34,"column":21}},"loc":{"start":{"line":34,"column":32},"end":{"line":52,"column":1}},"line":34},"1":{"name":"(anonymous_1)","decl":{"start":{"line":37,"column":25},"end":{"line":37,"column":26}},"loc":{"start":{"line":37,"column":37},"end":{"line":39,"column":3}},"line":37},"2":{"name":"(anonymous_2)","decl":{"start":{"line":41,"column":28},"end":{"line":41,"column":29}},"loc":{"start":{"line":41,"column":45},"end":{"line":43,"column":3}},"line":41},"3":{"name":"(anonymous_3)","decl":{"start":{"line":45,"column":27},"end":{"line":45,"column":28}},"loc":{"start":{"line":45,"column":43},"end":{"line":47,"column":3}},"line":45},"4":{"name":"(anonymous_4)","decl":{"start":{"line":49,"column":26},"end":{"line":49,"column":27}},"loc":{"start":{"line":49,"column":32},"end":{"line":51,"column":3}},"line":49}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"type":"binary-expr","locations":[{"start":{"line":4,"column":13},"end":{"line":4,"column":29}},{"start":{"line":4,"column":33},"end":{"line":4,"column":37}}],"line":4}},"s":{"0":11,"1":11,"2":11,"3":11,"4":11,"5":11,"6":11,"7":11,"8":11,"9":11,"10":11,"11":11,"12":11,"13":11,"14":11,"15":11,"16":11,"17":11,"18":11,"19":8,"20":8,"21":8,"22":8,"23":8,"24":8,"25":11},"f":{"0":8,"1":8,"2":0,"3":0,"4":0},"b":{"0":[11,7]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"331ebcfa441d0321ad66f7a1cbb4893152c6777e"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js","statementMap":{"0":{"start":{"line":1,"column":33},"end":{"line":1,"column":71}},"1":{"start":{"line":5,"column":4},"end":{"line":21,"column":5}},"2":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"3":{"start":{"line":8,"column":8},"end":{"line":8,"column":39}},"4":{"start":{"line":11,"column":21},"end":{"line":11,"column":32}},"5":{"start":{"line":12,"column":20},"end":{"line":12,"column":54}},"6":{"start":{"line":14,"column":6},"end":{"line":18,"column":9}},"7":{"start":{"line":20,"column":6},"end":{"line":20,"column":16}},"8":{"start":{"line":25,"column":0},"end":{"line":25,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":4,"column":2},"end":{"line":4,"column":3}},"loc":{"start":{"line":4,"column":50},"end":{"line":22,"column":3}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"type":"if","locations":[{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":10},"end":{"line":7,"column":35}},"type":"binary-expr","locations":[{"start":{"line":7,"column":10},"end":{"line":7,"column":19}},{"start":{"line":7,"column":23},"end":{"line":7,"column":35}}],"line":7}},"s":{"0":3,"1":2,"2":2,"3":1,"4":1,"5":1,"6":1,"7":1,"8":3},"f":{"0":2},"b":{"0":[1,1],"1":[2,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"5a3a8d6179df7a779a1e7786dcd48a5a6657888b"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js","statementMap":{"0":{"start":{"line":1,"column":43},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":24}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":52}},"3":{"start":{"line":8,"column":8},"end":{"line":34,"column":9}},"4":{"start":{"line":9,"column":34},"end":{"line":9,"column":42}},"5":{"start":{"line":10,"column":27},"end":{"line":10,"column":38}},"6":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"7":{"start":{"line":13,"column":16},"end":{"line":13,"column":97}},"8":{"start":{"line":17,"column":36},"end":{"line":29,"column":14}},"9":{"start":{"line":31,"column":12},"end":{"line":31,"column":55}},"10":{"start":{"line":33,"column":12},"end":{"line":33,"column":22}},"11":{"start":{"line":39,"column":8},"end":{"line":55,"column":9}},"12":{"start":{"line":40,"column":27},"end":{"line":40,"column":38}},"13":{"start":{"line":41,"column":26},"end":{"line":50,"column":14}},"14":{"start":{"line":52,"column":12},"end":{"line":52,"column":28}},"15":{"start":{"line":54,"column":12},"end":{"line":54,"column":22}},"16":{"start":{"line":60,"column":8},"end":{"line":79,"column":9}},"17":{"start":{"line":61,"column":31},"end":{"line":61,"column":41}},"18":{"start":{"line":62,"column":27},"end":{"line":62,"column":38}},"19":{"start":{"line":65,"column":25},"end":{"line":65,"column":52}},"20":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"21":{"start":{"line":67,"column":16},"end":{"line":67,"column":44}},"22":{"start":{"line":70,"column":29},"end":{"line":74,"column":14}},"23":{"start":{"line":76,"column":12},"end":{"line":76,"column":31}},"24":{"start":{"line":78,"column":12},"end":{"line":78,"column":22}},"25":{"start":{"line":83,"column":8},"end":{"line":99,"column":9}},"26":{"start":{"line":84,"column":27},"end":{"line":84,"column":38}},"27":{"start":{"line":85,"column":36},"end":{"line":95,"column":14}},"28":{"start":{"line":96,"column":12},"end":{"line":96,"column":55}},"29":{"start":{"line":98,"column":12},"end":{"line":98,"column":22}},"30":{"start":{"line":104,"column":8},"end":{"line":147,"column":9}},"31":{"start":{"line":105,"column":31},"end":{"line":105,"column":41}},"32":{"start":{"line":106,"column":32},"end":{"line":106,"column":40}},"33":{"start":{"line":107,"column":27},"end":{"line":107,"column":38}},"34":{"start":{"line":108,"column":23},"end":{"line":108,"column":46}},"35":{"start":{"line":110,"column":25},"end":{"line":110,"column":52}},"36":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"37":{"start":{"line":112,"column":16},"end":{"line":112,"column":70}},"38":{"start":{"line":117,"column":33},"end":{"line":117,"column":84}},"39":{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},"40":{"start":{"line":119,"column":16},"end":{"line":119,"column":99}},"41":{"start":{"line":123,"column":32},"end":{"line":127,"column":14}},"42":{"start":{"line":129,"column":12},"end":{"line":129,"column":73}},"43":{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},"44":{"start":{"line":132,"column":39},"end":{"line":132,"column":63}},"45":{"start":{"line":134,"column":34},"end":{"line":138,"column":18}},"46":{"start":{"line":140,"column":16},"end":{"line":140,"column":75}},"47":{"start":{"line":143,"column":12},"end":{"line":143,"column":30}},"48":{"start":{"line":144,"column":12},"end":{"line":144,"column":46}},"49":{"start":{"line":146,"column":12},"end":{"line":146,"column":22}},"50":{"start":{"line":151,"column":0},"end":{"line":151,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":4},"end":{"line":7,"column":5}},"loc":{"start":{"line":7,"column":49},"end":{"line":35,"column":5}},"line":7},"1":{"name":"(anonymous_1)","decl":{"start":{"line":38,"column":4},"end":{"line":38,"column":5}},"loc":{"start":{"line":38,"column":46},"end":{"line":56,"column":5}},"line":38},"2":{"name":"(anonymous_2)","decl":{"start":{"line":59,"column":4},"end":{"line":59,"column":5}},"loc":{"start":{"line":59,"column":49},"end":{"line":80,"column":5}},"line":59},"3":{"name":"(anonymous_3)","decl":{"start":{"line":82,"column":4},"end":{"line":82,"column":5}},"loc":{"start":{"line":82,"column":46},"end":{"line":100,"column":5}},"line":82},"4":{"name":"(anonymous_4)","decl":{"start":{"line":103,"column":4},"end":{"line":103,"column":5}},"loc":{"start":{"line":103,"column":45},"end":{"line":148,"column":5}},"line":103}},"branchMap":{"0":{"loc":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"type":"if","locations":[{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},{"start":{},"end":{}}],"line":12},"1":{"loc":{"start":{"line":31,"column":23},"end":{"line":31,"column":42}},"type":"cond-expr","locations":[{"start":{"line":31,"column":33},"end":{"line":31,"column":36}},{"start":{"line":31,"column":39},"end":{"line":31,"column":42}}],"line":31},"2":{"loc":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"type":"if","locations":[{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},{"start":{},"end":{}}],"line":66},"3":{"loc":{"start":{"line":66,"column":16},"end":{"line":66,"column":78}},"type":"binary-expr","locations":[{"start":{"line":66,"column":16},"end":{"line":66,"column":21}},{"start":{"line":66,"column":26},"end":{"line":66,"column":48}},{"start":{"line":66,"column":52},"end":{"line":66,"column":77}}],"line":66},"4":{"loc":{"start":{"line":96,"column":23},"end":{"line":96,"column":42}},"type":"cond-expr","locations":[{"start":{"line":96,"column":33},"end":{"line":96,"column":36}},{"start":{"line":96,"column":39},"end":{"line":96,"column":42}}],"line":96},"5":{"loc":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"type":"if","locations":[{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},{"start":{},"end":{}}],"line":111},"6":{"loc":{"start":{"line":117,"column":33},"end":{"line":117,"column":84}},"type":"binary-expr","locations":[{"start":{"line":117,"column":33},"end":{"line":117,"column":55}},{"start":{"line":117,"column":59},"end":{"line":117,"column":84}}],"line":117},"7":{"loc":{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},"type":"if","locations":[{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},{"start":{},"end":{}}],"line":118},"8":{"loc":{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},"type":"if","locations":[{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},{"start":{},"end":{}}],"line":131}},"s":{"0":3,"1":3,"2":3,"3":4,"4":4,"5":4,"6":4,"7":1,"8":3,"9":2,"10":2,"11":2,"12":2,"13":2,"14":1,"15":1,"16":4,"17":4,"18":4,"19":4,"20":3,"21":2,"22":1,"23":1,"24":3,"25":3,"26":3,"27":3,"28":2,"29":1,"30":5,"31":5,"32":5,"33":5,"34":5,"35":5,"36":5,"37":1,"38":4,"39":4,"40":1,"41":3,"42":2,"43":2,"44":1,"45":1,"46":1,"47":2,"48":2,"49":3,"50":3},"f":{"0":4,"1":2,"2":4,"3":3,"4":5},"b":{"0":[1,3],"1":[1,1],"2":[2,1],"3":[3,2,1],"4":[1,1],"5":[1,4],"6":[4,1],"7":[1,3],"8":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2917d152140ab09724020f4ab1282f6f8aefef73"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js","statementMap":{"0":{"start":{"line":1,"column":46},"end":{"line":1,"column":66}},"1":{"start":{"line":6,"column":4},"end":{"line":33,"column":5}},"2":{"start":{"line":7,"column":49},"end":{"line":7,"column":57}},"3":{"start":{"line":10,"column":6},"end":{"line":12,"column":7}},"4":{"start":{"line":11,"column":8},"end":{"line":11,"column":98}},"5":{"start":{"line":15,"column":19},"end":{"line":20,"column":8}},"6":{"start":{"line":23,"column":21},"end":{"line":26,"column":9}},"7":{"start":{"line":23,"column":46},"end":{"line":26,"column":7}},"8":{"start":{"line":28,"column":6},"end":{"line":28,"column":37}},"9":{"start":{"line":30,"column":6},"end":{"line":30,"column":75}},"10":{"start":{"line":32,"column":6},"end":{"line":32,"column":16}},"11":{"start":{"line":38,"column":4},"end":{"line":52,"column":5}},"12":{"start":{"line":39,"column":20},"end":{"line":48,"column":8}},"13":{"start":{"line":49,"column":6},"end":{"line":49,"column":22}},"14":{"start":{"line":51,"column":6},"end":{"line":51,"column":16}},"15":{"start":{"line":57,"column":4},"end":{"line":66,"column":5}},"16":{"start":{"line":58,"column":20},"end":{"line":62,"column":8}},"17":{"start":{"line":63,"column":6},"end":{"line":63,"column":22}},"18":{"start":{"line":65,"column":6},"end":{"line":65,"column":16}},"19":{"start":{"line":71,"column":4},"end":{"line":83,"column":5}},"20":{"start":{"line":72,"column":21},"end":{"line":72,"column":31}},"21":{"start":{"line":73,"column":49},"end":{"line":73,"column":57}},"22":{"start":{"line":75,"column":19},"end":{"line":75,"column":42}},"23":{"start":{"line":76,"column":6},"end":{"line":76,"column":44}},"24":{"start":{"line":76,"column":17},"end":{"line":76,"column":44}},"25":{"start":{"line":77,"column":6},"end":{"line":77,"column":70}},"26":{"start":{"line":77,"column":39},"end":{"line":77,"column":70}},"27":{"start":{"line":79,"column":6},"end":{"line":79,"column":72}},"28":{"start":{"line":80,"column":6},"end":{"line":80,"column":63}},"29":{"start":{"line":82,"column":6},"end":{"line":82,"column":16}},"30":{"start":{"line":88,"column":4},"end":{"line":98,"column":5}},"31":{"start":{"line":89,"column":21},"end":{"line":89,"column":31}},"32":{"start":{"line":90,"column":19},"end":{"line":90,"column":42}},"33":{"start":{"line":91,"column":6},"end":{"line":91,"column":44}},"34":{"start":{"line":91,"column":17},"end":{"line":91,"column":44}},"35":{"start":{"line":92,"column":6},"end":{"line":92,"column":70}},"36":{"start":{"line":92,"column":39},"end":{"line":92,"column":70}},"37":{"start":{"line":94,"column":6},"end":{"line":94,"column":27}},"38":{"start":{"line":95,"column":6},"end":{"line":95,"column":57}},"39":{"start":{"line":97,"column":6},"end":{"line":97,"column":16}},"40":{"start":{"line":103,"column":4},"end":{"line":123,"column":5}},"41":{"start":{"line":104,"column":21},"end":{"line":104,"column":31}},"42":{"start":{"line":105,"column":19},"end":{"line":105,"column":42}},"43":{"start":{"line":106,"column":6},"end":{"line":106,"column":44}},"44":{"start":{"line":106,"column":17},"end":{"line":106,"column":44}},"45":{"start":{"line":108,"column":27},"end":{"line":110,"column":8}},"46":{"start":{"line":113,"column":6},"end":{"line":119,"column":7}},"47":{"start":{"line":114,"column":8},"end":{"line":114,"column":37}},"48":{"start":{"line":115,"column":8},"end":{"line":115,"column":33}},"49":{"start":{"line":117,"column":8},"end":{"line":117,"column":63}},"50":{"start":{"line":118,"column":8},"end":{"line":118,"column":31}},"51":{"start":{"line":120,"column":6},"end":{"line":120,"column":28}},"52":{"start":{"line":122,"column":6},"end":{"line":122,"column":16}},"53":{"start":{"line":127,"column":0},"end":{"line":127,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":2},"end":{"line":5,"column":3}},"loc":{"start":{"line":5,"column":42},"end":{"line":34,"column":3}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":23,"column":35},"end":{"line":23,"column":36}},"loc":{"start":{"line":23,"column":46},"end":{"line":26,"column":7}},"line":23},"2":{"name":"(anonymous_2)","decl":{"start":{"line":37,"column":2},"end":{"line":37,"column":3}},"loc":{"start":{"line":37,"column":49},"end":{"line":53,"column":3}},"line":37},"3":{"name":"(anonymous_3)","decl":{"start":{"line":56,"column":2},"end":{"line":56,"column":3}},"loc":{"start":{"line":56,"column":42},"end":{"line":67,"column":3}},"line":56},"4":{"name":"(anonymous_4)","decl":{"start":{"line":70,"column":2},"end":{"line":70,"column":3}},"loc":{"start":{"line":70,"column":42},"end":{"line":84,"column":3}},"line":70},"5":{"name":"(anonymous_5)","decl":{"start":{"line":87,"column":2},"end":{"line":87,"column":3}},"loc":{"start":{"line":87,"column":42},"end":{"line":99,"column":3}},"line":87},"6":{"name":"(anonymous_6)","decl":{"start":{"line":102,"column":2},"end":{"line":102,"column":3}},"loc":{"start":{"line":102,"column":42},"end":{"line":124,"column":3}},"line":102}},"branchMap":{"0":{"loc":{"start":{"line":10,"column":6},"end":{"line":12,"column":7}},"type":"if","locations":[{"start":{"line":10,"column":6},"end":{"line":12,"column":7}},{"start":{},"end":{}}],"line":10},"1":{"loc":{"start":{"line":10,"column":10},"end":{"line":10,"column":46}},"type":"binary-expr","locations":[{"start":{"line":10,"column":10},"end":{"line":10,"column":20}},{"start":{"line":10,"column":24},"end":{"line":10,"column":46}}],"line":10},"2":{"loc":{"start":{"line":76,"column":6},"end":{"line":76,"column":44}},"type":"if","locations":[{"start":{"line":76,"column":6},"end":{"line":76,"column":44}},{"start":{},"end":{}}],"line":76},"3":{"loc":{"start":{"line":77,"column":6},"end":{"line":77,"column":70}},"type":"if","locations":[{"start":{"line":77,"column":6},"end":{"line":77,"column":70}},{"start":{},"end":{}}],"line":77},"4":{"loc":{"start":{"line":91,"column":6},"end":{"line":91,"column":44}},"type":"if","locations":[{"start":{"line":91,"column":6},"end":{"line":91,"column":44}},{"start":{},"end":{}}],"line":91},"5":{"loc":{"start":{"line":92,"column":6},"end":{"line":92,"column":70}},"type":"if","locations":[{"start":{"line":92,"column":6},"end":{"line":92,"column":70}},{"start":{},"end":{}}],"line":92},"6":{"loc":{"start":{"line":106,"column":6},"end":{"line":106,"column":44}},"type":"if","locations":[{"start":{"line":106,"column":6},"end":{"line":106,"column":44}},{"start":{},"end":{}}],"line":106},"7":{"loc":{"start":{"line":113,"column":6},"end":{"line":119,"column":7}},"type":"if","locations":[{"start":{"line":113,"column":6},"end":{"line":119,"column":7}},{"start":{"line":116,"column":13},"end":{"line":119,"column":7}}],"line":113}},"s":{"0":3,"1":3,"2":3,"3":3,"4":1,"5":2,"6":1,"7":2,"8":1,"9":1,"10":2,"11":2,"12":2,"13":1,"14":1,"15":2,"16":2,"17":1,"18":1,"19":4,"20":4,"21":4,"22":4,"23":4,"24":1,"25":3,"26":1,"27":2,"28":1,"29":3,"30":4,"31":4,"32":4,"33":4,"34":1,"35":3,"36":1,"37":2,"38":1,"39":3,"40":4,"41":4,"42":4,"43":3,"44":1,"45":2,"46":2,"47":1,"48":1,"49":1,"50":1,"51":2,"52":2,"53":3},"f":{"0":3,"1":2,"2":2,"3":2,"4":4,"5":4,"6":4},"b":{"0":[1,2],"1":[3,3],"2":[1,3],"3":[1,2],"4":[1,3],"5":[1,2],"6":[1,2],"7":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"7acbe67c59c0a71f7523b6569d057e7acc03f284"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js","statementMap":{"0":{"start":{"line":1,"column":17},"end":{"line":1,"column":37}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":47}},"3":{"start":{"line":4,"column":25},"end":{"line":4,"column":55}},"4":{"start":{"line":5,"column":15},"end":{"line":5,"column":33}},"5":{"start":{"line":10,"column":8},"end":{"line":20,"column":9}},"6":{"start":{"line":11,"column":50},"end":{"line":11,"column":58}},"7":{"start":{"line":12,"column":28},"end":{"line":12,"column":76}},"8":{"start":{"line":13,"column":12},"end":{"line":17,"column":15}},"9":{"start":{"line":19,"column":12},"end":{"line":19,"column":22}},"10":{"start":{"line":24,"column":8},"end":{"line":44,"column":9}},"11":{"start":{"line":25,"column":40},"end":{"line":25,"column":48}},"12":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"13":{"start":{"line":27,"column":16},"end":{"line":27,"column":89}},"14":{"start":{"line":30,"column":25},"end":{"line":30,"column":65}},"15":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"16":{"start":{"line":32,"column":16},"end":{"line":32,"column":47}},"17":{"start":{"line":35,"column":36},"end":{"line":35,"column":79}},"18":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"19":{"start":{"line":37,"column":16},"end":{"line":37,"column":47}},"20":{"start":{"line":40,"column":26},"end":{"line":40,"column":52}},"21":{"start":{"line":41,"column":12},"end":{"line":41,"column":58}},"22":{"start":{"line":43,"column":12},"end":{"line":43,"column":22}},"23":{"start":{"line":48,"column":8},"end":{"line":73,"column":9}},"24":{"start":{"line":49,"column":37},"end":{"line":49,"column":45}},"25":{"start":{"line":51,"column":27},"end":{"line":54,"column":14}},"26":{"start":{"line":55,"column":28},"end":{"line":55,"column":47}},"27":{"start":{"line":57,"column":36},"end":{"line":66,"column":14}},"28":{"start":{"line":68,"column":33},"end":{"line":68,"column":59}},"29":{"start":{"line":69,"column":12},"end":{"line":69,"column":51}},"30":{"start":{"line":72,"column":12},"end":{"line":72,"column":22}},"31":{"start":{"line":77,"column":0},"end":{"line":77,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":9,"column":4},"end":{"line":9,"column":5}},"loc":{"start":{"line":9,"column":42},"end":{"line":21,"column":5}},"line":9},"1":{"name":"(anonymous_1)","decl":{"start":{"line":23,"column":4},"end":{"line":23,"column":5}},"loc":{"start":{"line":23,"column":39},"end":{"line":45,"column":5}},"line":23},"2":{"name":"(anonymous_2)","decl":{"start":{"line":47,"column":4},"end":{"line":47,"column":5}},"loc":{"start":{"line":47,"column":46},"end":{"line":74,"column":5}},"line":47}},"branchMap":{"0":{"loc":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"type":"if","locations":[{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},{"start":{},"end":{}}],"line":26},"1":{"loc":{"start":{"line":26,"column":16},"end":{"line":26,"column":35}},"type":"binary-expr","locations":[{"start":{"line":26,"column":16},"end":{"line":26,"column":22}},{"start":{"line":26,"column":26},"end":{"line":26,"column":35}}],"line":26},"2":{"loc":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"type":"if","locations":[{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},{"start":{},"end":{}}],"line":31},"3":{"loc":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"type":"if","locations":[{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},{"start":{},"end":{}}],"line":36}},"s":{"0":3,"1":3,"2":3,"3":3,"4":3,"5":2,"6":2,"7":2,"8":1,"9":1,"10":5,"11":5,"12":5,"13":1,"14":4,"15":3,"16":1,"17":2,"18":2,"19":1,"20":1,"21":1,"22":4,"23":2,"24":2,"25":2,"26":1,"27":1,"28":1,"29":1,"30":1,"31":3},"f":{"0":2,"1":5,"2":2},"b":{"0":[1,4],"1":[5,5],"2":[1,2],"3":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"b7038bc766a82e2013af060f79b91bd96e2958df"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":3,"column":14},"end":{"line":3,"column":64}},"2":{"start":{"line":4,"column":14},"end":{"line":4,"column":67}},"3":{"start":{"line":8,"column":2},"end":{"line":21,"column":12}},"4":{"start":{"line":25,"column":2},"end":{"line":32,"column":3}},"5":{"start":{"line":26,"column":19},"end":{"line":26,"column":54}},"6":{"start":{"line":27,"column":20},"end":{"line":27,"column":42}},"7":{"start":{"line":28,"column":4},"end":{"line":28,"column":30}},"8":{"start":{"line":30,"column":4},"end":{"line":30,"column":47}},"9":{"start":{"line":31,"column":4},"end":{"line":31,"column":63}},"10":{"start":{"line":35,"column":0},"end":{"line":35,"column":42}}},"fnMap":{"0":{"name":"cleanText","decl":{"start":{"line":7,"column":9},"end":{"line":7,"column":18}},"loc":{"start":{"line":7,"column":30},"end":{"line":22,"column":1}},"line":7},"1":{"name":"askGemini","decl":{"start":{"line":24,"column":15},"end":{"line":24,"column":24}},"loc":{"start":{"line":24,"column":33},"end":{"line":33,"column":1}},"line":24}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":19},"end":{"line":7,"column":28}},"type":"default-arg","locations":[{"start":{"line":7,"column":26},"end":{"line":7,"column":28}}],"line":7}},"s":{"0":8,"1":8,"2":8,"3":4,"4":3,"5":3,"6":2,"7":2,"8":1,"9":1,"10":8},"f":{"0":4,"1":3},"b":{"0":[1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"fd9791976abbe13793b9b2827d339e4ac9952aca"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":39},"end":{"line":2,"column":59}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":35}},"3":{"start":{"line":6,"column":2},"end":{"line":68,"column":3}},"4":{"start":{"line":8,"column":18},"end":{"line":8,"column":68}},"5":{"start":{"line":9,"column":18},"end":{"line":9,"column":71}},"6":{"start":{"line":11,"column":23},"end":{"line":14,"column":6}},"7":{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},"8":{"start":{"line":18,"column":6},"end":{"line":23,"column":9}},"9":{"start":{"line":26,"column":26},"end":{"line":31,"column":17}},"10":{"start":{"line":29,"column":10},"end":{"line":29,"column":86}},"11":{"start":{"line":33,"column":19},"end":{"line":39,"column":5}},"12":{"start":{"line":41,"column":19},"end":{"line":41,"column":54}},"13":{"start":{"line":42,"column":27},"end":{"line":42,"column":49}},"14":{"start":{"line":43,"column":23},"end":{"line":43,"column":69}},"15":{"start":{"line":43,"column":60},"end":{"line":43,"column":68}},"16":{"start":{"line":45,"column":29},"end":{"line":57,"column":6}},"17":{"start":{"line":59,"column":4},"end":{"line":59,"column":28}},"18":{"start":{"line":61,"column":4},"end":{"line":61,"column":60}},"19":{"start":{"line":62,"column":4},"end":{"line":67,"column":7}},"20":{"start":{"line":71,"column":0},"end":{"line":71,"column":42}}},"fnMap":{"0":{"name":"getAIRecommendations","decl":{"start":{"line":5,"column":15},"end":{"line":5,"column":35}},"loc":{"start":{"line":5,"column":44},"end":{"line":69,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":28,"column":8},"end":{"line":28,"column":9}},"loc":{"start":{"line":29,"column":10},"end":{"line":29,"column":86}},"line":29},"2":{"name":"(anonymous_2)","decl":{"start":{"line":43,"column":53},"end":{"line":43,"column":54}},"loc":{"start":{"line":43,"column":60},"end":{"line":43,"column":68}},"line":43}},"branchMap":{"0":{"loc":{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},"type":"if","locations":[{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},{"start":{},"end":{}}],"line":17},"1":{"loc":{"start":{"line":17,"column":8},"end":{"line":17,"column":44}},"type":"binary-expr","locations":[{"start":{"line":17,"column":8},"end":{"line":17,"column":19}},{"start":{"line":17,"column":23},"end":{"line":17,"column":44}}],"line":17},"2":{"loc":{"start":{"line":29,"column":49},"end":{"line":29,"column":83}},"type":"binary-expr","locations":[{"start":{"line":29,"column":49},"end":{"line":29,"column":73}},{"start":{"line":29,"column":77},"end":{"line":29,"column":83}}],"line":29}},"s":{"0":7,"1":7,"2":7,"3":4,"4":4,"5":4,"6":4,"7":3,"8":1,"9":2,"10":6,"11":2,"12":2,"13":2,"14":2,"15":5,"16":2,"17":2,"18":1,"19":1,"20":7},"f":{"0":4,"1":6,"2":5},"b":{"0":[1,2],"1":[3,3],"2":[6,2]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"b1fba11a44899570364f599bbe9715df05009abc"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\authMiddleware.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\authMiddleware.js","statementMap":{"0":{"start":{"line":1,"column":24},"end":{"line":1,"column":40}},"1":{"start":{"line":2,"column":17},"end":{"line":2,"column":37}},"2":{"start":{"line":4,"column":0},"end":{"line":28,"column":2}},"3":{"start":{"line":5,"column":2},"end":{"line":27,"column":3}},"4":{"start":{"line":6,"column":24},"end":{"line":6,"column":49}},"5":{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},"6":{"start":{"line":8,"column":6},"end":{"line":8,"column":68}},"7":{"start":{"line":11,"column":18},"end":{"line":11,"column":43}},"8":{"start":{"line":12,"column":20},"end":{"line":12,"column":38}},"9":{"start":{"line":13,"column":17},"end":{"line":13,"column":48}},"10":{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},"11":{"start":{"line":14,"column":15},"end":{"line":14,"column":73}},"12":{"start":{"line":16,"column":4},"end":{"line":16,"column":20}},"13":{"start":{"line":17,"column":4},"end":{"line":17,"column":28}},"14":{"start":{"line":18,"column":4},"end":{"line":18,"column":11}},"15":{"start":{"line":20,"column":4},"end":{"line":26,"column":5}},"16":{"start":{"line":21,"column":6},"end":{"line":21,"column":16}},"17":{"start":{"line":22,"column":11},"end":{"line":26,"column":5}},"18":{"start":{"line":23,"column":6},"end":{"line":23,"column":68}},"19":{"start":{"line":25,"column":6},"end":{"line":25,"column":68}}},"fnMap":{"0":{"name":"authMiddleware","decl":{"start":{"line":4,"column":32},"end":{"line":4,"column":46}},"loc":{"start":{"line":4,"column":63},"end":{"line":28,"column":1}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},"type":"if","locations":[{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":8},"end":{"line":7,"column":58}},"type":"binary-expr","locations":[{"start":{"line":7,"column":8},"end":{"line":7,"column":20}},{"start":{"line":7,"column":24},"end":{"line":7,"column":58}}],"line":7},"2":{"loc":{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},"type":"if","locations":[{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},{"start":{},"end":{}}],"line":14},"3":{"loc":{"start":{"line":20,"column":4},"end":{"line":26,"column":5}},"type":"if","locations":[{"start":{"line":20,"column":4},"end":{"line":26,"column":5}},{"start":{"line":22,"column":11},"end":{"line":26,"column":5}}],"line":20},"4":{"loc":{"start":{"line":22,"column":11},"end":{"line":26,"column":5}},"type":"if","locations":[{"start":{"line":22,"column":11},"end":{"line":26,"column":5}},{"start":{"line":24,"column":11},"end":{"line":26,"column":5}}],"line":22}},"s":{"0":6,"1":6,"2":6,"3":6,"4":6,"5":6,"6":2,"7":4,"8":4,"9":3,"10":2,"11":1,"12":1,"13":1,"14":1,"15":5,"16":3,"17":2,"18":1,"19":1},"f":{"0":6},"b":{"0":[2,4],"1":[6,5],"2":[1,1],"3":[3,2],"4":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"da15475db48041279c05eae50906191f14ebd303"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\cloudinary.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\cloudinary.js","statementMap":{"0":{"start":{"line":1,"column":19},"end":{"line":1,"column":43}},"1":{"start":{"line":2,"column":30},"end":{"line":2,"column":66}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":32}},"3":{"start":{"line":5,"column":0},"end":{"line":9,"column":3}},"4":{"start":{"line":11,"column":16},"end":{"line":18,"column":2}},"5":{"start":{"line":20,"column":15},"end":{"line":20,"column":34}},"6":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":5,"1":5,"2":5,"3":5,"4":5,"5":5,"6":5},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"b5c712c03dc49f3dc144389fe011736580e525df"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\handleError.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\handleError.js","statementMap":{"0":{"start":{"line":2,"column":2},"end":{"line":2,"column":31}},"1":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"2":{"start":{"line":5,"column":4},"end":{"line":5,"column":68}},"3":{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},"4":{"start":{"line":9,"column":4},"end":{"line":9,"column":74}},"5":{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},"6":{"start":{"line":13,"column":4},"end":{"line":13,"column":63}},"7":{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},"8":{"start":{"line":17,"column":4},"end":{"line":17,"column":75}},"9":{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},"10":{"start":{"line":21,"column":21},"end":{"line":21,"column":51}},"11":{"start":{"line":21,"column":41},"end":{"line":21,"column":50}},"12":{"start":{"line":22,"column":4},"end":{"line":22,"column":55}},"13":{"start":{"line":25,"column":2},"end":{"line":27,"column":5}},"14":{"start":{"line":30,"column":0},"end":{"line":30,"column":29}}},"fnMap":{"0":{"name":"handleError","decl":{"start":{"line":1,"column":9},"end":{"line":1,"column":20}},"loc":{"start":{"line":1,"column":41},"end":{"line":28,"column":1}},"line":1},"1":{"name":"(anonymous_1)","decl":{"start":{"line":21,"column":36},"end":{"line":21,"column":37}},"loc":{"start":{"line":21,"column":41},"end":{"line":21,"column":50}},"line":21}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"type":"if","locations":[{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},{"start":{},"end":{}}],"line":4},"1":{"loc":{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},{"start":{},"end":{}}],"line":8},"2":{"loc":{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},"type":"if","locations":[{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},{"start":{},"end":{}}],"line":12},"3":{"loc":{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},"type":"if","locations":[{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},{"start":{},"end":{}}],"line":16},"4":{"loc":{"start":{"line":17,"column":43},"end":{"line":17,"column":71}},"type":"binary-expr","locations":[{"start":{"line":17,"column":43},"end":{"line":17,"column":54}},{"start":{"line":17,"column":58},"end":{"line":17,"column":71}}],"line":17},"5":{"loc":{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},"type":"if","locations":[{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},{"start":{},"end":{}}],"line":20},"6":{"loc":{"start":{"line":20,"column":6},"end":{"line":20,"column":94}},"type":"binary-expr","locations":[{"start":{"line":20,"column":6},"end":{"line":20,"column":45}},{"start":{"line":20,"column":49},"end":{"line":20,"column":94}}],"line":20}},"s":{"0":8,"1":8,"2":1,"3":7,"4":1,"5":6,"6":1,"7":5,"8":2,"9":3,"10":2,"11":3,"12":2,"13":1,"14":3},"f":{"0":8,"1":3},"b":{"0":[1,7],"1":[1,6],"2":[1,5],"3":[2,3],"4":[2,1],"5":[2,1],"6":[3,2]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"c2354f978bf3faa64bb0eed70640c0f9b3ddd7a3"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js","statementMap":{"0":{"start":{"line":1,"column":12},"end":{"line":1,"column":35}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":37}},"2":{"start":{"line":5,"column":2},"end":{"line":5,"column":35}},"3":{"start":{"line":9,"column":2},"end":{"line":9,"column":35}},"4":{"start":{"line":12,"column":0},"end":{"line":12,"column":44}}},"fnMap":{"0":{"name":"signToken","decl":{"start":{"line":4,"column":9},"end":{"line":4,"column":18}},"loc":{"start":{"line":4,"column":28},"end":{"line":6,"column":1}},"line":4},"1":{"name":"verifyToken","decl":{"start":{"line":8,"column":9},"end":{"line":8,"column":20}},"loc":{"start":{"line":8,"column":28},"end":{"line":10,"column":1}},"line":8}},"branchMap":{},"s":{"0":10,"1":10,"2":1,"3":2,"4":10},"f":{"0":1,"1":2},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"d7b8e9b1304ab0135964e79a9372e3a90c422c73"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\aiRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\aiRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":21},"end":{"line":3,"column":59}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":7,"column":0},"end":{"line":7,"column":70}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":2,"1":2,"2":2,"3":2,"4":2,"5":2},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"84c1c0d1538754070138406039d321ec6a74e1d2"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\chatRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\chatRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":23},"end":{"line":3,"column":63}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":17}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":48}},"6":{"start":{"line":12,"column":0},"end":{"line":12,"column":49}},"7":{"start":{"line":15,"column":0},"end":{"line":15,"column":45}},"8":{"start":{"line":18,"column":0},"end":{"line":18,"column":64}},"9":{"start":{"line":21,"column":0},"end":{"line":21,"column":61}},"10":{"start":{"line":23,"column":0},"end":{"line":23,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":2,"1":2,"2":2,"3":2,"4":2,"5":2,"6":2,"7":2,"8":2,"9":2,"10":2},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"82ea6aef909da7b2c964a610d5e39ab2afbe64cc"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\index.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\index.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":4,"column":19},"end":{"line":4,"column":42}},"3":{"start":{"line":5,"column":19},"end":{"line":5,"column":42}},"4":{"start":{"line":6,"column":19},"end":{"line":6,"column":42}},"5":{"start":{"line":7,"column":17},"end":{"line":7,"column":38}},"6":{"start":{"line":9,"column":0},"end":{"line":9,"column":33}},"7":{"start":{"line":10,"column":0},"end":{"line":10,"column":33}},"8":{"start":{"line":11,"column":0},"end":{"line":11,"column":33}},"9":{"start":{"line":12,"column":0},"end":{"line":12,"column":28}},"10":{"start":{"line":14,"column":0},"end":{"line":14,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":2,"1":2,"2":2,"3":2,"4":2,"5":2,"6":2,"7":2,"8":2,"9":2,"10":2},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"35e9222ce2119a7ca65c7e97b3f75ef8fdeec91b"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\postRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\postRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":23},"end":{"line":3,"column":63}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":5,"column":15},"end":{"line":5,"column":47}},"5":{"start":{"line":8,"column":0},"end":{"line":8,"column":77}},"6":{"start":{"line":10,"column":0},"end":{"line":10,"column":50}},"7":{"start":{"line":11,"column":0},"end":{"line":11,"column":51}},"8":{"start":{"line":13,"column":0},"end":{"line":13,"column":52}},"9":{"start":{"line":14,"column":0},"end":{"line":14,"column":55}},"10":{"start":{"line":16,"column":0},"end":{"line":16,"column":58}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":2,"1":2,"2":2,"3":2,"4":2,"5":2,"6":2,"7":2,"8":2,"9":2,"10":2,"11":2},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"9dfcfb4e2b89bdf5bea27a6193353ae105013ec7"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\userRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\userRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":23},"end":{"line":2,"column":63}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":31}},"3":{"start":{"line":5,"column":0},"end":{"line":5,"column":50}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":44}},"5":{"start":{"line":7,"column":0},"end":{"line":7,"column":57}},"6":{"start":{"line":10,"column":0},"end":{"line":10,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":2,"1":2,"2":2,"3":2,"4":2,"5":2,"6":2},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"9a3c94306d7c8d600d66c8c45211556638027bfe"} } diff --git a/coverage/lcov-report/Dummy-Instagram/app.js.html b/coverage/lcov-report/Dummy-Instagram/app.js.html index 3089733..964f539 100644 --- a/coverage/lcov-report/Dummy-Instagram/app.js.html +++ b/coverage/lcov-report/Dummy-Instagram/app.js.html @@ -23,30 +23,30 @@

All files / Dummy-Instagram -
+

config -
+
Dummy-Instagram +
100%1/175%9/12100%0/0100%1/10%0/320%0/40%0/60%0/32
controllers -
+
Dummy-Instagram/controllers +
60.68%88/14565.3%32/4956.25%9/1661.87%86/1390%0/1460%0/490%0/160%0/140
helpers -
+
Dummy-Instagram/helpers +
35.13%13/370%0/50%0/736.11%13/3630%24/8032.25%10/3110%1/1029.87%23/77
models -
+
Dummy-Instagram/routes +
97.18%69/7170%7/1094.44%17/1897.18%69/710%0/47100%0/0100%0/00%0/47
1 2 @@ -122,138 +122,132 @@

All files / Dummy-Instagram 57 58 59 -60 -61 -62

  -  -  -  -  -  -  +6011x +11x +11x +11x +11x +11x +11x   -  -  -  -  +11x +11x +11x +11x           -  +11x     -  -  -  -  +11x +11x +11x +11x     -  +11x       -  +11x     -  -  +11x +8x   -  -  +8x +8x     -  -  +8x     -  -    +8x   -  -      +8x       -  -  -        - 
require('dotenv').config();
-const express = require('express');
-const app = express();
-const port = process.env.PORT || 3000;
-const handleError = require('./helpers/handleError');
-const routes = require('./routes');
-const cors = require('cors'); 
+ 
+ 
+ 
+ 
+11x
require('dotenv').config();
+const express = require('express');
+const app = express();
+const port = process.env.PORT || 3000;
+const handleError = require('./helpers/handleError');
+const routes = require('./routes');
+const cors = require('cors'); 
  
-const http = require('http');
-const server = http.createServer(app);
-const { Server } = require("socket.io");
-const io = new Server(server, {
+const http = require('http');
+const server = http.createServer(app);
+const { Server } = require("socket.io");
+const io = new Server(server, {
   cors: {
     origin: "*", 
   }
 });
  
-app.set('socketio', io); 
+app.set('socketio', io); 
  
 // Middleware
-app.use(cors()); 
-app.use(express.json());
-app.use(express.urlencoded({ extended: true }));
-app.use(express.static('public'));
+app.use(cors()); 
+app.use(express.json());
+app.use(express.urlencoded({ extended: true }));
+app.use(express.static('public'));
  
 // Router
-app.use("/", routes);
+app.use("/", routes);
  
  
 // Error handler
-app.use(handleError);
+app.use(handleError);
  
 // +++ Logika koneksi Socket.IO +++
-io.on('connection', (socket) => {
-  console.log('โœ… User connected:', socket.id);
+io.on('connection', (socket) => {
+  console.log('โœ… User connected:', socket.id);
  
-  socket.on('join_chat', (chatId) => {
-    socket.join(`chat_${chatId}`);
+  socket.on('join_chat', (chatId) => {
+    socket.join(`chat_${chatId}`);
   });
  
-  socket.on('send_message', (messageData) => {
-    io.to(`chat_${messageData.chatId}`).emit('new_message', messageData);
+  socket.on('send_message', (messageData) => {
+    // io.to(`chat_${messageData.chatId}`).emit('new_message', messageData);
   });
  
-  socket.on('user_typing', (typingData) => {
-    io.to(`chat_${typingData.chatId}`).emit('typing_status', typingData);
+  socket.on('user_typing', (typingData) => {
+    // io.to(`chat_${typingData.chatId}`).emit('typing_status', typingData);
   });
  
-  socket.on('disconnect', () => {
-    console.log('โŒ User disconnected:', socket.id);
+  socket.on('disconnect', () => {
+    // console.log('โŒ User disconnected:', socket.id);
   });
 });
  
+// if (process.env.NODE_ENV !== 'test') {
+//   server.listen(port, () => {
+//     console.log(`App listening on port http://localhost:${port}`);
+//   });
+// }
  
- 
-if (process.env.NODE_ENV !== 'test') {
-  server.listen(port, () => {
-    console.log(`App listening on port http://localhost:${port}`);
-  });
-}
- 
-module.exports = app;

+module.exports = app;

+ + diff --git a/client/package-lock.json b/client/package-lock.json new file mode 100644 index 0000000..96501c6 --- /dev/null +++ b/client/package-lock.json @@ -0,0 +1,2826 @@ +{ + "name": "client", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "client", + "version": "0.0.0", + "dependencies": { + "react": "^19.1.1", + "react-dom": "^19.1.1" + }, + "devDependencies": { + "@eslint/js": "^9.36.0", + "@types/react": "^19.1.16", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.4", + "eslint": "^9.36.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.22", + "globals": "^16.4.0", + "vite": "^7.1.7" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", + "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", + "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", + "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", + "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", + "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", + "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", + "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", + "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", + "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", + "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", + "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", + "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", + "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", + "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", + "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", + "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", + "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", + "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", + "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", + "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", + "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", + "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", + "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", + "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", + "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", + "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.0.tgz", + "integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.16.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz", + "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.37.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.37.0.tgz", + "integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz", + "integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.16.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz", + "integrity": "sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz", + "integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz", + "integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz", + "integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz", + "integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz", + "integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz", + "integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz", + "integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz", + "integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz", + "integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz", + "integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz", + "integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz", + "integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz", + "integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz", + "integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz", + "integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz", + "integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz", + "integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz", + "integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz", + "integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz", + "integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz", + "integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz", + "integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", + "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", + "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.4.tgz", + "integrity": "sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.4", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.38", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.16", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.16.tgz", + "integrity": "sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.26.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", + "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.9", + "caniuse-lite": "^1.0.30001746", + "electron-to-chromium": "^1.5.227", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001750", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001750.tgz", + "integrity": "sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.237", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.237.tgz", + "integrity": "sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==", + "dev": true, + "license": "ISC" + }, + "node_modules/esbuild": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", + "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.11", + "@esbuild/android-arm": "0.25.11", + "@esbuild/android-arm64": "0.25.11", + "@esbuild/android-x64": "0.25.11", + "@esbuild/darwin-arm64": "0.25.11", + "@esbuild/darwin-x64": "0.25.11", + "@esbuild/freebsd-arm64": "0.25.11", + "@esbuild/freebsd-x64": "0.25.11", + "@esbuild/linux-arm": "0.25.11", + "@esbuild/linux-arm64": "0.25.11", + "@esbuild/linux-ia32": "0.25.11", + "@esbuild/linux-loong64": "0.25.11", + "@esbuild/linux-mips64el": "0.25.11", + "@esbuild/linux-ppc64": "0.25.11", + "@esbuild/linux-riscv64": "0.25.11", + "@esbuild/linux-s390x": "0.25.11", + "@esbuild/linux-x64": "0.25.11", + "@esbuild/netbsd-arm64": "0.25.11", + "@esbuild/netbsd-x64": "0.25.11", + "@esbuild/openbsd-arm64": "0.25.11", + "@esbuild/openbsd-x64": "0.25.11", + "@esbuild/openharmony-arm64": "0.25.11", + "@esbuild/sunos-x64": "0.25.11", + "@esbuild/win32-arm64": "0.25.11", + "@esbuild/win32-ia32": "0.25.11", + "@esbuild/win32-x64": "0.25.11" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.37.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.37.0.tgz", + "integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.4.0", + "@eslint/core": "^0.16.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.37.0", + "@eslint/plugin-kit": "^0.4.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.24.tgz", + "integrity": "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", + "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", + "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.0" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rollup": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz", + "integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.4", + "@rollup/rollup-android-arm64": "4.52.4", + "@rollup/rollup-darwin-arm64": "4.52.4", + "@rollup/rollup-darwin-x64": "4.52.4", + "@rollup/rollup-freebsd-arm64": "4.52.4", + "@rollup/rollup-freebsd-x64": "4.52.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.4", + "@rollup/rollup-linux-arm-musleabihf": "4.52.4", + "@rollup/rollup-linux-arm64-gnu": "4.52.4", + "@rollup/rollup-linux-arm64-musl": "4.52.4", + "@rollup/rollup-linux-loong64-gnu": "4.52.4", + "@rollup/rollup-linux-ppc64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-musl": "4.52.4", + "@rollup/rollup-linux-s390x-gnu": "4.52.4", + "@rollup/rollup-linux-x64-gnu": "4.52.4", + "@rollup/rollup-linux-x64-musl": "4.52.4", + "@rollup/rollup-openharmony-arm64": "4.52.4", + "@rollup/rollup-win32-arm64-msvc": "4.52.4", + "@rollup/rollup-win32-ia32-msvc": "4.52.4", + "@rollup/rollup-win32-x64-gnu": "4.52.4", + "@rollup/rollup-win32-x64-msvc": "4.52.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "7.1.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.10.tgz", + "integrity": "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/client/package.json b/client/package.json new file mode 100644 index 0000000..06536b3 --- /dev/null +++ b/client/package.json @@ -0,0 +1,27 @@ +{ + "name": "client", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.1.1", + "react-dom": "^19.1.1" + }, + "devDependencies": { + "@eslint/js": "^9.36.0", + "@types/react": "^19.1.16", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.4", + "eslint": "^9.36.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.22", + "globals": "^16.4.0", + "vite": "^7.1.7" + } +} diff --git a/client/public/vite.svg b/client/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/client/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/App.css b/client/src/App.css new file mode 100644 index 0000000..b9d355d --- /dev/null +++ b/client/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/client/src/App.jsx b/client/src/App.jsx new file mode 100644 index 0000000..f67355a --- /dev/null +++ b/client/src/App.jsx @@ -0,0 +1,35 @@ +import { useState } from 'react' +import reactLogo from './assets/react.svg' +import viteLogo from '/vite.svg' +import './App.css' + +function App() { + const [count, setCount] = useState(0) + + return ( + <> + +

Vite + React

+
+ +

+ Edit src/App.jsx and save to test HMR +

+
+

+ Click on the Vite and React logos to learn more +

+ + ) +} + +export default App diff --git a/client/src/assets/react.svg b/client/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/client/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/index.css b/client/src/index.css new file mode 100644 index 0000000..08a3ac9 --- /dev/null +++ b/client/src/index.css @@ -0,0 +1,68 @@ +:root { + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/client/src/main.jsx b/client/src/main.jsx new file mode 100644 index 0000000..b9a1a6d --- /dev/null +++ b/client/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) diff --git a/client/vite.config.js b/client/vite.config.js new file mode 100644 index 0000000..8b0f57b --- /dev/null +++ b/client/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], +}) diff --git a/coverage/clover.xml b/coverage/clover.xml index e7c6f0a..a6b72c8 100644 --- a/coverage/clover.xml +++ b/coverage/clover.xml @@ -1,11 +1,11 @@ - - - + + + - + - + @@ -27,6 +27,14 @@ + + + + + + + + diff --git a/coverage/coverage-final.json b/coverage/coverage-final.json index 9b843ba..2f509ca 100644 --- a/coverage/coverage-final.json +++ b/coverage/coverage-final.json @@ -1,4 +1,4 @@ -{"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}},"1":{"start":{"line":2,"column":16},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":12},"end":{"line":3,"column":21}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"4":{"start":{"line":5,"column":20},"end":{"line":5,"column":52}},"5":{"start":{"line":6,"column":15},"end":{"line":6,"column":34}},"6":{"start":{"line":7,"column":13},"end":{"line":7,"column":28}},"7":{"start":{"line":9,"column":13},"end":{"line":9,"column":28}},"8":{"start":{"line":10,"column":15},"end":{"line":10,"column":37}},"9":{"start":{"line":11,"column":19},"end":{"line":11,"column":39}},"10":{"start":{"line":12,"column":11},"end":{"line":16,"column":2}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}},"12":{"start":{"line":21,"column":0},"end":{"line":21,"column":16}},"13":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}},"14":{"start":{"line":23,"column":0},"end":{"line":23,"column":48}},"15":{"start":{"line":24,"column":0},"end":{"line":24,"column":34}},"16":{"start":{"line":27,"column":0},"end":{"line":27,"column":21}},"17":{"start":{"line":31,"column":0},"end":{"line":31,"column":21}},"18":{"start":{"line":34,"column":0},"end":{"line":52,"column":3}},"19":{"start":{"line":37,"column":2},"end":{"line":39,"column":5}},"20":{"start":{"line":38,"column":4},"end":{"line":38,"column":34}},"21":{"start":{"line":60,"column":0},"end":{"line":60,"column":21}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":34,"column":20},"end":{"line":34,"column":21}},"loc":{"start":{"line":34,"column":32},"end":{"line":52,"column":1}},"line":34},"1":{"name":"(anonymous_1)","decl":{"start":{"line":37,"column":25},"end":{"line":37,"column":26}},"loc":{"start":{"line":37,"column":37},"end":{"line":39,"column":3}},"line":37}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"type":"binary-expr","locations":[{"start":{"line":4,"column":13},"end":{"line":4,"column":29}},{"start":{"line":4,"column":33},"end":{"line":4,"column":37}}],"line":4}},"s":{"0":11,"1":11,"2":11,"3":11,"4":11,"5":11,"6":11,"7":11,"8":11,"9":11,"10":11,"11":11,"12":11,"13":11,"14":11,"15":11,"16":11,"17":11,"18":11,"19":8,"20":8,"21":11},"f":{"0":8,"1":8},"b":{"0":[11,7]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"bbb5833951714a973c3acaee9d97f047ad7307c1"} +{"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}},"1":{"start":{"line":2,"column":16},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":12},"end":{"line":3,"column":21}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"4":{"start":{"line":5,"column":20},"end":{"line":5,"column":52}},"5":{"start":{"line":6,"column":15},"end":{"line":6,"column":34}},"6":{"start":{"line":7,"column":13},"end":{"line":7,"column":28}},"7":{"start":{"line":9,"column":13},"end":{"line":9,"column":28}},"8":{"start":{"line":10,"column":15},"end":{"line":10,"column":37}},"9":{"start":{"line":11,"column":19},"end":{"line":11,"column":39}},"10":{"start":{"line":12,"column":11},"end":{"line":16,"column":2}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}},"12":{"start":{"line":21,"column":0},"end":{"line":21,"column":16}},"13":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}},"14":{"start":{"line":23,"column":0},"end":{"line":23,"column":48}},"15":{"start":{"line":24,"column":0},"end":{"line":24,"column":34}},"16":{"start":{"line":27,"column":0},"end":{"line":27,"column":21}},"17":{"start":{"line":31,"column":0},"end":{"line":31,"column":21}},"18":{"start":{"line":34,"column":0},"end":{"line":52,"column":3}},"19":{"start":{"line":37,"column":2},"end":{"line":39,"column":5}},"20":{"start":{"line":38,"column":4},"end":{"line":38,"column":34}},"21":{"start":{"line":41,"column":2},"end":{"line":43,"column":5}},"22":{"start":{"line":42,"column":4},"end":{"line":42,"column":73}},"23":{"start":{"line":45,"column":2},"end":{"line":47,"column":5}},"24":{"start":{"line":46,"column":4},"end":{"line":46,"column":73}},"25":{"start":{"line":49,"column":2},"end":{"line":51,"column":5}},"26":{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},"27":{"start":{"line":55,"column":2},"end":{"line":57,"column":5}},"28":{"start":{"line":56,"column":4},"end":{"line":56,"column":66}},"29":{"start":{"line":60,"column":0},"end":{"line":60,"column":21}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":34,"column":20},"end":{"line":34,"column":21}},"loc":{"start":{"line":34,"column":32},"end":{"line":52,"column":1}},"line":34},"1":{"name":"(anonymous_1)","decl":{"start":{"line":37,"column":25},"end":{"line":37,"column":26}},"loc":{"start":{"line":37,"column":37},"end":{"line":39,"column":3}},"line":37},"2":{"name":"(anonymous_2)","decl":{"start":{"line":41,"column":28},"end":{"line":41,"column":29}},"loc":{"start":{"line":41,"column":45},"end":{"line":43,"column":3}},"line":41},"3":{"name":"(anonymous_3)","decl":{"start":{"line":45,"column":27},"end":{"line":45,"column":28}},"loc":{"start":{"line":45,"column":43},"end":{"line":47,"column":3}},"line":45},"4":{"name":"(anonymous_4)","decl":{"start":{"line":49,"column":26},"end":{"line":49,"column":27}},"loc":{"start":{"line":49,"column":32},"end":{"line":51,"column":3}},"line":49},"5":{"name":"(anonymous_5)","decl":{"start":{"line":55,"column":22},"end":{"line":55,"column":23}},"loc":{"start":{"line":55,"column":28},"end":{"line":57,"column":3}},"line":55}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"type":"binary-expr","locations":[{"start":{"line":4,"column":13},"end":{"line":4,"column":29}},{"start":{"line":4,"column":33},"end":{"line":4,"column":37}}],"line":4},"1":{"loc":{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},"type":"if","locations":[{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},{"start":{},"end":{}}],"line":54}},"s":{"0":11,"1":11,"2":11,"3":11,"4":11,"5":11,"6":11,"7":11,"8":11,"9":11,"10":11,"11":11,"12":11,"13":11,"14":11,"15":11,"16":11,"17":11,"18":11,"19":8,"20":8,"21":8,"22":0,"23":8,"24":0,"25":8,"26":11,"27":0,"28":0,"29":11},"f":{"0":8,"1":8,"2":0,"3":0,"4":0,"5":0},"b":{"0":[11,7],"1":[0,11]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2a1669a6594937f4b2db57508e47b0260b54d91b"} ,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js","statementMap":{"0":{"start":{"line":1,"column":33},"end":{"line":1,"column":71}},"1":{"start":{"line":5,"column":4},"end":{"line":21,"column":5}},"2":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"3":{"start":{"line":8,"column":8},"end":{"line":8,"column":39}},"4":{"start":{"line":11,"column":21},"end":{"line":11,"column":32}},"5":{"start":{"line":12,"column":20},"end":{"line":12,"column":54}},"6":{"start":{"line":14,"column":6},"end":{"line":18,"column":9}},"7":{"start":{"line":20,"column":6},"end":{"line":20,"column":16}},"8":{"start":{"line":25,"column":0},"end":{"line":25,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":4,"column":2},"end":{"line":4,"column":3}},"loc":{"start":{"line":4,"column":50},"end":{"line":22,"column":3}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"type":"if","locations":[{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":10},"end":{"line":7,"column":35}},"type":"binary-expr","locations":[{"start":{"line":7,"column":10},"end":{"line":7,"column":19}},{"start":{"line":7,"column":23},"end":{"line":7,"column":35}}],"line":7}},"s":{"0":3,"1":2,"2":2,"3":1,"4":1,"5":1,"6":1,"7":1,"8":3},"f":{"0":2},"b":{"0":[1,1],"1":[2,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"5a3a8d6179df7a779a1e7786dcd48a5a6657888b"} ,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js","statementMap":{"0":{"start":{"line":1,"column":43},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":24}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":52}},"3":{"start":{"line":8,"column":8},"end":{"line":34,"column":9}},"4":{"start":{"line":9,"column":34},"end":{"line":9,"column":42}},"5":{"start":{"line":10,"column":27},"end":{"line":10,"column":38}},"6":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"7":{"start":{"line":13,"column":16},"end":{"line":13,"column":97}},"8":{"start":{"line":17,"column":36},"end":{"line":29,"column":14}},"9":{"start":{"line":31,"column":12},"end":{"line":31,"column":55}},"10":{"start":{"line":33,"column":12},"end":{"line":33,"column":22}},"11":{"start":{"line":39,"column":8},"end":{"line":55,"column":9}},"12":{"start":{"line":40,"column":27},"end":{"line":40,"column":38}},"13":{"start":{"line":41,"column":26},"end":{"line":50,"column":14}},"14":{"start":{"line":52,"column":12},"end":{"line":52,"column":28}},"15":{"start":{"line":54,"column":12},"end":{"line":54,"column":22}},"16":{"start":{"line":60,"column":8},"end":{"line":79,"column":9}},"17":{"start":{"line":61,"column":31},"end":{"line":61,"column":41}},"18":{"start":{"line":62,"column":27},"end":{"line":62,"column":38}},"19":{"start":{"line":65,"column":25},"end":{"line":65,"column":52}},"20":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"21":{"start":{"line":67,"column":16},"end":{"line":67,"column":44}},"22":{"start":{"line":70,"column":29},"end":{"line":74,"column":14}},"23":{"start":{"line":76,"column":12},"end":{"line":76,"column":31}},"24":{"start":{"line":78,"column":12},"end":{"line":78,"column":22}},"25":{"start":{"line":83,"column":8},"end":{"line":99,"column":9}},"26":{"start":{"line":84,"column":27},"end":{"line":84,"column":38}},"27":{"start":{"line":85,"column":36},"end":{"line":95,"column":14}},"28":{"start":{"line":96,"column":12},"end":{"line":96,"column":55}},"29":{"start":{"line":98,"column":12},"end":{"line":98,"column":22}},"30":{"start":{"line":104,"column":8},"end":{"line":147,"column":9}},"31":{"start":{"line":105,"column":31},"end":{"line":105,"column":41}},"32":{"start":{"line":106,"column":32},"end":{"line":106,"column":40}},"33":{"start":{"line":107,"column":27},"end":{"line":107,"column":38}},"34":{"start":{"line":108,"column":23},"end":{"line":108,"column":46}},"35":{"start":{"line":110,"column":25},"end":{"line":110,"column":52}},"36":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"37":{"start":{"line":112,"column":16},"end":{"line":112,"column":70}},"38":{"start":{"line":117,"column":33},"end":{"line":117,"column":84}},"39":{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},"40":{"start":{"line":119,"column":16},"end":{"line":119,"column":99}},"41":{"start":{"line":123,"column":32},"end":{"line":127,"column":14}},"42":{"start":{"line":129,"column":12},"end":{"line":129,"column":73}},"43":{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},"44":{"start":{"line":132,"column":39},"end":{"line":132,"column":63}},"45":{"start":{"line":134,"column":34},"end":{"line":138,"column":18}},"46":{"start":{"line":140,"column":16},"end":{"line":140,"column":75}},"47":{"start":{"line":143,"column":12},"end":{"line":143,"column":30}},"48":{"start":{"line":144,"column":12},"end":{"line":144,"column":46}},"49":{"start":{"line":146,"column":12},"end":{"line":146,"column":22}},"50":{"start":{"line":151,"column":0},"end":{"line":151,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":4},"end":{"line":7,"column":5}},"loc":{"start":{"line":7,"column":49},"end":{"line":35,"column":5}},"line":7},"1":{"name":"(anonymous_1)","decl":{"start":{"line":38,"column":4},"end":{"line":38,"column":5}},"loc":{"start":{"line":38,"column":46},"end":{"line":56,"column":5}},"line":38},"2":{"name":"(anonymous_2)","decl":{"start":{"line":59,"column":4},"end":{"line":59,"column":5}},"loc":{"start":{"line":59,"column":49},"end":{"line":80,"column":5}},"line":59},"3":{"name":"(anonymous_3)","decl":{"start":{"line":82,"column":4},"end":{"line":82,"column":5}},"loc":{"start":{"line":82,"column":46},"end":{"line":100,"column":5}},"line":82},"4":{"name":"(anonymous_4)","decl":{"start":{"line":103,"column":4},"end":{"line":103,"column":5}},"loc":{"start":{"line":103,"column":45},"end":{"line":148,"column":5}},"line":103}},"branchMap":{"0":{"loc":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"type":"if","locations":[{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},{"start":{},"end":{}}],"line":12},"1":{"loc":{"start":{"line":31,"column":23},"end":{"line":31,"column":42}},"type":"cond-expr","locations":[{"start":{"line":31,"column":33},"end":{"line":31,"column":36}},{"start":{"line":31,"column":39},"end":{"line":31,"column":42}}],"line":31},"2":{"loc":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"type":"if","locations":[{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},{"start":{},"end":{}}],"line":66},"3":{"loc":{"start":{"line":66,"column":16},"end":{"line":66,"column":78}},"type":"binary-expr","locations":[{"start":{"line":66,"column":16},"end":{"line":66,"column":21}},{"start":{"line":66,"column":26},"end":{"line":66,"column":48}},{"start":{"line":66,"column":52},"end":{"line":66,"column":77}}],"line":66},"4":{"loc":{"start":{"line":96,"column":23},"end":{"line":96,"column":42}},"type":"cond-expr","locations":[{"start":{"line":96,"column":33},"end":{"line":96,"column":36}},{"start":{"line":96,"column":39},"end":{"line":96,"column":42}}],"line":96},"5":{"loc":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"type":"if","locations":[{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},{"start":{},"end":{}}],"line":111},"6":{"loc":{"start":{"line":117,"column":33},"end":{"line":117,"column":84}},"type":"binary-expr","locations":[{"start":{"line":117,"column":33},"end":{"line":117,"column":55}},{"start":{"line":117,"column":59},"end":{"line":117,"column":84}}],"line":117},"7":{"loc":{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},"type":"if","locations":[{"start":{"line":118,"column":12},"end":{"line":120,"column":13}},{"start":{},"end":{}}],"line":118},"8":{"loc":{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},"type":"if","locations":[{"start":{"line":131,"column":12},"end":{"line":141,"column":13}},{"start":{},"end":{}}],"line":131}},"s":{"0":3,"1":3,"2":3,"3":4,"4":4,"5":4,"6":4,"7":1,"8":3,"9":2,"10":2,"11":2,"12":2,"13":2,"14":1,"15":1,"16":4,"17":4,"18":4,"19":4,"20":3,"21":2,"22":1,"23":1,"24":3,"25":3,"26":3,"27":3,"28":2,"29":1,"30":5,"31":5,"32":5,"33":5,"34":5,"35":5,"36":5,"37":1,"38":4,"39":4,"40":1,"41":3,"42":2,"43":2,"44":1,"45":1,"46":1,"47":2,"48":2,"49":3,"50":3},"f":{"0":4,"1":2,"2":4,"3":3,"4":5},"b":{"0":[1,3],"1":[1,1],"2":[2,1],"3":[3,2,1],"4":[1,1],"5":[1,4],"6":[4,1],"7":[1,3],"8":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2917d152140ab09724020f4ab1282f6f8aefef73"} ,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js","statementMap":{"0":{"start":{"line":1,"column":46},"end":{"line":1,"column":66}},"1":{"start":{"line":6,"column":4},"end":{"line":33,"column":5}},"2":{"start":{"line":7,"column":49},"end":{"line":7,"column":57}},"3":{"start":{"line":10,"column":6},"end":{"line":12,"column":7}},"4":{"start":{"line":11,"column":8},"end":{"line":11,"column":98}},"5":{"start":{"line":15,"column":19},"end":{"line":20,"column":8}},"6":{"start":{"line":23,"column":21},"end":{"line":26,"column":9}},"7":{"start":{"line":23,"column":46},"end":{"line":26,"column":7}},"8":{"start":{"line":28,"column":6},"end":{"line":28,"column":37}},"9":{"start":{"line":30,"column":6},"end":{"line":30,"column":75}},"10":{"start":{"line":32,"column":6},"end":{"line":32,"column":16}},"11":{"start":{"line":38,"column":4},"end":{"line":52,"column":5}},"12":{"start":{"line":39,"column":20},"end":{"line":48,"column":8}},"13":{"start":{"line":49,"column":6},"end":{"line":49,"column":22}},"14":{"start":{"line":51,"column":6},"end":{"line":51,"column":16}},"15":{"start":{"line":57,"column":4},"end":{"line":66,"column":5}},"16":{"start":{"line":58,"column":20},"end":{"line":62,"column":8}},"17":{"start":{"line":63,"column":6},"end":{"line":63,"column":22}},"18":{"start":{"line":65,"column":6},"end":{"line":65,"column":16}},"19":{"start":{"line":71,"column":4},"end":{"line":83,"column":5}},"20":{"start":{"line":72,"column":21},"end":{"line":72,"column":31}},"21":{"start":{"line":73,"column":49},"end":{"line":73,"column":57}},"22":{"start":{"line":75,"column":19},"end":{"line":75,"column":42}},"23":{"start":{"line":76,"column":6},"end":{"line":76,"column":44}},"24":{"start":{"line":76,"column":17},"end":{"line":76,"column":44}},"25":{"start":{"line":77,"column":6},"end":{"line":77,"column":70}},"26":{"start":{"line":77,"column":39},"end":{"line":77,"column":70}},"27":{"start":{"line":79,"column":6},"end":{"line":79,"column":72}},"28":{"start":{"line":80,"column":6},"end":{"line":80,"column":63}},"29":{"start":{"line":82,"column":6},"end":{"line":82,"column":16}},"30":{"start":{"line":88,"column":4},"end":{"line":98,"column":5}},"31":{"start":{"line":89,"column":21},"end":{"line":89,"column":31}},"32":{"start":{"line":90,"column":19},"end":{"line":90,"column":42}},"33":{"start":{"line":91,"column":6},"end":{"line":91,"column":44}},"34":{"start":{"line":91,"column":17},"end":{"line":91,"column":44}},"35":{"start":{"line":92,"column":6},"end":{"line":92,"column":70}},"36":{"start":{"line":92,"column":39},"end":{"line":92,"column":70}},"37":{"start":{"line":94,"column":6},"end":{"line":94,"column":27}},"38":{"start":{"line":95,"column":6},"end":{"line":95,"column":57}},"39":{"start":{"line":97,"column":6},"end":{"line":97,"column":16}},"40":{"start":{"line":103,"column":4},"end":{"line":123,"column":5}},"41":{"start":{"line":104,"column":21},"end":{"line":104,"column":31}},"42":{"start":{"line":105,"column":19},"end":{"line":105,"column":42}},"43":{"start":{"line":106,"column":6},"end":{"line":106,"column":44}},"44":{"start":{"line":106,"column":17},"end":{"line":106,"column":44}},"45":{"start":{"line":108,"column":27},"end":{"line":110,"column":8}},"46":{"start":{"line":113,"column":6},"end":{"line":119,"column":7}},"47":{"start":{"line":114,"column":8},"end":{"line":114,"column":37}},"48":{"start":{"line":115,"column":8},"end":{"line":115,"column":33}},"49":{"start":{"line":117,"column":8},"end":{"line":117,"column":63}},"50":{"start":{"line":118,"column":8},"end":{"line":118,"column":31}},"51":{"start":{"line":120,"column":6},"end":{"line":120,"column":28}},"52":{"start":{"line":122,"column":6},"end":{"line":122,"column":16}},"53":{"start":{"line":127,"column":0},"end":{"line":127,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":2},"end":{"line":5,"column":3}},"loc":{"start":{"line":5,"column":42},"end":{"line":34,"column":3}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":23,"column":35},"end":{"line":23,"column":36}},"loc":{"start":{"line":23,"column":46},"end":{"line":26,"column":7}},"line":23},"2":{"name":"(anonymous_2)","decl":{"start":{"line":37,"column":2},"end":{"line":37,"column":3}},"loc":{"start":{"line":37,"column":49},"end":{"line":53,"column":3}},"line":37},"3":{"name":"(anonymous_3)","decl":{"start":{"line":56,"column":2},"end":{"line":56,"column":3}},"loc":{"start":{"line":56,"column":42},"end":{"line":67,"column":3}},"line":56},"4":{"name":"(anonymous_4)","decl":{"start":{"line":70,"column":2},"end":{"line":70,"column":3}},"loc":{"start":{"line":70,"column":42},"end":{"line":84,"column":3}},"line":70},"5":{"name":"(anonymous_5)","decl":{"start":{"line":87,"column":2},"end":{"line":87,"column":3}},"loc":{"start":{"line":87,"column":42},"end":{"line":99,"column":3}},"line":87},"6":{"name":"(anonymous_6)","decl":{"start":{"line":102,"column":2},"end":{"line":102,"column":3}},"loc":{"start":{"line":102,"column":42},"end":{"line":124,"column":3}},"line":102}},"branchMap":{"0":{"loc":{"start":{"line":10,"column":6},"end":{"line":12,"column":7}},"type":"if","locations":[{"start":{"line":10,"column":6},"end":{"line":12,"column":7}},{"start":{},"end":{}}],"line":10},"1":{"loc":{"start":{"line":10,"column":10},"end":{"line":10,"column":46}},"type":"binary-expr","locations":[{"start":{"line":10,"column":10},"end":{"line":10,"column":20}},{"start":{"line":10,"column":24},"end":{"line":10,"column":46}}],"line":10},"2":{"loc":{"start":{"line":76,"column":6},"end":{"line":76,"column":44}},"type":"if","locations":[{"start":{"line":76,"column":6},"end":{"line":76,"column":44}},{"start":{},"end":{}}],"line":76},"3":{"loc":{"start":{"line":77,"column":6},"end":{"line":77,"column":70}},"type":"if","locations":[{"start":{"line":77,"column":6},"end":{"line":77,"column":70}},{"start":{},"end":{}}],"line":77},"4":{"loc":{"start":{"line":91,"column":6},"end":{"line":91,"column":44}},"type":"if","locations":[{"start":{"line":91,"column":6},"end":{"line":91,"column":44}},{"start":{},"end":{}}],"line":91},"5":{"loc":{"start":{"line":92,"column":6},"end":{"line":92,"column":70}},"type":"if","locations":[{"start":{"line":92,"column":6},"end":{"line":92,"column":70}},{"start":{},"end":{}}],"line":92},"6":{"loc":{"start":{"line":106,"column":6},"end":{"line":106,"column":44}},"type":"if","locations":[{"start":{"line":106,"column":6},"end":{"line":106,"column":44}},{"start":{},"end":{}}],"line":106},"7":{"loc":{"start":{"line":113,"column":6},"end":{"line":119,"column":7}},"type":"if","locations":[{"start":{"line":113,"column":6},"end":{"line":119,"column":7}},{"start":{"line":116,"column":13},"end":{"line":119,"column":7}}],"line":113}},"s":{"0":3,"1":3,"2":3,"3":3,"4":1,"5":2,"6":1,"7":2,"8":1,"9":1,"10":2,"11":2,"12":2,"13":1,"14":1,"15":2,"16":2,"17":1,"18":1,"19":4,"20":4,"21":4,"22":4,"23":4,"24":1,"25":3,"26":1,"27":2,"28":1,"29":3,"30":4,"31":4,"32":4,"33":4,"34":1,"35":3,"36":1,"37":2,"38":1,"39":3,"40":4,"41":4,"42":4,"43":3,"44":1,"45":2,"46":2,"47":1,"48":1,"49":1,"50":1,"51":2,"52":2,"53":3},"f":{"0":3,"1":2,"2":2,"3":2,"4":4,"5":4,"6":4},"b":{"0":[1,2],"1":[3,3],"2":[1,3],"3":[1,2],"4":[1,3],"5":[1,2],"6":[1,2],"7":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"7acbe67c59c0a71f7523b6569d057e7acc03f284"} diff --git a/coverage/lcov-report/Dummy-Instagram/app.js.html b/coverage/lcov-report/Dummy-Instagram/app.js.html index 8c691d7..c4899b4 100644 --- a/coverage/lcov-report/Dummy-Instagram/app.js.html +++ b/coverage/lcov-report/Dummy-Instagram/app.js.html @@ -23,30 +23,30 @@

All files / Dummy-Instagram
- 100% + 86.66% Statements - 22/22 + 26/30
- 100% + 75% Branches - 2/2 + 3/4
- 100% + 33.33% Functions - 2/2 + 2/6
- 100% + 86.66% Lines - 22/22 + 26/30
@@ -162,22 +162,22 @@

All files / Dummy-Instagram 8x     +8x +      +8x +      +8x         -  -  -  -  -  -  -  -  +11x +  +        @@ -215,30 +215,30 @@

All files / Dummy-Instagram   // +++ Logika koneksi Socket.IO +++ io.on('connection', (socket) => { - // console.log('โœ… User connected:', socket.id); + // console.log('โœ… User connected:', socket.id); //comment untuk npx jest   socket.on('join_chat', (chatId) => { socket.join(`chat_${chatId}`); });   - // socket.on('send_message', (messageData) => { - // // io.to(`chat_${messageData.chatId}`).emit('new_message', messageData); //comment untuk npx jest - // }); + socket.on('send_message', (messageData) => { //comment untuk npx jest + io.to(`chat_${messageData.chatId}`).emit('new_message', messageData); + });   - // socket.on('user_typing', (typingData) => { - // // io.to(`chat_${typingData.chatId}`).emit('typing_status', typingData); //comment untuk npx jest - // }); + socket.on('user_typing', (typingData) => { //comment untuk npx jest + io.to(`chat_${typingData.chatId}`).emit('typing_status', typingData); + });   - // socket.on('disconnect', () => { - // // console.log('โŒ User disconnected:', socket.id); //comment untuk npx jest - // }); + socket.on('disconnect', () => { //comment untuk npx jest + // console.log('โŒ User disconnected:', socket.id); + }); });   -// if (process.env.NODE_ENV !== 'test') { //comment untuk npx jest -// server.listen(port, () => { -// console.log(`App listening on port http://localhost:${port}`); -// }); -// } +Iif (process.env.NODE_ENV !== 'test') { //comment untuk npx jest + server.listen(port, () => { + console.log(`App listening on port http://localhost:${port}`); + }); +}   module.exports = app;

@@ -247,7 +247,7 @@

All files / Dummy-Instagram - - diff --git a/client/package-lock.json b/client/package-lock.json deleted file mode 100644 index cd98212..0000000 --- a/client/package-lock.json +++ /dev/null @@ -1,3308 +0,0 @@ -{ - "name": "client", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "client", - "version": "0.0.0", - "dependencies": { - "bootstrap": "^5.3.2", - "react": "^19.1.1", - "react-bootstrap": "^2.10.0", - "react-dom": "^19.1.1", - "react-router-dom": "^6.22.0", - "socket.io-client": "^4.7.4" - }, - "devDependencies": { - "@eslint/js": "^9.36.0", - "@types/react": "^19.1.16", - "@types/react-dom": "^19.1.9", - "@vitejs/plugin-react": "^5.0.4", - "eslint": "^9.36.0", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.22", - "globals": "^16.4.0", - "vite": "^7.1.7" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", - "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", - "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.4" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", - "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", - "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", - "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", - "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", - "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", - "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", - "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", - "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", - "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", - "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", - "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", - "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", - "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", - "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", - "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", - "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", - "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", - "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", - "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", - "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", - "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", - "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", - "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", - "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", - "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", - "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", - "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", - "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.6", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.0.tgz", - "integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.16.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz", - "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "9.37.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.37.0.tgz", - "integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz", - "integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.16.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, - "node_modules/@react-aria/ssr": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.10.tgz", - "integrity": "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==", - "license": "Apache-2.0", - "dependencies": { - "@swc/helpers": "^0.5.0" - }, - "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" - } - }, - "node_modules/@remix-run/router": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", - "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@restart/hooks": { - "version": "0.4.16", - "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", - "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==", - "license": "MIT", - "dependencies": { - "dequal": "^2.0.3" - }, - "peerDependencies": { - "react": ">=16.8.0" - } - }, - "node_modules/@restart/ui": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.9.4.tgz", - "integrity": "sha512-N4C7haUc3vn4LTwVUPlkJN8Ach/+yIMvRuTVIhjilNHqegY60SGLrzud6errOMNJwSnmYFnt1J0H/k8FE3A4KA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.26.0", - "@popperjs/core": "^2.11.8", - "@react-aria/ssr": "^3.5.0", - "@restart/hooks": "^0.5.0", - "@types/warning": "^3.0.3", - "dequal": "^2.0.3", - "dom-helpers": "^5.2.0", - "uncontrollable": "^8.0.4", - "warning": "^4.0.3" - }, - "peerDependencies": { - "react": ">=16.14.0", - "react-dom": ">=16.14.0" - } - }, - "node_modules/@restart/ui/node_modules/@restart/hooks": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.5.1.tgz", - "integrity": "sha512-EMoH04NHS1pbn07iLTjIjgttuqb7qu4+/EyhAx27MHpoENcB2ZdSsLTNxmKD+WEPnZigo62Qc8zjGnNxoSE/5Q==", - "license": "MIT", - "dependencies": { - "dequal": "^2.0.3" - }, - "peerDependencies": { - "react": ">=16.8.0" - } - }, - "node_modules/@restart/ui/node_modules/uncontrollable": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz", - "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==", - "license": "MIT", - "peerDependencies": { - "react": ">=16.14.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.38", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz", - "integrity": "sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz", - "integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz", - "integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz", - "integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz", - "integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz", - "integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz", - "integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz", - "integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz", - "integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz", - "integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz", - "integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz", - "integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz", - "integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz", - "integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz", - "integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz", - "integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz", - "integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz", - "integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz", - "integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz", - "integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz", - "integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz", - "integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz", - "integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", - "license": "MIT" - }, - "node_modules/@swc/helpers": { - "version": "0.5.17", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", - "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.8.0" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", - "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", - "license": "MIT", - "dependencies": { - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", - "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, - "node_modules/@types/react-transition-group": { - "version": "4.4.12", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", - "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/warning": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", - "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==", - "license": "MIT" - }, - "node_modules/@vitejs/plugin-react": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.4.tgz", - "integrity": "sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.28.4", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.38", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.8.16", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.16.tgz", - "integrity": "sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "node_modules/bootstrap": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz", - "integrity": "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/twbs" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/bootstrap" - } - ], - "license": "MIT", - "peerDependencies": { - "@popperjs/core": "^2.11.8" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/browserslist": { - "version": "4.26.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", - "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.8.9", - "caniuse-lite": "^1.0.30001746", - "electron-to-chromium": "^1.5.227", - "node-releases": "^2.0.21", - "update-browserslist-db": "^1.1.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001750", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001750.tgz", - "integrity": "sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/classnames": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", - "license": "MIT" - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.237", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.237.tgz", - "integrity": "sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==", - "dev": true, - "license": "ISC" - }, - "node_modules/engine.io-client": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz", - "integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.17.1", - "xmlhttprequest-ssl": "~2.1.1" - } - }, - "node_modules/engine.io-client/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/engine.io-parser": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", - "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/esbuild": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", - "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.11", - "@esbuild/android-arm": "0.25.11", - "@esbuild/android-arm64": "0.25.11", - "@esbuild/android-x64": "0.25.11", - "@esbuild/darwin-arm64": "0.25.11", - "@esbuild/darwin-x64": "0.25.11", - "@esbuild/freebsd-arm64": "0.25.11", - "@esbuild/freebsd-x64": "0.25.11", - "@esbuild/linux-arm": "0.25.11", - "@esbuild/linux-arm64": "0.25.11", - "@esbuild/linux-ia32": "0.25.11", - "@esbuild/linux-loong64": "0.25.11", - "@esbuild/linux-mips64el": "0.25.11", - "@esbuild/linux-ppc64": "0.25.11", - "@esbuild/linux-riscv64": "0.25.11", - "@esbuild/linux-s390x": "0.25.11", - "@esbuild/linux-x64": "0.25.11", - "@esbuild/netbsd-arm64": "0.25.11", - "@esbuild/netbsd-x64": "0.25.11", - "@esbuild/openbsd-arm64": "0.25.11", - "@esbuild/openbsd-x64": "0.25.11", - "@esbuild/openharmony-arm64": "0.25.11", - "@esbuild/sunos-x64": "0.25.11", - "@esbuild/win32-arm64": "0.25.11", - "@esbuild/win32-ia32": "0.25.11", - "@esbuild/win32-x64": "0.25.11" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.37.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.37.0.tgz", - "integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.0", - "@eslint/config-helpers": "^0.4.0", - "@eslint/core": "^0.16.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.37.0", - "@eslint/plugin-kit": "^0.4.0", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", - "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-react-refresh": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.24.tgz", - "integrity": "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "eslint": ">=8.40" - } - }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", - "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.23", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", - "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types-extra": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", - "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", - "license": "MIT", - "dependencies": { - "react-is": "^16.3.2", - "warning": "^4.0.0" - }, - "peerDependencies": { - "react": ">=0.14.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/react": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", - "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-bootstrap": { - "version": "2.10.10", - "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.10.tgz", - "integrity": "sha512-gMckKUqn8aK/vCnfwoBpBVFUGT9SVQxwsYrp9yDHt0arXMamxALerliKBxr1TPbntirK/HGrUAHYbAeQTa9GHQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.24.7", - "@restart/hooks": "^0.4.9", - "@restart/ui": "^1.9.4", - "@types/prop-types": "^15.7.12", - "@types/react-transition-group": "^4.4.6", - "classnames": "^2.3.2", - "dom-helpers": "^5.2.1", - "invariant": "^2.2.4", - "prop-types": "^15.8.1", - "prop-types-extra": "^1.1.0", - "react-transition-group": "^4.4.5", - "uncontrollable": "^7.2.1", - "warning": "^4.0.3" - }, - "peerDependencies": { - "@types/react": ">=16.14.8", - "react": ">=16.14.0", - "react-dom": ">=16.14.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-dom": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", - "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", - "license": "MIT", - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.0" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, - "node_modules/react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", - "license": "MIT" - }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-router": { - "version": "6.30.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.1.tgz", - "integrity": "sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==", - "license": "MIT", - "dependencies": { - "@remix-run/router": "1.23.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/react-router-dom": { - "version": "6.30.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.1.tgz", - "integrity": "sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==", - "license": "MIT", - "dependencies": { - "@remix-run/router": "1.23.0", - "react-router": "6.30.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, - "node_modules/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", - "license": "BSD-3-Clause", - "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/rollup": { - "version": "4.52.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz", - "integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.52.4", - "@rollup/rollup-android-arm64": "4.52.4", - "@rollup/rollup-darwin-arm64": "4.52.4", - "@rollup/rollup-darwin-x64": "4.52.4", - "@rollup/rollup-freebsd-arm64": "4.52.4", - "@rollup/rollup-freebsd-x64": "4.52.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.52.4", - "@rollup/rollup-linux-arm-musleabihf": "4.52.4", - "@rollup/rollup-linux-arm64-gnu": "4.52.4", - "@rollup/rollup-linux-arm64-musl": "4.52.4", - "@rollup/rollup-linux-loong64-gnu": "4.52.4", - "@rollup/rollup-linux-ppc64-gnu": "4.52.4", - "@rollup/rollup-linux-riscv64-gnu": "4.52.4", - "@rollup/rollup-linux-riscv64-musl": "4.52.4", - "@rollup/rollup-linux-s390x-gnu": "4.52.4", - "@rollup/rollup-linux-x64-gnu": "4.52.4", - "@rollup/rollup-linux-x64-musl": "4.52.4", - "@rollup/rollup-openharmony-arm64": "4.52.4", - "@rollup/rollup-win32-arm64-msvc": "4.52.4", - "@rollup/rollup-win32-ia32-msvc": "4.52.4", - "@rollup/rollup-win32-x64-gnu": "4.52.4", - "@rollup/rollup-win32-x64-msvc": "4.52.4", - "fsevents": "~2.3.2" - } - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/socket.io-client": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz", - "integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.2", - "engine.io-client": "~6.6.1", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-client/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-parser/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/uncontrollable": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", - "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.6.3", - "@types/react": ">=16.9.11", - "invariant": "^2.2.4", - "react-lifecycles-compat": "^3.0.4" - }, - "peerDependencies": { - "react": ">=15.0.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/vite": { - "version": "7.1.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.10.tgz", - "integrity": "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xmlhttprequest-ssl": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", - "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/client/package.json b/client/package.json deleted file mode 100644 index 484b240..0000000 --- a/client/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "client", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "lint": "eslint .", - "preview": "vite preview" - }, - "dependencies": { - "react": "^19.1.1", - "react-dom": "^19.1.1", - "react-router-dom": "^6.22.0", - "react-bootstrap": "^2.10.0", - "bootstrap": "^5.3.2", - "socket.io-client": "^4.7.4" - }, - "devDependencies": { - "@eslint/js": "^9.36.0", - "@types/react": "^19.1.16", - "@types/react-dom": "^19.1.9", - "@vitejs/plugin-react": "^5.0.4", - "eslint": "^9.36.0", - "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.22", - "globals": "^16.4.0", - "vite": "^7.1.7" - } -} diff --git a/client/public/vite.svg b/client/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/client/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/App.jsx b/client/src/App.jsx deleted file mode 100644 index 1b30a12..0000000 --- a/client/src/App.jsx +++ /dev/null @@ -1,10 +0,0 @@ -function App() { - - return ( -<> - - - ); -} - -export default App; diff --git a/client/src/assets/react.svg b/client/src/assets/react.svg deleted file mode 100644 index 6c87de9..0000000 --- a/client/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/client/src/main.jsx b/client/src/main.jsx deleted file mode 100644 index 3d9da8a..0000000 --- a/client/src/main.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' -import App from './App.jsx' - -createRoot(document.getElementById('root')).render( - - - , -) diff --git a/client/vite.config.js b/client/vite.config.js deleted file mode 100644 index 8b0f57b..0000000 --- a/client/vite.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' - -// https://vite.dev/config/ -export default defineConfig({ - plugins: [react()], -}) diff --git a/coverage/clover.xml b/coverage/clover.xml index 4e25b6d..e90ec73 100644 --- a/coverage/clover.xml +++ b/coverage/clover.xml @@ -1,206 +1,206 @@ - - - + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + - + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - + + + @@ -208,13 +208,13 @@ - + - - - + + + @@ -231,39 +231,39 @@ - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + @@ -280,80 +280,80 @@ - + - - + + - + - + - - - - - - - + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - + + + + + + + + diff --git a/coverage/coverage-final.json b/coverage/coverage-final.json index 0115405..cede639 100644 --- a/coverage/coverage-final.json +++ b/coverage/coverage-final.json @@ -1,17 +1,17 @@ -{"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}},"1":{"start":{"line":2,"column":16},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":12},"end":{"line":3,"column":21}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"4":{"start":{"line":5,"column":20},"end":{"line":5,"column":52}},"5":{"start":{"line":6,"column":15},"end":{"line":6,"column":34}},"6":{"start":{"line":7,"column":13},"end":{"line":7,"column":28}},"7":{"start":{"line":9,"column":13},"end":{"line":9,"column":28}},"8":{"start":{"line":10,"column":15},"end":{"line":10,"column":37}},"9":{"start":{"line":11,"column":19},"end":{"line":11,"column":39}},"10":{"start":{"line":12,"column":11},"end":{"line":16,"column":2}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}},"12":{"start":{"line":21,"column":0},"end":{"line":21,"column":16}},"13":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}},"14":{"start":{"line":23,"column":0},"end":{"line":23,"column":48}},"15":{"start":{"line":24,"column":0},"end":{"line":24,"column":34}},"16":{"start":{"line":27,"column":0},"end":{"line":27,"column":21}},"17":{"start":{"line":31,"column":0},"end":{"line":31,"column":21}},"18":{"start":{"line":34,"column":0},"end":{"line":52,"column":3}},"19":{"start":{"line":37,"column":2},"end":{"line":39,"column":5}},"20":{"start":{"line":38,"column":4},"end":{"line":38,"column":34}},"21":{"start":{"line":41,"column":2},"end":{"line":43,"column":5}},"22":{"start":{"line":42,"column":4},"end":{"line":42,"column":73}},"23":{"start":{"line":45,"column":2},"end":{"line":47,"column":5}},"24":{"start":{"line":46,"column":4},"end":{"line":46,"column":73}},"25":{"start":{"line":49,"column":2},"end":{"line":51,"column":5}},"26":{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},"27":{"start":{"line":55,"column":2},"end":{"line":57,"column":5}},"28":{"start":{"line":56,"column":4},"end":{"line":56,"column":66}},"29":{"start":{"line":60,"column":0},"end":{"line":60,"column":21}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":34,"column":20},"end":{"line":34,"column":21}},"loc":{"start":{"line":34,"column":32},"end":{"line":52,"column":1}},"line":34},"1":{"name":"(anonymous_1)","decl":{"start":{"line":37,"column":25},"end":{"line":37,"column":26}},"loc":{"start":{"line":37,"column":37},"end":{"line":39,"column":3}},"line":37},"2":{"name":"(anonymous_2)","decl":{"start":{"line":41,"column":28},"end":{"line":41,"column":29}},"loc":{"start":{"line":41,"column":45},"end":{"line":43,"column":3}},"line":41},"3":{"name":"(anonymous_3)","decl":{"start":{"line":45,"column":27},"end":{"line":45,"column":28}},"loc":{"start":{"line":45,"column":43},"end":{"line":47,"column":3}},"line":45},"4":{"name":"(anonymous_4)","decl":{"start":{"line":49,"column":26},"end":{"line":49,"column":27}},"loc":{"start":{"line":49,"column":32},"end":{"line":51,"column":3}},"line":49},"5":{"name":"(anonymous_5)","decl":{"start":{"line":55,"column":22},"end":{"line":55,"column":23}},"loc":{"start":{"line":55,"column":28},"end":{"line":57,"column":3}},"line":55}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"type":"binary-expr","locations":[{"start":{"line":4,"column":13},"end":{"line":4,"column":29}},{"start":{"line":4,"column":33},"end":{"line":4,"column":37}}],"line":4},"1":{"loc":{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},"type":"if","locations":[{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},{"start":{},"end":{}}],"line":54}},"s":{"0":11,"1":11,"2":11,"3":11,"4":11,"5":11,"6":11,"7":11,"8":11,"9":11,"10":11,"11":11,"12":11,"13":11,"14":11,"15":11,"16":11,"17":11,"18":11,"19":8,"20":8,"21":8,"22":0,"23":8,"24":0,"25":8,"26":11,"27":0,"28":0,"29":11},"f":{"0":8,"1":8,"2":0,"3":0,"4":0,"5":0},"b":{"0":[11,7],"1":[0,11]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2a1669a6594937f4b2db57508e47b0260b54d91b"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js","statementMap":{"0":{"start":{"line":1,"column":33},"end":{"line":1,"column":71}},"1":{"start":{"line":5,"column":4},"end":{"line":21,"column":5}},"2":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"3":{"start":{"line":8,"column":8},"end":{"line":8,"column":39}},"4":{"start":{"line":11,"column":21},"end":{"line":11,"column":32}},"5":{"start":{"line":12,"column":20},"end":{"line":12,"column":54}},"6":{"start":{"line":14,"column":6},"end":{"line":18,"column":9}},"7":{"start":{"line":20,"column":6},"end":{"line":20,"column":16}},"8":{"start":{"line":25,"column":0},"end":{"line":25,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":4,"column":2},"end":{"line":4,"column":3}},"loc":{"start":{"line":4,"column":50},"end":{"line":22,"column":3}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"type":"if","locations":[{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":10},"end":{"line":7,"column":35}},"type":"binary-expr","locations":[{"start":{"line":7,"column":10},"end":{"line":7,"column":19}},{"start":{"line":7,"column":23},"end":{"line":7,"column":35}}],"line":7}},"s":{"0":3,"1":2,"2":2,"3":1,"4":1,"5":1,"6":1,"7":1,"8":3},"f":{"0":2},"b":{"0":[1,1],"1":[2,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"5a3a8d6179df7a779a1e7786dcd48a5a6657888b"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js","statementMap":{"0":{"start":{"line":1,"column":43},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":24}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":52}},"3":{"start":{"line":8,"column":8},"end":{"line":34,"column":9}},"4":{"start":{"line":9,"column":34},"end":{"line":9,"column":42}},"5":{"start":{"line":10,"column":27},"end":{"line":10,"column":38}},"6":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"7":{"start":{"line":13,"column":16},"end":{"line":13,"column":97}},"8":{"start":{"line":17,"column":36},"end":{"line":29,"column":14}},"9":{"start":{"line":31,"column":12},"end":{"line":31,"column":55}},"10":{"start":{"line":33,"column":12},"end":{"line":33,"column":22}},"11":{"start":{"line":39,"column":8},"end":{"line":55,"column":9}},"12":{"start":{"line":40,"column":27},"end":{"line":40,"column":38}},"13":{"start":{"line":41,"column":26},"end":{"line":50,"column":14}},"14":{"start":{"line":52,"column":12},"end":{"line":52,"column":28}},"15":{"start":{"line":54,"column":12},"end":{"line":54,"column":22}},"16":{"start":{"line":60,"column":8},"end":{"line":79,"column":9}},"17":{"start":{"line":61,"column":31},"end":{"line":61,"column":41}},"18":{"start":{"line":62,"column":27},"end":{"line":62,"column":38}},"19":{"start":{"line":65,"column":25},"end":{"line":65,"column":52}},"20":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"21":{"start":{"line":67,"column":16},"end":{"line":67,"column":44}},"22":{"start":{"line":70,"column":29},"end":{"line":74,"column":14}},"23":{"start":{"line":76,"column":12},"end":{"line":76,"column":31}},"24":{"start":{"line":78,"column":12},"end":{"line":78,"column":22}},"25":{"start":{"line":83,"column":8},"end":{"line":99,"column":9}},"26":{"start":{"line":84,"column":27},"end":{"line":84,"column":38}},"27":{"start":{"line":85,"column":36},"end":{"line":95,"column":14}},"28":{"start":{"line":96,"column":12},"end":{"line":96,"column":55}},"29":{"start":{"line":98,"column":12},"end":{"line":98,"column":22}},"30":{"start":{"line":104,"column":8},"end":{"line":153,"column":9}},"31":{"start":{"line":105,"column":31},"end":{"line":105,"column":41}},"32":{"start":{"line":106,"column":32},"end":{"line":106,"column":40}},"33":{"start":{"line":107,"column":27},"end":{"line":107,"column":38}},"34":{"start":{"line":108,"column":23},"end":{"line":108,"column":46}},"35":{"start":{"line":110,"column":25},"end":{"line":110,"column":52}},"36":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"37":{"start":{"line":112,"column":16},"end":{"line":112,"column":70}},"38":{"start":{"line":115,"column":33},"end":{"line":115,"column":84}},"39":{"start":{"line":116,"column":12},"end":{"line":118,"column":13}},"40":{"start":{"line":117,"column":16},"end":{"line":117,"column":99}},"41":{"start":{"line":121,"column":32},"end":{"line":125,"column":14}},"42":{"start":{"line":126,"column":12},"end":{"line":126,"column":73}},"43":{"start":{"line":129,"column":12},"end":{"line":149,"column":13}},"44":{"start":{"line":131,"column":39},"end":{"line":131,"column":63}},"45":{"start":{"line":134,"column":34},"end":{"line":138,"column":18}},"46":{"start":{"line":141,"column":16},"end":{"line":141,"column":75}},"47":{"start":{"line":144,"column":16},"end":{"line":144,"column":55}},"48":{"start":{"line":148,"column":16},"end":{"line":148,"column":57}},"49":{"start":{"line":152,"column":12},"end":{"line":152,"column":22}},"50":{"start":{"line":157,"column":0},"end":{"line":157,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":4},"end":{"line":7,"column":5}},"loc":{"start":{"line":7,"column":49},"end":{"line":35,"column":5}},"line":7},"1":{"name":"(anonymous_1)","decl":{"start":{"line":38,"column":4},"end":{"line":38,"column":5}},"loc":{"start":{"line":38,"column":46},"end":{"line":56,"column":5}},"line":38},"2":{"name":"(anonymous_2)","decl":{"start":{"line":59,"column":4},"end":{"line":59,"column":5}},"loc":{"start":{"line":59,"column":49},"end":{"line":80,"column":5}},"line":59},"3":{"name":"(anonymous_3)","decl":{"start":{"line":82,"column":4},"end":{"line":82,"column":5}},"loc":{"start":{"line":82,"column":46},"end":{"line":100,"column":5}},"line":82},"4":{"name":"(anonymous_4)","decl":{"start":{"line":103,"column":4},"end":{"line":103,"column":5}},"loc":{"start":{"line":103,"column":45},"end":{"line":154,"column":5}},"line":103}},"branchMap":{"0":{"loc":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"type":"if","locations":[{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},{"start":{},"end":{}}],"line":12},"1":{"loc":{"start":{"line":31,"column":23},"end":{"line":31,"column":42}},"type":"cond-expr","locations":[{"start":{"line":31,"column":33},"end":{"line":31,"column":36}},{"start":{"line":31,"column":39},"end":{"line":31,"column":42}}],"line":31},"2":{"loc":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"type":"if","locations":[{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},{"start":{},"end":{}}],"line":66},"3":{"loc":{"start":{"line":66,"column":16},"end":{"line":66,"column":78}},"type":"binary-expr","locations":[{"start":{"line":66,"column":16},"end":{"line":66,"column":21}},{"start":{"line":66,"column":26},"end":{"line":66,"column":48}},{"start":{"line":66,"column":52},"end":{"line":66,"column":77}}],"line":66},"4":{"loc":{"start":{"line":96,"column":23},"end":{"line":96,"column":42}},"type":"cond-expr","locations":[{"start":{"line":96,"column":33},"end":{"line":96,"column":36}},{"start":{"line":96,"column":39},"end":{"line":96,"column":42}}],"line":96},"5":{"loc":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"type":"if","locations":[{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},{"start":{},"end":{}}],"line":111},"6":{"loc":{"start":{"line":115,"column":33},"end":{"line":115,"column":84}},"type":"binary-expr","locations":[{"start":{"line":115,"column":33},"end":{"line":115,"column":55}},{"start":{"line":115,"column":59},"end":{"line":115,"column":84}}],"line":115},"7":{"loc":{"start":{"line":116,"column":12},"end":{"line":118,"column":13}},"type":"if","locations":[{"start":{"line":116,"column":12},"end":{"line":118,"column":13}},{"start":{},"end":{}}],"line":116},"8":{"loc":{"start":{"line":129,"column":12},"end":{"line":149,"column":13}},"type":"if","locations":[{"start":{"line":129,"column":12},"end":{"line":149,"column":13}},{"start":{"line":146,"column":19},"end":{"line":149,"column":13}}],"line":129}},"s":{"0":3,"1":3,"2":3,"3":4,"4":4,"5":4,"6":4,"7":1,"8":3,"9":2,"10":2,"11":2,"12":2,"13":2,"14":1,"15":1,"16":4,"17":4,"18":4,"19":4,"20":3,"21":2,"22":1,"23":1,"24":3,"25":3,"26":3,"27":3,"28":2,"29":1,"30":5,"31":5,"32":5,"33":5,"34":5,"35":5,"36":5,"37":1,"38":4,"39":4,"40":1,"41":3,"42":2,"43":2,"44":1,"45":1,"46":1,"47":1,"48":1,"49":3,"50":3},"f":{"0":4,"1":2,"2":4,"3":3,"4":5},"b":{"0":[1,3],"1":[1,1],"2":[2,1],"3":[3,2,1],"4":[1,1],"5":[1,4],"6":[4,1],"7":[1,3],"8":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"7fb9f2a22e313178dcad36188b8f2f364ea0ea21"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js","statementMap":{"0":{"start":{"line":1,"column":46},"end":{"line":1,"column":66}},"1":{"start":{"line":6,"column":4},"end":{"line":39,"column":5}},"2":{"start":{"line":7,"column":49},"end":{"line":7,"column":57}},"3":{"start":{"line":8,"column":21},"end":{"line":8,"column":32}},"4":{"start":{"line":11,"column":6},"end":{"line":13,"column":7}},"5":{"start":{"line":12,"column":8},"end":{"line":12,"column":98}},"6":{"start":{"line":16,"column":19},"end":{"line":22,"column":8}},"7":{"start":{"line":25,"column":29},"end":{"line":28,"column":9}},"8":{"start":{"line":25,"column":54},"end":{"line":28,"column":7}},"9":{"start":{"line":30,"column":6},"end":{"line":30,"column":45}},"10":{"start":{"line":32,"column":6},"end":{"line":36,"column":9}},"11":{"start":{"line":38,"column":6},"end":{"line":38,"column":16}},"12":{"start":{"line":44,"column":4},"end":{"line":58,"column":5}},"13":{"start":{"line":45,"column":20},"end":{"line":54,"column":8}},"14":{"start":{"line":55,"column":6},"end":{"line":55,"column":22}},"15":{"start":{"line":57,"column":6},"end":{"line":57,"column":16}},"16":{"start":{"line":63,"column":4},"end":{"line":72,"column":5}},"17":{"start":{"line":64,"column":20},"end":{"line":68,"column":8}},"18":{"start":{"line":69,"column":6},"end":{"line":69,"column":22}},"19":{"start":{"line":71,"column":6},"end":{"line":71,"column":16}},"20":{"start":{"line":77,"column":4},"end":{"line":89,"column":5}},"21":{"start":{"line":78,"column":21},"end":{"line":78,"column":31}},"22":{"start":{"line":79,"column":49},"end":{"line":79,"column":57}},"23":{"start":{"line":81,"column":19},"end":{"line":81,"column":42}},"24":{"start":{"line":82,"column":6},"end":{"line":82,"column":44}},"25":{"start":{"line":82,"column":17},"end":{"line":82,"column":44}},"26":{"start":{"line":83,"column":6},"end":{"line":83,"column":70}},"27":{"start":{"line":83,"column":39},"end":{"line":83,"column":70}},"28":{"start":{"line":85,"column":6},"end":{"line":85,"column":72}},"29":{"start":{"line":86,"column":6},"end":{"line":86,"column":63}},"30":{"start":{"line":88,"column":6},"end":{"line":88,"column":16}},"31":{"start":{"line":94,"column":4},"end":{"line":104,"column":5}},"32":{"start":{"line":95,"column":21},"end":{"line":95,"column":31}},"33":{"start":{"line":96,"column":19},"end":{"line":96,"column":42}},"34":{"start":{"line":97,"column":6},"end":{"line":97,"column":44}},"35":{"start":{"line":97,"column":17},"end":{"line":97,"column":44}},"36":{"start":{"line":98,"column":6},"end":{"line":98,"column":70}},"37":{"start":{"line":98,"column":39},"end":{"line":98,"column":70}},"38":{"start":{"line":100,"column":6},"end":{"line":100,"column":27}},"39":{"start":{"line":101,"column":6},"end":{"line":101,"column":57}},"40":{"start":{"line":103,"column":6},"end":{"line":103,"column":16}},"41":{"start":{"line":109,"column":4},"end":{"line":129,"column":5}},"42":{"start":{"line":110,"column":21},"end":{"line":110,"column":31}},"43":{"start":{"line":111,"column":19},"end":{"line":111,"column":42}},"44":{"start":{"line":112,"column":6},"end":{"line":112,"column":44}},"45":{"start":{"line":112,"column":17},"end":{"line":112,"column":44}},"46":{"start":{"line":114,"column":27},"end":{"line":116,"column":8}},"47":{"start":{"line":119,"column":6},"end":{"line":125,"column":7}},"48":{"start":{"line":120,"column":8},"end":{"line":120,"column":37}},"49":{"start":{"line":121,"column":8},"end":{"line":121,"column":33}},"50":{"start":{"line":123,"column":8},"end":{"line":123,"column":63}},"51":{"start":{"line":124,"column":8},"end":{"line":124,"column":31}},"52":{"start":{"line":126,"column":6},"end":{"line":126,"column":28}},"53":{"start":{"line":128,"column":6},"end":{"line":128,"column":16}},"54":{"start":{"line":133,"column":0},"end":{"line":133,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":2},"end":{"line":5,"column":3}},"loc":{"start":{"line":5,"column":42},"end":{"line":40,"column":3}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":25,"column":43},"end":{"line":25,"column":44}},"loc":{"start":{"line":25,"column":54},"end":{"line":28,"column":7}},"line":25},"2":{"name":"(anonymous_2)","decl":{"start":{"line":43,"column":2},"end":{"line":43,"column":3}},"loc":{"start":{"line":43,"column":49},"end":{"line":59,"column":3}},"line":43},"3":{"name":"(anonymous_3)","decl":{"start":{"line":62,"column":2},"end":{"line":62,"column":3}},"loc":{"start":{"line":62,"column":42},"end":{"line":73,"column":3}},"line":62},"4":{"name":"(anonymous_4)","decl":{"start":{"line":76,"column":2},"end":{"line":76,"column":3}},"loc":{"start":{"line":76,"column":42},"end":{"line":90,"column":3}},"line":76},"5":{"name":"(anonymous_5)","decl":{"start":{"line":93,"column":2},"end":{"line":93,"column":3}},"loc":{"start":{"line":93,"column":42},"end":{"line":105,"column":3}},"line":93},"6":{"name":"(anonymous_6)","decl":{"start":{"line":108,"column":2},"end":{"line":108,"column":3}},"loc":{"start":{"line":108,"column":42},"end":{"line":130,"column":3}},"line":108}},"branchMap":{"0":{"loc":{"start":{"line":11,"column":6},"end":{"line":13,"column":7}},"type":"if","locations":[{"start":{"line":11,"column":6},"end":{"line":13,"column":7}},{"start":{},"end":{}}],"line":11},"1":{"loc":{"start":{"line":11,"column":10},"end":{"line":11,"column":46}},"type":"binary-expr","locations":[{"start":{"line":11,"column":10},"end":{"line":11,"column":20}},{"start":{"line":11,"column":24},"end":{"line":11,"column":46}}],"line":11},"2":{"loc":{"start":{"line":19,"column":19},"end":{"line":19,"column":61}},"type":"binary-expr","locations":[{"start":{"line":19,"column":19},"end":{"line":19,"column":39}},{"start":{"line":19,"column":43},"end":{"line":19,"column":61}}],"line":19},"3":{"loc":{"start":{"line":82,"column":6},"end":{"line":82,"column":44}},"type":"if","locations":[{"start":{"line":82,"column":6},"end":{"line":82,"column":44}},{"start":{},"end":{}}],"line":82},"4":{"loc":{"start":{"line":83,"column":6},"end":{"line":83,"column":70}},"type":"if","locations":[{"start":{"line":83,"column":6},"end":{"line":83,"column":70}},{"start":{},"end":{}}],"line":83},"5":{"loc":{"start":{"line":97,"column":6},"end":{"line":97,"column":44}},"type":"if","locations":[{"start":{"line":97,"column":6},"end":{"line":97,"column":44}},{"start":{},"end":{}}],"line":97},"6":{"loc":{"start":{"line":98,"column":6},"end":{"line":98,"column":70}},"type":"if","locations":[{"start":{"line":98,"column":6},"end":{"line":98,"column":70}},{"start":{},"end":{}}],"line":98},"7":{"loc":{"start":{"line":112,"column":6},"end":{"line":112,"column":44}},"type":"if","locations":[{"start":{"line":112,"column":6},"end":{"line":112,"column":44}},{"start":{},"end":{}}],"line":112},"8":{"loc":{"start":{"line":119,"column":6},"end":{"line":125,"column":7}},"type":"if","locations":[{"start":{"line":119,"column":6},"end":{"line":125,"column":7}},{"start":{"line":122,"column":13},"end":{"line":125,"column":7}}],"line":119}},"s":{"0":3,"1":3,"2":3,"3":3,"4":3,"5":1,"6":2,"7":1,"8":2,"9":1,"10":1,"11":2,"12":2,"13":2,"14":1,"15":1,"16":2,"17":2,"18":1,"19":1,"20":4,"21":4,"22":4,"23":4,"24":4,"25":1,"26":3,"27":1,"28":2,"29":1,"30":3,"31":4,"32":4,"33":4,"34":4,"35":1,"36":3,"37":1,"38":2,"39":1,"40":3,"41":4,"42":4,"43":4,"44":3,"45":1,"46":2,"47":2,"48":1,"49":1,"50":1,"51":1,"52":2,"53":2,"54":3},"f":{"0":3,"1":2,"2":2,"3":2,"4":4,"5":4,"6":4},"b":{"0":[1,2],"1":[3,3],"2":[2,2],"3":[1,3],"4":[1,2],"5":[1,3],"6":[1,2],"7":[1,2],"8":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"da83669b89c6341d66d13214118e1535c1f4dd7b"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js","statementMap":{"0":{"start":{"line":1,"column":17},"end":{"line":1,"column":37}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":47}},"3":{"start":{"line":4,"column":25},"end":{"line":4,"column":55}},"4":{"start":{"line":5,"column":15},"end":{"line":5,"column":33}},"5":{"start":{"line":10,"column":8},"end":{"line":20,"column":9}},"6":{"start":{"line":11,"column":50},"end":{"line":11,"column":58}},"7":{"start":{"line":12,"column":28},"end":{"line":12,"column":76}},"8":{"start":{"line":13,"column":12},"end":{"line":17,"column":15}},"9":{"start":{"line":19,"column":12},"end":{"line":19,"column":22}},"10":{"start":{"line":24,"column":8},"end":{"line":44,"column":9}},"11":{"start":{"line":25,"column":40},"end":{"line":25,"column":48}},"12":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"13":{"start":{"line":27,"column":16},"end":{"line":27,"column":89}},"14":{"start":{"line":30,"column":25},"end":{"line":30,"column":65}},"15":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"16":{"start":{"line":32,"column":16},"end":{"line":32,"column":47}},"17":{"start":{"line":35,"column":36},"end":{"line":35,"column":79}},"18":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"19":{"start":{"line":37,"column":16},"end":{"line":37,"column":47}},"20":{"start":{"line":40,"column":26},"end":{"line":40,"column":52}},"21":{"start":{"line":41,"column":12},"end":{"line":41,"column":58}},"22":{"start":{"line":43,"column":12},"end":{"line":43,"column":22}},"23":{"start":{"line":48,"column":8},"end":{"line":73,"column":9}},"24":{"start":{"line":49,"column":37},"end":{"line":49,"column":45}},"25":{"start":{"line":51,"column":27},"end":{"line":54,"column":14}},"26":{"start":{"line":55,"column":28},"end":{"line":55,"column":47}},"27":{"start":{"line":57,"column":36},"end":{"line":66,"column":14}},"28":{"start":{"line":68,"column":33},"end":{"line":68,"column":59}},"29":{"start":{"line":69,"column":12},"end":{"line":69,"column":51}},"30":{"start":{"line":72,"column":12},"end":{"line":72,"column":22}},"31":{"start":{"line":77,"column":0},"end":{"line":77,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":9,"column":4},"end":{"line":9,"column":5}},"loc":{"start":{"line":9,"column":42},"end":{"line":21,"column":5}},"line":9},"1":{"name":"(anonymous_1)","decl":{"start":{"line":23,"column":4},"end":{"line":23,"column":5}},"loc":{"start":{"line":23,"column":39},"end":{"line":45,"column":5}},"line":23},"2":{"name":"(anonymous_2)","decl":{"start":{"line":47,"column":4},"end":{"line":47,"column":5}},"loc":{"start":{"line":47,"column":46},"end":{"line":74,"column":5}},"line":47}},"branchMap":{"0":{"loc":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"type":"if","locations":[{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},{"start":{},"end":{}}],"line":26},"1":{"loc":{"start":{"line":26,"column":16},"end":{"line":26,"column":35}},"type":"binary-expr","locations":[{"start":{"line":26,"column":16},"end":{"line":26,"column":22}},{"start":{"line":26,"column":26},"end":{"line":26,"column":35}}],"line":26},"2":{"loc":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"type":"if","locations":[{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},{"start":{},"end":{}}],"line":31},"3":{"loc":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"type":"if","locations":[{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},{"start":{},"end":{}}],"line":36}},"s":{"0":3,"1":3,"2":3,"3":3,"4":3,"5":2,"6":2,"7":2,"8":1,"9":1,"10":5,"11":5,"12":5,"13":1,"14":4,"15":3,"16":1,"17":2,"18":2,"19":1,"20":1,"21":1,"22":4,"23":2,"24":2,"25":2,"26":1,"27":1,"28":1,"29":1,"30":1,"31":3},"f":{"0":2,"1":5,"2":2},"b":{"0":[1,4],"1":[5,5],"2":[1,2],"3":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"b7038bc766a82e2013af060f79b91bd96e2958df"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":3,"column":14},"end":{"line":3,"column":64}},"2":{"start":{"line":4,"column":14},"end":{"line":4,"column":69}},"3":{"start":{"line":8,"column":2},"end":{"line":21,"column":12}},"4":{"start":{"line":25,"column":2},"end":{"line":32,"column":3}},"5":{"start":{"line":26,"column":19},"end":{"line":26,"column":54}},"6":{"start":{"line":27,"column":20},"end":{"line":27,"column":42}},"7":{"start":{"line":28,"column":4},"end":{"line":28,"column":30}},"8":{"start":{"line":30,"column":4},"end":{"line":30,"column":47}},"9":{"start":{"line":31,"column":4},"end":{"line":31,"column":63}},"10":{"start":{"line":35,"column":0},"end":{"line":35,"column":42}}},"fnMap":{"0":{"name":"cleanText","decl":{"start":{"line":7,"column":9},"end":{"line":7,"column":18}},"loc":{"start":{"line":7,"column":30},"end":{"line":22,"column":1}},"line":7},"1":{"name":"askGemini","decl":{"start":{"line":24,"column":15},"end":{"line":24,"column":24}},"loc":{"start":{"line":24,"column":33},"end":{"line":33,"column":1}},"line":24}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":19},"end":{"line":7,"column":28}},"type":"default-arg","locations":[{"start":{"line":7,"column":26},"end":{"line":7,"column":28}}],"line":7}},"s":{"0":8,"1":8,"2":8,"3":4,"4":3,"5":3,"6":2,"7":2,"8":1,"9":1,"10":8},"f":{"0":4,"1":3},"b":{"0":[1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2e50e4f0c73211fc77ec6e98c2ee2a41538ee44c"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":39},"end":{"line":2,"column":59}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":35}},"3":{"start":{"line":6,"column":2},"end":{"line":68,"column":3}},"4":{"start":{"line":8,"column":18},"end":{"line":8,"column":68}},"5":{"start":{"line":9,"column":18},"end":{"line":9,"column":71}},"6":{"start":{"line":11,"column":23},"end":{"line":14,"column":6}},"7":{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},"8":{"start":{"line":18,"column":6},"end":{"line":23,"column":9}},"9":{"start":{"line":26,"column":26},"end":{"line":31,"column":17}},"10":{"start":{"line":29,"column":10},"end":{"line":29,"column":86}},"11":{"start":{"line":33,"column":19},"end":{"line":39,"column":5}},"12":{"start":{"line":41,"column":19},"end":{"line":41,"column":54}},"13":{"start":{"line":42,"column":27},"end":{"line":42,"column":49}},"14":{"start":{"line":43,"column":23},"end":{"line":43,"column":69}},"15":{"start":{"line":43,"column":60},"end":{"line":43,"column":68}},"16":{"start":{"line":45,"column":29},"end":{"line":57,"column":6}},"17":{"start":{"line":59,"column":4},"end":{"line":59,"column":28}},"18":{"start":{"line":61,"column":4},"end":{"line":61,"column":60}},"19":{"start":{"line":62,"column":4},"end":{"line":67,"column":7}},"20":{"start":{"line":71,"column":0},"end":{"line":71,"column":42}}},"fnMap":{"0":{"name":"getAIRecommendations","decl":{"start":{"line":5,"column":15},"end":{"line":5,"column":35}},"loc":{"start":{"line":5,"column":44},"end":{"line":69,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":28,"column":8},"end":{"line":28,"column":9}},"loc":{"start":{"line":29,"column":10},"end":{"line":29,"column":86}},"line":29},"2":{"name":"(anonymous_2)","decl":{"start":{"line":43,"column":53},"end":{"line":43,"column":54}},"loc":{"start":{"line":43,"column":60},"end":{"line":43,"column":68}},"line":43}},"branchMap":{"0":{"loc":{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},"type":"if","locations":[{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},{"start":{},"end":{}}],"line":17},"1":{"loc":{"start":{"line":17,"column":8},"end":{"line":17,"column":44}},"type":"binary-expr","locations":[{"start":{"line":17,"column":8},"end":{"line":17,"column":19}},{"start":{"line":17,"column":23},"end":{"line":17,"column":44}}],"line":17},"2":{"loc":{"start":{"line":29,"column":49},"end":{"line":29,"column":83}},"type":"binary-expr","locations":[{"start":{"line":29,"column":49},"end":{"line":29,"column":73}},{"start":{"line":29,"column":77},"end":{"line":29,"column":83}}],"line":29}},"s":{"0":7,"1":7,"2":7,"3":4,"4":4,"5":4,"6":4,"7":3,"8":1,"9":2,"10":6,"11":2,"12":2,"13":2,"14":2,"15":5,"16":2,"17":2,"18":1,"19":1,"20":7},"f":{"0":4,"1":6,"2":5},"b":{"0":[1,2],"1":[3,3],"2":[6,2]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"b1fba11a44899570364f599bbe9715df05009abc"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\authMiddleware.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\authMiddleware.js","statementMap":{"0":{"start":{"line":1,"column":24},"end":{"line":1,"column":40}},"1":{"start":{"line":2,"column":17},"end":{"line":2,"column":37}},"2":{"start":{"line":4,"column":0},"end":{"line":28,"column":2}},"3":{"start":{"line":5,"column":2},"end":{"line":27,"column":3}},"4":{"start":{"line":6,"column":24},"end":{"line":6,"column":49}},"5":{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},"6":{"start":{"line":8,"column":6},"end":{"line":8,"column":68}},"7":{"start":{"line":11,"column":18},"end":{"line":11,"column":43}},"8":{"start":{"line":12,"column":20},"end":{"line":12,"column":38}},"9":{"start":{"line":13,"column":17},"end":{"line":13,"column":48}},"10":{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},"11":{"start":{"line":14,"column":15},"end":{"line":14,"column":73}},"12":{"start":{"line":16,"column":4},"end":{"line":16,"column":20}},"13":{"start":{"line":17,"column":4},"end":{"line":17,"column":28}},"14":{"start":{"line":18,"column":4},"end":{"line":18,"column":11}},"15":{"start":{"line":20,"column":4},"end":{"line":26,"column":5}},"16":{"start":{"line":21,"column":6},"end":{"line":21,"column":16}},"17":{"start":{"line":22,"column":11},"end":{"line":26,"column":5}},"18":{"start":{"line":23,"column":6},"end":{"line":23,"column":68}},"19":{"start":{"line":25,"column":6},"end":{"line":25,"column":68}}},"fnMap":{"0":{"name":"authMiddleware","decl":{"start":{"line":4,"column":32},"end":{"line":4,"column":46}},"loc":{"start":{"line":4,"column":63},"end":{"line":28,"column":1}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},"type":"if","locations":[{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":8},"end":{"line":7,"column":58}},"type":"binary-expr","locations":[{"start":{"line":7,"column":8},"end":{"line":7,"column":20}},{"start":{"line":7,"column":24},"end":{"line":7,"column":58}}],"line":7},"2":{"loc":{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},"type":"if","locations":[{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},{"start":{},"end":{}}],"line":14},"3":{"loc":{"start":{"line":20,"column":4},"end":{"line":26,"column":5}},"type":"if","locations":[{"start":{"line":20,"column":4},"end":{"line":26,"column":5}},{"start":{"line":22,"column":11},"end":{"line":26,"column":5}}],"line":20},"4":{"loc":{"start":{"line":22,"column":11},"end":{"line":26,"column":5}},"type":"if","locations":[{"start":{"line":22,"column":11},"end":{"line":26,"column":5}},{"start":{"line":24,"column":11},"end":{"line":26,"column":5}}],"line":22}},"s":{"0":6,"1":6,"2":6,"3":6,"4":6,"5":6,"6":2,"7":4,"8":4,"9":3,"10":2,"11":1,"12":1,"13":1,"14":1,"15":5,"16":3,"17":2,"18":1,"19":1},"f":{"0":6},"b":{"0":[2,4],"1":[6,5],"2":[1,1],"3":[3,2],"4":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"da15475db48041279c05eae50906191f14ebd303"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\cloudinary.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\cloudinary.js","statementMap":{"0":{"start":{"line":1,"column":19},"end":{"line":1,"column":43}},"1":{"start":{"line":2,"column":30},"end":{"line":2,"column":66}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":32}},"3":{"start":{"line":5,"column":0},"end":{"line":9,"column":3}},"4":{"start":{"line":11,"column":16},"end":{"line":18,"column":2}},"5":{"start":{"line":20,"column":15},"end":{"line":20,"column":34}},"6":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":5,"1":5,"2":5,"3":5,"4":5,"5":5,"6":5},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"b5c712c03dc49f3dc144389fe011736580e525df"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\handleError.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\handleError.js","statementMap":{"0":{"start":{"line":2,"column":2},"end":{"line":2,"column":31}},"1":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"2":{"start":{"line":5,"column":4},"end":{"line":5,"column":68}},"3":{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},"4":{"start":{"line":9,"column":4},"end":{"line":9,"column":74}},"5":{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},"6":{"start":{"line":13,"column":4},"end":{"line":13,"column":63}},"7":{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},"8":{"start":{"line":17,"column":4},"end":{"line":17,"column":75}},"9":{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},"10":{"start":{"line":21,"column":21},"end":{"line":21,"column":51}},"11":{"start":{"line":21,"column":41},"end":{"line":21,"column":50}},"12":{"start":{"line":22,"column":4},"end":{"line":22,"column":55}},"13":{"start":{"line":25,"column":2},"end":{"line":27,"column":5}},"14":{"start":{"line":30,"column":0},"end":{"line":30,"column":29}}},"fnMap":{"0":{"name":"handleError","decl":{"start":{"line":1,"column":9},"end":{"line":1,"column":20}},"loc":{"start":{"line":1,"column":41},"end":{"line":28,"column":1}},"line":1},"1":{"name":"(anonymous_1)","decl":{"start":{"line":21,"column":36},"end":{"line":21,"column":37}},"loc":{"start":{"line":21,"column":41},"end":{"line":21,"column":50}},"line":21}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"type":"if","locations":[{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},{"start":{},"end":{}}],"line":4},"1":{"loc":{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},{"start":{},"end":{}}],"line":8},"2":{"loc":{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},"type":"if","locations":[{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},{"start":{},"end":{}}],"line":12},"3":{"loc":{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},"type":"if","locations":[{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},{"start":{},"end":{}}],"line":16},"4":{"loc":{"start":{"line":17,"column":43},"end":{"line":17,"column":71}},"type":"binary-expr","locations":[{"start":{"line":17,"column":43},"end":{"line":17,"column":54}},{"start":{"line":17,"column":58},"end":{"line":17,"column":71}}],"line":17},"5":{"loc":{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},"type":"if","locations":[{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},{"start":{},"end":{}}],"line":20},"6":{"loc":{"start":{"line":20,"column":6},"end":{"line":20,"column":94}},"type":"binary-expr","locations":[{"start":{"line":20,"column":6},"end":{"line":20,"column":45}},{"start":{"line":20,"column":49},"end":{"line":20,"column":94}}],"line":20}},"s":{"0":8,"1":8,"2":1,"3":7,"4":1,"5":6,"6":1,"7":5,"8":2,"9":3,"10":2,"11":3,"12":2,"13":1,"14":3},"f":{"0":8,"1":3},"b":{"0":[1,7],"1":[1,6],"2":[1,5],"3":[2,3],"4":[2,1],"5":[2,1],"6":[3,2]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"c2354f978bf3faa64bb0eed70640c0f9b3ddd7a3"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js","statementMap":{"0":{"start":{"line":1,"column":12},"end":{"line":1,"column":35}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":37}},"2":{"start":{"line":5,"column":2},"end":{"line":5,"column":35}},"3":{"start":{"line":9,"column":2},"end":{"line":9,"column":35}},"4":{"start":{"line":12,"column":0},"end":{"line":12,"column":44}}},"fnMap":{"0":{"name":"signToken","decl":{"start":{"line":4,"column":9},"end":{"line":4,"column":18}},"loc":{"start":{"line":4,"column":28},"end":{"line":6,"column":1}},"line":4},"1":{"name":"verifyToken","decl":{"start":{"line":8,"column":9},"end":{"line":8,"column":20}},"loc":{"start":{"line":8,"column":28},"end":{"line":10,"column":1}},"line":8}},"branchMap":{},"s":{"0":10,"1":10,"2":1,"3":2,"4":10},"f":{"0":1,"1":2},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"d7b8e9b1304ab0135964e79a9372e3a90c422c73"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\aiRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\aiRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":21},"end":{"line":3,"column":59}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":7,"column":0},"end":{"line":7,"column":70}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":2,"1":2,"2":2,"3":2,"4":2,"5":2},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"84c1c0d1538754070138406039d321ec6a74e1d2"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\chatRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\chatRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":23},"end":{"line":3,"column":63}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":17}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":48}},"6":{"start":{"line":12,"column":0},"end":{"line":12,"column":49}},"7":{"start":{"line":15,"column":0},"end":{"line":15,"column":45}},"8":{"start":{"line":18,"column":0},"end":{"line":18,"column":64}},"9":{"start":{"line":21,"column":0},"end":{"line":21,"column":61}},"10":{"start":{"line":23,"column":0},"end":{"line":23,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":2,"1":2,"2":2,"3":2,"4":2,"5":2,"6":2,"7":2,"8":2,"9":2,"10":2},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"82ea6aef909da7b2c964a610d5e39ab2afbe64cc"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\index.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\index.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":4,"column":19},"end":{"line":4,"column":42}},"3":{"start":{"line":5,"column":19},"end":{"line":5,"column":42}},"4":{"start":{"line":6,"column":19},"end":{"line":6,"column":42}},"5":{"start":{"line":7,"column":17},"end":{"line":7,"column":38}},"6":{"start":{"line":16,"column":0},"end":{"line":16,"column":33}},"7":{"start":{"line":17,"column":0},"end":{"line":17,"column":33}},"8":{"start":{"line":18,"column":0},"end":{"line":18,"column":33}},"9":{"start":{"line":19,"column":0},"end":{"line":19,"column":28}},"10":{"start":{"line":21,"column":0},"end":{"line":21,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":2,"1":2,"2":2,"3":2,"4":2,"5":2,"6":2,"7":2,"8":2,"9":2,"10":2},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"e64227b43051f4e83574447d7ab08252f7f48992"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\postRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\postRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":23},"end":{"line":3,"column":63}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":5,"column":15},"end":{"line":5,"column":47}},"5":{"start":{"line":8,"column":0},"end":{"line":8,"column":77}},"6":{"start":{"line":10,"column":0},"end":{"line":10,"column":50}},"7":{"start":{"line":11,"column":0},"end":{"line":11,"column":51}},"8":{"start":{"line":13,"column":0},"end":{"line":13,"column":52}},"9":{"start":{"line":14,"column":0},"end":{"line":14,"column":55}},"10":{"start":{"line":16,"column":0},"end":{"line":16,"column":58}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":2,"1":2,"2":2,"3":2,"4":2,"5":2,"6":2,"7":2,"8":2,"9":2,"10":2,"11":2},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"9dfcfb4e2b89bdf5bea27a6193353ae105013ec7"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\userRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\userRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":23},"end":{"line":2,"column":63}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":31}},"3":{"start":{"line":5,"column":0},"end":{"line":5,"column":50}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":44}},"5":{"start":{"line":7,"column":0},"end":{"line":7,"column":57}},"6":{"start":{"line":10,"column":0},"end":{"line":10,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":2,"1":2,"2":2,"3":2,"4":2,"5":2,"6":2},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"9a3c94306d7c8d600d66c8c45211556638027bfe"} +{"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}},"1":{"start":{"line":2,"column":16},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":12},"end":{"line":3,"column":21}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"4":{"start":{"line":5,"column":20},"end":{"line":5,"column":52}},"5":{"start":{"line":6,"column":15},"end":{"line":6,"column":34}},"6":{"start":{"line":7,"column":13},"end":{"line":7,"column":28}},"7":{"start":{"line":9,"column":13},"end":{"line":9,"column":28}},"8":{"start":{"line":10,"column":15},"end":{"line":10,"column":37}},"9":{"start":{"line":11,"column":19},"end":{"line":11,"column":39}},"10":{"start":{"line":12,"column":11},"end":{"line":16,"column":2}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}},"12":{"start":{"line":21,"column":0},"end":{"line":21,"column":16}},"13":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}},"14":{"start":{"line":23,"column":0},"end":{"line":23,"column":48}},"15":{"start":{"line":24,"column":0},"end":{"line":24,"column":34}},"16":{"start":{"line":27,"column":0},"end":{"line":27,"column":21}},"17":{"start":{"line":31,"column":0},"end":{"line":31,"column":21}},"18":{"start":{"line":34,"column":0},"end":{"line":52,"column":3}},"19":{"start":{"line":37,"column":2},"end":{"line":39,"column":5}},"20":{"start":{"line":38,"column":4},"end":{"line":38,"column":34}},"21":{"start":{"line":41,"column":2},"end":{"line":43,"column":5}},"22":{"start":{"line":42,"column":4},"end":{"line":42,"column":73}},"23":{"start":{"line":45,"column":2},"end":{"line":47,"column":5}},"24":{"start":{"line":46,"column":4},"end":{"line":46,"column":73}},"25":{"start":{"line":49,"column":2},"end":{"line":51,"column":5}},"26":{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},"27":{"start":{"line":55,"column":2},"end":{"line":57,"column":5}},"28":{"start":{"line":56,"column":4},"end":{"line":56,"column":66}},"29":{"start":{"line":60,"column":0},"end":{"line":60,"column":21}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":34,"column":20},"end":{"line":34,"column":21}},"loc":{"start":{"line":34,"column":32},"end":{"line":52,"column":1}},"line":34},"1":{"name":"(anonymous_1)","decl":{"start":{"line":37,"column":25},"end":{"line":37,"column":26}},"loc":{"start":{"line":37,"column":37},"end":{"line":39,"column":3}},"line":37},"2":{"name":"(anonymous_2)","decl":{"start":{"line":41,"column":28},"end":{"line":41,"column":29}},"loc":{"start":{"line":41,"column":45},"end":{"line":43,"column":3}},"line":41},"3":{"name":"(anonymous_3)","decl":{"start":{"line":45,"column":27},"end":{"line":45,"column":28}},"loc":{"start":{"line":45,"column":43},"end":{"line":47,"column":3}},"line":45},"4":{"name":"(anonymous_4)","decl":{"start":{"line":49,"column":26},"end":{"line":49,"column":27}},"loc":{"start":{"line":49,"column":32},"end":{"line":51,"column":3}},"line":49},"5":{"name":"(anonymous_5)","decl":{"start":{"line":55,"column":22},"end":{"line":55,"column":23}},"loc":{"start":{"line":55,"column":28},"end":{"line":57,"column":3}},"line":55}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"type":"binary-expr","locations":[{"start":{"line":4,"column":13},"end":{"line":4,"column":29}},{"start":{"line":4,"column":33},"end":{"line":4,"column":37}}],"line":4},"1":{"loc":{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},"type":"if","locations":[{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},{"start":{},"end":{}}],"line":54}},"s":{"0":7,"1":7,"2":7,"3":7,"4":7,"5":7,"6":7,"7":7,"8":7,"9":7,"10":7,"11":7,"12":7,"13":7,"14":7,"15":7,"16":7,"17":7,"18":7,"19":7,"20":7,"21":7,"22":0,"23":7,"24":0,"25":7,"26":7,"27":0,"28":0,"29":7},"f":{"0":7,"1":7,"2":0,"3":0,"4":0,"5":0},"b":{"0":[7,7],"1":[0,7]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2a1669a6594937f4b2db57508e47b0260b54d91b"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js","statementMap":{"0":{"start":{"line":1,"column":33},"end":{"line":1,"column":71}},"1":{"start":{"line":5,"column":4},"end":{"line":21,"column":5}},"2":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"3":{"start":{"line":8,"column":8},"end":{"line":8,"column":39}},"4":{"start":{"line":11,"column":21},"end":{"line":11,"column":32}},"5":{"start":{"line":12,"column":20},"end":{"line":12,"column":54}},"6":{"start":{"line":14,"column":6},"end":{"line":18,"column":9}},"7":{"start":{"line":20,"column":6},"end":{"line":20,"column":16}},"8":{"start":{"line":25,"column":0},"end":{"line":25,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":4,"column":2},"end":{"line":4,"column":3}},"loc":{"start":{"line":4,"column":50},"end":{"line":22,"column":3}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"type":"if","locations":[{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":10},"end":{"line":7,"column":35}},"type":"binary-expr","locations":[{"start":{"line":7,"column":10},"end":{"line":7,"column":19}},{"start":{"line":7,"column":23},"end":{"line":7,"column":35}}],"line":7}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0},"f":{"0":0},"b":{"0":[0,0],"1":[0,0]}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js","statementMap":{"0":{"start":{"line":1,"column":43},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":24}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":52}},"3":{"start":{"line":8,"column":8},"end":{"line":34,"column":9}},"4":{"start":{"line":9,"column":34},"end":{"line":9,"column":42}},"5":{"start":{"line":10,"column":27},"end":{"line":10,"column":38}},"6":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"7":{"start":{"line":13,"column":16},"end":{"line":13,"column":97}},"8":{"start":{"line":17,"column":36},"end":{"line":29,"column":14}},"9":{"start":{"line":31,"column":12},"end":{"line":31,"column":55}},"10":{"start":{"line":33,"column":12},"end":{"line":33,"column":22}},"11":{"start":{"line":39,"column":8},"end":{"line":55,"column":9}},"12":{"start":{"line":40,"column":27},"end":{"line":40,"column":38}},"13":{"start":{"line":41,"column":26},"end":{"line":50,"column":14}},"14":{"start":{"line":52,"column":12},"end":{"line":52,"column":28}},"15":{"start":{"line":54,"column":12},"end":{"line":54,"column":22}},"16":{"start":{"line":60,"column":8},"end":{"line":79,"column":9}},"17":{"start":{"line":61,"column":31},"end":{"line":61,"column":41}},"18":{"start":{"line":62,"column":27},"end":{"line":62,"column":38}},"19":{"start":{"line":65,"column":25},"end":{"line":65,"column":52}},"20":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"21":{"start":{"line":67,"column":16},"end":{"line":67,"column":44}},"22":{"start":{"line":70,"column":29},"end":{"line":74,"column":14}},"23":{"start":{"line":76,"column":12},"end":{"line":76,"column":31}},"24":{"start":{"line":78,"column":12},"end":{"line":78,"column":22}},"25":{"start":{"line":83,"column":8},"end":{"line":99,"column":9}},"26":{"start":{"line":84,"column":27},"end":{"line":84,"column":38}},"27":{"start":{"line":85,"column":36},"end":{"line":95,"column":14}},"28":{"start":{"line":96,"column":12},"end":{"line":96,"column":55}},"29":{"start":{"line":98,"column":12},"end":{"line":98,"column":22}},"30":{"start":{"line":104,"column":8},"end":{"line":153,"column":9}},"31":{"start":{"line":105,"column":31},"end":{"line":105,"column":41}},"32":{"start":{"line":106,"column":32},"end":{"line":106,"column":40}},"33":{"start":{"line":107,"column":27},"end":{"line":107,"column":38}},"34":{"start":{"line":108,"column":23},"end":{"line":108,"column":46}},"35":{"start":{"line":110,"column":25},"end":{"line":110,"column":52}},"36":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"37":{"start":{"line":112,"column":16},"end":{"line":112,"column":70}},"38":{"start":{"line":115,"column":33},"end":{"line":115,"column":84}},"39":{"start":{"line":116,"column":12},"end":{"line":118,"column":13}},"40":{"start":{"line":117,"column":16},"end":{"line":117,"column":99}},"41":{"start":{"line":121,"column":32},"end":{"line":125,"column":14}},"42":{"start":{"line":126,"column":12},"end":{"line":126,"column":73}},"43":{"start":{"line":129,"column":12},"end":{"line":149,"column":13}},"44":{"start":{"line":131,"column":39},"end":{"line":131,"column":63}},"45":{"start":{"line":134,"column":34},"end":{"line":138,"column":18}},"46":{"start":{"line":141,"column":16},"end":{"line":141,"column":75}},"47":{"start":{"line":144,"column":16},"end":{"line":144,"column":55}},"48":{"start":{"line":148,"column":16},"end":{"line":148,"column":57}},"49":{"start":{"line":152,"column":12},"end":{"line":152,"column":22}},"50":{"start":{"line":157,"column":0},"end":{"line":157,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":4},"end":{"line":7,"column":5}},"loc":{"start":{"line":7,"column":49},"end":{"line":35,"column":5}},"line":7},"1":{"name":"(anonymous_1)","decl":{"start":{"line":38,"column":4},"end":{"line":38,"column":5}},"loc":{"start":{"line":38,"column":46},"end":{"line":56,"column":5}},"line":38},"2":{"name":"(anonymous_2)","decl":{"start":{"line":59,"column":4},"end":{"line":59,"column":5}},"loc":{"start":{"line":59,"column":49},"end":{"line":80,"column":5}},"line":59},"3":{"name":"(anonymous_3)","decl":{"start":{"line":82,"column":4},"end":{"line":82,"column":5}},"loc":{"start":{"line":82,"column":46},"end":{"line":100,"column":5}},"line":82},"4":{"name":"(anonymous_4)","decl":{"start":{"line":103,"column":4},"end":{"line":103,"column":5}},"loc":{"start":{"line":103,"column":45},"end":{"line":154,"column":5}},"line":103}},"branchMap":{"0":{"loc":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"type":"if","locations":[{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},{"start":{},"end":{}}],"line":12},"1":{"loc":{"start":{"line":31,"column":23},"end":{"line":31,"column":42}},"type":"cond-expr","locations":[{"start":{"line":31,"column":33},"end":{"line":31,"column":36}},{"start":{"line":31,"column":39},"end":{"line":31,"column":42}}],"line":31},"2":{"loc":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"type":"if","locations":[{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},{"start":{},"end":{}}],"line":66},"3":{"loc":{"start":{"line":66,"column":16},"end":{"line":66,"column":78}},"type":"binary-expr","locations":[{"start":{"line":66,"column":16},"end":{"line":66,"column":21}},{"start":{"line":66,"column":26},"end":{"line":66,"column":48}},{"start":{"line":66,"column":52},"end":{"line":66,"column":77}}],"line":66},"4":{"loc":{"start":{"line":96,"column":23},"end":{"line":96,"column":42}},"type":"cond-expr","locations":[{"start":{"line":96,"column":33},"end":{"line":96,"column":36}},{"start":{"line":96,"column":39},"end":{"line":96,"column":42}}],"line":96},"5":{"loc":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"type":"if","locations":[{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},{"start":{},"end":{}}],"line":111},"6":{"loc":{"start":{"line":115,"column":33},"end":{"line":115,"column":84}},"type":"binary-expr","locations":[{"start":{"line":115,"column":33},"end":{"line":115,"column":55}},{"start":{"line":115,"column":59},"end":{"line":115,"column":84}}],"line":115},"7":{"loc":{"start":{"line":116,"column":12},"end":{"line":118,"column":13}},"type":"if","locations":[{"start":{"line":116,"column":12},"end":{"line":118,"column":13}},{"start":{},"end":{}}],"line":116},"8":{"loc":{"start":{"line":129,"column":12},"end":{"line":149,"column":13}},"type":"if","locations":[{"start":{"line":129,"column":12},"end":{"line":149,"column":13}},{"start":{"line":146,"column":19},"end":{"line":149,"column":13}}],"line":129}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0]}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js","statementMap":{"0":{"start":{"line":1,"column":46},"end":{"line":1,"column":66}},"1":{"start":{"line":6,"column":4},"end":{"line":39,"column":5}},"2":{"start":{"line":7,"column":49},"end":{"line":7,"column":57}},"3":{"start":{"line":8,"column":21},"end":{"line":8,"column":32}},"4":{"start":{"line":11,"column":6},"end":{"line":13,"column":7}},"5":{"start":{"line":12,"column":8},"end":{"line":12,"column":98}},"6":{"start":{"line":16,"column":19},"end":{"line":22,"column":8}},"7":{"start":{"line":25,"column":29},"end":{"line":28,"column":9}},"8":{"start":{"line":25,"column":54},"end":{"line":28,"column":7}},"9":{"start":{"line":30,"column":6},"end":{"line":30,"column":45}},"10":{"start":{"line":32,"column":6},"end":{"line":36,"column":9}},"11":{"start":{"line":38,"column":6},"end":{"line":38,"column":16}},"12":{"start":{"line":44,"column":4},"end":{"line":58,"column":5}},"13":{"start":{"line":45,"column":20},"end":{"line":54,"column":8}},"14":{"start":{"line":55,"column":6},"end":{"line":55,"column":22}},"15":{"start":{"line":57,"column":6},"end":{"line":57,"column":16}},"16":{"start":{"line":63,"column":4},"end":{"line":72,"column":5}},"17":{"start":{"line":64,"column":20},"end":{"line":68,"column":8}},"18":{"start":{"line":69,"column":6},"end":{"line":69,"column":22}},"19":{"start":{"line":71,"column":6},"end":{"line":71,"column":16}},"20":{"start":{"line":77,"column":4},"end":{"line":89,"column":5}},"21":{"start":{"line":78,"column":21},"end":{"line":78,"column":31}},"22":{"start":{"line":79,"column":49},"end":{"line":79,"column":57}},"23":{"start":{"line":81,"column":19},"end":{"line":81,"column":42}},"24":{"start":{"line":82,"column":6},"end":{"line":82,"column":44}},"25":{"start":{"line":82,"column":17},"end":{"line":82,"column":44}},"26":{"start":{"line":83,"column":6},"end":{"line":83,"column":70}},"27":{"start":{"line":83,"column":39},"end":{"line":83,"column":70}},"28":{"start":{"line":85,"column":6},"end":{"line":85,"column":72}},"29":{"start":{"line":86,"column":6},"end":{"line":86,"column":63}},"30":{"start":{"line":88,"column":6},"end":{"line":88,"column":16}},"31":{"start":{"line":94,"column":4},"end":{"line":104,"column":5}},"32":{"start":{"line":95,"column":21},"end":{"line":95,"column":31}},"33":{"start":{"line":96,"column":19},"end":{"line":96,"column":42}},"34":{"start":{"line":97,"column":6},"end":{"line":97,"column":44}},"35":{"start":{"line":97,"column":17},"end":{"line":97,"column":44}},"36":{"start":{"line":98,"column":6},"end":{"line":98,"column":70}},"37":{"start":{"line":98,"column":39},"end":{"line":98,"column":70}},"38":{"start":{"line":100,"column":6},"end":{"line":100,"column":27}},"39":{"start":{"line":101,"column":6},"end":{"line":101,"column":57}},"40":{"start":{"line":103,"column":6},"end":{"line":103,"column":16}},"41":{"start":{"line":109,"column":4},"end":{"line":129,"column":5}},"42":{"start":{"line":110,"column":21},"end":{"line":110,"column":31}},"43":{"start":{"line":111,"column":19},"end":{"line":111,"column":42}},"44":{"start":{"line":112,"column":6},"end":{"line":112,"column":44}},"45":{"start":{"line":112,"column":17},"end":{"line":112,"column":44}},"46":{"start":{"line":114,"column":27},"end":{"line":116,"column":8}},"47":{"start":{"line":119,"column":6},"end":{"line":125,"column":7}},"48":{"start":{"line":120,"column":8},"end":{"line":120,"column":37}},"49":{"start":{"line":121,"column":8},"end":{"line":121,"column":33}},"50":{"start":{"line":123,"column":8},"end":{"line":123,"column":63}},"51":{"start":{"line":124,"column":8},"end":{"line":124,"column":31}},"52":{"start":{"line":126,"column":6},"end":{"line":126,"column":28}},"53":{"start":{"line":128,"column":6},"end":{"line":128,"column":16}},"54":{"start":{"line":133,"column":0},"end":{"line":133,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":2},"end":{"line":5,"column":3}},"loc":{"start":{"line":5,"column":42},"end":{"line":40,"column":3}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":25,"column":43},"end":{"line":25,"column":44}},"loc":{"start":{"line":25,"column":54},"end":{"line":28,"column":7}},"line":25},"2":{"name":"(anonymous_2)","decl":{"start":{"line":43,"column":2},"end":{"line":43,"column":3}},"loc":{"start":{"line":43,"column":49},"end":{"line":59,"column":3}},"line":43},"3":{"name":"(anonymous_3)","decl":{"start":{"line":62,"column":2},"end":{"line":62,"column":3}},"loc":{"start":{"line":62,"column":42},"end":{"line":73,"column":3}},"line":62},"4":{"name":"(anonymous_4)","decl":{"start":{"line":76,"column":2},"end":{"line":76,"column":3}},"loc":{"start":{"line":76,"column":42},"end":{"line":90,"column":3}},"line":76},"5":{"name":"(anonymous_5)","decl":{"start":{"line":93,"column":2},"end":{"line":93,"column":3}},"loc":{"start":{"line":93,"column":42},"end":{"line":105,"column":3}},"line":93},"6":{"name":"(anonymous_6)","decl":{"start":{"line":108,"column":2},"end":{"line":108,"column":3}},"loc":{"start":{"line":108,"column":42},"end":{"line":130,"column":3}},"line":108}},"branchMap":{"0":{"loc":{"start":{"line":11,"column":6},"end":{"line":13,"column":7}},"type":"if","locations":[{"start":{"line":11,"column":6},"end":{"line":13,"column":7}},{"start":{},"end":{}}],"line":11},"1":{"loc":{"start":{"line":11,"column":10},"end":{"line":11,"column":46}},"type":"binary-expr","locations":[{"start":{"line":11,"column":10},"end":{"line":11,"column":20}},{"start":{"line":11,"column":24},"end":{"line":11,"column":46}}],"line":11},"2":{"loc":{"start":{"line":19,"column":19},"end":{"line":19,"column":61}},"type":"binary-expr","locations":[{"start":{"line":19,"column":19},"end":{"line":19,"column":39}},{"start":{"line":19,"column":43},"end":{"line":19,"column":61}}],"line":19},"3":{"loc":{"start":{"line":82,"column":6},"end":{"line":82,"column":44}},"type":"if","locations":[{"start":{"line":82,"column":6},"end":{"line":82,"column":44}},{"start":{},"end":{}}],"line":82},"4":{"loc":{"start":{"line":83,"column":6},"end":{"line":83,"column":70}},"type":"if","locations":[{"start":{"line":83,"column":6},"end":{"line":83,"column":70}},{"start":{},"end":{}}],"line":83},"5":{"loc":{"start":{"line":97,"column":6},"end":{"line":97,"column":44}},"type":"if","locations":[{"start":{"line":97,"column":6},"end":{"line":97,"column":44}},{"start":{},"end":{}}],"line":97},"6":{"loc":{"start":{"line":98,"column":6},"end":{"line":98,"column":70}},"type":"if","locations":[{"start":{"line":98,"column":6},"end":{"line":98,"column":70}},{"start":{},"end":{}}],"line":98},"7":{"loc":{"start":{"line":112,"column":6},"end":{"line":112,"column":44}},"type":"if","locations":[{"start":{"line":112,"column":6},"end":{"line":112,"column":44}},{"start":{},"end":{}}],"line":112},"8":{"loc":{"start":{"line":119,"column":6},"end":{"line":125,"column":7}},"type":"if","locations":[{"start":{"line":119,"column":6},"end":{"line":125,"column":7}},{"start":{"line":122,"column":13},"end":{"line":125,"column":7}}],"line":119}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0]}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js","statementMap":{"0":{"start":{"line":1,"column":17},"end":{"line":1,"column":37}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":47}},"3":{"start":{"line":4,"column":25},"end":{"line":4,"column":55}},"4":{"start":{"line":5,"column":15},"end":{"line":5,"column":33}},"5":{"start":{"line":10,"column":8},"end":{"line":20,"column":9}},"6":{"start":{"line":11,"column":50},"end":{"line":11,"column":58}},"7":{"start":{"line":12,"column":28},"end":{"line":12,"column":76}},"8":{"start":{"line":13,"column":12},"end":{"line":17,"column":15}},"9":{"start":{"line":19,"column":12},"end":{"line":19,"column":22}},"10":{"start":{"line":24,"column":8},"end":{"line":44,"column":9}},"11":{"start":{"line":25,"column":40},"end":{"line":25,"column":48}},"12":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"13":{"start":{"line":27,"column":16},"end":{"line":27,"column":89}},"14":{"start":{"line":30,"column":25},"end":{"line":30,"column":65}},"15":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"16":{"start":{"line":32,"column":16},"end":{"line":32,"column":47}},"17":{"start":{"line":35,"column":36},"end":{"line":35,"column":79}},"18":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"19":{"start":{"line":37,"column":16},"end":{"line":37,"column":47}},"20":{"start":{"line":40,"column":26},"end":{"line":40,"column":52}},"21":{"start":{"line":41,"column":12},"end":{"line":41,"column":58}},"22":{"start":{"line":43,"column":12},"end":{"line":43,"column":22}},"23":{"start":{"line":48,"column":8},"end":{"line":73,"column":9}},"24":{"start":{"line":49,"column":37},"end":{"line":49,"column":45}},"25":{"start":{"line":51,"column":27},"end":{"line":54,"column":14}},"26":{"start":{"line":55,"column":28},"end":{"line":55,"column":47}},"27":{"start":{"line":57,"column":36},"end":{"line":66,"column":14}},"28":{"start":{"line":68,"column":33},"end":{"line":68,"column":59}},"29":{"start":{"line":69,"column":12},"end":{"line":69,"column":51}},"30":{"start":{"line":72,"column":12},"end":{"line":72,"column":22}},"31":{"start":{"line":77,"column":0},"end":{"line":77,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":9,"column":4},"end":{"line":9,"column":5}},"loc":{"start":{"line":9,"column":42},"end":{"line":21,"column":5}},"line":9},"1":{"name":"(anonymous_1)","decl":{"start":{"line":23,"column":4},"end":{"line":23,"column":5}},"loc":{"start":{"line":23,"column":39},"end":{"line":45,"column":5}},"line":23},"2":{"name":"(anonymous_2)","decl":{"start":{"line":47,"column":4},"end":{"line":47,"column":5}},"loc":{"start":{"line":47,"column":46},"end":{"line":74,"column":5}},"line":47}},"branchMap":{"0":{"loc":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"type":"if","locations":[{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},{"start":{},"end":{}}],"line":26},"1":{"loc":{"start":{"line":26,"column":16},"end":{"line":26,"column":35}},"type":"binary-expr","locations":[{"start":{"line":26,"column":16},"end":{"line":26,"column":22}},{"start":{"line":26,"column":26},"end":{"line":26,"column":35}}],"line":26},"2":{"loc":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"type":"if","locations":[{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},{"start":{},"end":{}}],"line":31},"3":{"loc":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"type":"if","locations":[{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},{"start":{},"end":{}}],"line":36}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0},"f":{"0":0,"1":0,"2":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0]}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":3,"column":14},"end":{"line":3,"column":64}},"2":{"start":{"line":4,"column":14},"end":{"line":4,"column":69}},"3":{"start":{"line":8,"column":2},"end":{"line":21,"column":12}},"4":{"start":{"line":25,"column":2},"end":{"line":32,"column":3}},"5":{"start":{"line":26,"column":19},"end":{"line":26,"column":54}},"6":{"start":{"line":27,"column":20},"end":{"line":27,"column":42}},"7":{"start":{"line":28,"column":4},"end":{"line":28,"column":30}},"8":{"start":{"line":30,"column":4},"end":{"line":30,"column":47}},"9":{"start":{"line":31,"column":4},"end":{"line":31,"column":63}},"10":{"start":{"line":35,"column":0},"end":{"line":35,"column":42}}},"fnMap":{"0":{"name":"cleanText","decl":{"start":{"line":7,"column":9},"end":{"line":7,"column":18}},"loc":{"start":{"line":7,"column":30},"end":{"line":22,"column":1}},"line":7},"1":{"name":"askGemini","decl":{"start":{"line":24,"column":15},"end":{"line":24,"column":24}},"loc":{"start":{"line":24,"column":33},"end":{"line":33,"column":1}},"line":24}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":19},"end":{"line":7,"column":28}},"type":"default-arg","locations":[{"start":{"line":7,"column":26},"end":{"line":7,"column":28}}],"line":7}},"s":{"0":5,"1":5,"2":5,"3":4,"4":3,"5":3,"6":2,"7":2,"8":1,"9":1,"10":5},"f":{"0":4,"1":3},"b":{"0":[1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2e50e4f0c73211fc77ec6e98c2ee2a41538ee44c"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":39},"end":{"line":2,"column":59}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":35}},"3":{"start":{"line":6,"column":2},"end":{"line":68,"column":3}},"4":{"start":{"line":8,"column":18},"end":{"line":8,"column":68}},"5":{"start":{"line":9,"column":18},"end":{"line":9,"column":71}},"6":{"start":{"line":11,"column":23},"end":{"line":14,"column":6}},"7":{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},"8":{"start":{"line":18,"column":6},"end":{"line":23,"column":9}},"9":{"start":{"line":26,"column":26},"end":{"line":31,"column":17}},"10":{"start":{"line":29,"column":10},"end":{"line":29,"column":86}},"11":{"start":{"line":33,"column":19},"end":{"line":39,"column":5}},"12":{"start":{"line":41,"column":19},"end":{"line":41,"column":54}},"13":{"start":{"line":42,"column":27},"end":{"line":42,"column":49}},"14":{"start":{"line":43,"column":23},"end":{"line":43,"column":69}},"15":{"start":{"line":43,"column":60},"end":{"line":43,"column":68}},"16":{"start":{"line":45,"column":29},"end":{"line":57,"column":6}},"17":{"start":{"line":59,"column":4},"end":{"line":59,"column":28}},"18":{"start":{"line":61,"column":4},"end":{"line":61,"column":60}},"19":{"start":{"line":62,"column":4},"end":{"line":67,"column":7}},"20":{"start":{"line":71,"column":0},"end":{"line":71,"column":42}}},"fnMap":{"0":{"name":"getAIRecommendations","decl":{"start":{"line":5,"column":15},"end":{"line":5,"column":35}},"loc":{"start":{"line":5,"column":44},"end":{"line":69,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":28,"column":8},"end":{"line":28,"column":9}},"loc":{"start":{"line":29,"column":10},"end":{"line":29,"column":86}},"line":29},"2":{"name":"(anonymous_2)","decl":{"start":{"line":43,"column":53},"end":{"line":43,"column":54}},"loc":{"start":{"line":43,"column":60},"end":{"line":43,"column":68}},"line":43}},"branchMap":{"0":{"loc":{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},"type":"if","locations":[{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},{"start":{},"end":{}}],"line":17},"1":{"loc":{"start":{"line":17,"column":8},"end":{"line":17,"column":44}},"type":"binary-expr","locations":[{"start":{"line":17,"column":8},"end":{"line":17,"column":19}},{"start":{"line":17,"column":23},"end":{"line":17,"column":44}}],"line":17},"2":{"loc":{"start":{"line":29,"column":49},"end":{"line":29,"column":83}},"type":"binary-expr","locations":[{"start":{"line":29,"column":49},"end":{"line":29,"column":73}},{"start":{"line":29,"column":77},"end":{"line":29,"column":83}}],"line":29}},"s":{"0":4,"1":4,"2":4,"3":4,"4":4,"5":4,"6":4,"7":3,"8":1,"9":2,"10":6,"11":2,"12":2,"13":2,"14":2,"15":5,"16":2,"17":2,"18":1,"19":1,"20":4},"f":{"0":4,"1":6,"2":5},"b":{"0":[1,2],"1":[3,3],"2":[6,2]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"b1fba11a44899570364f599bbe9715df05009abc"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\authMiddleware.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\authMiddleware.js","statementMap":{"0":{"start":{"line":1,"column":24},"end":{"line":1,"column":40}},"1":{"start":{"line":2,"column":17},"end":{"line":2,"column":37}},"2":{"start":{"line":4,"column":0},"end":{"line":28,"column":2}},"3":{"start":{"line":5,"column":2},"end":{"line":27,"column":3}},"4":{"start":{"line":6,"column":24},"end":{"line":6,"column":49}},"5":{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},"6":{"start":{"line":8,"column":6},"end":{"line":8,"column":68}},"7":{"start":{"line":11,"column":18},"end":{"line":11,"column":43}},"8":{"start":{"line":12,"column":20},"end":{"line":12,"column":38}},"9":{"start":{"line":13,"column":17},"end":{"line":13,"column":48}},"10":{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},"11":{"start":{"line":14,"column":15},"end":{"line":14,"column":73}},"12":{"start":{"line":16,"column":4},"end":{"line":16,"column":20}},"13":{"start":{"line":17,"column":4},"end":{"line":17,"column":28}},"14":{"start":{"line":18,"column":4},"end":{"line":18,"column":11}},"15":{"start":{"line":20,"column":4},"end":{"line":26,"column":5}},"16":{"start":{"line":21,"column":6},"end":{"line":21,"column":16}},"17":{"start":{"line":22,"column":11},"end":{"line":26,"column":5}},"18":{"start":{"line":23,"column":6},"end":{"line":23,"column":68}},"19":{"start":{"line":25,"column":6},"end":{"line":25,"column":68}}},"fnMap":{"0":{"name":"authMiddleware","decl":{"start":{"line":4,"column":32},"end":{"line":4,"column":46}},"loc":{"start":{"line":4,"column":63},"end":{"line":28,"column":1}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},"type":"if","locations":[{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":8},"end":{"line":7,"column":58}},"type":"binary-expr","locations":[{"start":{"line":7,"column":8},"end":{"line":7,"column":20}},{"start":{"line":7,"column":24},"end":{"line":7,"column":58}}],"line":7},"2":{"loc":{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},"type":"if","locations":[{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},{"start":{},"end":{}}],"line":14},"3":{"loc":{"start":{"line":20,"column":4},"end":{"line":26,"column":5}},"type":"if","locations":[{"start":{"line":20,"column":4},"end":{"line":26,"column":5}},{"start":{"line":22,"column":11},"end":{"line":26,"column":5}}],"line":20},"4":{"loc":{"start":{"line":22,"column":11},"end":{"line":26,"column":5}},"type":"if","locations":[{"start":{"line":22,"column":11},"end":{"line":26,"column":5}},{"start":{"line":24,"column":11},"end":{"line":26,"column":5}}],"line":22}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0},"f":{"0":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0]}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\cloudinary.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\cloudinary.js","statementMap":{"0":{"start":{"line":1,"column":19},"end":{"line":1,"column":43}},"1":{"start":{"line":2,"column":30},"end":{"line":2,"column":66}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":32}},"3":{"start":{"line":5,"column":0},"end":{"line":9,"column":3}},"4":{"start":{"line":11,"column":16},"end":{"line":18,"column":2}},"5":{"start":{"line":20,"column":15},"end":{"line":20,"column":34}},"6":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":4,"1":4,"2":4,"3":4,"4":4,"5":4,"6":4},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"b5c712c03dc49f3dc144389fe011736580e525df"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\handleError.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\handleError.js","statementMap":{"0":{"start":{"line":2,"column":2},"end":{"line":2,"column":31}},"1":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"2":{"start":{"line":5,"column":4},"end":{"line":5,"column":68}},"3":{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},"4":{"start":{"line":9,"column":4},"end":{"line":9,"column":74}},"5":{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},"6":{"start":{"line":13,"column":4},"end":{"line":13,"column":63}},"7":{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},"8":{"start":{"line":17,"column":4},"end":{"line":17,"column":75}},"9":{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},"10":{"start":{"line":21,"column":21},"end":{"line":21,"column":51}},"11":{"start":{"line":21,"column":41},"end":{"line":21,"column":50}},"12":{"start":{"line":22,"column":4},"end":{"line":22,"column":55}},"13":{"start":{"line":25,"column":2},"end":{"line":27,"column":5}},"14":{"start":{"line":30,"column":0},"end":{"line":30,"column":29}}},"fnMap":{"0":{"name":"handleError","decl":{"start":{"line":1,"column":9},"end":{"line":1,"column":20}},"loc":{"start":{"line":1,"column":41},"end":{"line":28,"column":1}},"line":1},"1":{"name":"(anonymous_1)","decl":{"start":{"line":21,"column":36},"end":{"line":21,"column":37}},"loc":{"start":{"line":21,"column":41},"end":{"line":21,"column":50}},"line":21}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"type":"if","locations":[{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},{"start":{},"end":{}}],"line":4},"1":{"loc":{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},{"start":{},"end":{}}],"line":8},"2":{"loc":{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},"type":"if","locations":[{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},{"start":{},"end":{}}],"line":12},"3":{"loc":{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},"type":"if","locations":[{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},{"start":{},"end":{}}],"line":16},"4":{"loc":{"start":{"line":17,"column":43},"end":{"line":17,"column":71}},"type":"binary-expr","locations":[{"start":{"line":17,"column":43},"end":{"line":17,"column":54}},{"start":{"line":17,"column":58},"end":{"line":17,"column":71}}],"line":17},"5":{"loc":{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},"type":"if","locations":[{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},{"start":{},"end":{}}],"line":20},"6":{"loc":{"start":{"line":20,"column":6},"end":{"line":20,"column":94}},"type":"binary-expr","locations":[{"start":{"line":20,"column":6},"end":{"line":20,"column":45}},{"start":{"line":20,"column":49},"end":{"line":20,"column":94}}],"line":20}},"s":{"0":8,"1":8,"2":1,"3":7,"4":1,"5":6,"6":1,"7":5,"8":2,"9":3,"10":2,"11":3,"12":2,"13":1,"14":2},"f":{"0":8,"1":3},"b":{"0":[1,7],"1":[1,6],"2":[1,5],"3":[2,3],"4":[2,1],"5":[2,1],"6":[3,2]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"c2354f978bf3faa64bb0eed70640c0f9b3ddd7a3"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js","statementMap":{"0":{"start":{"line":1,"column":12},"end":{"line":1,"column":35}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":37}},"2":{"start":{"line":5,"column":2},"end":{"line":5,"column":35}},"3":{"start":{"line":9,"column":2},"end":{"line":9,"column":35}},"4":{"start":{"line":12,"column":0},"end":{"line":12,"column":44}}},"fnMap":{"0":{"name":"signToken","decl":{"start":{"line":4,"column":9},"end":{"line":4,"column":18}},"loc":{"start":{"line":4,"column":28},"end":{"line":6,"column":1}},"line":4},"1":{"name":"verifyToken","decl":{"start":{"line":8,"column":9},"end":{"line":8,"column":20}},"loc":{"start":{"line":8,"column":28},"end":{"line":10,"column":1}},"line":8}},"branchMap":{},"s":{"0":3,"1":3,"2":1,"3":2,"4":3},"f":{"0":1,"1":2},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"d7b8e9b1304ab0135964e79a9372e3a90c422c73"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\aiRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\aiRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":21},"end":{"line":3,"column":59}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":7,"column":0},"end":{"line":7,"column":70}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0},"f":{},"b":{}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\chatRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\chatRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":23},"end":{"line":3,"column":63}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":17}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":48}},"6":{"start":{"line":12,"column":0},"end":{"line":12,"column":49}},"7":{"start":{"line":15,"column":0},"end":{"line":15,"column":45}},"8":{"start":{"line":18,"column":0},"end":{"line":18,"column":64}},"9":{"start":{"line":21,"column":0},"end":{"line":21,"column":61}},"10":{"start":{"line":23,"column":0},"end":{"line":23,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"f":{},"b":{}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\index.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\index.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":4,"column":19},"end":{"line":4,"column":42}},"3":{"start":{"line":5,"column":19},"end":{"line":5,"column":42}},"4":{"start":{"line":6,"column":19},"end":{"line":6,"column":42}},"5":{"start":{"line":7,"column":17},"end":{"line":7,"column":38}},"6":{"start":{"line":16,"column":0},"end":{"line":16,"column":33}},"7":{"start":{"line":17,"column":0},"end":{"line":17,"column":33}},"8":{"start":{"line":18,"column":0},"end":{"line":18,"column":33}},"9":{"start":{"line":19,"column":0},"end":{"line":19,"column":28}},"10":{"start":{"line":21,"column":0},"end":{"line":21,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"e64227b43051f4e83574447d7ab08252f7f48992"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\postRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\postRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":23},"end":{"line":3,"column":63}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":5,"column":15},"end":{"line":5,"column":47}},"5":{"start":{"line":8,"column":0},"end":{"line":8,"column":77}},"6":{"start":{"line":10,"column":0},"end":{"line":10,"column":50}},"7":{"start":{"line":11,"column":0},"end":{"line":11,"column":51}},"8":{"start":{"line":13,"column":0},"end":{"line":13,"column":52}},"9":{"start":{"line":14,"column":0},"end":{"line":14,"column":55}},"10":{"start":{"line":16,"column":0},"end":{"line":16,"column":58}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0},"f":{},"b":{}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\userRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\userRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":23},"end":{"line":2,"column":63}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":31}},"3":{"start":{"line":5,"column":0},"end":{"line":5,"column":50}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":44}},"5":{"start":{"line":7,"column":0},"end":{"line":7,"column":57}},"6":{"start":{"line":10,"column":0},"end":{"line":10,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0},"f":{},"b":{}} } diff --git a/coverage/lcov-report/Dummy-Instagram/app.js.html b/coverage/lcov-report/Dummy-Instagram/app.js.html index deea665..ffa1f1b 100644 --- a/coverage/lcov-report/Dummy-Instagram/app.js.html +++ b/coverage/lcov-report/Dummy-Instagram/app.js.html @@ -122,66 +122,66 @@

All files / Dummy-Instagram 57 58 59 -6011x -11x -11x -11x -11x -11x -11x +607x +7x +7x +7x +7x +7x +7x   -11x -11x -11x -11x +7x +7x +7x +7x           -11x +7x     -11x -11x -11x -11x +7x +7x +7x +7x     -11x +7x       -11x +7x     -11x +7x     -8x -8x +7x +7x     -8x +7x       -8x +7x       -8x +7x         -11x +7x           -11x
require('dotenv').config();
+7x
require('dotenv').config();
 const express = require('express');
 const app = express();
 const port = process.env.PORT || 3000;
@@ -247,7 +247,7 @@ 

All files / Dummy-Instagram + + diff --git a/client/package-lock.json b/client/package-lock.json new file mode 100644 index 0000000..2e8791a --- /dev/null +++ b/client/package-lock.json @@ -0,0 +1,3499 @@ +{ + "name": "client", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "client", + "version": "0.0.0", + "dependencies": { + "@react-oauth/google": "^0.12.2", + "axios": "^1.12.2", + "bootstrap": "^5.3.8", + "react": "^19.1.1", + "react-bootstrap": "^2.10.10", + "react-bootstrap-icons": "^1.11.6", + "react-dom": "^19.1.1", + "react-router-dom": "^7.9.4", + "sweetalert2": "^11.26.2" + }, + "devDependencies": { + "@eslint/js": "^9.36.0", + "@types/react": "^19.1.16", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.4", + "eslint": "^9.36.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.22", + "globals": "^16.4.0", + "vite": "^7.1.7" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", + "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", + "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", + "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", + "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", + "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", + "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", + "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", + "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", + "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", + "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", + "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", + "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", + "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", + "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", + "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", + "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", + "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", + "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", + "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", + "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", + "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", + "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", + "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", + "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", + "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", + "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.0.tgz", + "integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.16.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz", + "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.37.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.37.0.tgz", + "integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz", + "integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.16.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.10.tgz", + "integrity": "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-oauth/google": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@react-oauth/google/-/google-0.12.2.tgz", + "integrity": "sha512-d1GVm2uD4E44EJft2RbKtp8Z1fp/gK8Lb6KHgs3pHlM0PxCXGLaq8LLYQYENnN4xPWO1gkL4apBtlPKzpLvZwg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@restart/hooks": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", + "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@restart/ui": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.9.4.tgz", + "integrity": "sha512-N4C7haUc3vn4LTwVUPlkJN8Ach/+yIMvRuTVIhjilNHqegY60SGLrzud6errOMNJwSnmYFnt1J0H/k8FE3A4KA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.0", + "@popperjs/core": "^2.11.8", + "@react-aria/ssr": "^3.5.0", + "@restart/hooks": "^0.5.0", + "@types/warning": "^3.0.3", + "dequal": "^2.0.3", + "dom-helpers": "^5.2.0", + "uncontrollable": "^8.0.4", + "warning": "^4.0.3" + }, + "peerDependencies": { + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + } + }, + "node_modules/@restart/ui/node_modules/@restart/hooks": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.5.1.tgz", + "integrity": "sha512-EMoH04NHS1pbn07iLTjIjgttuqb7qu4+/EyhAx27MHpoENcB2ZdSsLTNxmKD+WEPnZigo62Qc8zjGnNxoSE/5Q==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@restart/ui/node_modules/uncontrollable": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz", + "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.14.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.38", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz", + "integrity": "sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz", + "integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz", + "integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz", + "integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz", + "integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz", + "integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz", + "integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz", + "integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz", + "integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz", + "integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz", + "integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz", + "integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz", + "integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz", + "integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz", + "integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz", + "integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz", + "integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz", + "integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz", + "integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz", + "integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz", + "integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz", + "integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz", + "integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", + "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", + "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/warning": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.4.tgz", + "integrity": "sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.4", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.38", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", + "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.16", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.16.tgz", + "integrity": "sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/bootstrap": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz", + "integrity": "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "license": "MIT", + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.26.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", + "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.9", + "caniuse-lite": "^1.0.30001746", + "electron-to-chromium": "^1.5.227", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001751", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", + "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.237", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.237.tgz", + "integrity": "sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg==", + "dev": true, + "license": "ISC" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", + "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.11", + "@esbuild/android-arm": "0.25.11", + "@esbuild/android-arm64": "0.25.11", + "@esbuild/android-x64": "0.25.11", + "@esbuild/darwin-arm64": "0.25.11", + "@esbuild/darwin-x64": "0.25.11", + "@esbuild/freebsd-arm64": "0.25.11", + "@esbuild/freebsd-x64": "0.25.11", + "@esbuild/linux-arm": "0.25.11", + "@esbuild/linux-arm64": "0.25.11", + "@esbuild/linux-ia32": "0.25.11", + "@esbuild/linux-loong64": "0.25.11", + "@esbuild/linux-mips64el": "0.25.11", + "@esbuild/linux-ppc64": "0.25.11", + "@esbuild/linux-riscv64": "0.25.11", + "@esbuild/linux-s390x": "0.25.11", + "@esbuild/linux-x64": "0.25.11", + "@esbuild/netbsd-arm64": "0.25.11", + "@esbuild/netbsd-x64": "0.25.11", + "@esbuild/openbsd-arm64": "0.25.11", + "@esbuild/openbsd-x64": "0.25.11", + "@esbuild/openharmony-arm64": "0.25.11", + "@esbuild/sunos-x64": "0.25.11", + "@esbuild/win32-arm64": "0.25.11", + "@esbuild/win32-ia32": "0.25.11", + "@esbuild/win32-x64": "0.25.11" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.37.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.37.0.tgz", + "integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.4.0", + "@eslint/core": "^0.16.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.37.0", + "@eslint/plugin-kit": "^0.4.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.24.tgz", + "integrity": "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.25", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.25.tgz", + "integrity": "sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA==", + "dev": true, + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types-extra": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", + "license": "MIT", + "dependencies": { + "react-is": "^16.3.2", + "warning": "^4.0.0" + }, + "peerDependencies": { + "react": ">=0.14.0" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-bootstrap": { + "version": "2.10.10", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.10.tgz", + "integrity": "sha512-gMckKUqn8aK/vCnfwoBpBVFUGT9SVQxwsYrp9yDHt0arXMamxALerliKBxr1TPbntirK/HGrUAHYbAeQTa9GHQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.7", + "@restart/hooks": "^0.4.9", + "@restart/ui": "^1.9.4", + "@types/prop-types": "^15.7.12", + "@types/react-transition-group": "^4.4.6", + "classnames": "^2.3.2", + "dom-helpers": "^5.2.1", + "invariant": "^2.2.4", + "prop-types": "^15.8.1", + "prop-types-extra": "^1.1.0", + "react-transition-group": "^4.4.5", + "uncontrollable": "^7.2.1", + "warning": "^4.0.3" + }, + "peerDependencies": { + "@types/react": ">=16.14.8", + "react": ">=16.14.0", + "react-dom": ">=16.14.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-bootstrap-icons": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/react-bootstrap-icons/-/react-bootstrap-icons-1.11.6.tgz", + "integrity": "sha512-ycXiyeSyzbS1C4+MlPTYe0riB+UlZ7LV7YZQYqlERV2cxDiKtntI0huHmP/3VVvzPt4tGxqK0K+Y6g7We3U6tQ==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": ">=16.8.6" + } + }, + "node_modules/react-dom": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", + "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.4.tgz", + "integrity": "sha512-SD3G8HKviFHg9xj7dNODUKDFgpG4xqD5nhyd0mYoB5iISepuZAvzSr8ywxgxKJ52yRzf/HWtVHc9AWwoTbljvA==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.9.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.4.tgz", + "integrity": "sha512-f30P6bIkmYvnHHa5Gcu65deIXoA2+r3Eb6PJIAddvsT9aGlchMatJ51GgpU470aSqRRbFX22T70yQNUGuW3DfA==", + "license": "MIT", + "dependencies": { + "react-router": "7.9.4" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rollup": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz", + "integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.4", + "@rollup/rollup-android-arm64": "4.52.4", + "@rollup/rollup-darwin-arm64": "4.52.4", + "@rollup/rollup-darwin-x64": "4.52.4", + "@rollup/rollup-freebsd-arm64": "4.52.4", + "@rollup/rollup-freebsd-x64": "4.52.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.4", + "@rollup/rollup-linux-arm-musleabihf": "4.52.4", + "@rollup/rollup-linux-arm64-gnu": "4.52.4", + "@rollup/rollup-linux-arm64-musl": "4.52.4", + "@rollup/rollup-linux-loong64-gnu": "4.52.4", + "@rollup/rollup-linux-ppc64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-musl": "4.52.4", + "@rollup/rollup-linux-s390x-gnu": "4.52.4", + "@rollup/rollup-linux-x64-gnu": "4.52.4", + "@rollup/rollup-linux-x64-musl": "4.52.4", + "@rollup/rollup-openharmony-arm64": "4.52.4", + "@rollup/rollup-win32-arm64-msvc": "4.52.4", + "@rollup/rollup-win32-ia32-msvc": "4.52.4", + "@rollup/rollup-win32-x64-gnu": "4.52.4", + "@rollup/rollup-win32-x64-msvc": "4.52.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sweetalert2": { + "version": "11.26.2", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.26.2.tgz", + "integrity": "sha512-tR5oADjrN6gv+0Y/tpfMXM/rSlx/QHmRhygBHhWh29iw1AO/x7D8OhghyogaY+NLZrd4qfhssVafRBHi+DREzQ==", + "license": "MIT", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/limonte" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "7.1.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.10.tgz", + "integrity": "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/client/package.json b/client/package.json new file mode 100644 index 0000000..8c4ef4b --- /dev/null +++ b/client/package.json @@ -0,0 +1,34 @@ +{ + "name": "client", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@react-oauth/google": "^0.12.2", + "axios": "^1.12.2", + "bootstrap": "^5.3.8", + "react": "^19.1.1", + "react-bootstrap": "^2.10.10", + "react-bootstrap-icons": "^1.11.6", + "react-dom": "^19.1.1", + "react-router-dom": "^7.9.4", + "sweetalert2": "^11.26.2" + }, + "devDependencies": { + "@eslint/js": "^9.36.0", + "@types/react": "^19.1.16", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.4", + "eslint": "^9.36.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.22", + "globals": "^16.4.0", + "vite": "^7.1.7" + } +} diff --git a/client/public/vite.svg b/client/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/client/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/App.jsx b/client/src/App.jsx new file mode 100644 index 0000000..2d1438d --- /dev/null +++ b/client/src/App.jsx @@ -0,0 +1,70 @@ +import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; +import { GoogleOAuthProvider } from '@react-oauth/google'; +import Login from './pages/Login'; +import Register from './pages/Register'; +import Home from './pages/Home'; +import Messages from './pages/Messages'; + +const GOOGLE_CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID || '426382311425-flmdrhl6n7tmqcamg1lj8c8cmrkqgtpa.apps.googleusercontent.com'; + +function App() { + const ProtectedRoute = ({ children }) => { + const token = localStorage.getItem('access_token'); + if (!token) { + return ; + } + return children; + }; + + const AuthRoute = ({ children }) => { + const token = localStorage.getItem('access_token'); + if (token) { + return ; + } + return children; + }; + + return ( + + + + + + + } + /> + + + + } + /> + + + + } + /> + + + + } + /> + } /> + + + + ); +} + +export default App; \ No newline at end of file diff --git a/client/src/assets/react.svg b/client/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/client/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/components/AIChatModal.jsx b/client/src/components/AIChatModal.jsx new file mode 100644 index 0000000..af66750 --- /dev/null +++ b/client/src/components/AIChatModal.jsx @@ -0,0 +1,311 @@ +import { useState, useEffect, useRef } from 'react'; +import { Modal, Form, Button, ListGroup, Badge, Spinner } from 'react-bootstrap'; +import { ChatDotsFill, Send, Robot, XCircle } from 'react-bootstrap-icons'; +import http from '../helpers/http'; +import Swal from 'sweetalert2'; + +const AIChatModal = ({ show, onHide }) => { + const [messages, setMessages] = useState([]); + const [newMessage, setNewMessage] = useState(''); + const [loading, setLoading] = useState(false); + const [sending, setSending] = useState(false); + const [chatId, setChatId] = useState(null); + const messagesEndRef = useRef(null); + + useEffect(() => { + if (show) { + initializeChat(); + } + }, [show]); + + useEffect(() => { + scrollToBottom(); + }, [messages]); + + const scrollToBottom = () => { + messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); + }; + + const initializeChat = async () => { + try { + setLoading(true); + // Create or get AI chat + const { data: chat } = await http.post('/chats/ai'); + setChatId(chat.id); + + // Load existing messages + const { data: msgs } = await http.get(`/chats/${chat.id}/messages`); + setMessages(msgs); + + // Welcome message if no messages + if (msgs.length === 0) { + setMessages([{ + id: 'welcome', + content: "Hello! I'm your AI assistant. How can I help you today? ๐Ÿค–", + senderId: null, + createdAt: new Date().toISOString() + }]); + } + } catch (error) { + console.error('Error initializing chat:', error); + Swal.fire({ + icon: 'error', + title: 'Failed to start chat', + text: error.response?.data?.message || 'Something went wrong', + }); + } finally { + setLoading(false); + } + }; + + const handleSendMessage = async (e) => { + e.preventDefault(); + + if (!newMessage.trim() || !chatId) return; + + const messageContent = newMessage.trim(); + setNewMessage(''); + setSending(true); + + // Add user message to UI immediately + const userMsg = { + id: Date.now(), + content: messageContent, + senderId: 'user', + createdAt: new Date().toISOString() + }; + setMessages(prev => [...prev, userMsg]); + + try { + // Send message to backend + const { data: aiResponse } = await http.post(`/chats/${chatId}/messages`, { + content: messageContent + }); + + // Add AI response to messages + setMessages(prev => [...prev, aiResponse]); + } catch (error) { + console.error('Error sending message:', error); + Swal.fire({ + icon: 'error', + title: 'Failed to send message', + text: error.response?.data?.message || 'Something went wrong', + toast: true, + position: 'top-end', + timer: 3000, + showConfirmButton: false + }); + } finally { + setSending(false); + } + }; + + const formatTime = (dateString) => { + const date = new Date(dateString); + return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); + }; + + return ( + + + + + AI Assistant + + + + + + {/* Messages Container */} +
+ {loading ? ( +
+ +

Starting chat...

+
+ ) : ( + <> + {messages.map((msg, index) => ( +
+
+ {msg.senderId === null && ( +
+ + AI Assistant +
+ )} +
+ {msg.content} +
+ + {formatTime(msg.createdAt)} + +
+
+ ))} + {sending && ( +
+
+
+ + + +
+
+
+ )} +
+ + )} +
+ + + +
+
+ setNewMessage(e.target.value)} + disabled={sending || loading} + style={{ + flex: 1, + borderRadius: '20px', + resize: 'none', + padding: '15px 20px', + fontSize: '16px', + lineHeight: '1.5', + border: '2px solid #e0e0e0', + transition: 'all 0.3s ease', + minHeight: '90px', + boxShadow: '0 2px 8px rgba(0, 0, 0, 0.05)' + }} + onFocus={(e) => { + e.target.style.borderColor = '#667eea'; + e.target.style.boxShadow = '0 4px 12px rgba(102, 126, 234, 0.15)'; + }} + onBlur={(e) => { + e.target.style.borderColor = '#e0e0e0'; + e.target.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.05)'; + }} + onKeyDown={(e) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + handleSendMessage(e); + } + }} + /> + +
+ + ๐Ÿ’ก Tip: Press Enter to send, Shift + Enter for new line + +
+
+ + ); +}; + +export default AIChatModal; diff --git a/client/src/components/CreatePostModal.jsx b/client/src/components/CreatePostModal.jsx new file mode 100644 index 0000000..fee3940 --- /dev/null +++ b/client/src/components/CreatePostModal.jsx @@ -0,0 +1,278 @@ +import { useState, useRef } from 'react'; +import { Modal, Form, Button, Row, Col, Image, Spinner } from 'react-bootstrap'; +import { XCircle, Upload, ImageFill } from 'react-bootstrap-icons'; +import http from '../helpers/http'; +import Swal from 'sweetalert2'; + +const CreatePostModal = ({ show, onHide, onPostCreated }) => { + const [content, setContent] = useState(''); + const [images, setImages] = useState([]); + const [imagePreviews, setImagePreviews] = useState([]); + const [isPrivate, setIsPrivate] = useState(false); + const [categoryId, setCategoryId] = useState(''); + const [loading, setLoading] = useState(false); + const fileInputRef = useRef(null); + + const categories = [ + { id: 1, name: 'Travel' }, + { id: 2, name: 'Food' }, + { id: 3, name: 'Fashion' }, + { id: 4, name: 'Technology' }, + { id: 5, name: 'Lifestyle' }, + ]; + + const handleImageChange = (e) => { + const files = Array.from(e.target.files); + + if (images.length + files.length > 5) { + Swal.fire({ + icon: 'warning', + title: 'Too many images', + text: 'You can only upload up to 5 images per post', + }); + return; + } + + setImages([...images, ...files]); + + // Create previews + files.forEach(file => { + const reader = new FileReader(); + reader.onloadend = () => { + setImagePreviews(prev => [...prev, reader.result]); + }; + reader.readAsDataURL(file); + }); + }; + + const removeImage = (index) => { + setImages(images.filter((_, i) => i !== index)); + setImagePreviews(imagePreviews.filter((_, i) => i !== index)); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + + if (images.length === 0) { + Swal.fire({ + icon: 'warning', + title: 'No images', + text: 'Please select at least one image', + }); + return; + } + + setLoading(true); + + try { + const formData = new FormData(); + formData.append('content', content); + formData.append('isPrivate', isPrivate); + if (categoryId) formData.append('categoryId', categoryId); + + images.forEach(image => { + formData.append('images', image); + }); + + const { data } = await http.post('/posts', formData, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }); + + Swal.fire({ + icon: 'success', + title: 'Post Created!', + text: 'Your post has been shared successfully', + timer: 1500, + showConfirmButton: false, + }); + + // Reset form + setContent(''); + setImages([]); + setImagePreviews([]); + setIsPrivate(false); + setCategoryId(''); + + onHide(); + if (onPostCreated) onPostCreated(); + } catch (error) { + Swal.fire({ + icon: 'error', + title: 'Failed to create post', + text: error.response?.data?.message || 'Something went wrong', + }); + } finally { + setLoading(false); + } + }; + + return ( + + + Create New Post + + + +
+ {/* Image Upload Section */} + + + + Upload Images (Max 5) + + + {/* Image Previews */} + {imagePreviews.length > 0 && ( + + {imagePreviews.map((preview, index) => ( + +
+ {`Preview + +
+ + ))} +
+ )} + + {/* Upload Button */} + {images.length < 5 && ( +
fileInputRef.current?.click()} + > + +

Click to upload images

+ + {images.length}/5 images selected + +
+ )} + + +
+ + {/* Caption */} + + Caption + setContent(e.target.value)} + placeholder="Write a caption..." + className="instagram-input" + /> + + + {/* Category */} + + Category + setCategoryId(e.target.value)} + className="instagram-input" + > + + {categories.map(cat => ( + + ))} + + + + {/* Privacy Toggle */} + + setIsPrivate(e.target.checked)} + className="fw-semibold" + /> + + {isPrivate ? 'Only you can see this post' : 'Everyone can see this post'} + + + + {/* Submit Button */} +
+ +
+
+
+
+ ); +}; + +export default CreatePostModal; diff --git a/client/src/components/PostCard.jsx b/client/src/components/PostCard.jsx new file mode 100644 index 0000000..cbc9977 --- /dev/null +++ b/client/src/components/PostCard.jsx @@ -0,0 +1,193 @@ +import { useState } from 'react'; +import { Card, Carousel, Button } from 'react-bootstrap'; +import { Heart, HeartFill, ChatDots, Send, Bookmark } from 'react-bootstrap-icons'; +import http from '../helpers/http'; +import Swal from 'sweetalert2'; + +const PostCard = ({ post, onLikeToggle }) => { + const [isLiked, setIsLiked] = useState(false); + const [likesCount, setLikesCount] = useState(post.Likes?.length || 0); + const [showFullCaption, setShowFullCaption] = useState(false); + + // Check if current user has liked this post + useState(() => { + const token = localStorage.getItem('access_token'); + if (token && post.Likes) { + // You might want to decode token to get user id and check if they liked + // For now, we'll use a simple approach + const liked = post.Likes.some(like => like.UserId === post.UserId); + setIsLiked(liked); + } + }, [post.Likes]); + + const handleLike = async () => { + try { + const { data } = await http.post(`/posts/${post.id}/like`); + + // Toggle like state + setIsLiked(!isLiked); + setLikesCount(isLiked ? likesCount - 1 : likesCount + 1); + + if (onLikeToggle) onLikeToggle(post.id); + } catch (error) { + Swal.fire({ + icon: 'error', + title: 'Failed to like post', + text: error.response?.data?.message || 'Something went wrong', + }); + } + }; + + const formatDate = (dateString) => { + const date = new Date(dateString); + const now = new Date(); + const diffMs = now - date; + const diffMins = Math.floor(diffMs / 60000); + const diffHours = Math.floor(diffMs / 3600000); + const diffDays = Math.floor(diffMs / 86400000); + + if (diffMins < 1) return 'Just now'; + if (diffMins < 60) return `${diffMins}m ago`; + if (diffHours < 24) return `${diffHours}h ago`; + if (diffDays < 7) return `${diffDays}d ago`; + return date.toLocaleDateString(); + }; + + const truncateText = (text, maxLength = 100) => { + if (!text) return ''; + if (text.length <= maxLength) return text; + return showFullCaption ? text : `${text.substring(0, maxLength)}...`; + }; + + return ( + + {/* Post Header */} + +
+ {post.User?.username?.charAt(0).toUpperCase() || 'U'} +
+
+
{post.User?.username || 'Unknown User'}
+ {formatDate(post.createdAt)} +
+ {post.Category && ( + + {post.Category.name} + + )} +
+ + {/* Post Images Carousel */} + {post.Images && post.Images.length > 0 && ( +
+ {post.Images.length === 1 ? ( + Post + ) : ( + 1} controls={post.Images.length > 1}> + {post.Images.map((image, index) => ( + + {`Post + + ))} + + )} +
+ )} + + {/* Post Actions */} + +
+ + + + +
+ + {/* Likes Count */} + {likesCount > 0 && ( +
+ {likesCount} {likesCount === 1 ? 'like' : 'likes'} +
+ )} + + {/* Post Caption */} + {post.content && ( +
+ {post.User?.username} + {truncateText(post.content, 100)} + {post.content.length > 100 && ( + + )} +
+ )} +
+
+ ); +}; + +export default PostCard; diff --git a/client/src/components/StartChatModal.jsx b/client/src/components/StartChatModal.jsx new file mode 100644 index 0000000..5cc79cf --- /dev/null +++ b/client/src/components/StartChatModal.jsx @@ -0,0 +1,202 @@ +import { useState, useEffect } from 'react'; +import { Modal, Form, Button, Spinner, ListGroup } from 'react-bootstrap'; +import { PersonCircle, Search } from 'react-bootstrap-icons'; +import http from '../helpers/http'; +import Swal from 'sweetalert2'; +import { useNavigate } from 'react-router-dom'; + +const StartChatModal = ({ show, onHide }) => { + const navigate = useNavigate(); + const [users, setUsers] = useState([]); + const [loading, setLoading] = useState(false); + const [searchQuery, setSearchQuery] = useState(''); + const [creating, setCreating] = useState(false); + + // Safe way to get current user ID + const getCurrentUserId = () => { + try { + const token = localStorage.getItem('access_token'); + if (!token) return null; + const payload = JSON.parse(atob(token.split('.')[1])); + return payload.id; + } catch (error) { + console.error('Error parsing token:', error); + return null; + } + }; + + const currentUserId = getCurrentUserId(); + + useEffect(() => { + if (show) { + fetchUsers(); + } + }, [show]); + + const fetchUsers = async () => { + try { + setLoading(true); + console.log('Fetching users from posts...'); + + // Fetch posts to get unique users + const { data } = await http.get('/posts'); + console.log('Posts data:', data); + + // Extract unique users from posts (excluding current user) + const uniqueUsers = []; + const userIds = new Set(); + + data.forEach(post => { + if (post.User && post.User.id !== currentUserId && !userIds.has(post.User.id)) { + userIds.add(post.User.id); + uniqueUsers.push({ + id: post.User.id, + username: post.User.username, + email: post.User.email + }); + } + }); + + console.log('Unique users found:', uniqueUsers); + setUsers(uniqueUsers); + } catch (error) { + console.error('Error fetching users:', error); + console.error('Error details:', error.response?.data); + } finally { + setLoading(false); + } + }; + + const handleStartChat = async (partnerId) => { + try { + setCreating(true); + const { data } = await http.post('/chats', { partnerId }); + + Swal.fire({ + icon: 'success', + title: 'Chat started!', + timer: 1500, + showConfirmButton: false, + background: 'rgba(255, 255, 255, 0.95)', + backdrop: 'rgba(102, 126, 234, 0.4)' + }); + + onHide(); + navigate('/messages'); + } catch (error) { + console.error('Error starting chat:', error); + Swal.fire({ + icon: 'error', + title: 'Error', + text: error.response?.data?.message || 'Failed to start chat', + background: 'rgba(255, 255, 255, 0.95)', + backdrop: 'rgba(102, 126, 234, 0.4)' + }); + } finally { + setCreating(false); + } + }; + + const filteredUsers = users.filter(user => + user.username.toLowerCase().includes(searchQuery.toLowerCase()) || + user.email.toLowerCase().includes(searchQuery.toLowerCase()) + ); + + return ( + + + Start New Chat + + + {/* Search Bar */} + +
+ + setSearchQuery(e.target.value)} + className="ps-5" + style={{ + borderRadius: '15px', + border: '2px solid #e0e0e0', + padding: '12px 12px 12px 45px' + }} + /> +
+
+ + {/* Users List */} +
+ {loading ? ( +
+ +

Loading users...

+
+ ) : filteredUsers.length === 0 ? ( +
+ +

+ {searchQuery ? 'No users found' : 'No users available'} +

+
+ ) : ( + + {filteredUsers.map((user) => ( + handleStartChat(user.id)} + > +
+
+ {user.username.charAt(0).toUpperCase()} +
+
+
{user.username}
+ {user.email} +
+ +
+
+ ))} +
+ )} +
+
+
+ ); +}; + +export default StartChatModal; diff --git a/client/src/helpers/http.js b/client/src/helpers/http.js new file mode 100644 index 0000000..77ebdd9 --- /dev/null +++ b/client/src/helpers/http.js @@ -0,0 +1,36 @@ +import axios from "axios"; + +const http = axios.create({ + baseURL: import.meta.env.VITE_API_URL || "https://dariusjoshua.shop", + headers: { + 'Content-Type': 'application/json', + }, +}); + +// Add token to requests if it exists +http.interceptors.request.use( + (config) => { + const token = localStorage.getItem('access_token'); + if (token) { + config.headers.Authorization = `Bearer ${token}`; + } + return config; + }, + (error) => { + return Promise.reject(error); + } +); + +// Handle response errors +http.interceptors.response.use( + (response) => response, + (error) => { + if (error.response?.status === 401) { + localStorage.removeItem('access_token'); + window.location.href = '/login'; + } + return Promise.reject(error); + } +); + +export default http; diff --git a/client/src/index.css b/client/src/index.css new file mode 100644 index 0000000..f57b47d --- /dev/null +++ b/client/src/index.css @@ -0,0 +1,687 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica', 'Arial', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; + overflow-x: hidden; +} + +#root { + min-height: 100vh; + background: transparent; +} + +/* Instagram Colors */ +:root { + --instagram-blue: #0095f6; + --instagram-blue-hover: #1877f2; + --instagram-border: rgba(255, 255, 255, 0.2); + --instagram-bg: rgba(255, 255, 255, 0.95); +} + +/* Animated Background */ +@keyframes gradient { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} + +/* Instagram Gradient Logo */ +.instagram-gradient { + background: linear-gradient(45deg, #f09433 0%, #e6683c 25%, #dc2743 50%, #cc2366 75%, #bc1888 100%); + color: white; + padding: 12px 24px; + border-radius: 12px; + font-weight: 700; + display: inline-block; + box-shadow: 0 8px 20px rgba(240, 148, 51, 0.4); + transition: all 0.3s ease; + animation: pulse 2s ease-in-out infinite; +} + +.instagram-gradient:hover { + transform: translateY(-2px) scale(1.05); + box-shadow: 0 12px 30px rgba(240, 148, 51, 0.6); +} + +@keyframes pulse { + 0%, 100% { + box-shadow: 0 8px 20px rgba(240, 148, 51, 0.4); + } + 50% { + box-shadow: 0 8px 30px rgba(240, 148, 51, 0.6); + } +} + +/* Instagram Card - Glass Morphism */ +.instagram-card { + background: rgba(255, 255, 255, 0.95) !important; + backdrop-filter: blur(20px) !important; + -webkit-backdrop-filter: blur(20px) !important; + border: 1px solid rgba(255, 255, 255, 0.3) !important; + border-radius: 20px !important; + padding: 40px !important; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3) !important; + transition: all 0.4s ease !important; +} + +.instagram-card:hover { + transform: translateY(-5px) !important; + box-shadow: 0 30px 80px rgba(0, 0, 0, 0.4) !important; +} + +/* Instagram Button - Premium Style */ +.instagram-button { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; + color: white !important; + font-weight: 600 !important; + border: none !important; + border-radius: 12px !important; + padding: 12px !important; + width: 100% !important; + transition: all 0.3s ease !important; + box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4) !important; + position: relative !important; + overflow: hidden !important; +} + +.instagram-button::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); + transition: left 0.5s; +} + +.instagram-button:hover:not(:disabled)::before { + left: 100%; +} + +.instagram-button:hover:not(:disabled) { + transform: translateY(-2px) !important; + box-shadow: 0 10px 30px rgba(102, 126, 234, 0.6) !important; + background: linear-gradient(135deg, #764ba2 0%, #667eea 100%) !important; + color: white !important; +} + +.instagram-button:active:not(:disabled) { + transform: translateY(0) !important; +} + +.instagram-button:disabled { + opacity: 0.6 !important; + cursor: not-allowed !important; + box-shadow: none !important; +} + +/* Instagram Input - Modern Glass Style */ +.instagram-input { + width: 100% !important; + padding: 14px !important; + border: 2px solid rgba(102, 126, 234, 0.2) !important; + border-radius: 12px !important; + font-size: 14px !important; + background: rgba(255, 255, 255, 0.9) !important; + transition: all 0.3s ease !important; + backdrop-filter: blur(10px) !important; +} + +.instagram-input:hover { + border-color: rgba(102, 126, 234, 0.4) !important; + background: rgba(255, 255, 255, 0.95) !important; +} + +.instagram-input:focus { + background: white !important; + border-color: #667eea !important; + outline: none !important; + box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1) !important; + transform: translateY(-2px) !important; +} + +/* Auth Container - Animated Gradient Background */ +.auth-container { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; + background: linear-gradient(-45deg, #667eea, #764ba2, #f093fb, #f5576c); + background-size: 400% 400%; + animation: gradient 15s ease infinite; + position: relative; +} + +.auth-container::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.05'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); + opacity: 0.3; +} + +.auth-box { + max-width: 400px; + width: 100%; + position: relative; + z-index: 1; + animation: fadeInUp 0.6s ease-out; +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Divider - Enhanced */ +.divider { + display: flex; + align-items: center; + text-align: center; + margin: 24px 0; +} + +.divider::before, +.divider::after { + content: ''; + flex: 1; + height: 2px; + background: linear-gradient(90deg, transparent, rgba(102, 126, 234, 0.3), transparent); +} + +.divider span { + padding: 0 20px; + color: #666; + font-weight: 700; + font-size: 13px; + letter-spacing: 1px; + text-transform: uppercase; +} + +/* Google Button Wrapper - Enhanced */ +.google-login-wrapper { + display: flex; + justify-content: center; + margin-bottom: 20px; + transition: all 0.3s ease; +} + +.google-login-wrapper:hover { + transform: scale(1.02); +} + +.google-login-wrapper > div { + width: 100% !important; + border-radius: 12px !important; + overflow: hidden !important; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1) !important; +} + +.google-login-wrapper iframe { + width: 100% !important; + border-radius: 12px !important; +} + +/* Spinner */ +.spinner-border-sm { + width: 1rem; + height: 1rem; + border-width: 0.2em; +} + +/* Stats Card - Premium Animated */ +.stats-card { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + padding: 28px; + border-radius: 20px; + text-align: center; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); + transition: all 0.4s ease; + position: relative; + overflow: hidden; +} + +.stats-card::before { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 70%); + transition: all 0.6s ease; + transform: scale(0); +} + +.stats-card:hover::before { + transform: scale(1); +} + +.stats-card:hover { + transform: translateY(-10px) scale(1.05); + box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3); +} + +.stats-card-blue { + background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); + box-shadow: 0 10px 30px rgba(79, 172, 254, 0.4); +} + +.stats-card-blue:hover { + box-shadow: 0 20px 50px rgba(79, 172, 254, 0.6); +} + +.stats-card-pink { + background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); + box-shadow: 0 10px 30px rgba(240, 147, 251, 0.4); +} + +.stats-card-pink:hover { + box-shadow: 0 20px 50px rgba(240, 147, 251, 0.6); +} + +.stats-card-green { + background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); + box-shadow: 0 10px 30px rgba(67, 233, 123, 0.4); +} + +.stats-card-green:hover { + box-shadow: 0 20px 50px rgba(67, 233, 123, 0.6); +} + +/* Link Styles - Enhanced */ +a { + color: #667eea; + text-decoration: none; + font-weight: 600; + transition: all 0.3s ease; + position: relative; +} + +a::after { + content: ''; + position: absolute; + bottom: -2px; + left: 0; + width: 0; + height: 2px; + background: linear-gradient(90deg, #667eea, #764ba2); + transition: width 0.3s ease; +} + +a:hover { + color: #764ba2; + text-decoration: none; +} + +a:hover::after { + width: 100%; +} + +/* Bootstrap Overrides - Premium Style */ +.container { + background-color: transparent !important; +} + +.card { + background: rgba(255, 255, 255, 0.95) !important; + backdrop-filter: blur(20px) !important; + border: 1px solid rgba(255, 255, 255, 0.3) !important; + border-radius: 20px !important; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3) !important; + transition: all 0.4s ease !important; +} + +.card:hover { + transform: translateY(-5px) !important; + box-shadow: 0 30px 80px rgba(0, 0, 0, 0.4) !important; +} + +.form-control { + background: rgba(255, 255, 255, 0.9) !important; + border: 2px solid rgba(102, 126, 234, 0.2) !important; + border-radius: 12px !important; + padding: 14px !important; + transition: all 0.3s ease !important; +} + +.form-control:hover { + border-color: rgba(102, 126, 234, 0.4) !important; +} + +.form-control:focus { + background: white !important; + border-color: #667eea !important; + box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.1) !important; + transform: translateY(-2px) !important; +} + +.btn-primary { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important; + border: none !important; + border-radius: 12px !important; + padding: 12px 24px !important; + box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4) !important; + transition: all 0.3s ease !important; +} + +.btn-primary:hover { + transform: translateY(-2px) !important; + box-shadow: 0 10px 30px rgba(102, 126, 234, 0.6) !important; + background: linear-gradient(135deg, #764ba2 0%, #667eea 100%) !important; +} + +.btn-danger { + background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%) !important; + border: none !important; + border-radius: 12px !important; + box-shadow: 0 6px 20px rgba(245, 87, 108, 0.4) !important; + transition: all 0.3s ease !important; +} + +.btn-danger:hover { + transform: translateY(-2px) !important; + box-shadow: 0 10px 30px rgba(245, 87, 108, 0.6) !important; + background: linear-gradient(135deg, #f5576c 0%, #f093fb 100%) !important; +} + +.navbar { + background: rgba(255, 255, 255, 0.95) !important; + backdrop-filter: blur(20px) !important; + border-bottom: 1px solid rgba(102, 126, 234, 0.1) !important; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1) !important; +} + +/* Text Gradient Effect */ +.text-gradient { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +/* Floating Animation */ +@keyframes float { + 0%, 100% { + transform: translateY(0); + } + 50% { + transform: translateY(-10px); + } +} + +.float-animation { + animation: float 3s ease-in-out infinite; +} + +/* Shimmer Effect */ +@keyframes shimmer { + 0% { + background-position: -1000px 0; + } + 100% { + background-position: 1000px 0; + } +} + +.shimmer { + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.5), transparent); + background-size: 1000px 100%; + animation: shimmer 2s infinite; +} + +/* Form Group Spacing */ +.form-group, +.mb-3 { + margin-bottom: 1.2rem !important; +} + +/* Enhanced Text */ +.text-muted { + color: #666 !important; + font-weight: 500 !important; +} + +h1, h2, h3, h4, h5 { + font-weight: 700 !important; + letter-spacing: -0.5px !important; +} + +/* Smooth Scroll */ +html { + scroll-behavior: smooth; +} + +/* Post Card Styles */ +.post-card { + background: rgba(255, 255, 255, 0.95) !important; + backdrop-filter: blur(20px) !important; + border-radius: 16px !important; + overflow: hidden !important; + transition: all 0.3s ease !important; +} + +.post-card:hover { + transform: translateY(-3px) !important; + box-shadow: 0 15px 40px rgba(0, 0, 0, 0.2) !important; +} + +.post-images-container { + position: relative; + overflow: hidden; +} + +.post-images-container img { + transition: transform 0.3s ease; +} + +.post-images-container:hover img { + transform: scale(1.02); +} + +/* Like Button Animation */ +.like-button { + transition: all 0.3s ease !important; +} + +.like-button:hover { + transform: scale(1.15) !important; +} + +.heart-icon { + transition: all 0.2s ease; + filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.1)); +} + +.like-button:active .heart-icon { + transform: scale(0.9); +} + +/* Carousel Styles */ +.carousel-indicators [data-bs-target] { + background-color: rgba(102, 126, 234, 0.5) !important; + width: 8px !important; + height: 8px !important; + border-radius: 50% !important; + margin: 0 4px !important; +} + +.carousel-indicators .active { + background-color: #667eea !important; +} + +.carousel-control-prev-icon, +.carousel-control-next-icon { + background-color: rgba(102, 126, 234, 0.8) !important; + border-radius: 50% !important; + padding: 15px !important; +} + +/* Floating Chat Button */ +.floating-chat-btn { + position: fixed; + bottom: 30px; + right: 30px; + width: 60px; + height: 60px; + border-radius: 50%; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border: none; + box-shadow: 0 6px 25px rgba(102, 126, 234, 0.5); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.3s ease; + z-index: 1000; + animation: pulse 2s ease-in-out infinite; +} + +.floating-chat-btn:hover { + transform: scale(1.1) translateY(-3px); + box-shadow: 0 10px 35px rgba(102, 126, 234, 0.7); +} + +.floating-chat-btn:active { + transform: scale(0.95); +} + +/* Typing Indicator */ +.typing-indicator { + display: flex; + align-items: center; + gap: 4px; +} + +.typing-indicator span { + width: 8px; + height: 8px; + background-color: #667eea; + border-radius: 50%; + animation: typing 1.4s infinite; +} + +.typing-indicator span:nth-child(2) { + animation-delay: 0.2s; +} + +.typing-indicator span:nth-child(3) { + animation-delay: 0.4s; +} + +@keyframes typing { + 0%, 60%, 100% { + transform: translateY(0); + opacity: 0.7; + } + 30% { + transform: translateY(-10px); + opacity: 1; + } +} + +/* Chat Message Animation */ +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Chat Modal Styles */ +.ai-chat-modal .modal-content { + background: rgba(255, 255, 255, 0.98); + backdrop-filter: blur(20px); + border-radius: 20px; + border: 1px solid rgba(102, 126, 234, 0.2); + overflow: hidden; +} + +.message-bubble { + word-wrap: break-word; + word-break: break-word; + overflow-wrap: break-word; + transition: all 0.2s ease; + white-space: pre-wrap; + line-height: 1.6; + font-size: 14px; +} + +.message-bubble:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important; +} + +.message-bubble div { + max-width: 100%; + overflow-wrap: break-word; +} + +/* Selection Style */ +::selection { + background: rgba(102, 126, 234, 0.3); + color: #333; +} + +::-webkit-scrollbar { + width: 10px; +} + +::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.1); +} + +::-webkit-scrollbar-thumb { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: 5px; +} + +::-webkit-scrollbar-thumb:hover { + background: linear-gradient(135deg, #764ba2 0%, #667eea 100%); +} + +/* Responsive */ +@media (max-width: 576px) { + .instagram-card { + padding: 24px !important; + border-radius: 16px !important; + } + + .auth-container { + padding: 12px !important; + } + + .stats-card { + margin-bottom: 12px; + } +} diff --git a/client/src/main.jsx b/client/src/main.jsx new file mode 100644 index 0000000..a08ba09 --- /dev/null +++ b/client/src/main.jsx @@ -0,0 +1,11 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import 'bootstrap/dist/css/bootstrap.min.css' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) diff --git a/client/src/pages/Home.jsx b/client/src/pages/Home.jsx new file mode 100644 index 0000000..04e6f6d --- /dev/null +++ b/client/src/pages/Home.jsx @@ -0,0 +1,228 @@ +import { useState, useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { Container, Row, Col, Button, Navbar, Spinner } from 'react-bootstrap'; +import { PlusCircleFill, ChatDotsFill, ChatLeftTextFill } from 'react-bootstrap-icons'; +import Swal from 'sweetalert2'; +import http from '../helpers/http'; +import PostCard from '../components/PostCard'; +import CreatePostModal from '../components/CreatePostModal'; +import AIChatModal from '../components/AIChatModal'; + +const Home = () => { + const navigate = useNavigate(); + const [posts, setPosts] = useState([]); + const [loading, setLoading] = useState(true); + const [showCreateModal, setShowCreateModal] = useState(false); + const [showChatModal, setShowChatModal] = useState(false); + + useEffect(() => { + fetchPosts(); + }, []); + + const fetchPosts = async () => { + try { + setLoading(true); + const { data } = await http.get('/posts'); + setPosts(data); + } catch (error) { + console.error('Error fetching posts:', error); + Swal.fire({ + icon: 'error', + title: 'Failed to load posts', + text: error.response?.data?.message || 'Something went wrong', + }); + } finally { + setLoading(false); + } + }; + + const handlePostCreated = () => { + fetchPosts(); + }; + + const handleLikeToggle = (postId) => { + // Refresh posts after like/unlike + fetchPosts(); + }; + + const handleLogout = () => { + Swal.fire({ + title: 'Are you sure?', + text: 'You will be logged out', + icon: 'warning', + showCancelButton: true, + confirmButtonColor: '#0095f6', + cancelButtonColor: '#d33', + confirmButtonText: 'Yes, logout', + cancelButtonText: 'Cancel' + }).then((result) => { + if (result.isConfirmed) { + localStorage.removeItem('access_token'); + Swal.fire({ + icon: 'success', + title: 'Logged out successfully!', + timer: 1500, + showConfirmButton: false, + }); + setTimeout(() => { + navigate('/login'); + }, 1500); + } + }); + }; + + return ( +
+ {/* Header */} + + + +
+ Instagram +
+
+
+ + + +
+
+
+ + {/* Main Content */} + + + + {/* Loading State */} + {loading ? ( +
+ +

Loading posts...

+
+ ) : posts.length === 0 ? ( + /* Empty State */ +
+
+ + + + +
+

No Posts Yet!

+

+ Be the first to share your moments! ๐Ÿ“ธ +

+ +
+ ) : ( + /* Posts Feed */ +
+ {posts.map(post => ( + + ))} +
+ )} + +
+
+ + {/* Create Post Modal */} + setShowCreateModal(false)} + onPostCreated={handlePostCreated} + /> + + {/* AI Chat Modal */} + setShowChatModal(false)} + /> + + {/* Floating Chat Button */} + +
+ ); +}; + +export default Home; diff --git a/client/src/pages/Login.jsx b/client/src/pages/Login.jsx new file mode 100644 index 0000000..af0d92a --- /dev/null +++ b/client/src/pages/Login.jsx @@ -0,0 +1,227 @@ +import { useState } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; +import { GoogleLogin } from '@react-oauth/google'; +import { Container, Row, Col, Form, Button, Spinner } from 'react-bootstrap'; +import http from '../helpers/http'; +import Swal from 'sweetalert2'; + +const Login = () => { + const navigate = useNavigate(); + const [formData, setFormData] = useState({ + email: '', + password: '', + }); + const [loading, setLoading] = useState(false); + + const handleChange = (e) => { + setFormData({ + ...formData, + [e.target.name]: e.target.value, + }); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + setLoading(true); + + try { + const { data } = await http.post('/users/login', formData); + localStorage.setItem('access_token', data.access_token); + + Swal.fire({ + icon: 'success', + title: 'Login Successful!', + text: 'Welcome back!', + timer: 1500, + showConfirmButton: false, + }); + + setTimeout(() => { + navigate('/'); + }, 1500); + } catch (error) { + Swal.fire({ + icon: 'error', + title: 'Login Failed', + text: error.response?.data?.message || 'Invalid email or password', + }); + } finally { + setLoading(false); + } + }; + + const handleGoogleSuccess = async (credentialResponse) => { + setLoading(true); + try { + const { data } = await http.post('/users/auth/google', { + google_token: credentialResponse.credential, + }); + + localStorage.setItem('access_token', data.access_token); + + Swal.fire({ + icon: 'success', + title: 'Login Successful!', + text: 'Welcome!', + timer: 1500, + showConfirmButton: false, + }); + + setTimeout(() => { + navigate('/'); + }, 1500); + } catch (error) { + Swal.fire({ + icon: 'error', + title: 'Google Login Failed', + text: error.response?.data?.message || 'Something went wrong', + }); + } finally { + setLoading(false); + } + }; + + const handleGoogleError = () => { + Swal.fire({ + icon: 'error', + title: 'Google Login Failed', + text: 'Please try again', + }); + }; + + return ( +
+ + + +
+ {/* Logo and Title */} +
+
+ Instagram +
+

+ Sign in to see photos and videos from your friends. +

+
+ + {/* Card */} +
+ {/* Google Login */} +
+ +
+ + {/* Divider */} +
+ OR +
+ + {/* Login Form */} +
+ + + + + + + + + +
+ + {/* Forgot Password */} + +
+ + {/* Sign Up Link */} +
+

+ Don't have an account?{' '} + + Sign up + +

+
+ + {/* Get the App */} +
+

Get the app.

+ + + Download on App Store + + + Get it on Google Play + + +
+
+ +
+
+
+ ); +}; + +export default Login; diff --git a/client/src/pages/Messages.jsx b/client/src/pages/Messages.jsx new file mode 100644 index 0000000..78746c3 --- /dev/null +++ b/client/src/pages/Messages.jsx @@ -0,0 +1,569 @@ +import { useState, useEffect, useRef } from 'react'; +import { Container, Row, Col, Card, Form, Button, Spinner, InputGroup, Badge } from 'react-bootstrap'; +import { + Search, + Send, + ArrowLeft, + PersonCircle, + CheckAll, + Clock, + EmojiSmile, + PlusCircleFill +} from 'react-bootstrap-icons'; +import { useNavigate } from 'react-router-dom'; +import http from '../helpers/http'; +import Swal from 'sweetalert2'; +import StartChatModal from '../components/StartChatModal'; + +const Messages = () => { + const navigate = useNavigate(); + const [chats, setChats] = useState([]); + const [selectedChat, setSelectedChat] = useState(null); + const [messages, setMessages] = useState([]); + const [newMessage, setNewMessage] = useState(''); + const [loading, setLoading] = useState(true); + const [sending, setSending] = useState(false); + const [searchQuery, setSearchQuery] = useState(''); + const [showStartChatModal, setShowStartChatModal] = useState(false); + const messagesEndRef = useRef(null); + + // Safe way to get current user ID + const getCurrentUserId = () => { + try { + const token = localStorage.getItem('access_token'); + if (!token) return null; + const payload = JSON.parse(atob(token.split('.')[1])); + return payload.id; + } catch (error) { + console.error('Error parsing token:', error); + return null; + } + }; + + const currentUserId = getCurrentUserId(); + + // Fetch all user chats + useEffect(() => { + console.log('Messages component mounted'); + console.log('Current User ID:', currentUserId); + + if (!currentUserId) { + console.error('No user ID found! Redirecting to login...'); + navigate('/login'); + return; + } + + fetchChats(); + }, []); + + // Fetch messages when chat is selected + useEffect(() => { + if (selectedChat) { + fetchMessages(selectedChat.id); + } + }, [selectedChat]); + + // Auto scroll to bottom + useEffect(() => { + scrollToBottom(); + }, [messages]); + + const scrollToBottom = () => { + messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); + }; + + const fetchChats = async () => { + try { + setLoading(true); + console.log('Fetching chats...'); + const { data } = await http.get('/chats'); + console.log('Chats received:', data); + + // Filter only non-AI chats + const userChats = data.filter(chat => !chat.isAIChat); + console.log('User chats (non-AI):', userChats); + setChats(userChats); + } catch (error) { + console.error('Error fetching chats:', error); + console.error('Error details:', error.response?.data); + + // Set empty array jika error (normal jika belum ada chat) + setChats([]); + + // Only show error alert if it's not a server error + if (error.response?.status !== 500) { + Swal.fire({ + icon: 'info', + title: 'No chats yet', + text: 'Start a new conversation by clicking the "New Chat" button', + background: 'rgba(255, 255, 255, 0.95)', + backdrop: 'rgba(102, 126, 234, 0.4)', + timer: 3000 + }); + } + } finally { + setLoading(false); + } + }; + + const fetchMessages = async (chatId) => { + try { + console.log('Fetching messages for chat:', chatId); + const { data } = await http.get(`/chats/${chatId}/messages`); + console.log('Messages received:', data); + setMessages(data); + } catch (error) { + console.error('Error fetching messages:', error); + console.error('Error details:', error.response?.data); + } + }; + + const handleSendMessage = async (e) => { + e.preventDefault(); + if (!newMessage.trim() || !selectedChat) return; + + try { + setSending(true); + const { data } = await http.post(`/chats/${selectedChat.id}/messages`, { + content: newMessage.trim() + }); + + setMessages([...messages, data]); + setNewMessage(''); + + // Update chat list order + fetchChats(); + } catch (error) { + console.error('Error sending message:', error); + Swal.fire({ + icon: 'error', + title: 'Error', + text: 'Failed to send message', + background: 'rgba(255, 255, 255, 0.95)', + backdrop: 'rgba(102, 126, 234, 0.4)' + }); + } finally { + setSending(false); + } + }; + + const getPartner = (chat) => { + if (!chat) return null; + return chat.UserId === currentUserId ? chat.partner : chat.creator; + }; + + const formatTime = (timestamp) => { + const date = new Date(timestamp); + const now = new Date(); + const diffMs = now - date; + const diffMins = Math.floor(diffMs / 60000); + const diffHours = Math.floor(diffMs / 3600000); + const diffDays = Math.floor(diffMs / 86400000); + + if (diffMins < 1) return 'Just now'; + if (diffMins < 60) return `${diffMins}m ago`; + if (diffHours < 24) return `${diffHours}h ago`; + if (diffDays < 7) return `${diffDays}d ago`; + + return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }); + }; + + const formatMessageTime = (timestamp) => { + const date = new Date(timestamp); + return date.toLocaleTimeString('en-US', { + hour: '2-digit', + minute: '2-digit', + hour12: true + }); + }; + + const filteredChats = chats.filter(chat => { + const partner = getPartner(chat); + return partner?.username.toLowerCase().includes(searchQuery.toLowerCase()); + }); + + return ( +
+ + {/* Header */} +
+
+ +

Messages

+
+
+ + +
+
+ + + {/* Chat List Sidebar */} + + + +
Chats
+ + + + + setSearchQuery(e.target.value)} + className="border-0" + style={{ borderRadius: '0 15px 15px 0' }} + /> + +
+ + + {loading ? ( +
+ +
+ ) : filteredChats.length === 0 ? ( +
+ +

No conversations yet

+ Start chatting by clicking on a user's profile +
+ ) : ( + filteredChats.map((chat) => { + const partner = getPartner(chat); + return ( +
setSelectedChat(chat)} + className="p-3 border-bottom" + style={{ + cursor: 'pointer', + background: selectedChat?.id === chat.id + ? 'linear-gradient(135deg, rgba(102, 126, 234, 0.1), rgba(118, 75, 162, 0.1))' + : 'transparent', + transition: 'all 0.3s ease' + }} + onMouseEnter={(e) => { + if (selectedChat?.id !== chat.id) { + e.currentTarget.style.background = 'rgba(102, 126, 234, 0.05)'; + } + }} + onMouseLeave={(e) => { + if (selectedChat?.id !== chat.id) { + e.currentTarget.style.background = 'transparent'; + } + }} + > +
+
+ {partner?.username.charAt(0).toUpperCase()} +
+
+
+
+ {partner?.username} +
+ + {formatTime(chat.updatedAt)} + +
+ + Click to open chat + +
+
+
+ ); + }) + )} +
+
+ + + {/* Chat Window */} + + + {!selectedChat ? ( +
+ +

Select a conversation

+

Choose a chat from the list to start messaging

+
+ ) : ( + <> + {/* Chat Header */} + +
+
+ {getPartner(selectedChat)?.username.charAt(0).toUpperCase()} +
+
+
+ {getPartner(selectedChat)?.username} +
+ + Active now + +
+
+
+ + {/* Messages Area */} + + {messages.length === 0 ? ( +
+ +

No messages yet. Start the conversation!

+
+ ) : ( + messages.map((msg, index) => { + const isOwn = msg.senderId === currentUserId; + return ( +
+
+
+ {msg.content} +
+
+ + {formatMessageTime(msg.createdAt)} + + {isOwn && ( + + )} +
+
+
+ ); + }) + )} +
+ + + {/* Message Input */} + +
+
+ setNewMessage(e.target.value)} + disabled={sending} + style={{ + flex: 1, + borderRadius: '20px', + resize: 'none', + padding: '12px 18px', + fontSize: '15px', + lineHeight: '1.5', + border: '2px solid #e0e0e0', + transition: 'all 0.3s ease', + boxShadow: '0 2px 8px rgba(0, 0, 0, 0.05)' + }} + onFocus={(e) => { + e.target.style.borderColor = '#667eea'; + e.target.style.boxShadow = '0 4px 12px rgba(102, 126, 234, 0.15)'; + }} + onBlur={(e) => { + e.target.style.borderColor = '#e0e0e0'; + e.target.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.05)'; + }} + onKeyDown={(e) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + handleSendMessage(e); + } + }} + /> + +
+ + ๐Ÿ’ก Press Enter to send, Shift + Enter for new line + +
+
+ + )} + + + + + + {/* Start Chat Modal */} + { + setShowStartChatModal(false); + fetchChats(); // Refresh chats after closing modal + }} + /> +
+ ); +}; + +export default Messages; diff --git a/client/src/pages/Register.jsx b/client/src/pages/Register.jsx new file mode 100644 index 0000000..19459ae --- /dev/null +++ b/client/src/pages/Register.jsx @@ -0,0 +1,246 @@ +import { useState } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; +import { GoogleLogin } from '@react-oauth/google'; +import { Container, Row, Col, Form, Button, Spinner } from 'react-bootstrap'; +import http from '../helpers/http'; +import Swal from 'sweetalert2'; + +const Register = () => { + const navigate = useNavigate(); + const [formData, setFormData] = useState({ + email: '', + username: '', + password: '', + }); + const [loading, setLoading] = useState(false); + + const handleChange = (e) => { + setFormData({ + ...formData, + [e.target.name]: e.target.value, + }); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + setLoading(true); + + try { + await http.post('/users/register', formData); + + Swal.fire({ + icon: 'success', + title: 'Registration Successful!', + text: 'Please login to continue', + timer: 2000, + showConfirmButton: false, + }); + + setTimeout(() => { + navigate('/login'); + }, 2000); + } catch (error) { + Swal.fire({ + icon: 'error', + title: 'Registration Failed', + text: error.response?.data?.message || 'Something went wrong', + }); + } finally { + setLoading(false); + } + }; + + const handleGoogleSuccess = async (credentialResponse) => { + setLoading(true); + try { + const { data } = await http.post('/users/auth/google', { + google_token: credentialResponse.credential, + }); + + localStorage.setItem('access_token', data.access_token); + + Swal.fire({ + icon: 'success', + title: 'Registration Successful!', + text: 'Welcome!', + timer: 1500, + showConfirmButton: false, + }); + + setTimeout(() => { + navigate('/'); + }, 1500); + } catch (error) { + Swal.fire({ + icon: 'error', + title: 'Google Registration Failed', + text: error.response?.data?.message || 'Something went wrong', + }); + } finally { + setLoading(false); + } + }; + + const handleGoogleError = () => { + Swal.fire({ + icon: 'error', + title: 'Google Sign Up Failed', + text: 'Please try again', + }); + }; + + return ( +
+ + + +
+ {/* Logo and Title */} +
+
+ Instagram +
+
+ Sign up to see photos and videos from your friends. +
+
+ + {/* Card */} +
+ {/* Google Sign Up */} +
+ +
+ + {/* Divider */} +
+ OR +
+ + {/* Register Form */} +
+ + + + + + + + + + + + +

+ People who use our service may have uploaded your contact information to Instagram.{' '} + Learn More +

+ +

+ By signing up, you agree to our{' '} + Terms,{' '} + Privacy Policy and{' '} + Cookies Policy. +

+ + +
+
+ + {/* Login Link */} +
+

+ Have an account?{' '} + + Log in + +

+
+ + {/* Get the App */} +
+

Get the app.

+ + + Download on App Store + + + Get it on Google Play + + +
+
+ +
+
+
+ ); +}; + +export default Register; diff --git a/client/vite.config.js b/client/vite.config.js new file mode 100644 index 0000000..8b0f57b --- /dev/null +++ b/client/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], +}) diff --git a/config/config.js b/config/config.js index 44af6d3..f57ac89 100644 --- a/config/config.js +++ b/config/config.js @@ -3,10 +3,18 @@ * Supports Supabase / PostgreSQL with SSL */ -require('dotenv').config(); // pastikan dotenv dipanggil di awal +require('dotenv').config(); // load environment variables first const useSSL = process.env.DB_SSL === 'true'; +// Test database should use SQLite for faster tests +const testConfig = { + dialect: 'sqlite', + storage: ':memory:', + logging: false, + define: { timestamps: true } +}; + module.exports = { development: { url: process.env.DATABASE_URL, @@ -16,19 +24,13 @@ module.exports = { dialectOptions: useSSL ? { ssl: { require: true, rejectUnauthorized: false } } : {}, }, - test: { - url: process.env.DATABASE_URL, - dialect: 'postgres', - logging: false, - define: { timestamps: true }, - dialectOptions: useSSL ? { ssl: { require: true, rejectUnauthorized: false } } : {}, - }, + test: testConfig, production: { url: process.env.DATABASE_URL, - dialect: 'postgres', + dialect: 'postgres', logging: false, define: { timestamps: true }, dialectOptions: useSSL ? { ssl: { require: true, rejectUnauthorized: false } } : {}, - }, -}; + } +}; \ No newline at end of file diff --git a/controllers/chatController.js b/controllers/chatController.js index cc9a62c..0bc98a3 100644 --- a/controllers/chatController.js +++ b/controllers/chatController.js @@ -43,14 +43,15 @@ class ChatController { [Op.or]: [{ UserId: userId }, { partnerId: userId }], }, include: [ - { model: User, as: "creator", attributes: ["id", "username", "profilePic"] }, - { model: User, as: "partner", attributes: ["id", "username", "profilePic"] }, + { model: User, as: "creator", attributes: ["id", "username", "email"], required: false }, + { model: User, as: "partner", attributes: ["id", "username", "email"], required: false }, ], order: [["updatedAt", "DESC"]], }); res.json(chats); } catch (err) { + console.error('Error in getUserChats:', err); next(err); } } diff --git a/controllers/userController.js b/controllers/userController.js index 569d72c..1e43341 100644 --- a/controllers/userController.js +++ b/controllers/userController.js @@ -60,7 +60,6 @@ class UserController { username: payload.name, email: payload.email, password: Math.random().toString(36), - profilePic: payload.picture, }, hooks: false }); diff --git a/coverage/clover.xml b/coverage/clover.xml index e90ec73..79f319f 100644 --- a/coverage/clover.xml +++ b/coverage/clover.xml @@ -1,41 +1,41 @@ - - - + + + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - + @@ -195,43 +195,43 @@ - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + @@ -256,43 +256,43 @@ - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - + + + + + + - + @@ -317,18 +317,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/coverage/coverage-final.json b/coverage/coverage-final.json index cede639..6d0584a 100644 --- a/coverage/coverage-final.json +++ b/coverage/coverage-final.json @@ -1,17 +1,17 @@ -{"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}},"1":{"start":{"line":2,"column":16},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":12},"end":{"line":3,"column":21}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"4":{"start":{"line":5,"column":20},"end":{"line":5,"column":52}},"5":{"start":{"line":6,"column":15},"end":{"line":6,"column":34}},"6":{"start":{"line":7,"column":13},"end":{"line":7,"column":28}},"7":{"start":{"line":9,"column":13},"end":{"line":9,"column":28}},"8":{"start":{"line":10,"column":15},"end":{"line":10,"column":37}},"9":{"start":{"line":11,"column":19},"end":{"line":11,"column":39}},"10":{"start":{"line":12,"column":11},"end":{"line":16,"column":2}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}},"12":{"start":{"line":21,"column":0},"end":{"line":21,"column":16}},"13":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}},"14":{"start":{"line":23,"column":0},"end":{"line":23,"column":48}},"15":{"start":{"line":24,"column":0},"end":{"line":24,"column":34}},"16":{"start":{"line":27,"column":0},"end":{"line":27,"column":21}},"17":{"start":{"line":31,"column":0},"end":{"line":31,"column":21}},"18":{"start":{"line":34,"column":0},"end":{"line":52,"column":3}},"19":{"start":{"line":37,"column":2},"end":{"line":39,"column":5}},"20":{"start":{"line":38,"column":4},"end":{"line":38,"column":34}},"21":{"start":{"line":41,"column":2},"end":{"line":43,"column":5}},"22":{"start":{"line":42,"column":4},"end":{"line":42,"column":73}},"23":{"start":{"line":45,"column":2},"end":{"line":47,"column":5}},"24":{"start":{"line":46,"column":4},"end":{"line":46,"column":73}},"25":{"start":{"line":49,"column":2},"end":{"line":51,"column":5}},"26":{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},"27":{"start":{"line":55,"column":2},"end":{"line":57,"column":5}},"28":{"start":{"line":56,"column":4},"end":{"line":56,"column":66}},"29":{"start":{"line":60,"column":0},"end":{"line":60,"column":21}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":34,"column":20},"end":{"line":34,"column":21}},"loc":{"start":{"line":34,"column":32},"end":{"line":52,"column":1}},"line":34},"1":{"name":"(anonymous_1)","decl":{"start":{"line":37,"column":25},"end":{"line":37,"column":26}},"loc":{"start":{"line":37,"column":37},"end":{"line":39,"column":3}},"line":37},"2":{"name":"(anonymous_2)","decl":{"start":{"line":41,"column":28},"end":{"line":41,"column":29}},"loc":{"start":{"line":41,"column":45},"end":{"line":43,"column":3}},"line":41},"3":{"name":"(anonymous_3)","decl":{"start":{"line":45,"column":27},"end":{"line":45,"column":28}},"loc":{"start":{"line":45,"column":43},"end":{"line":47,"column":3}},"line":45},"4":{"name":"(anonymous_4)","decl":{"start":{"line":49,"column":26},"end":{"line":49,"column":27}},"loc":{"start":{"line":49,"column":32},"end":{"line":51,"column":3}},"line":49},"5":{"name":"(anonymous_5)","decl":{"start":{"line":55,"column":22},"end":{"line":55,"column":23}},"loc":{"start":{"line":55,"column":28},"end":{"line":57,"column":3}},"line":55}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"type":"binary-expr","locations":[{"start":{"line":4,"column":13},"end":{"line":4,"column":29}},{"start":{"line":4,"column":33},"end":{"line":4,"column":37}}],"line":4},"1":{"loc":{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},"type":"if","locations":[{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},{"start":{},"end":{}}],"line":54}},"s":{"0":7,"1":7,"2":7,"3":7,"4":7,"5":7,"6":7,"7":7,"8":7,"9":7,"10":7,"11":7,"12":7,"13":7,"14":7,"15":7,"16":7,"17":7,"18":7,"19":7,"20":7,"21":7,"22":0,"23":7,"24":0,"25":7,"26":7,"27":0,"28":0,"29":7},"f":{"0":7,"1":7,"2":0,"3":0,"4":0,"5":0},"b":{"0":[7,7],"1":[0,7]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2a1669a6594937f4b2db57508e47b0260b54d91b"} +{"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\app.js","statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":27}},"1":{"start":{"line":2,"column":16},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":12},"end":{"line":3,"column":21}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"4":{"start":{"line":5,"column":20},"end":{"line":5,"column":52}},"5":{"start":{"line":6,"column":15},"end":{"line":6,"column":34}},"6":{"start":{"line":7,"column":13},"end":{"line":7,"column":28}},"7":{"start":{"line":9,"column":13},"end":{"line":9,"column":28}},"8":{"start":{"line":10,"column":15},"end":{"line":10,"column":37}},"9":{"start":{"line":11,"column":19},"end":{"line":11,"column":39}},"10":{"start":{"line":12,"column":11},"end":{"line":16,"column":2}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}},"12":{"start":{"line":21,"column":0},"end":{"line":21,"column":16}},"13":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}},"14":{"start":{"line":23,"column":0},"end":{"line":23,"column":48}},"15":{"start":{"line":24,"column":0},"end":{"line":24,"column":34}},"16":{"start":{"line":27,"column":0},"end":{"line":27,"column":21}},"17":{"start":{"line":31,"column":0},"end":{"line":31,"column":21}},"18":{"start":{"line":34,"column":0},"end":{"line":52,"column":3}},"19":{"start":{"line":37,"column":2},"end":{"line":39,"column":5}},"20":{"start":{"line":38,"column":4},"end":{"line":38,"column":34}},"21":{"start":{"line":41,"column":2},"end":{"line":43,"column":5}},"22":{"start":{"line":42,"column":4},"end":{"line":42,"column":73}},"23":{"start":{"line":45,"column":2},"end":{"line":47,"column":5}},"24":{"start":{"line":46,"column":4},"end":{"line":46,"column":73}},"25":{"start":{"line":49,"column":2},"end":{"line":51,"column":5}},"26":{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},"27":{"start":{"line":55,"column":2},"end":{"line":57,"column":5}},"28":{"start":{"line":56,"column":4},"end":{"line":56,"column":66}},"29":{"start":{"line":60,"column":0},"end":{"line":60,"column":21}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":34,"column":20},"end":{"line":34,"column":21}},"loc":{"start":{"line":34,"column":32},"end":{"line":52,"column":1}},"line":34},"1":{"name":"(anonymous_1)","decl":{"start":{"line":37,"column":25},"end":{"line":37,"column":26}},"loc":{"start":{"line":37,"column":37},"end":{"line":39,"column":3}},"line":37},"2":{"name":"(anonymous_2)","decl":{"start":{"line":41,"column":28},"end":{"line":41,"column":29}},"loc":{"start":{"line":41,"column":45},"end":{"line":43,"column":3}},"line":41},"3":{"name":"(anonymous_3)","decl":{"start":{"line":45,"column":27},"end":{"line":45,"column":28}},"loc":{"start":{"line":45,"column":43},"end":{"line":47,"column":3}},"line":45},"4":{"name":"(anonymous_4)","decl":{"start":{"line":49,"column":26},"end":{"line":49,"column":27}},"loc":{"start":{"line":49,"column":32},"end":{"line":51,"column":3}},"line":49},"5":{"name":"(anonymous_5)","decl":{"start":{"line":55,"column":22},"end":{"line":55,"column":23}},"loc":{"start":{"line":55,"column":28},"end":{"line":57,"column":3}},"line":55}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":13},"end":{"line":4,"column":37}},"type":"binary-expr","locations":[{"start":{"line":4,"column":13},"end":{"line":4,"column":29}},{"start":{"line":4,"column":33},"end":{"line":4,"column":37}}],"line":4},"1":{"loc":{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},"type":"if","locations":[{"start":{"line":54,"column":0},"end":{"line":58,"column":1}},{"start":{},"end":{}}],"line":54}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0},"b":{"0":[0,0],"1":[0,0]}} ,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\aiController.js","statementMap":{"0":{"start":{"line":1,"column":33},"end":{"line":1,"column":71}},"1":{"start":{"line":5,"column":4},"end":{"line":21,"column":5}},"2":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"3":{"start":{"line":8,"column":8},"end":{"line":8,"column":39}},"4":{"start":{"line":11,"column":21},"end":{"line":11,"column":32}},"5":{"start":{"line":12,"column":20},"end":{"line":12,"column":54}},"6":{"start":{"line":14,"column":6},"end":{"line":18,"column":9}},"7":{"start":{"line":20,"column":6},"end":{"line":20,"column":16}},"8":{"start":{"line":25,"column":0},"end":{"line":25,"column":30}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":4,"column":2},"end":{"line":4,"column":3}},"loc":{"start":{"line":4,"column":50},"end":{"line":22,"column":3}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},"type":"if","locations":[{"start":{"line":7,"column":6},"end":{"line":9,"column":7}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":10},"end":{"line":7,"column":35}},"type":"binary-expr","locations":[{"start":{"line":7,"column":10},"end":{"line":7,"column":19}},{"start":{"line":7,"column":23},"end":{"line":7,"column":35}}],"line":7}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0},"f":{"0":0},"b":{"0":[0,0],"1":[0,0]}} ,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\chatController.js","statementMap":{"0":{"start":{"line":1,"column":43},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":24}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":52}},"3":{"start":{"line":8,"column":8},"end":{"line":34,"column":9}},"4":{"start":{"line":9,"column":34},"end":{"line":9,"column":42}},"5":{"start":{"line":10,"column":27},"end":{"line":10,"column":38}},"6":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"7":{"start":{"line":13,"column":16},"end":{"line":13,"column":97}},"8":{"start":{"line":17,"column":36},"end":{"line":29,"column":14}},"9":{"start":{"line":31,"column":12},"end":{"line":31,"column":55}},"10":{"start":{"line":33,"column":12},"end":{"line":33,"column":22}},"11":{"start":{"line":39,"column":8},"end":{"line":55,"column":9}},"12":{"start":{"line":40,"column":27},"end":{"line":40,"column":38}},"13":{"start":{"line":41,"column":26},"end":{"line":50,"column":14}},"14":{"start":{"line":52,"column":12},"end":{"line":52,"column":28}},"15":{"start":{"line":54,"column":12},"end":{"line":54,"column":22}},"16":{"start":{"line":60,"column":8},"end":{"line":79,"column":9}},"17":{"start":{"line":61,"column":31},"end":{"line":61,"column":41}},"18":{"start":{"line":62,"column":27},"end":{"line":62,"column":38}},"19":{"start":{"line":65,"column":25},"end":{"line":65,"column":52}},"20":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"21":{"start":{"line":67,"column":16},"end":{"line":67,"column":44}},"22":{"start":{"line":70,"column":29},"end":{"line":74,"column":14}},"23":{"start":{"line":76,"column":12},"end":{"line":76,"column":31}},"24":{"start":{"line":78,"column":12},"end":{"line":78,"column":22}},"25":{"start":{"line":83,"column":8},"end":{"line":99,"column":9}},"26":{"start":{"line":84,"column":27},"end":{"line":84,"column":38}},"27":{"start":{"line":85,"column":36},"end":{"line":95,"column":14}},"28":{"start":{"line":96,"column":12},"end":{"line":96,"column":55}},"29":{"start":{"line":98,"column":12},"end":{"line":98,"column":22}},"30":{"start":{"line":104,"column":8},"end":{"line":153,"column":9}},"31":{"start":{"line":105,"column":31},"end":{"line":105,"column":41}},"32":{"start":{"line":106,"column":32},"end":{"line":106,"column":40}},"33":{"start":{"line":107,"column":27},"end":{"line":107,"column":38}},"34":{"start":{"line":108,"column":23},"end":{"line":108,"column":46}},"35":{"start":{"line":110,"column":25},"end":{"line":110,"column":52}},"36":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"37":{"start":{"line":112,"column":16},"end":{"line":112,"column":70}},"38":{"start":{"line":115,"column":33},"end":{"line":115,"column":84}},"39":{"start":{"line":116,"column":12},"end":{"line":118,"column":13}},"40":{"start":{"line":117,"column":16},"end":{"line":117,"column":99}},"41":{"start":{"line":121,"column":32},"end":{"line":125,"column":14}},"42":{"start":{"line":126,"column":12},"end":{"line":126,"column":73}},"43":{"start":{"line":129,"column":12},"end":{"line":149,"column":13}},"44":{"start":{"line":131,"column":39},"end":{"line":131,"column":63}},"45":{"start":{"line":134,"column":34},"end":{"line":138,"column":18}},"46":{"start":{"line":141,"column":16},"end":{"line":141,"column":75}},"47":{"start":{"line":144,"column":16},"end":{"line":144,"column":55}},"48":{"start":{"line":148,"column":16},"end":{"line":148,"column":57}},"49":{"start":{"line":152,"column":12},"end":{"line":152,"column":22}},"50":{"start":{"line":157,"column":0},"end":{"line":157,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":7,"column":4},"end":{"line":7,"column":5}},"loc":{"start":{"line":7,"column":49},"end":{"line":35,"column":5}},"line":7},"1":{"name":"(anonymous_1)","decl":{"start":{"line":38,"column":4},"end":{"line":38,"column":5}},"loc":{"start":{"line":38,"column":46},"end":{"line":56,"column":5}},"line":38},"2":{"name":"(anonymous_2)","decl":{"start":{"line":59,"column":4},"end":{"line":59,"column":5}},"loc":{"start":{"line":59,"column":49},"end":{"line":80,"column":5}},"line":59},"3":{"name":"(anonymous_3)","decl":{"start":{"line":82,"column":4},"end":{"line":82,"column":5}},"loc":{"start":{"line":82,"column":46},"end":{"line":100,"column":5}},"line":82},"4":{"name":"(anonymous_4)","decl":{"start":{"line":103,"column":4},"end":{"line":103,"column":5}},"loc":{"start":{"line":103,"column":45},"end":{"line":154,"column":5}},"line":103}},"branchMap":{"0":{"loc":{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},"type":"if","locations":[{"start":{"line":12,"column":12},"end":{"line":14,"column":13}},{"start":{},"end":{}}],"line":12},"1":{"loc":{"start":{"line":31,"column":23},"end":{"line":31,"column":42}},"type":"cond-expr","locations":[{"start":{"line":31,"column":33},"end":{"line":31,"column":36}},{"start":{"line":31,"column":39},"end":{"line":31,"column":42}}],"line":31},"2":{"loc":{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},"type":"if","locations":[{"start":{"line":66,"column":12},"end":{"line":68,"column":13}},{"start":{},"end":{}}],"line":66},"3":{"loc":{"start":{"line":66,"column":16},"end":{"line":66,"column":78}},"type":"binary-expr","locations":[{"start":{"line":66,"column":16},"end":{"line":66,"column":21}},{"start":{"line":66,"column":26},"end":{"line":66,"column":48}},{"start":{"line":66,"column":52},"end":{"line":66,"column":77}}],"line":66},"4":{"loc":{"start":{"line":96,"column":23},"end":{"line":96,"column":42}},"type":"cond-expr","locations":[{"start":{"line":96,"column":33},"end":{"line":96,"column":36}},{"start":{"line":96,"column":39},"end":{"line":96,"column":42}}],"line":96},"5":{"loc":{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},"type":"if","locations":[{"start":{"line":111,"column":12},"end":{"line":113,"column":13}},{"start":{},"end":{}}],"line":111},"6":{"loc":{"start":{"line":115,"column":33},"end":{"line":115,"column":84}},"type":"binary-expr","locations":[{"start":{"line":115,"column":33},"end":{"line":115,"column":55}},{"start":{"line":115,"column":59},"end":{"line":115,"column":84}}],"line":115},"7":{"loc":{"start":{"line":116,"column":12},"end":{"line":118,"column":13}},"type":"if","locations":[{"start":{"line":116,"column":12},"end":{"line":118,"column":13}},{"start":{},"end":{}}],"line":116},"8":{"loc":{"start":{"line":129,"column":12},"end":{"line":149,"column":13}},"type":"if","locations":[{"start":{"line":129,"column":12},"end":{"line":149,"column":13}},{"start":{"line":146,"column":19},"end":{"line":149,"column":13}}],"line":129}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0]}} ,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\postController.js","statementMap":{"0":{"start":{"line":1,"column":46},"end":{"line":1,"column":66}},"1":{"start":{"line":6,"column":4},"end":{"line":39,"column":5}},"2":{"start":{"line":7,"column":49},"end":{"line":7,"column":57}},"3":{"start":{"line":8,"column":21},"end":{"line":8,"column":32}},"4":{"start":{"line":11,"column":6},"end":{"line":13,"column":7}},"5":{"start":{"line":12,"column":8},"end":{"line":12,"column":98}},"6":{"start":{"line":16,"column":19},"end":{"line":22,"column":8}},"7":{"start":{"line":25,"column":29},"end":{"line":28,"column":9}},"8":{"start":{"line":25,"column":54},"end":{"line":28,"column":7}},"9":{"start":{"line":30,"column":6},"end":{"line":30,"column":45}},"10":{"start":{"line":32,"column":6},"end":{"line":36,"column":9}},"11":{"start":{"line":38,"column":6},"end":{"line":38,"column":16}},"12":{"start":{"line":44,"column":4},"end":{"line":58,"column":5}},"13":{"start":{"line":45,"column":20},"end":{"line":54,"column":8}},"14":{"start":{"line":55,"column":6},"end":{"line":55,"column":22}},"15":{"start":{"line":57,"column":6},"end":{"line":57,"column":16}},"16":{"start":{"line":63,"column":4},"end":{"line":72,"column":5}},"17":{"start":{"line":64,"column":20},"end":{"line":68,"column":8}},"18":{"start":{"line":69,"column":6},"end":{"line":69,"column":22}},"19":{"start":{"line":71,"column":6},"end":{"line":71,"column":16}},"20":{"start":{"line":77,"column":4},"end":{"line":89,"column":5}},"21":{"start":{"line":78,"column":21},"end":{"line":78,"column":31}},"22":{"start":{"line":79,"column":49},"end":{"line":79,"column":57}},"23":{"start":{"line":81,"column":19},"end":{"line":81,"column":42}},"24":{"start":{"line":82,"column":6},"end":{"line":82,"column":44}},"25":{"start":{"line":82,"column":17},"end":{"line":82,"column":44}},"26":{"start":{"line":83,"column":6},"end":{"line":83,"column":70}},"27":{"start":{"line":83,"column":39},"end":{"line":83,"column":70}},"28":{"start":{"line":85,"column":6},"end":{"line":85,"column":72}},"29":{"start":{"line":86,"column":6},"end":{"line":86,"column":63}},"30":{"start":{"line":88,"column":6},"end":{"line":88,"column":16}},"31":{"start":{"line":94,"column":4},"end":{"line":104,"column":5}},"32":{"start":{"line":95,"column":21},"end":{"line":95,"column":31}},"33":{"start":{"line":96,"column":19},"end":{"line":96,"column":42}},"34":{"start":{"line":97,"column":6},"end":{"line":97,"column":44}},"35":{"start":{"line":97,"column":17},"end":{"line":97,"column":44}},"36":{"start":{"line":98,"column":6},"end":{"line":98,"column":70}},"37":{"start":{"line":98,"column":39},"end":{"line":98,"column":70}},"38":{"start":{"line":100,"column":6},"end":{"line":100,"column":27}},"39":{"start":{"line":101,"column":6},"end":{"line":101,"column":57}},"40":{"start":{"line":103,"column":6},"end":{"line":103,"column":16}},"41":{"start":{"line":109,"column":4},"end":{"line":129,"column":5}},"42":{"start":{"line":110,"column":21},"end":{"line":110,"column":31}},"43":{"start":{"line":111,"column":19},"end":{"line":111,"column":42}},"44":{"start":{"line":112,"column":6},"end":{"line":112,"column":44}},"45":{"start":{"line":112,"column":17},"end":{"line":112,"column":44}},"46":{"start":{"line":114,"column":27},"end":{"line":116,"column":8}},"47":{"start":{"line":119,"column":6},"end":{"line":125,"column":7}},"48":{"start":{"line":120,"column":8},"end":{"line":120,"column":37}},"49":{"start":{"line":121,"column":8},"end":{"line":121,"column":33}},"50":{"start":{"line":123,"column":8},"end":{"line":123,"column":63}},"51":{"start":{"line":124,"column":8},"end":{"line":124,"column":31}},"52":{"start":{"line":126,"column":6},"end":{"line":126,"column":28}},"53":{"start":{"line":128,"column":6},"end":{"line":128,"column":16}},"54":{"start":{"line":133,"column":0},"end":{"line":133,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":5,"column":2},"end":{"line":5,"column":3}},"loc":{"start":{"line":5,"column":42},"end":{"line":40,"column":3}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":25,"column":43},"end":{"line":25,"column":44}},"loc":{"start":{"line":25,"column":54},"end":{"line":28,"column":7}},"line":25},"2":{"name":"(anonymous_2)","decl":{"start":{"line":43,"column":2},"end":{"line":43,"column":3}},"loc":{"start":{"line":43,"column":49},"end":{"line":59,"column":3}},"line":43},"3":{"name":"(anonymous_3)","decl":{"start":{"line":62,"column":2},"end":{"line":62,"column":3}},"loc":{"start":{"line":62,"column":42},"end":{"line":73,"column":3}},"line":62},"4":{"name":"(anonymous_4)","decl":{"start":{"line":76,"column":2},"end":{"line":76,"column":3}},"loc":{"start":{"line":76,"column":42},"end":{"line":90,"column":3}},"line":76},"5":{"name":"(anonymous_5)","decl":{"start":{"line":93,"column":2},"end":{"line":93,"column":3}},"loc":{"start":{"line":93,"column":42},"end":{"line":105,"column":3}},"line":93},"6":{"name":"(anonymous_6)","decl":{"start":{"line":108,"column":2},"end":{"line":108,"column":3}},"loc":{"start":{"line":108,"column":42},"end":{"line":130,"column":3}},"line":108}},"branchMap":{"0":{"loc":{"start":{"line":11,"column":6},"end":{"line":13,"column":7}},"type":"if","locations":[{"start":{"line":11,"column":6},"end":{"line":13,"column":7}},{"start":{},"end":{}}],"line":11},"1":{"loc":{"start":{"line":11,"column":10},"end":{"line":11,"column":46}},"type":"binary-expr","locations":[{"start":{"line":11,"column":10},"end":{"line":11,"column":20}},{"start":{"line":11,"column":24},"end":{"line":11,"column":46}}],"line":11},"2":{"loc":{"start":{"line":19,"column":19},"end":{"line":19,"column":61}},"type":"binary-expr","locations":[{"start":{"line":19,"column":19},"end":{"line":19,"column":39}},{"start":{"line":19,"column":43},"end":{"line":19,"column":61}}],"line":19},"3":{"loc":{"start":{"line":82,"column":6},"end":{"line":82,"column":44}},"type":"if","locations":[{"start":{"line":82,"column":6},"end":{"line":82,"column":44}},{"start":{},"end":{}}],"line":82},"4":{"loc":{"start":{"line":83,"column":6},"end":{"line":83,"column":70}},"type":"if","locations":[{"start":{"line":83,"column":6},"end":{"line":83,"column":70}},{"start":{},"end":{}}],"line":83},"5":{"loc":{"start":{"line":97,"column":6},"end":{"line":97,"column":44}},"type":"if","locations":[{"start":{"line":97,"column":6},"end":{"line":97,"column":44}},{"start":{},"end":{}}],"line":97},"6":{"loc":{"start":{"line":98,"column":6},"end":{"line":98,"column":70}},"type":"if","locations":[{"start":{"line":98,"column":6},"end":{"line":98,"column":70}},{"start":{},"end":{}}],"line":98},"7":{"loc":{"start":{"line":112,"column":6},"end":{"line":112,"column":44}},"type":"if","locations":[{"start":{"line":112,"column":6},"end":{"line":112,"column":44}},{"start":{},"end":{}}],"line":112},"8":{"loc":{"start":{"line":119,"column":6},"end":{"line":125,"column":7}},"type":"if","locations":[{"start":{"line":119,"column":6},"end":{"line":125,"column":7}},{"start":{"line":122,"column":13},"end":{"line":125,"column":7}}],"line":119}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0},"f":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0]}} ,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\controllers\\userController.js","statementMap":{"0":{"start":{"line":1,"column":17},"end":{"line":1,"column":37}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":34}},"2":{"start":{"line":3,"column":22},"end":{"line":3,"column":47}},"3":{"start":{"line":4,"column":25},"end":{"line":4,"column":55}},"4":{"start":{"line":5,"column":15},"end":{"line":5,"column":33}},"5":{"start":{"line":10,"column":8},"end":{"line":20,"column":9}},"6":{"start":{"line":11,"column":50},"end":{"line":11,"column":58}},"7":{"start":{"line":12,"column":28},"end":{"line":12,"column":76}},"8":{"start":{"line":13,"column":12},"end":{"line":17,"column":15}},"9":{"start":{"line":19,"column":12},"end":{"line":19,"column":22}},"10":{"start":{"line":24,"column":8},"end":{"line":44,"column":9}},"11":{"start":{"line":25,"column":40},"end":{"line":25,"column":48}},"12":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"13":{"start":{"line":27,"column":16},"end":{"line":27,"column":89}},"14":{"start":{"line":30,"column":25},"end":{"line":30,"column":65}},"15":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"16":{"start":{"line":32,"column":16},"end":{"line":32,"column":47}},"17":{"start":{"line":35,"column":36},"end":{"line":35,"column":79}},"18":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"19":{"start":{"line":37,"column":16},"end":{"line":37,"column":47}},"20":{"start":{"line":40,"column":26},"end":{"line":40,"column":52}},"21":{"start":{"line":41,"column":12},"end":{"line":41,"column":58}},"22":{"start":{"line":43,"column":12},"end":{"line":43,"column":22}},"23":{"start":{"line":48,"column":8},"end":{"line":73,"column":9}},"24":{"start":{"line":49,"column":37},"end":{"line":49,"column":45}},"25":{"start":{"line":51,"column":27},"end":{"line":54,"column":14}},"26":{"start":{"line":55,"column":28},"end":{"line":55,"column":47}},"27":{"start":{"line":57,"column":36},"end":{"line":66,"column":14}},"28":{"start":{"line":68,"column":33},"end":{"line":68,"column":59}},"29":{"start":{"line":69,"column":12},"end":{"line":69,"column":51}},"30":{"start":{"line":72,"column":12},"end":{"line":72,"column":22}},"31":{"start":{"line":77,"column":0},"end":{"line":77,"column":32}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":9,"column":4},"end":{"line":9,"column":5}},"loc":{"start":{"line":9,"column":42},"end":{"line":21,"column":5}},"line":9},"1":{"name":"(anonymous_1)","decl":{"start":{"line":23,"column":4},"end":{"line":23,"column":5}},"loc":{"start":{"line":23,"column":39},"end":{"line":45,"column":5}},"line":23},"2":{"name":"(anonymous_2)","decl":{"start":{"line":47,"column":4},"end":{"line":47,"column":5}},"loc":{"start":{"line":47,"column":46},"end":{"line":74,"column":5}},"line":47}},"branchMap":{"0":{"loc":{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},"type":"if","locations":[{"start":{"line":26,"column":12},"end":{"line":28,"column":13}},{"start":{},"end":{}}],"line":26},"1":{"loc":{"start":{"line":26,"column":16},"end":{"line":26,"column":35}},"type":"binary-expr","locations":[{"start":{"line":26,"column":16},"end":{"line":26,"column":22}},{"start":{"line":26,"column":26},"end":{"line":26,"column":35}}],"line":26},"2":{"loc":{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},"type":"if","locations":[{"start":{"line":31,"column":12},"end":{"line":33,"column":13}},{"start":{},"end":{}}],"line":31},"3":{"loc":{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},"type":"if","locations":[{"start":{"line":36,"column":12},"end":{"line":38,"column":13}},{"start":{},"end":{}}],"line":36}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0},"f":{"0":0,"1":0,"2":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0]}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":3,"column":14},"end":{"line":3,"column":64}},"2":{"start":{"line":4,"column":14},"end":{"line":4,"column":69}},"3":{"start":{"line":8,"column":2},"end":{"line":21,"column":12}},"4":{"start":{"line":25,"column":2},"end":{"line":32,"column":3}},"5":{"start":{"line":26,"column":19},"end":{"line":26,"column":54}},"6":{"start":{"line":27,"column":20},"end":{"line":27,"column":42}},"7":{"start":{"line":28,"column":4},"end":{"line":28,"column":30}},"8":{"start":{"line":30,"column":4},"end":{"line":30,"column":47}},"9":{"start":{"line":31,"column":4},"end":{"line":31,"column":63}},"10":{"start":{"line":35,"column":0},"end":{"line":35,"column":42}}},"fnMap":{"0":{"name":"cleanText","decl":{"start":{"line":7,"column":9},"end":{"line":7,"column":18}},"loc":{"start":{"line":7,"column":30},"end":{"line":22,"column":1}},"line":7},"1":{"name":"askGemini","decl":{"start":{"line":24,"column":15},"end":{"line":24,"column":24}},"loc":{"start":{"line":24,"column":33},"end":{"line":33,"column":1}},"line":24}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":19},"end":{"line":7,"column":28}},"type":"default-arg","locations":[{"start":{"line":7,"column":26},"end":{"line":7,"column":28}}],"line":7}},"s":{"0":5,"1":5,"2":5,"3":4,"4":3,"5":3,"6":2,"7":2,"8":1,"9":1,"10":5},"f":{"0":4,"1":3},"b":{"0":[1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"2e50e4f0c73211fc77ec6e98c2ee2a41538ee44c"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":39},"end":{"line":2,"column":59}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":35}},"3":{"start":{"line":6,"column":2},"end":{"line":68,"column":3}},"4":{"start":{"line":8,"column":18},"end":{"line":8,"column":68}},"5":{"start":{"line":9,"column":18},"end":{"line":9,"column":71}},"6":{"start":{"line":11,"column":23},"end":{"line":14,"column":6}},"7":{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},"8":{"start":{"line":18,"column":6},"end":{"line":23,"column":9}},"9":{"start":{"line":26,"column":26},"end":{"line":31,"column":17}},"10":{"start":{"line":29,"column":10},"end":{"line":29,"column":86}},"11":{"start":{"line":33,"column":19},"end":{"line":39,"column":5}},"12":{"start":{"line":41,"column":19},"end":{"line":41,"column":54}},"13":{"start":{"line":42,"column":27},"end":{"line":42,"column":49}},"14":{"start":{"line":43,"column":23},"end":{"line":43,"column":69}},"15":{"start":{"line":43,"column":60},"end":{"line":43,"column":68}},"16":{"start":{"line":45,"column":29},"end":{"line":57,"column":6}},"17":{"start":{"line":59,"column":4},"end":{"line":59,"column":28}},"18":{"start":{"line":61,"column":4},"end":{"line":61,"column":60}},"19":{"start":{"line":62,"column":4},"end":{"line":67,"column":7}},"20":{"start":{"line":71,"column":0},"end":{"line":71,"column":42}}},"fnMap":{"0":{"name":"getAIRecommendations","decl":{"start":{"line":5,"column":15},"end":{"line":5,"column":35}},"loc":{"start":{"line":5,"column":44},"end":{"line":69,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":28,"column":8},"end":{"line":28,"column":9}},"loc":{"start":{"line":29,"column":10},"end":{"line":29,"column":86}},"line":29},"2":{"name":"(anonymous_2)","decl":{"start":{"line":43,"column":53},"end":{"line":43,"column":54}},"loc":{"start":{"line":43,"column":60},"end":{"line":43,"column":68}},"line":43}},"branchMap":{"0":{"loc":{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},"type":"if","locations":[{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},{"start":{},"end":{}}],"line":17},"1":{"loc":{"start":{"line":17,"column":8},"end":{"line":17,"column":44}},"type":"binary-expr","locations":[{"start":{"line":17,"column":8},"end":{"line":17,"column":19}},{"start":{"line":17,"column":23},"end":{"line":17,"column":44}}],"line":17},"2":{"loc":{"start":{"line":29,"column":49},"end":{"line":29,"column":83}},"type":"binary-expr","locations":[{"start":{"line":29,"column":49},"end":{"line":29,"column":73}},{"start":{"line":29,"column":77},"end":{"line":29,"column":83}}],"line":29}},"s":{"0":4,"1":4,"2":4,"3":4,"4":4,"5":4,"6":4,"7":3,"8":1,"9":2,"10":6,"11":2,"12":2,"13":2,"14":2,"15":5,"16":2,"17":2,"18":1,"19":1,"20":4},"f":{"0":4,"1":6,"2":5},"b":{"0":[1,2],"1":[3,3],"2":[6,2]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"b1fba11a44899570364f599bbe9715df05009abc"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiHelper.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":3,"column":14},"end":{"line":3,"column":64}},"2":{"start":{"line":4,"column":14},"end":{"line":4,"column":69}},"3":{"start":{"line":8,"column":2},"end":{"line":21,"column":12}},"4":{"start":{"line":25,"column":2},"end":{"line":32,"column":3}},"5":{"start":{"line":26,"column":19},"end":{"line":26,"column":54}},"6":{"start":{"line":27,"column":20},"end":{"line":27,"column":42}},"7":{"start":{"line":28,"column":4},"end":{"line":28,"column":30}},"8":{"start":{"line":30,"column":4},"end":{"line":30,"column":47}},"9":{"start":{"line":31,"column":4},"end":{"line":31,"column":63}},"10":{"start":{"line":35,"column":0},"end":{"line":35,"column":42}}},"fnMap":{"0":{"name":"cleanText","decl":{"start":{"line":7,"column":9},"end":{"line":7,"column":18}},"loc":{"start":{"line":7,"column":30},"end":{"line":22,"column":1}},"line":7},"1":{"name":"askGemini","decl":{"start":{"line":24,"column":15},"end":{"line":24,"column":24}},"loc":{"start":{"line":24,"column":33},"end":{"line":33,"column":1}},"line":24}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":19},"end":{"line":7,"column":28}},"type":"default-arg","locations":[{"start":{"line":7,"column":26},"end":{"line":7,"column":28}}],"line":7}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"f":{"0":0,"1":0},"b":{"0":[0]}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\aiRecommendation.js","statementMap":{"0":{"start":{"line":1,"column":31},"end":{"line":1,"column":63}},"1":{"start":{"line":2,"column":39},"end":{"line":2,"column":59}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":35}},"3":{"start":{"line":6,"column":2},"end":{"line":68,"column":3}},"4":{"start":{"line":8,"column":18},"end":{"line":8,"column":68}},"5":{"start":{"line":9,"column":18},"end":{"line":9,"column":71}},"6":{"start":{"line":11,"column":23},"end":{"line":14,"column":6}},"7":{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},"8":{"start":{"line":18,"column":6},"end":{"line":23,"column":9}},"9":{"start":{"line":26,"column":26},"end":{"line":31,"column":17}},"10":{"start":{"line":29,"column":10},"end":{"line":29,"column":86}},"11":{"start":{"line":33,"column":19},"end":{"line":39,"column":5}},"12":{"start":{"line":41,"column":19},"end":{"line":41,"column":54}},"13":{"start":{"line":42,"column":27},"end":{"line":42,"column":49}},"14":{"start":{"line":43,"column":23},"end":{"line":43,"column":69}},"15":{"start":{"line":43,"column":60},"end":{"line":43,"column":68}},"16":{"start":{"line":45,"column":29},"end":{"line":57,"column":6}},"17":{"start":{"line":59,"column":4},"end":{"line":59,"column":28}},"18":{"start":{"line":61,"column":4},"end":{"line":61,"column":60}},"19":{"start":{"line":62,"column":4},"end":{"line":67,"column":7}},"20":{"start":{"line":71,"column":0},"end":{"line":71,"column":42}}},"fnMap":{"0":{"name":"getAIRecommendations","decl":{"start":{"line":5,"column":15},"end":{"line":5,"column":35}},"loc":{"start":{"line":5,"column":44},"end":{"line":69,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":28,"column":8},"end":{"line":28,"column":9}},"loc":{"start":{"line":29,"column":10},"end":{"line":29,"column":86}},"line":29},"2":{"name":"(anonymous_2)","decl":{"start":{"line":43,"column":53},"end":{"line":43,"column":54}},"loc":{"start":{"line":43,"column":60},"end":{"line":43,"column":68}},"line":43}},"branchMap":{"0":{"loc":{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},"type":"if","locations":[{"start":{"line":17,"column":4},"end":{"line":24,"column":5}},{"start":{},"end":{}}],"line":17},"1":{"loc":{"start":{"line":17,"column":8},"end":{"line":17,"column":44}},"type":"binary-expr","locations":[{"start":{"line":17,"column":8},"end":{"line":17,"column":19}},{"start":{"line":17,"column":23},"end":{"line":17,"column":44}}],"line":17},"2":{"loc":{"start":{"line":29,"column":49},"end":{"line":29,"column":83}},"type":"binary-expr","locations":[{"start":{"line":29,"column":49},"end":{"line":29,"column":73}},{"start":{"line":29,"column":77},"end":{"line":29,"column":83}}],"line":29}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0,"20":0},"f":{"0":0,"1":0,"2":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0]}} ,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\authMiddleware.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\authMiddleware.js","statementMap":{"0":{"start":{"line":1,"column":24},"end":{"line":1,"column":40}},"1":{"start":{"line":2,"column":17},"end":{"line":2,"column":37}},"2":{"start":{"line":4,"column":0},"end":{"line":28,"column":2}},"3":{"start":{"line":5,"column":2},"end":{"line":27,"column":3}},"4":{"start":{"line":6,"column":24},"end":{"line":6,"column":49}},"5":{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},"6":{"start":{"line":8,"column":6},"end":{"line":8,"column":68}},"7":{"start":{"line":11,"column":18},"end":{"line":11,"column":43}},"8":{"start":{"line":12,"column":20},"end":{"line":12,"column":38}},"9":{"start":{"line":13,"column":17},"end":{"line":13,"column":48}},"10":{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},"11":{"start":{"line":14,"column":15},"end":{"line":14,"column":73}},"12":{"start":{"line":16,"column":4},"end":{"line":16,"column":20}},"13":{"start":{"line":17,"column":4},"end":{"line":17,"column":28}},"14":{"start":{"line":18,"column":4},"end":{"line":18,"column":11}},"15":{"start":{"line":20,"column":4},"end":{"line":26,"column":5}},"16":{"start":{"line":21,"column":6},"end":{"line":21,"column":16}},"17":{"start":{"line":22,"column":11},"end":{"line":26,"column":5}},"18":{"start":{"line":23,"column":6},"end":{"line":23,"column":68}},"19":{"start":{"line":25,"column":6},"end":{"line":25,"column":68}}},"fnMap":{"0":{"name":"authMiddleware","decl":{"start":{"line":4,"column":32},"end":{"line":4,"column":46}},"loc":{"start":{"line":4,"column":63},"end":{"line":28,"column":1}},"line":4}},"branchMap":{"0":{"loc":{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},"type":"if","locations":[{"start":{"line":7,"column":4},"end":{"line":9,"column":5}},{"start":{},"end":{}}],"line":7},"1":{"loc":{"start":{"line":7,"column":8},"end":{"line":7,"column":58}},"type":"binary-expr","locations":[{"start":{"line":7,"column":8},"end":{"line":7,"column":20}},{"start":{"line":7,"column":24},"end":{"line":7,"column":58}}],"line":7},"2":{"loc":{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},"type":"if","locations":[{"start":{"line":14,"column":4},"end":{"line":14,"column":73}},{"start":{},"end":{}}],"line":14},"3":{"loc":{"start":{"line":20,"column":4},"end":{"line":26,"column":5}},"type":"if","locations":[{"start":{"line":20,"column":4},"end":{"line":26,"column":5}},{"start":{"line":22,"column":11},"end":{"line":26,"column":5}}],"line":20},"4":{"loc":{"start":{"line":22,"column":11},"end":{"line":26,"column":5}},"type":"if","locations":[{"start":{"line":22,"column":11},"end":{"line":26,"column":5}},{"start":{"line":24,"column":11},"end":{"line":26,"column":5}}],"line":22}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0,"15":0,"16":0,"17":0,"18":0,"19":0},"f":{"0":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0]}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\cloudinary.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\cloudinary.js","statementMap":{"0":{"start":{"line":1,"column":19},"end":{"line":1,"column":43}},"1":{"start":{"line":2,"column":30},"end":{"line":2,"column":66}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":32}},"3":{"start":{"line":5,"column":0},"end":{"line":9,"column":3}},"4":{"start":{"line":11,"column":16},"end":{"line":18,"column":2}},"5":{"start":{"line":20,"column":15},"end":{"line":20,"column":34}},"6":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":4,"1":4,"2":4,"3":4,"4":4,"5":4,"6":4},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"b5c712c03dc49f3dc144389fe011736580e525df"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\handleError.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\handleError.js","statementMap":{"0":{"start":{"line":2,"column":2},"end":{"line":2,"column":31}},"1":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"2":{"start":{"line":5,"column":4},"end":{"line":5,"column":68}},"3":{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},"4":{"start":{"line":9,"column":4},"end":{"line":9,"column":74}},"5":{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},"6":{"start":{"line":13,"column":4},"end":{"line":13,"column":63}},"7":{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},"8":{"start":{"line":17,"column":4},"end":{"line":17,"column":75}},"9":{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},"10":{"start":{"line":21,"column":21},"end":{"line":21,"column":51}},"11":{"start":{"line":21,"column":41},"end":{"line":21,"column":50}},"12":{"start":{"line":22,"column":4},"end":{"line":22,"column":55}},"13":{"start":{"line":25,"column":2},"end":{"line":27,"column":5}},"14":{"start":{"line":30,"column":0},"end":{"line":30,"column":29}}},"fnMap":{"0":{"name":"handleError","decl":{"start":{"line":1,"column":9},"end":{"line":1,"column":20}},"loc":{"start":{"line":1,"column":41},"end":{"line":28,"column":1}},"line":1},"1":{"name":"(anonymous_1)","decl":{"start":{"line":21,"column":36},"end":{"line":21,"column":37}},"loc":{"start":{"line":21,"column":41},"end":{"line":21,"column":50}},"line":21}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"type":"if","locations":[{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},{"start":{},"end":{}}],"line":4},"1":{"loc":{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},{"start":{},"end":{}}],"line":8},"2":{"loc":{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},"type":"if","locations":[{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},{"start":{},"end":{}}],"line":12},"3":{"loc":{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},"type":"if","locations":[{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},{"start":{},"end":{}}],"line":16},"4":{"loc":{"start":{"line":17,"column":43},"end":{"line":17,"column":71}},"type":"binary-expr","locations":[{"start":{"line":17,"column":43},"end":{"line":17,"column":54}},{"start":{"line":17,"column":58},"end":{"line":17,"column":71}}],"line":17},"5":{"loc":{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},"type":"if","locations":[{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},{"start":{},"end":{}}],"line":20},"6":{"loc":{"start":{"line":20,"column":6},"end":{"line":20,"column":94}},"type":"binary-expr","locations":[{"start":{"line":20,"column":6},"end":{"line":20,"column":45}},{"start":{"line":20,"column":49},"end":{"line":20,"column":94}}],"line":20}},"s":{"0":8,"1":8,"2":1,"3":7,"4":1,"5":6,"6":1,"7":5,"8":2,"9":3,"10":2,"11":3,"12":2,"13":1,"14":2},"f":{"0":8,"1":3},"b":{"0":[1,7],"1":[1,6],"2":[1,5],"3":[2,3],"4":[2,1],"5":[2,1],"6":[3,2]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"c2354f978bf3faa64bb0eed70640c0f9b3ddd7a3"} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js","statementMap":{"0":{"start":{"line":1,"column":12},"end":{"line":1,"column":35}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":37}},"2":{"start":{"line":5,"column":2},"end":{"line":5,"column":35}},"3":{"start":{"line":9,"column":2},"end":{"line":9,"column":35}},"4":{"start":{"line":12,"column":0},"end":{"line":12,"column":44}}},"fnMap":{"0":{"name":"signToken","decl":{"start":{"line":4,"column":9},"end":{"line":4,"column":18}},"loc":{"start":{"line":4,"column":28},"end":{"line":6,"column":1}},"line":4},"1":{"name":"verifyToken","decl":{"start":{"line":8,"column":9},"end":{"line":8,"column":20}},"loc":{"start":{"line":8,"column":28},"end":{"line":10,"column":1}},"line":8}},"branchMap":{},"s":{"0":3,"1":3,"2":1,"3":2,"4":3},"f":{"0":1,"1":2},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"d7b8e9b1304ab0135964e79a9372e3a90c422c73"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\cloudinary.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\cloudinary.js","statementMap":{"0":{"start":{"line":1,"column":19},"end":{"line":1,"column":43}},"1":{"start":{"line":2,"column":30},"end":{"line":2,"column":66}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":32}},"3":{"start":{"line":5,"column":0},"end":{"line":9,"column":3}},"4":{"start":{"line":11,"column":16},"end":{"line":18,"column":2}},"5":{"start":{"line":20,"column":15},"end":{"line":20,"column":34}},"6":{"start":{"line":22,"column":0},"end":{"line":22,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0},"f":{},"b":{}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\handleError.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\handleError.js","statementMap":{"0":{"start":{"line":2,"column":2},"end":{"line":2,"column":31}},"1":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"2":{"start":{"line":5,"column":4},"end":{"line":5,"column":68}},"3":{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},"4":{"start":{"line":9,"column":4},"end":{"line":9,"column":74}},"5":{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},"6":{"start":{"line":13,"column":4},"end":{"line":13,"column":63}},"7":{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},"8":{"start":{"line":17,"column":4},"end":{"line":17,"column":75}},"9":{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},"10":{"start":{"line":21,"column":21},"end":{"line":21,"column":51}},"11":{"start":{"line":21,"column":41},"end":{"line":21,"column":50}},"12":{"start":{"line":22,"column":4},"end":{"line":22,"column":55}},"13":{"start":{"line":25,"column":2},"end":{"line":27,"column":5}},"14":{"start":{"line":30,"column":0},"end":{"line":30,"column":29}}},"fnMap":{"0":{"name":"handleError","decl":{"start":{"line":1,"column":9},"end":{"line":1,"column":20}},"loc":{"start":{"line":1,"column":41},"end":{"line":28,"column":1}},"line":1},"1":{"name":"(anonymous_1)","decl":{"start":{"line":21,"column":36},"end":{"line":21,"column":37}},"loc":{"start":{"line":21,"column":41},"end":{"line":21,"column":50}},"line":21}},"branchMap":{"0":{"loc":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"type":"if","locations":[{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},{"start":{},"end":{}}],"line":4},"1":{"loc":{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},"type":"if","locations":[{"start":{"line":8,"column":2},"end":{"line":10,"column":3}},{"start":{},"end":{}}],"line":8},"2":{"loc":{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},"type":"if","locations":[{"start":{"line":12,"column":2},"end":{"line":14,"column":3}},{"start":{},"end":{}}],"line":12},"3":{"loc":{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},"type":"if","locations":[{"start":{"line":16,"column":2},"end":{"line":18,"column":3}},{"start":{},"end":{}}],"line":16},"4":{"loc":{"start":{"line":17,"column":43},"end":{"line":17,"column":71}},"type":"binary-expr","locations":[{"start":{"line":17,"column":43},"end":{"line":17,"column":54}},{"start":{"line":17,"column":58},"end":{"line":17,"column":71}}],"line":17},"5":{"loc":{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},"type":"if","locations":[{"start":{"line":20,"column":2},"end":{"line":23,"column":3}},{"start":{},"end":{}}],"line":20},"6":{"loc":{"start":{"line":20,"column":6},"end":{"line":20,"column":94}},"type":"binary-expr","locations":[{"start":{"line":20,"column":6},"end":{"line":20,"column":45}},{"start":{"line":20,"column":49},"end":{"line":20,"column":94}}],"line":20}},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0,"12":0,"13":0,"14":0},"f":{"0":0,"1":0},"b":{"0":[0,0],"1":[0,0],"2":[0,0],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0]}} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\helpers\\jwt.js","statementMap":{"0":{"start":{"line":1,"column":12},"end":{"line":1,"column":35}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":37}},"2":{"start":{"line":5,"column":2},"end":{"line":5,"column":35}},"3":{"start":{"line":9,"column":2},"end":{"line":9,"column":35}},"4":{"start":{"line":12,"column":0},"end":{"line":12,"column":44}}},"fnMap":{"0":{"name":"signToken","decl":{"start":{"line":4,"column":9},"end":{"line":4,"column":18}},"loc":{"start":{"line":4,"column":28},"end":{"line":6,"column":1}},"line":4},"1":{"name":"verifyToken","decl":{"start":{"line":8,"column":9},"end":{"line":8,"column":20}},"loc":{"start":{"line":8,"column":28},"end":{"line":10,"column":1}},"line":8}},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0},"f":{"0":0,"1":0},"b":{}} ,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\aiRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\aiRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":21},"end":{"line":3,"column":59}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":7,"column":0},"end":{"line":7,"column":70}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0},"f":{},"b":{}} ,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\chatRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\chatRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":23},"end":{"line":3,"column":63}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":17}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":48}},"6":{"start":{"line":12,"column":0},"end":{"line":12,"column":49}},"7":{"start":{"line":15,"column":0},"end":{"line":15,"column":45}},"8":{"start":{"line":18,"column":0},"end":{"line":18,"column":64}},"9":{"start":{"line":21,"column":0},"end":{"line":21,"column":61}},"10":{"start":{"line":23,"column":0},"end":{"line":23,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"f":{},"b":{}} -,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\index.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\index.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":4,"column":19},"end":{"line":4,"column":42}},"3":{"start":{"line":5,"column":19},"end":{"line":5,"column":42}},"4":{"start":{"line":6,"column":19},"end":{"line":6,"column":42}},"5":{"start":{"line":7,"column":17},"end":{"line":7,"column":38}},"6":{"start":{"line":16,"column":0},"end":{"line":16,"column":33}},"7":{"start":{"line":17,"column":0},"end":{"line":17,"column":33}},"8":{"start":{"line":18,"column":0},"end":{"line":18,"column":33}},"9":{"start":{"line":19,"column":0},"end":{"line":19,"column":28}},"10":{"start":{"line":21,"column":0},"end":{"line":21,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1},"f":{},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"e64227b43051f4e83574447d7ab08252f7f48992"} +,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\index.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\index.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":4,"column":19},"end":{"line":4,"column":42}},"3":{"start":{"line":5,"column":19},"end":{"line":5,"column":42}},"4":{"start":{"line":6,"column":19},"end":{"line":6,"column":42}},"5":{"start":{"line":7,"column":17},"end":{"line":7,"column":38}},"6":{"start":{"line":16,"column":0},"end":{"line":16,"column":33}},"7":{"start":{"line":17,"column":0},"end":{"line":17,"column":33}},"8":{"start":{"line":18,"column":0},"end":{"line":18,"column":33}},"9":{"start":{"line":19,"column":0},"end":{"line":19,"column":28}},"10":{"start":{"line":21,"column":0},"end":{"line":21,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0},"f":{},"b":{}} ,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\postRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\postRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":15},"end":{"line":2,"column":31}},"2":{"start":{"line":3,"column":23},"end":{"line":3,"column":63}},"3":{"start":{"line":4,"column":13},"end":{"line":4,"column":49}},"4":{"start":{"line":5,"column":15},"end":{"line":5,"column":47}},"5":{"start":{"line":8,"column":0},"end":{"line":8,"column":77}},"6":{"start":{"line":10,"column":0},"end":{"line":10,"column":50}},"7":{"start":{"line":11,"column":0},"end":{"line":11,"column":51}},"8":{"start":{"line":13,"column":0},"end":{"line":13,"column":52}},"9":{"start":{"line":14,"column":0},"end":{"line":14,"column":55}},"10":{"start":{"line":16,"column":0},"end":{"line":16,"column":58}},"11":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0,"9":0,"10":0,"11":0},"f":{},"b":{}} ,"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\userRouter.js": {"path":"C:\\Users\\ASUS\\OneDrive - Bina Nusantara\\Desktop\\Phase 2\\Dummy-Instagram\\routes\\userRouter.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":23},"end":{"line":2,"column":63}},"2":{"start":{"line":3,"column":15},"end":{"line":3,"column":31}},"3":{"start":{"line":5,"column":0},"end":{"line":5,"column":50}},"4":{"start":{"line":6,"column":0},"end":{"line":6,"column":44}},"5":{"start":{"line":7,"column":0},"end":{"line":7,"column":57}},"6":{"start":{"line":10,"column":0},"end":{"line":10,"column":24}}},"fnMap":{},"branchMap":{},"s":{"0":0,"1":0,"2":0,"3":0,"4":0,"5":0,"6":0},"f":{},"b":{}} } diff --git a/coverage/lcov-report/Dummy-Instagram/app.js.html b/coverage/lcov-report/Dummy-Instagram/app.js.html index ffa1f1b..06616e1 100644 --- a/coverage/lcov-report/Dummy-Instagram/app.js.html +++ b/coverage/lcov-report/Dummy-Instagram/app.js.html @@ -23,30 +23,30 @@

All files / Dummy-Instagram

-
+
1 2 @@ -122,132 +122,132 @@

All files / Dummy-Instagram 57 58 59 -60

7x -7x -7x -7x -7x -7x -7x +60  +  +  +  +  +  +    -7x -7x -7x -7x +  +  +  +            -7x +      -7x -7x -7x -7x +  +  +  +      -7x +        -7x +      -7x +      -7x -7x +  +      -7x +        -7x +        -7x +          -7x +            -7x
require('dotenv').config();
-const express = require('express');
-const app = express();
-const port = process.env.PORT || 3000;
-const handleError = require('./helpers/handleError');
-const routes = require('./routes');
-const cors = require('cors'); 
+ 
require('dotenv').config();
+const express = require('express');
+const app = express();
+const port = process.env.PORT || 3000;
+const handleError = require('./helpers/handleError');
+const routes = require('./routes');
+const cors = require('cors'); 
  
-const http = require('http');
-const server = http.createServer(app);
-const { Server } = require("socket.io");
-const io = new Server(server, {
+const http = require('http');
+const server = http.createServer(app);
+const { Server } = require("socket.io");
+const io = new Server(server, {
   cors: {
     origin: "*", 
   }
 });
  
-app.set('socketio', io); 
+app.set('socketio', io); 
  
 // Middleware
-app.use(cors()); 
-app.use(express.json());
-app.use(express.urlencoded({ extended: true }));
-app.use(express.static('public'));
+app.use(cors()); 
+app.use(express.json());
+app.use(express.urlencoded({ extended: true }));
+app.use(express.static('public'));
  
 // Router
-app.use("/", routes);
+app.use("/", routes);
  
  
 // Error handler
-app.use(handleError);
+app.use(handleError);
  
 // +++ Logika koneksi Socket.IO +++
-io.on('connection', (socket) => {
+io.on('connection', (socket) => {
   // console.log('โœ… User connected:', socket.id); //comment untuk npx jest
  
-  socket.on('join_chat', (chatId) => {
-    socket.join(`chat_${chatId}`);
+  socket.on('join_chat', (chatId) => {
+    socket.join(`chat_${chatId}`);
   });
  
-  socket.on('send_message', (messageData) => { //comment untuk npx jest
+  socket.on('send_message', (messageData) => { //comment untuk npx jest
     io.to(`chat_${messageData.chatId}`).emit('new_message', messageData); 
   });
  
-  socket.on('user_typing', (typingData) => { //comment untuk npx jest
+  socket.on('user_typing', (typingData) => { //comment untuk npx jest
     io.to(`chat_${typingData.chatId}`).emit('typing_status', typingData); 
   });
  
-  socket.on('disconnect', () => { //comment untuk npx jest
+  socket.on('disconnect', () => { //comment untuk npx jest
     // console.log('โŒ User disconnected:', socket.id); 
   });
 });
  
-Iif (process.env.NODE_ENV !== 'test') { //comment untuk npx jest
+if (process.env.NODE_ENV !== 'test') { //comment untuk npx jest
   server.listen(port, () => {
     console.log(`App listening on port http://localhost:${port}`);
   });
 }
  
-module.exports = app;
+module.exports = app;

+ + + + + + + + + + + + + + + + +
+

Welcome

+

Firebase Hosting Setup Complete

+

You're seeing this because you've successfully setup Firebase Hosting. Now it's time to go build something extraordinary!

+ Open Hosting Documentation +
+

Firebase SDK Loading…

+ + + + diff --git a/client/src/components/PostCard.jsx b/client/src/components/PostCard.jsx index cbc9977..45fc56b 100644 --- a/client/src/components/PostCard.jsx +++ b/client/src/components/PostCard.jsx @@ -1,33 +1,43 @@ import { useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { toggleLike, setLikeCount, setLikeState } from '../store/likesSlice'; import { Card, Carousel, Button } from 'react-bootstrap'; import { Heart, HeartFill, ChatDots, Send, Bookmark } from 'react-bootstrap-icons'; import http from '../helpers/http'; import Swal from 'sweetalert2'; const PostCard = ({ post, onLikeToggle }) => { - const [isLiked, setIsLiked] = useState(false); - const [likesCount, setLikesCount] = useState(post.Likes?.length || 0); + const dispatch = useDispatch(); + const isLiked = useSelector(state => state.likes.likedById[post.id]) || false; + const likesCount = useSelector(state => state.likes.counts[post.id]) ?? (post.Likes?.length || 0); const [showFullCaption, setShowFullCaption] = useState(false); - // Check if current user has liked this post + // Initialize redux like state on mount useState(() => { - const token = localStorage.getItem('access_token'); - if (token && post.Likes) { - // You might want to decode token to get user id and check if they liked - // For now, we'll use a simple approach - const liked = post.Likes.some(like => like.UserId === post.UserId); - setIsLiked(liked); + if (post && post.id) { + dispatch(setLikeCount({ postId: post.id, count: post.Likes?.length || 0 })); + // naive liked detection: current user liked if Likes contains current user id + const token = localStorage.getItem('access_token'); + if (token && post.Likes) { + // decode token minimal (not verifying) to get id + try { + const payload = JSON.parse(atob(token.split('.')[1])); + const userId = payload.id; + const liked = post.Likes.some(like => like.UserId === userId); + dispatch(setLikeState({ postId: post.id, liked })); + } catch (e) { + // ignore + } + } } - }, [post.Likes]); + }, [post]); const handleLike = async () => { try { const { data } = await http.post(`/posts/${post.id}/like`); - - // Toggle like state - setIsLiked(!isLiked); - setLikesCount(isLiked ? likesCount - 1 : likesCount + 1); - + + // Optimistically toggle redux state + dispatch(toggleLike(post.id)); if (onLikeToggle) onLikeToggle(post.id); } catch (error) { Swal.fire({ diff --git a/client/src/main.jsx b/client/src/main.jsx index a08ba09..6207f81 100644 --- a/client/src/main.jsx +++ b/client/src/main.jsx @@ -3,9 +3,13 @@ import { createRoot } from 'react-dom/client' import 'bootstrap/dist/css/bootstrap.min.css' import './index.css' import App from './App.jsx' +import { Provider } from 'react-redux' +import { store } from './store' createRoot(document.getElementById('root')).render( - + + + , ) diff --git a/client/src/store/index.js b/client/src/store/index.js new file mode 100644 index 0000000..3aca6fc --- /dev/null +++ b/client/src/store/index.js @@ -0,0 +1,10 @@ +import { configureStore } from '@reduxjs/toolkit'; +import likesReducer from './likesSlice'; + +export const store = configureStore({ + reducer: { + likes: likesReducer, + } +}); + +export default store; diff --git a/client/src/store/likesSlice.js b/client/src/store/likesSlice.js new file mode 100644 index 0000000..b576c0f --- /dev/null +++ b/client/src/store/likesSlice.js @@ -0,0 +1,30 @@ +import { createSlice } from '@reduxjs/toolkit'; + +const initialState = { + likedById: {}, // postId -> boolean + counts: {}, // postId -> number +}; + +const likesSlice = createSlice({ + name: 'likes', + initialState, + reducers: { + setLikeState(state, action) { + const { postId, liked } = action.payload; + state.likedById[postId] = liked; + }, + setLikeCount(state, action) { + const { postId, count } = action.payload; + state.counts[postId] = count; + }, + toggleLike(state, action) { + const postId = action.payload; + const current = !!state.likedById[postId]; + state.likedById[postId] = !current; + state.counts[postId] = (state.counts[postId] || 0) + (current ? -1 : 1); + } + } +}); + +export const { setLikeState, setLikeCount, toggleLike } = likesSlice.actions; +export default likesSlice.reducer; diff --git a/data/posts.json b/data/posts.json index b884f60..d7cf6cd 100644 --- a/data/posts.json +++ b/data/posts.json @@ -6,10 +6,10 @@ "isPrivate": false, "images": [ { - "imageUrl": "https://res.cloudinary.com/dxs0yxeyr/image/upload/v1697435786/nature1_kj2mql.jpg" + "imageUrl": "https://images.unsplash.com/photo-1501973801540-537f08ccae7b?w=1200&auto=format&fit=crop" }, { - "imageUrl": "https://res.cloudinary.com/dxs0yxeyr/image/upload/v1697435786/nature2_ls3nop.jpg" + "imageUrl": "https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=1200&auto=format&fit=crop" } ] }, @@ -20,7 +20,7 @@ "isPrivate": false, "images": [ { - "imageUrl": "https://res.cloudinary.com/dxs0yxeyr/image/upload/v1697435786/food1_rt4mqk.jpg" + "imageUrl": "https://images.unsplash.com/photo-1504674900247-0877df9cc836?w=1200&auto=format&fit=crop" } ] }, @@ -31,10 +31,10 @@ "isPrivate": false, "images": [ { - "imageUrl": "https://res.cloudinary.com/dxs0yxeyr/image/upload/v1697435786/travel1_uw5nxz.jpg" + "imageUrl": "https://images.unsplash.com/photo-1549880338-65ddcdfd017b?w=1200&auto=format&fit=crop" }, { - "imageUrl": "https://res.cloudinary.com/dxs0yxeyr/image/upload/v1697435786/travel2_vq6mry.jpg" + "imageUrl": "https://images.unsplash.com/photo-1526481280698-3bfa7568d2dd?w=1200&auto=format&fit=crop" } ] }, @@ -45,7 +45,7 @@ "isPrivate": false, "images": [ { - "imageUrl": "https://res.cloudinary.com/dxs0yxeyr/image/upload/v1697435786/fashion1_sh8tpv.jpg" + "imageUrl": "https://images.unsplash.com/photo-1495121605193-b116b5b09a7f?w=1200&auto=format&fit=crop" } ] }, @@ -56,7 +56,7 @@ "isPrivate": false, "images": [ { - "imageUrl": "https://res.cloudinary.com/dxs0yxeyr/image/upload/v1697435786/tech1_iy9wqm.jpg" + "imageUrl": "https://images.unsplash.com/photo-1518779578993-ec3579fee39f?w=1200&auto=format&fit=crop" } ] } From 57f98585d38a12396bddb5ea398364e12be79add Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Fri, 17 Oct 2025 00:42:39 +0700 Subject: [PATCH 51/62] feat: Add Discover Users modal --- client/.firebase/hosting.ZGlzdA.cache | 2 +- client/package-lock.json | 1910 +++++++++++++++++- client/package.json | 7 +- client/src/components/DiscoverUsersModal.jsx | 207 ++ client/src/pages/Messages.jsx | 40 +- 5 files changed, 2031 insertions(+), 135 deletions(-) create mode 100644 client/src/components/DiscoverUsersModal.jsx diff --git a/client/.firebase/hosting.ZGlzdA.cache b/client/.firebase/hosting.ZGlzdA.cache index 9b2a5f4..11e21ff 100644 --- a/client/.firebase/hosting.ZGlzdA.cache +++ b/client/.firebase/hosting.ZGlzdA.cache @@ -1,4 +1,4 @@ vite.svg,1760631936123,699a02e0e68a579f687d364bbbe7633161244f35af068220aee37b1b33dfb3c7 index.html,1760635244928,159f7338c31e9060b9f797753de8b14d202f0c67e7c6391c7055e6a151d06224 -assets/index-CIpsl6Aj.css,1760635244928,ec30b7cd4a9d868211d83512ac0b4b2899f1ce907c7981290b698e6c16eadff0 assets/index-D0DNAjur.js,1760635244928,8b9b7ad078f955807e4e150d042a441318eba5448f09809235e262fd8d20a45a +assets/index-CIpsl6Aj.css,1760635244928,ec30b7cd4a9d868211d83512ac0b4b2899f1ce907c7981290b698e6c16eadff0 diff --git a/client/package-lock.json b/client/package-lock.json index 9f0131e..68f3de3 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -25,11 +25,12 @@ "@types/react": "^19.1.16", "@types/react-dom": "^19.1.9", "@vitejs/plugin-react": "^5.0.4", - "eslint": "^9.36.0", + "eslint": "^9.37.0", + "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.22", + "eslint-plugin-react-refresh": "^0.4.24", "globals": "^16.4.0", - "vite": "^7.1.7" + "vite": "^7.1.10" } }, "node_modules/@babel/code-frame": { @@ -1664,12 +1665,176 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/axios": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", @@ -1762,6 +1927,25 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -1775,6 +1959,23 @@ "node": ">= 0.4" } }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1905,6 +2106,60 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -1930,6 +2185,42 @@ "dev": true, "license": "MIT" }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1948,6 +2239,19 @@ "node": ">=6" } }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/dom-helpers": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", @@ -1979,6 +2283,75 @@ "dev": true, "license": "ISC" }, + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -1997,6 +2370,34 @@ "node": ">= 0.4" } }, + "node_modules/es-iterator-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.6", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -2024,6 +2425,37 @@ "node": ">= 0.4" } }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/esbuild": { "version": "0.25.11", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", @@ -2150,10 +2582,43 @@ } } }, - "node_modules/eslint-plugin-react-hooks": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", - "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", "dev": true, "license": "MIT", "engines": { @@ -2377,6 +2842,22 @@ } } }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/form-data": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", @@ -2417,6 +2898,47 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -2464,6 +2986,24 @@ "node": ">= 0.4" } }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -2490,6 +3030,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -2502,6 +3059,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2512,6 +3082,35 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -2598,6 +3197,21 @@ "node": ">=0.8.19" } }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -2607,149 +3221,549 @@ "loose-envify": "^1.0.0" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "has-bigints": "^1.0.2" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": ">=6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, "engines": { - "node": ">=6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", "dependencies": { - "json-buffer": "3.0.1" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^5.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -2864,6 +3878,104 @@ "node": ">=0.10.0" } }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -2882,6 +3994,24 @@ "node": ">= 0.8.0" } }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -2947,6 +4077,13 @@ "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2967,6 +4104,16 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -3224,12 +4371,74 @@ "redux": "^5.0.0" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/reselect": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", "license": "MIT" }, + "node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -3282,6 +4491,61 @@ "fsevents": "~2.3.2" } }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -3298,11 +4562,60 @@ "semver": "bin/semver.js" } }, - "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", - "license": "MIT" + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } }, "node_modules/shebang-command": { "version": "2.0.0", @@ -3327,6 +4640,82 @@ "node": ">=8" } }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -3337,6 +4726,118 @@ "node": ">=0.10.0" } }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -3363,6 +4864,19 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/sweetalert2": { "version": "11.26.2", "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.26.2.tgz", @@ -3409,6 +4923,103 @@ "node": ">= 0.8.0" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/uncontrollable": { "version": "7.2.1", "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", @@ -3574,6 +5185,95 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/client/package.json b/client/package.json index d11b3be..69db6c8 100644 --- a/client/package.json +++ b/client/package.json @@ -27,10 +27,11 @@ "@types/react": "^19.1.16", "@types/react-dom": "^19.1.9", "@vitejs/plugin-react": "^5.0.4", - "eslint": "^9.36.0", + "eslint": "^9.37.0", + "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.22", + "eslint-plugin-react-refresh": "^0.4.24", "globals": "^16.4.0", - "vite": "^7.1.7" + "vite": "^7.1.10" } } diff --git a/client/src/components/DiscoverUsersModal.jsx b/client/src/components/DiscoverUsersModal.jsx new file mode 100644 index 0000000..ced32e8 --- /dev/null +++ b/client/src/components/DiscoverUsersModal.jsx @@ -0,0 +1,207 @@ +import { useState, useEffect } from 'react'; +import { Modal, ListGroup, Button, Spinner, Form, InputGroup } from 'react-bootstrap'; +import { PersonPlus, Search } from 'react-bootstrap-icons'; +import http from '../helpers/http'; +import Swal from 'sweetalert2'; + +const DiscoverUsersModal = ({ show, onHide, onChatCreated }) => { + const [users, setUsers] = useState([]); + const [loading, setLoading] = useState(false); + const [searchQuery, setSearchQuery] = useState(''); + const [creatingChat, setCreatingChat] = useState(null); + + useEffect(() => { + if (show) { + fetchUsers(); + } + }, [show]); + + const fetchUsers = async () => { + setLoading(true); + try { + // Get users from posts (users who have posted) + const { data: posts } = await http.get('/posts'); + + // Extract unique users + const uniqueUsers = []; + const userIds = new Set(); + + posts.forEach(post => { + if (post.User && !userIds.has(post.User.id)) { + userIds.add(post.User.id); + uniqueUsers.push(post.User); + } + }); + + // Get current user ID to filter out + const token = localStorage.getItem('access_token'); + if (token) { + try { + const payload = JSON.parse(atob(token.split('.')[1])); + const currentUserId = payload.id; + setUsers(uniqueUsers.filter(u => u.id !== currentUserId)); + } catch (e) { + setUsers(uniqueUsers); + } + } else { + setUsers(uniqueUsers); + } + } catch (error) { + console.error('Error fetching users:', error); + Swal.fire({ + icon: 'error', + title: 'Failed to load users', + text: error.response?.data?.message || 'Something went wrong', + }); + } finally { + setLoading(false); + } + }; + + const handleStartChat = async (userId) => { + setCreatingChat(userId); + try { + const { data } = await http.post('/chats', { partnerId: userId }); + + Swal.fire({ + icon: 'success', + title: 'Chat created!', + text: 'You can now start messaging', + timer: 1500, + showConfirmButton: false + }); + + if (onChatCreated) { + onChatCreated(data); + } + + onHide(); + } catch (error) { + console.error('Error creating chat:', error); + Swal.fire({ + icon: 'error', + title: 'Failed to create chat', + text: error.response?.data?.message || 'Something went wrong', + }); + } finally { + setCreatingChat(null); + } + }; + + const filteredUsers = users.filter(user => + user.username?.toLowerCase().includes(searchQuery.toLowerCase()) || + user.email?.toLowerCase().includes(searchQuery.toLowerCase()) + ); + + return ( + + + + + Discover Users + + + + {/* Search Bar */} +
+ + + + + setSearchQuery(e.target.value)} + className="border-start-0 ps-0" + /> + +
+ + {/* Users List */} +
+ {loading ? ( +
+ +

Loading users...

+
+ ) : filteredUsers.length === 0 ? ( +
+ +

+ {searchQuery ? 'No users found matching your search' : 'No users available'} +

+
+ ) : ( + + {filteredUsers.map((user) => ( + +
+ {/* Avatar */} +
+ {user.username?.charAt(0).toUpperCase() || 'U'} +
+ + {/* User Info */} +
+
{user.username || 'Unknown User'}
+ {user.email} +
+
+ + {/* Start Chat Button */} + +
+ ))} +
+ )} +
+
+
+ ); +}; + +export default DiscoverUsersModal; diff --git a/client/src/pages/Messages.jsx b/client/src/pages/Messages.jsx index 78746c3..2ad4814 100644 --- a/client/src/pages/Messages.jsx +++ b/client/src/pages/Messages.jsx @@ -14,6 +14,7 @@ import { useNavigate } from 'react-router-dom'; import http from '../helpers/http'; import Swal from 'sweetalert2'; import StartChatModal from '../components/StartChatModal'; +import DiscoverUsersModal from '../components/DiscoverUsersModal'; const Messages = () => { const navigate = useNavigate(); @@ -25,6 +26,7 @@ const Messages = () => { const [sending, setSending] = useState(false); const [searchQuery, setSearchQuery] = useState(''); const [showStartChatModal, setShowStartChatModal] = useState(false); + const [showDiscoverModal, setShowDiscoverModal] = useState(false); const messagesEndRef = useRef(null); // Safe way to get current user ID @@ -205,30 +207,7 @@ const Messages = () => {
-
@@ -557,11 +536,20 @@ const Messages = () => { {/* Start Chat Modal */} { + handleClose={() => { setShowStartChatModal(false); fetchChats(); // Refresh chats after closing modal }} /> + + setShowDiscoverModal(false)} + onChatCreated={() => { + setShowDiscoverModal(false); + fetchChats(); // Refresh chat list when new chat is created + }} + />
); }; From 303c754cbab54b2fad187e8a1198d4a25e693ddb Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Fri, 17 Oct 2025 00:57:37 +0700 Subject: [PATCH 52/62] Error login Instagram --- client/.env.example | 6 ++++++ client/.firebase/hosting.ZGlzdA.cache | 7 ++++--- client/.gitignore | 3 +++ client/package-lock.json | 6 +++--- client/src/pages/Login.jsx | 18 +++++++++++++++--- client/src/pages/Register.jsx | 18 +++++++++++++++--- 6 files changed, 46 insertions(+), 12 deletions(-) create mode 100644 client/.env.example diff --git a/client/.env.example b/client/.env.example new file mode 100644 index 0000000..91de6a2 --- /dev/null +++ b/client/.env.example @@ -0,0 +1,6 @@ +# Google OAuth Client ID +# Get from https://console.cloud.google.com/apis/credentials +VITE_GOOGLE_CLIENT_ID=your-google-client-id-here.apps.googleusercontent.com + +# Backend API URL +VITE_API_URL=http://localhost:3000 diff --git a/client/.firebase/hosting.ZGlzdA.cache b/client/.firebase/hosting.ZGlzdA.cache index 11e21ff..d267dc5 100644 --- a/client/.firebase/hosting.ZGlzdA.cache +++ b/client/.firebase/hosting.ZGlzdA.cache @@ -1,4 +1,5 @@ vite.svg,1760631936123,699a02e0e68a579f687d364bbbe7633161244f35af068220aee37b1b33dfb3c7 -index.html,1760635244928,159f7338c31e9060b9f797753de8b14d202f0c67e7c6391c7055e6a151d06224 -assets/index-D0DNAjur.js,1760635244928,8b9b7ad078f955807e4e150d042a441318eba5448f09809235e262fd8d20a45a -assets/index-CIpsl6Aj.css,1760635244928,ec30b7cd4a9d868211d83512ac0b4b2899f1ce907c7981290b698e6c16eadff0 +404.html,1760635348044,762bf484ba67404bd1a3b181546ea28d60dfddf18e9dd4795d8d25bcf3c1a890 +index.html,1760637398168,b836e2f06b3cb8b5cbad4fa9413fafb0583a0fa710e88674d6e8cfe533086b8b +assets/index-CIpsl6Aj.css,1760637398168,ec30b7cd4a9d868211d83512ac0b4b2899f1ce907c7981290b698e6c16eadff0 +assets/index-BoXBpEHk.js,1760637398168,0ce25924f31411de187682daaec39723c2b5d4a8cc90ea060e0e86b6e47700d9 diff --git a/client/.gitignore b/client/.gitignore index a547bf3..7ba22ff 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -11,6 +11,9 @@ node_modules dist dist-ssr *.local +.env +.env.local +.env.production # Editor directories and files .vscode/* diff --git a/client/package-lock.json b/client/package-lock.json index 68f3de3..d2cae30 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1854,9 +1854,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.16", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.16.tgz", - "integrity": "sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==", + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.17.tgz", + "integrity": "sha512-j5zJcx6golJYTG6c05LUZ3Z8Gi+M62zRT/ycz4Xq4iCOdpcxwg7ngEYD4KA0eWZC7U17qh/Smq8bYbACJ0ipBA==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/client/src/pages/Login.jsx b/client/src/pages/Login.jsx index af0d92a..17331fd 100644 --- a/client/src/pages/Login.jsx +++ b/client/src/pages/Login.jsx @@ -51,12 +51,15 @@ const Login = () => { }; const handleGoogleSuccess = async (credentialResponse) => { + console.log('Google Login Success:', credentialResponse); setLoading(true); try { + console.log('Sending Google token to backend...'); const { data } = await http.post('/users/auth/google', { google_token: credentialResponse.credential, }); + console.log('Backend response:', data); localStorage.setItem('access_token', data.access_token); Swal.fire({ @@ -65,27 +68,36 @@ const Login = () => { text: 'Welcome!', timer: 1500, showConfirmButton: false, + background: 'rgba(255, 255, 255, 0.95)', + backdrop: 'rgba(102, 126, 234, 0.4)', }); setTimeout(() => { navigate('/'); }, 1500); } catch (error) { + console.error('Google Login Error:', error); + console.error('Error response:', error.response?.data); Swal.fire({ icon: 'error', title: 'Google Login Failed', - text: error.response?.data?.message || 'Something went wrong', + text: error.response?.data?.message || 'Something went wrong. Please try again.', + background: 'rgba(255, 255, 255, 0.95)', + backdrop: 'rgba(102, 126, 234, 0.4)', }); } finally { setLoading(false); } }; - const handleGoogleError = () => { + const handleGoogleError = (error) => { + console.error('Google OAuth Error:', error); Swal.fire({ icon: 'error', title: 'Google Login Failed', - text: 'Please try again', + text: 'Could not connect to Google. Please try again.', + background: 'rgba(255, 255, 255, 0.95)', + backdrop: 'rgba(102, 126, 234, 0.4)', }); }; diff --git a/client/src/pages/Register.jsx b/client/src/pages/Register.jsx index 19459ae..3795a5f 100644 --- a/client/src/pages/Register.jsx +++ b/client/src/pages/Register.jsx @@ -51,12 +51,15 @@ const Register = () => { }; const handleGoogleSuccess = async (credentialResponse) => { + console.log('Google Registration Success:', credentialResponse); setLoading(true); try { + console.log('Sending Google token to backend...'); const { data } = await http.post('/users/auth/google', { google_token: credentialResponse.credential, }); + console.log('Backend response:', data); localStorage.setItem('access_token', data.access_token); Swal.fire({ @@ -65,27 +68,36 @@ const Register = () => { text: 'Welcome!', timer: 1500, showConfirmButton: false, + background: 'rgba(255, 255, 255, 0.95)', + backdrop: 'rgba(102, 126, 234, 0.4)', }); setTimeout(() => { navigate('/'); }, 1500); } catch (error) { + console.error('Google Registration Error:', error); + console.error('Error response:', error.response?.data); Swal.fire({ icon: 'error', title: 'Google Registration Failed', - text: error.response?.data?.message || 'Something went wrong', + text: error.response?.data?.message || 'Something went wrong. Please try again.', + background: 'rgba(255, 255, 255, 0.95)', + backdrop: 'rgba(102, 126, 234, 0.4)', }); } finally { setLoading(false); } }; - const handleGoogleError = () => { + const handleGoogleError = (error) => { + console.error('Google OAuth Error:', error); Swal.fire({ icon: 'error', title: 'Google Sign Up Failed', - text: 'Please try again', + text: 'Could not connect to Google. Please try again.', + background: 'rgba(255, 255, 255, 0.95)', + backdrop: 'rgba(102, 126, 234, 0.4)', }); }; From 7c63ecf8d5632551d80db7cbf26d8cf5d7254ea8 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Fri, 17 Oct 2025 01:04:18 +0700 Subject: [PATCH 53/62] feat: Add Profile page to display user posts --- GOOGLE_LOGIN_FIX.md | 171 +++++++++++++++++ client/.firebase/hosting.ZGlzdA.cache | 6 +- client/src/App.jsx | 9 + client/src/pages/Home.jsx | 16 +- client/src/pages/Profile.jsx | 262 ++++++++++++++++++++++++++ 5 files changed, 460 insertions(+), 4 deletions(-) create mode 100644 GOOGLE_LOGIN_FIX.md create mode 100644 client/src/pages/Profile.jsx diff --git a/GOOGLE_LOGIN_FIX.md b/GOOGLE_LOGIN_FIX.md new file mode 100644 index 0000000..5302d54 --- /dev/null +++ b/GOOGLE_LOGIN_FIX.md @@ -0,0 +1,171 @@ +# Google OAuth Login - Troubleshooting Guide + +## โœ… Perbaikan yang Sudah Dilakukan + +### 1. **Menambahkan File .env** +File `.env` dibuat di folder `client/` dengan konfigurasi: +```env +VITE_GOOGLE_CLIENT_ID=426382311425-flmdrhl6n7tmqcamg1lj8c8cmrkqgtpa.apps.googleusercontent.com +VITE_API_URL=https://dariusjoshua.shop +``` + +### 2. **Update .gitignore** +Menambahkan `.env` ke `.gitignore` agar credential tidak ter-commit: +``` +.env +.env.local +.env.production +``` + +### 3. **Improve Error Handling** +- Menambahkan console.log untuk debugging +- Better error messages dengan Swal styling +- Error parameter di handleGoogleError + +### 4. **File .env.example** +Template untuk developer lain: +```env +VITE_GOOGLE_CLIENT_ID=your-google-client-id-here.apps.googleusercontent.com +VITE_API_URL=http://localhost:3000 +``` + +## ๐Ÿ” Debugging Steps + +Jika Google Login masih error, ikuti langkah berikut: + +### Step 1: Cek Console Browser +1. Buka browser DevTools (F12) +2. Pergi ke tab Console +3. Klik tombol "Sign in with Google" +4. Lihat error message yang muncul + +### Step 2: Verifikasi Google OAuth Setup + +#### Di Google Cloud Console: +1. Buka: https://console.cloud.google.com/apis/credentials +2. Pilih project: "ch2ph2-project" atau yang sesuai +3. Klik Client ID yang digunakan +4. Verifikasi **Authorized JavaScript origins**: + ``` + https://ch2ph2-project.web.app + http://localhost:5173 + http://localhost:3000 + ``` +5. Verifikasi **Authorized redirect URIs**: + ``` + https://ch2ph2-project.web.app + https://ch2ph2-project.web.app/login + http://localhost:5173 + ``` + +### Step 3: Cek Backend Environment + +Di server Biznet Gio, pastikan `.env` memiliki: +```env +GOOGLE_CLIENT_ID=426382311425-flmdrhl6n7tmqcamg1lj8c8cmrkqgtpa.apps.googleusercontent.com +``` + +Atau di `ecosystem.config.js`: +```javascript +env: { + GOOGLE_CLIENT_ID: '426382311425-flmdrhl6n7tmqcamg1lj8c8cmrkqgtpa.apps.googleusercontent.com', + // ... env lainnya +} +``` + +### Step 4: Test Backend Endpoint + +Test endpoint Google Auth di backend: +```bash +curl -X POST https://dariusjoshua.shop/users/auth/google \ + -H "Content-Type: application/json" \ + -d '{"google_token":"SAMPLE_TOKEN"}' +``` + +Expected response (jika token invalid): +```json +{ + "message": "Invalid token" +} +``` + +## ๐Ÿšจ Common Errors + +### Error 1: "Popup closed by user" +**Cause:** User menutup popup Google OAuth +**Solution:** Normal behavior, user harus klik lagi + +### Error 2: "Invalid Google token" +**Cause:** Client ID tidak match antara frontend dan backend +**Solution:** +- Pastikan `VITE_GOOGLE_CLIENT_ID` di frontend sama dengan `GOOGLE_CLIENT_ID` di backend +- Restart backend setelah update .env + +### Error 3: "Origin not allowed" +**Cause:** Domain tidak terdaftar di Google Cloud Console +**Solution:** +1. Pergi ke Google Cloud Console +2. Tambahkan domain ke "Authorized JavaScript origins" +3. Tunggu beberapa menit untuk propagasi + +### Error 4: "Network error" +**Cause:** Backend tidak bisa diakses +**Solution:** +- Cek apakah backend running: `pm2 status` +- Cek logs: `pm2 logs Dummy-Instagrams` +- Test API: `curl https://dariusjoshua.shop/posts` + +## ๐Ÿงช Testing + +### Local Testing (Development) +```bash +cd client +npm run dev +``` +Akses: http://localhost:5173/login + +### Production Testing +Akses: https://ch2ph2-project.web.app/login + +### Test Accounts +Gunakan Google account pribadi Anda untuk test. + +## ๐Ÿ“ Console Logs + +Setelah perbaikan, di browser console akan muncul: +``` +Google Login Success: {credential: "eyJhbG...", clientId: "426382311425..."} +Sending Google token to backend... +Backend response: {access_token: "eyJhbGciOi..."} +``` + +Jika error: +``` +Google Login Error: Error: Request failed with status code 500 +Error response: {message: "Invalid token"} +``` + +## ๐Ÿ”„ Rebuild & Deploy + +Setiap kali update kode: +```bash +cd client +npm run build +firebase deploy +``` + +## โœจ What's Fixed + +โœ… Environment variables (.env file) +โœ… Better error handling with console.log +โœ… Improved error messages +โœ… .gitignore updated +โœ… .env.example for documentation +โœ… Styled Swal alerts + +## ๐Ÿ“ž Next Steps + +Jika masih ada masalah: +1. Share screenshot console error +2. Share screenshot Network tab (XHR request) +3. Cek backend logs: `pm2 logs Dummy-Instagrams --lines 100` diff --git a/client/.firebase/hosting.ZGlzdA.cache b/client/.firebase/hosting.ZGlzdA.cache index d267dc5..62de020 100644 --- a/client/.firebase/hosting.ZGlzdA.cache +++ b/client/.firebase/hosting.ZGlzdA.cache @@ -1,5 +1,5 @@ vite.svg,1760631936123,699a02e0e68a579f687d364bbbe7633161244f35af068220aee37b1b33dfb3c7 404.html,1760635348044,762bf484ba67404bd1a3b181546ea28d60dfddf18e9dd4795d8d25bcf3c1a890 -index.html,1760637398168,b836e2f06b3cb8b5cbad4fa9413fafb0583a0fa710e88674d6e8cfe533086b8b -assets/index-CIpsl6Aj.css,1760637398168,ec30b7cd4a9d868211d83512ac0b4b2899f1ce907c7981290b698e6c16eadff0 -assets/index-BoXBpEHk.js,1760637398168,0ce25924f31411de187682daaec39723c2b5d4a8cc90ea060e0e86b6e47700d9 +index.html,1760637804203,ca4b78bd2c4b12b1beec3f63bb67f02a4be08af535e534a63dcfd77c4031a2eb +assets/index-CIpsl6Aj.css,1760637804203,ec30b7cd4a9d868211d83512ac0b4b2899f1ce907c7981290b698e6c16eadff0 +assets/index-BcBqiLfD.js,1760637804203,54dd37fa1f85e1692a72157d0d197ad4b9d652e293ca55f2dd04465c736c18d2 diff --git a/client/src/App.jsx b/client/src/App.jsx index 2d1438d..74f7c2f 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -4,6 +4,7 @@ import Login from './pages/Login'; import Register from './pages/Register'; import Home from './pages/Home'; import Messages from './pages/Messages'; +import Profile from './pages/Profile'; const GOOGLE_CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID || '426382311425-flmdrhl6n7tmqcamg1lj8c8cmrkqgtpa.apps.googleusercontent.com'; @@ -60,6 +61,14 @@ function App() { } /> + + + + } + /> } /> diff --git a/client/src/pages/Home.jsx b/client/src/pages/Home.jsx index 04e6f6d..a2a4b6b 100644 --- a/client/src/pages/Home.jsx +++ b/client/src/pages/Home.jsx @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Container, Row, Col, Button, Navbar, Spinner } from 'react-bootstrap'; -import { PlusCircleFill, ChatDotsFill, ChatLeftTextFill } from 'react-bootstrap-icons'; +import { PlusCircleFill, ChatDotsFill, ChatLeftTextFill, PersonCircle } from 'react-bootstrap-icons'; import Swal from 'sweetalert2'; import http from '../helpers/http'; import PostCard from '../components/PostCard'; @@ -87,6 +87,20 @@ const Home = () => {
+ +

{user?.username || 'Profile'}

+ +
+ + {/* Profile Info Card */} + + + + +
+ {user?.username?.charAt(0).toUpperCase() || 'U'} +
+ + +

{user?.username || 'User'}

+

{user?.email || ''}

+ + +
{posts.length}
+
Posts
+ + +
0
+
Followers
+ + +
0
+
Following
+ +
+ +
+
+
+ + {/* Tabs */} + + + {/* Posts Grid */} + {loading ? ( +
+ +
+ ) : posts.length === 0 ? ( + + + +
No posts yet
+

Start sharing your moments!

+ +
+
+ ) : ( + + {posts.map((post) => ( + + + + ))} + + )} + +
+ ); +}; + +export default Profile; From 2949cd447f38e5981e8b10cd979a0ffbe09fbb8d Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Fri, 17 Oct 2025 01:20:38 +0700 Subject: [PATCH 54/62] Add more users and posts --- data/posts.json | 30 +++++++---------- data/users.json | 52 +++++++++++++++++++++++++++++- seeders/20251016000001-seed-all.js | 26 +++++++++++---- 3 files changed, 82 insertions(+), 26 deletions(-) diff --git a/data/posts.json b/data/posts.json index d7cf6cd..b1befe2 100644 --- a/data/posts.json +++ b/data/posts.json @@ -1,62 +1,56 @@ [ { - "content": "Beautiful sunset at the beach! ๐ŸŒ…", + "content": "Beautiful sunset!", "UserId": 1, "CategoryId": 1, "isPrivate": false, "images": [ { - "imageUrl": "https://images.unsplash.com/photo-1501973801540-537f08ccae7b?w=1200&auto=format&fit=crop" - }, - { - "imageUrl": "https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=1200&auto=format&fit=crop" + "imageUrl": "https://picsum.photos/seed/beach1/1200/800" } ] }, { - "content": "Delicious homemade pasta! ๐Ÿ", + "content": "Delicious pasta!", "UserId": 2, "CategoryId": 2, "isPrivate": false, "images": [ { - "imageUrl": "https://images.unsplash.com/photo-1504674900247-0877df9cc836?w=1200&auto=format&fit=crop" + "imageUrl": "https://picsum.photos/seed/food1/1200/800" } ] }, { - "content": "Exploring the streets of Tokyo ๐Ÿ—ผ", - "UserId": 2, + "content": "Tokyo streets!", + "UserId": 3, "CategoryId": 3, "isPrivate": false, "images": [ { - "imageUrl": "https://images.unsplash.com/photo-1549880338-65ddcdfd017b?w=1200&auto=format&fit=crop" - }, - { - "imageUrl": "https://images.unsplash.com/photo-1526481280698-3bfa7568d2dd?w=1200&auto=format&fit=crop" + "imageUrl": "https://picsum.photos/seed/travel1/1200/800" } ] }, { - "content": "New collection dropping soon! ๐Ÿ‘—", + "content": "Fashion collection!", "UserId": 4, "CategoryId": 4, "isPrivate": false, "images": [ { - "imageUrl": "https://images.unsplash.com/photo-1495121605193-b116b5b09a7f?w=1200&auto=format&fit=crop" + "imageUrl": "https://picsum.photos/seed/fashion1/1200/800" } ] }, { - "content": "Latest tech gadgets review ๐Ÿ“ฑ", - "UserId": 3, + "content": "Tech review!", + "UserId": 5, "CategoryId": 5, "isPrivate": false, "images": [ { - "imageUrl": "https://images.unsplash.com/photo-1518779578993-ec3579fee39f?w=1200&auto=format&fit=crop" + "imageUrl": "https://picsum.photos/seed/tech1/1200/800" } ] } diff --git a/data/users.json b/data/users.json index a6134df..835ed38 100644 --- a/data/users.json +++ b/data/users.json @@ -7,7 +7,7 @@ { "username": "jane_smith", "email": "jane@example.com", - "password": "password123t" + "password": "password123" }, { "username": "mike_wilson", @@ -23,5 +23,55 @@ "username": "alex_brown", "email": "alex@example.com", "password": "password123" + }, + { + "username": "emma_watson", + "email": "emma@example.com", + "password": "password123" + }, + { + "username": "david_chen", + "email": "david@example.com", + "password": "password123" + }, + { + "username": "lisa_anderson", + "email": "lisa@example.com", + "password": "password123" + }, + { + "username": "ryan_taylor", + "email": "ryan@example.com", + "password": "password123" + }, + { + "username": "sophia_lee", + "email": "sophia@example.com", + "password": "password123" + }, + { + "username": "james_martinez", + "email": "james@example.com", + "password": "password123" + }, + { + "username": "olivia_garcia", + "email": "olivia@example.com", + "password": "password123" + }, + { + "username": "daniel_rodriguez", + "email": "daniel@example.com", + "password": "password123" + }, + { + "username": "ava_johnson", + "email": "ava@example.com", + "password": "password123" + }, + { + "username": "noah_kim", + "email": "noah@example.com", + "password": "password123" } ] diff --git a/seeders/20251016000001-seed-all.js b/seeders/20251016000001-seed-all.js index 4e1b1d1..735fe2e 100644 --- a/seeders/20251016000001-seed-all.js +++ b/seeders/20251016000001-seed-all.js @@ -41,15 +41,27 @@ module.exports = { const postsWithoutImages = posts.map(({ images, ...post }) => post); await queryInterface.bulkInsert('Posts', addTimestamps(postsWithoutImages)); - // Seed images + // Get actual post IDs from database + const [insertedPosts] = await queryInterface.sequelize.query( + 'SELECT id FROM "Posts" ORDER BY id ASC' + ); + + // Seed images with correct PostId const images = posts.reduce((acc, post, index) => { - const postImages = post.images.map(image => ({ - ...image, - PostId: index + 1 - })); - return [...acc, ...postImages]; + const actualPostId = insertedPosts[index]?.id; + if (actualPostId && post.images) { + const postImages = post.images.map(image => ({ + ...image, + PostId: actualPostId + })); + return [...acc, ...postImages]; + } + return acc; }, []); - await queryInterface.bulkInsert('Images', addTimestamps(images)); + + if (images.length > 0) { + await queryInterface.bulkInsert('Images', addTimestamps(images)); + } // Seed likes await queryInterface.bulkInsert('Likes', addTimestamps(likes)); From 1269b1ee9a4cf483a31119e48007cfa46e01ce62 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Fri, 17 Oct 2025 01:25:56 +0700 Subject: [PATCH 55/62] feat: Add 35 posts --- data/posts.json | 377 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 370 insertions(+), 7 deletions(-) diff --git a/data/posts.json b/data/posts.json index b1befe2..7ee112c 100644 --- a/data/posts.json +++ b/data/posts.json @@ -1,39 +1,45 @@ [ { - "content": "Beautiful sunset!", + "content": "Beautiful beach sunset!", "UserId": 1, "CategoryId": 1, "isPrivate": false, "images": [ { "imageUrl": "https://picsum.photos/seed/beach1/1200/800" + }, + { + "imageUrl": "https://picsum.photos/seed/beach2/1200/800" } ] }, { - "content": "Delicious pasta!", + "content": "Homemade pasta dinner!", "UserId": 2, "CategoryId": 2, "isPrivate": false, "images": [ { - "imageUrl": "https://picsum.photos/seed/food1/1200/800" + "imageUrl": "https://picsum.photos/seed/pasta1/1200/800" } ] }, { - "content": "Tokyo streets!", + "content": "Tokyo city lights!", "UserId": 3, "CategoryId": 3, "isPrivate": false, "images": [ { - "imageUrl": "https://picsum.photos/seed/travel1/1200/800" + "imageUrl": "https://picsum.photos/seed/tokyo1/1200/800" + }, + { + "imageUrl": "https://picsum.photos/seed/tokyo2/1200/800" } ] }, { - "content": "Fashion collection!", + "content": "New fashion collection!", "UserId": 4, "CategoryId": 4, "isPrivate": false, @@ -44,7 +50,7 @@ ] }, { - "content": "Tech review!", + "content": "Latest smartphone review!", "UserId": 5, "CategoryId": 5, "isPrivate": false, @@ -53,5 +59,362 @@ "imageUrl": "https://picsum.photos/seed/tech1/1200/800" } ] + }, + { + "content": "Morning coffee vibes", + "UserId": 6, + "CategoryId": 2, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/coffee1/1200/800" + } + ] + }, + { + "content": "Mountain hiking adventure!", + "UserId": 7, + "CategoryId": 1, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/mountain1/1200/800" + }, + { + "imageUrl": "https://picsum.photos/seed/mountain2/1200/800" + }, + { + "imageUrl": "https://picsum.photos/seed/mountain3/1200/800" + } + ] + }, + { + "content": "Street art in Barcelona", + "UserId": 8, + "CategoryId": 3, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/art1/1200/800" + } + ] + }, + { + "content": "Fitness workout session", + "UserId": 9, + "CategoryId": 1, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/gym1/1200/800" + } + ] + }, + { + "content": "Sushi making class", + "UserId": 10, + "CategoryId": 2, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/sushi1/1200/800" + }, + { + "imageUrl": "https://picsum.photos/seed/sushi2/1200/800" + } + ] + }, + { + "content": "City skyline at night", + "UserId": 11, + "CategoryId": 1, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/skyline1/1200/800" + } + ] + }, + { + "content": "New sneakers unboxing", + "UserId": 12, + "CategoryId": 4, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/shoes1/1200/800" + } + ] + }, + { + "content": "Road trip memories", + "UserId": 13, + "CategoryId": 3, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/road1/1200/800" + }, + { + "imageUrl": "https://picsum.photos/seed/road2/1200/800" + } + ] + }, + { + "content": "Gaming setup tour", + "UserId": 14, + "CategoryId": 5, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/gaming1/1200/800" + } + ] + }, + { + "content": "Tropical beach paradise", + "UserId": 15, + "CategoryId": 3, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/tropical1/1200/800" + }, + { + "imageUrl": "https://picsum.photos/seed/tropical2/1200/800" + } + ] + }, + { + "content": "French pastry baking", + "UserId": 1, + "CategoryId": 2, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/pastry1/1200/800" + } + ] + }, + { + "content": "Winter snow wonderland", + "UserId": 2, + "CategoryId": 1, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/snow1/1200/800" + } + ] + }, + { + "content": "Vintage thrift finds", + "UserId": 3, + "CategoryId": 4, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/vintage1/1200/800" + }, + { + "imageUrl": "https://picsum.photos/seed/vintage2/1200/800" + } + ] + }, + { + "content": "Photography gear review", + "UserId": 4, + "CategoryId": 5, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/camera1/1200/800" + } + ] + }, + { + "content": "Brunch cafe vibes", + "UserId": 5, + "CategoryId": 2, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/brunch1/1200/800" + } + ] + }, + { + "content": "Yoga at sunset", + "UserId": 6, + "CategoryId": 1, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/yoga1/1200/800" + } + ] + }, + { + "content": "European architecture", + "UserId": 7, + "CategoryId": 3, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/arch1/1200/800" + }, + { + "imageUrl": "https://picsum.photos/seed/arch2/1200/800" + } + ] + }, + { + "content": "Minimalist wardrobe", + "UserId": 8, + "CategoryId": 4, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/wardrobe1/1200/800" + } + ] + }, + { + "content": "Smart home devices", + "UserId": 9, + "CategoryId": 5, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/smart1/1200/800" + } + ] + }, + { + "content": "Coastal road drive", + "UserId": 10, + "CategoryId": 3, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/coast1/1200/800" + } + ] + }, + { + "content": "Healthy breakfast bowl", + "UserId": 11, + "CategoryId": 2, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/breakfast1/1200/800" + } + ] + }, + { + "content": "Urban street photography", + "UserId": 12, + "CategoryId": 1, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/urban1/1200/800" + } + ] + }, + { + "content": "Designer handbag collection", + "UserId": 13, + "CategoryId": 4, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/bag1/1200/800" + } + ] + }, + { + "content": "Laptop setup workspace", + "UserId": 14, + "CategoryId": 5, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/workspace1/1200/800" + } + ] + }, + { + "content": "Waterfall hiking trail", + "UserId": 15, + "CategoryId": 1, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/waterfall1/1200/800" + }, + { + "imageUrl": "https://picsum.photos/seed/waterfall2/1200/800" + } + ] + }, + { + "content": "Italian pizza making", + "UserId": 1, + "CategoryId": 2, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/pizza1/1200/800" + } + ] + }, + { + "content": "Autumn forest walk", + "UserId": 2, + "CategoryId": 1, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/autumn1/1200/800" + } + ] + }, + { + "content": "Streetwear outfit", + "UserId": 3, + "CategoryId": 4, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/streetwear1/1200/800" + } + ] + }, + { + "content": "Wireless earbuds test", + "UserId": 4, + "CategoryId": 5, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/earbuds1/1200/800" + } + ] + }, + { + "content": "Desert landscape adventure", + "UserId": 5, + "CategoryId": 3, + "isPrivate": false, + "images": [ + { + "imageUrl": "https://picsum.photos/seed/desert1/1200/800" + }, + { + "imageUrl": "https://picsum.photos/seed/desert2/1200/800" + } + ] } ] \ No newline at end of file From d52868f61ea82aa416fd04156ba1db955c36b28d Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Fri, 17 Oct 2025 02:28:14 +0700 Subject: [PATCH 56/62] Clean Data Server & 3/4 Client --- DEPLOYMENT.md | 423 ------- DEPLOYMENT_SUCCESS.md | 123 -- DEPLOY_GUIDE.md | 159 --- DEPLOY_NOW.md | 81 -- GOOGLE_LOGIN_FIX.md | 171 --- READY_TO_DEPLOY.md | 126 -- app.js | 28 +- client/.firebase/hosting.ZGlzdA.cache | 2 +- client/src/pages/Login.jsx | 2 - client/src/pages/Profile.jsx | 161 ++- coverage/clover.xml | 735 ++++++----- coverage/coverage-final.json | 41 +- .../lcov-report/Dummy-Instagram/app.js.html | 150 +-- .../Dummy-Instagram/config/config.js.html | 47 +- .../Dummy-Instagram/config/index.html | 14 +- .../controllers/aiController.js.html | 58 +- .../controllers/chatController.js.html | 239 ++-- .../Dummy-Instagram/controllers/index.html | 108 +- .../controllers/postController.js.html | 230 ++-- .../controllers/userController.js.html | 155 ++- .../Dummy-Instagram/helpers/aiHelper.js.html | 68 +- .../helpers/aiRecommendation.js.html | 104 +- .../helpers/authMiddleware.js.html | 96 +- .../helpers/cloudinary.js.html | 38 +- .../helpers/handleError.js.html | 78 +- .../Dummy-Instagram/helpers/index.html | 140 +-- .../Dummy-Instagram/helpers/jwt.js.html | 38 +- .../lcov-report/Dummy-Instagram/index.html | 42 +- .../Dummy-Instagram/models/category.js.html | 12 +- .../Dummy-Instagram/models/chat.js.html | 16 +- .../Dummy-Instagram/models/image.js.html | 12 +- .../Dummy-Instagram/models/index.html | 30 +- .../Dummy-Instagram/models/index.js.html | 54 +- .../Dummy-Instagram/models/like.js.html | 14 +- .../Dummy-Instagram/models/message.js.html | 16 +- .../Dummy-Instagram/models/post.js.html | 18 +- .../Dummy-Instagram/models/user.js.html | 56 +- .../Dummy-Instagram/routes/aiRouter.js.html | 34 +- .../Dummy-Instagram/routes/chatRouter.js.html | 54 +- .../Dummy-Instagram/routes/index.html | 82 +- .../Dummy-Instagram/routes/index.js.html | 54 +- .../Dummy-Instagram/routes/postRouter.js.html | 58 +- .../Dummy-Instagram/routes/userRouter.js.html | 38 +- coverage/lcov-report/index.html | 130 +- coverage/lcov.info | 1097 ++++++++++------- data/posts.json | 2 +- deploy.sh | 42 - ecosystem.config.js | 30 - 48 files changed, 2350 insertions(+), 3156 deletions(-) delete mode 100644 DEPLOYMENT.md delete mode 100644 DEPLOYMENT_SUCCESS.md delete mode 100644 DEPLOY_GUIDE.md delete mode 100644 DEPLOY_NOW.md delete mode 100644 GOOGLE_LOGIN_FIX.md delete mode 100644 READY_TO_DEPLOY.md delete mode 100644 deploy.sh delete mode 100644 ecosystem.config.js diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md deleted file mode 100644 index 2d07cfc..0000000 --- a/DEPLOYMENT.md +++ /dev/null @@ -1,423 +0,0 @@ -# ๐Ÿš€ Deployment Guide - Biznet Gio - -## ๐Ÿ“‹ Prerequisites - -1. **Server Requirements:** - - Ubuntu 20.04 LTS or higher - - Node.js 18.x or higher - - PostgreSQL (Supabase) - - Minimum 2GB RAM - - PM2 installed globally - -2. **Accounts Needed:** - - Biznet Gio account - - Supabase account (Database) - - Cloudinary account (Image storage) - - Google Cloud Console (OAuth) - - Google AI Studio (Gemini API) - -## ๐Ÿ”ง Server Setup - -### 1. Connect to Biznet Gio Server - -```bash -ssh root@your-server-ip -# or -ssh username@your-server-ip -``` - -### 2. Install Node.js & PM2 - -```bash -# Install Node.js 18.x -curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - -sudo apt-get install -y nodejs - -# Verify installation -node -v -npm -v - -# Install PM2 globally -sudo npm install -g pm2 - -# Verify PM2 -pm2 -v -``` - -### 3. Install Git (if not installed) - -```bash -sudo apt-get update -sudo apt-get install git -y -``` - -## ๐Ÿ“ฆ Deploy Application - -### 1. Clone Repository - -```bash -# Navigate to web directory -cd /var/www # or your preferred directory - -# Clone your repository -git clone https://github.com/Joshua080324/Dummy-Instagram.git -cd Dummy-Instagram -``` - -### 2. Install Dependencies - -```bash -# Install all production dependencies -npm install --production - -# Or install all including dev (if needed) -npm install -``` - -### 3. Create .env File - -```bash -# Copy example env -cp .env.example .env - -# Edit with your credentials -nano .env -``` - -**Paste your credentials:** -```env -NODE_ENV=production -PORT=3000 -JWT_SECRET=supersecret -DATABASE_URL=postgresql://postgres.qwmcsdckdvqjxlstutli:H%2587jz%40TDxZgZzx@aws-1-ap-southeast-1.pooler.supabase.com:6543/postgres -DB_SSL=true -CLOUDINARY_CLOUD_NAME=dlgeccfib -CLOUDINARY_API_KEY=493418276358618 -CLOUDINARY_API_SECRET=Jm0DznPX6DFesMHcKI2DPFowSuk -GOOGLE_CLIENT_ID=426382311425-flmdrhl6n7tmqcamg1lj8c8cmrkqgtpa.apps.googleusercontent.com -GOOGLE_CLIENT_SECRET=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 -GEMINI_API_KEY=AIzaSyAR-KSEtz-cdfkqE3tN0tS0LK_Xen82FC4 -``` - -Save: `Ctrl + X`, then `Y`, then `Enter` - -### 4. Run Database Migrations - -```bash -# Run migrations to create tables -npm run migrate - -# Optional: Seed data -npm run seed -``` - -### 5. Create Logs Directory - -```bash -mkdir -p logs -``` - -### 6. Start Application with PM2 - -```bash -# Start with ecosystem config -pm2 start ecosystem.config.js - -# Or start directly -pm2 start app.js --name dummy-instagram -``` - -### 7. Save PM2 Process & Setup Startup - -```bash -# Save current PM2 process list -pm2 save - -# Generate startup script -pm2 startup - -# Copy and run the command shown (usually starts with sudo) -``` - -## ๐Ÿ” Verify Deployment - -### Check PM2 Status - -```bash -# View all processes -pm2 list - -# View logs -pm2 logs dummy-instagram - -# View specific logs -pm2 logs dummy-instagram --lines 100 - -# Monitor -pm2 monit -``` - -### Test API Endpoints - -```bash -# Test health check -curl http://localhost:3000/ - -# Test posts endpoint (requires auth) -curl http://localhost:3000/posts -``` - -## ๐ŸŒ Configure Nginx (Reverse Proxy) - -### 1. Install Nginx - -```bash -sudo apt-get install nginx -y -``` - -### 2. Create Nginx Configuration - -```bash -sudo nano /etc/nginx/sites-available/dummy-instagram -``` - -**Paste this configuration:** -```nginx -server { - listen 80; - server_name dariusjoshua.shop www.dariusjoshua.shop; - - location / { - proxy_pass http://localhost:3000; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection 'upgrade'; - proxy_set_header Host $host; - proxy_cache_bypass $http_upgrade; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - # Socket.IO support - location /socket.io/ { - proxy_pass http://localhost:3000; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $host; - } -} -``` - -### 3. Enable Site & Restart Nginx - -```bash -# Create symbolic link -sudo ln -s /etc/nginx/sites-available/dummy-instagram /etc/nginx/sites-enabled/ - -# Test configuration -sudo nginx -t - -# Restart Nginx -sudo systemctl restart nginx - -# Enable Nginx on boot -sudo systemctl enable nginx -``` - -### 4. Setup SSL with Certbot (HTTPS) - -```bash -# Install Certbot -sudo apt-get install certbot python3-certbot-nginx -y - -# Get SSL certificate -sudo certbot --nginx -d dariusjoshua.shop -d www.dariusjoshua.shop - -# Follow prompts and select redirect HTTP to HTTPS -``` - -## ๐Ÿ”„ PM2 Commands Cheat Sheet - -```bash -# Start application -pm2 start ecosystem.config.js -pm2 start app.js --name dummy-instagram - -# Restart application -pm2 restart dummy-instagram -pm2 restart all - -# Stop application -pm2 stop dummy-instagram -pm2 stop all - -# Delete from PM2 -pm2 delete dummy-instagram - -# View logs -pm2 logs # All logs -pm2 logs dummy-instagram # Specific app -pm2 logs --lines 50 # Last 50 lines - -# Monitor -pm2 monit # Live monitoring -pm2 status # Status overview -pm2 list # List all processes - -# Clear logs -pm2 flush - -# Save current process list -pm2 save - -# Reload without downtime -pm2 reload dummy-instagram -``` - -## ๐Ÿ”„ Update Deployment - -```bash -# Navigate to project -cd /var/www/Dummy-Instagram - -# Pull latest changes -git pull origin main # or development - -# Install new dependencies -npm install --production - -# Run new migrations -npm run migrate - -# Restart with PM2 -pm2 restart dummy-instagram - -# Check logs for errors -pm2 logs dummy-instagram --lines 50 -``` - -## ๐Ÿ› Troubleshooting - -### Check if Port 3000 is in Use - -```bash -sudo lsof -i :3000 -# or -sudo netstat -tulpn | grep 3000 -``` - -### Kill Process on Port 3000 - -```bash -sudo kill -9 $(sudo lsof -t -i:3000) -``` - -### Check Application Logs - -```bash -# PM2 logs -pm2 logs dummy-instagram - -# Error logs -tail -f logs/pm2-error.log - -# Output logs -tail -f logs/pm2-out.log -``` - -### Database Connection Issues - -```bash -# Test database connection -node -e "const { sequelize } = require('./models'); sequelize.authenticate().then(() => console.log('DB OK')).catch(err => console.error(err));" -``` - -### Reset PM2 - -```bash -pm2 kill -pm2 start ecosystem.config.js -pm2 save -``` - -## ๐Ÿ”’ Security Best Practices - -1. **Firewall Setup:** -```bash -sudo ufw allow 22 # SSH -sudo ufw allow 80 # HTTP -sudo ufw allow 443 # HTTPS -sudo ufw enable -``` - -2. **Change Default SSH Port (Optional):** -```bash -sudo nano /etc/ssh/sshd_config -# Change Port 22 to something else -sudo systemctl restart sshd -``` - -3. **Regular Updates:** -```bash -sudo apt-get update -sudo apt-get upgrade -``` - -## ๐Ÿ“Š Monitoring - -### Setup PM2 Plus (Optional - Monitoring Dashboard) - -```bash -# Link to PM2 Plus -pm2 link - -# Or use free monitoring -pm2 register -``` - -## ๐ŸŽฏ Performance Optimization - -### Enable Cluster Mode - -Edit `ecosystem.config.js`: -```javascript -exec_mode: 'cluster', -instances: 'max', // or specific number like 2 -``` - -Then restart: -```bash -pm2 reload ecosystem.config.js -``` - -## โœ… Deployment Checklist - -- [ ] Server access confirmed -- [ ] Node.js & PM2 installed -- [ ] Repository cloned -- [ ] Dependencies installed -- [ ] .env file configured -- [ ] Database migrations run -- [ ] Logs directory created -- [ ] PM2 process started -- [ ] PM2 startup configured -- [ ] Nginx configured -- [ ] SSL certificate installed -- [ ] API endpoints tested -- [ ] Frontend connected successfully - -## ๐Ÿ“ž Support - -If you encounter issues: -1. Check PM2 logs: `pm2 logs dummy-instagram` -2. Check Nginx logs: `sudo tail -f /var/log/nginx/error.log` -3. Check database connection -4. Verify environment variables - ---- - -**Last Updated:** December 2024 -**Deployed by:** Darius Joshua -**Server:** Biznet Gio diff --git a/DEPLOYMENT_SUCCESS.md b/DEPLOYMENT_SUCCESS.md deleted file mode 100644 index cb12a3e..0000000 --- a/DEPLOYMENT_SUCCESS.md +++ /dev/null @@ -1,123 +0,0 @@ -# โœ… DEPLOYMENT SUCCESSFUL! - -## ๐ŸŽฏ Backend Production Status: RUNNING โœ… - -### Verified Endpoints: -- โœ… GET /posts โ†’ 5 posts available -- โœ… POST /users/login โ†’ Authentication working -- โœ… All APIs responding correctly - ---- - -## ๐Ÿ“‹ Useful PM2 Commands (Run on Server): - -### Check Status: -```bash -sudo pm2 list -# Should show "Dummy-Instagrams" with status "online" -``` - -### View Logs (Real-time): -```bash -sudo pm2 logs Dummy-Instagrams -# Press Ctrl+C to exit -``` - -### View Last 50 Lines: -```bash -sudo pm2 logs Dummy-Instagrams --lines 50 -``` - -### Restart App: -```bash -sudo pm2 restart Dummy-Instagrams -``` - -### Stop App: -```bash -sudo pm2 stop Dummy-Instagrams -``` - -### Save PM2 Config (Important - for auto-restart on reboot): -```bash -sudo pm2 save -``` - -### Setup Auto-Start on Boot: -```bash -sudo pm2 startup -# Follow the command it gives you -``` - -### Monitor Resources: -```bash -sudo pm2 monit -# Shows CPU & Memory usage -``` - ---- - -## ๐Ÿ”‘ Test Login Credentials: - -``` -Email: john@example.com -Password: password123 - -Email: jane@example.com -Password: password123t - -Email: mike@example.com -Password: password123 - -Email: sarah@example.com -Password: password123 - -Email: alex@example.com -Password: password123 -``` - ---- - -## ๐ŸŒ Frontend URLs: - -### If Frontend on Same Server: -- Access via: http://dariusjoshua.shop -- Or: http://your-server-ip - -### If Frontend Separate (like Vercel/Netlify): -- Already configured to use: https://dariusjoshua.shop as backend - ---- - -## ๐ŸŽจ Features Ready to Test: - -1. โœ… **Login/Register** - Including Google OAuth -2. โœ… **Home Feed** - 5 posts with images -3. โœ… **Like System** - Click heart to like/unlike -4. โœ… **Create Post** - Upload images (Cloudinary) -5. โœ… **Messages** - Chat with other users -6. โœ… **AI Chat** - Chat with Gemini AI -7. โœ… **Premium UI** - Bootstrap 5 with animations - ---- - -## ๐Ÿ“Š Database (Production - Supabase): - -- โœ… All migrations applied -- โœ… Seeded with sample data: - - 5 Users - - 5 Posts (public) - - 5 Categories - - Sample chats & messages - - Sample likes - ---- - -## ๐ŸŽ‰ YOU'RE LIVE! - -Your Dummy Instagram app is now running in production! - -**Backend API:** https://dariusjoshua.shop -**Status:** โœ… ONLINE - -Everything is working perfectly! ๐Ÿš€ diff --git a/DEPLOY_GUIDE.md b/DEPLOY_GUIDE.md deleted file mode 100644 index e13948d..0000000 --- a/DEPLOY_GUIDE.md +++ /dev/null @@ -1,159 +0,0 @@ -# ๐Ÿš€ Deployment Guide - Biznet Gio - -## โœ… Database Sudah Di-Seed dari Local! -**Data production sudah siap**, tinggal pull dan restart PM2. - -## Langkah-Langkah Deploy Backend (Super Simple!) - -### 1๏ธโƒฃ SSH ke Server Biznet Gio -```bash -ssh user@dariusjoshua.shop -# Atau gunakan IP server Anda -``` - -### 2๏ธโƒฃ Masuk ke Direktori Aplikasi -```bash -cd /var/www/Dummy-Instagram -# Atau path ke direktori aplikasi Anda -``` - -### 3๏ธโƒฃ Pull Kode Terbaru dari GitHub -```bash -git pull origin development -``` - -### 4๏ธโƒฃ Install Dependencies (jika ada yang baru) -```bash -npm install --production -``` - -### 5๏ธโƒฃ Start/Restart PM2 -```bash -# Jika pertama kali deploy -pm2 start ecosystem.config.js - -# Jika sudah pernah deploy (restart) -pm2 restart dummy - -# Atau restart semua apps -pm2 restart all -``` - -### 8๏ธโƒฃ Cek Status & Logs -```bash -# Lihat status PM2 -pm2 list - -# Lihat logs aplikasi -pm2 logs dummy - -# Atau lihat logs tertentu -pm2 logs dummy --lines 100 -``` - ---- - -## ๐Ÿ” Troubleshooting - -### Error: Module not found -```bash -npm install -pm2 restart dummy -``` - -### Error: Database connection failed -- Cek apakah DATABASE_URL di ecosystem.config.js sudah benar -- Pastikan database Supabase/PostgreSQL bisa diakses -- Test koneksi: `npm run migrate` - -### Error: Port already in use -```bash -# Cek proses yang pakai port 80 -sudo lsof -i :80 - -# Kill proses jika perlu -sudo kill -9 - -# Atau ubah PORT di ecosystem.config.js -``` - -### Data Posts Tidak Muncul -```bash -# Re-seed database -npm run seed:undo -npm run seed -pm2 restart dummy -``` - ---- - -## โœ… Verifikasi Deployment - -### Test API Endpoints: -```bash -# Test posts endpoint -curl https://dariusjoshua.shop/posts - -# Test login endpoint -curl -X POST https://dariusjoshua.shop/users/login \ - -H "Content-Type: application/json" \ - -d '{"email":"john@example.com","password":"password123"}' - -# Test chats endpoint (need token) -curl https://dariusjoshua.shop/chats \ - -H "Authorization: Bearer YOUR_TOKEN_HERE" -``` - -### Akun Login Default (Setelah Seeding): -- Email: `john@example.com` / Password: `password123` -- Email: `jane@example.com` / Password: `password123` -- Email: `mike@example.com` / Password: `password123` -- Email: `sarah@example.com` / Password: `password123` -- Email: `alex@example.com` / Password: `password123` - ---- - -## ๐Ÿ“ฆ File Penting yang Sudah Dikonfigurasi - -โœ… **ecosystem.config.js** - PM2 configuration dengan semua environment variables -โœ… **seeders/** - Data sample untuk users, posts, categories, chats, messages -โœ… **data/posts.json** - Posts dengan field `isPrivate: false` untuk public feed -โœ… **.env.example** - Template environment variables -โœ… **package.json** - Scripts untuk migrate dan seed - ---- - -## ๐ŸŽฏ Quick Deploy Commands (Copy-Paste) - -```bash -# Full deployment in one go (SUPER SIMPLE!) -cd /var/www/Dummy-Instagram && \ -git pull origin development && \ -npm install --production && \ -pm2 restart dummy && \ -pm2 logs dummy --lines 20 -``` - -**Note**: Database sudah di-seed dari local, tidak perlu seeding lagi! - ---- - -## ๐Ÿ” Security Checklist - -- โœ… Environment variables tidak di-commit ke git -- โœ… Database credentials ada di ecosystem.config.js (sudah dikonfigurasi) -- โœ… CORS sudah disetup di backend -- โœ… JWT secret sudah dikonfigurasi -- โš ๏ธ **PENTING**: Ganti semua credentials di ecosystem.config.js dengan yang real di production! - ---- - -## ๐Ÿ“ž Support - -Jika ada masalah: -1. Cek PM2 logs: `pm2 logs dummy` -2. Cek error logs: `pm2 logs dummy --err` -3. Restart PM2: `pm2 restart dummy` -4. Check process: `pm2 list` - -**Happy Deploying! ๐Ÿš€** diff --git a/DEPLOY_NOW.md b/DEPLOY_NOW.md deleted file mode 100644 index 99687b5..0000000 --- a/DEPLOY_NOW.md +++ /dev/null @@ -1,81 +0,0 @@ -# ๐Ÿš€ DEPLOY SEKARANG! - -## โœ… Yang Sudah Selesai: -- โœ… Database production sudah di-seed dengan 5 posts, 5 users, categories, dll -- โœ… Semua fix sudah di-push ke GitHub -- โœ… Code siap production - -## ๐Ÿ“‹ Copy-Paste Command Ini di Server Biznet Gio: - -```bash -cd /var/www/Dummy-Instagram && \ -git pull origin development && \ -npm install --production && \ -sudo pm2 start ecosystem.config.js && \ -sudo pm2 logs -``` - -## ๐ŸŽฏ Atau Step by Step: - -```bash -# 1. SSH ke server -ssh user@dariusjoshua.shop - -# 2. Masuk ke folder app -cd /var/www/Dummy-Instagram - -# 3. Pull kode terbaru -git pull origin development - -# 4. Install dependencies -npm install --production - -# 5. Start PM2 dengan ecosystem config -sudo pm2 start ecosystem.config.js - -# 6. Lihat logs (pastikan tidak ada error) -sudo pm2 logs - -# 7. Save PM2 process list -sudo pm2 save - -# 8. Setup PM2 startup -sudo pm2 startup -``` - -## โœ… Setelah Deploy: - -Buka browser dan test: -- https://dariusjoshua.shop/posts (should return 5 posts) -- Login dengan: john@example.com / password123 - -## ๐Ÿ”ง Useful PM2 Commands: - -```bash -# Lihat status semua apps -sudo pm2 list - -# Restart app tertentu -sudo pm2 restart Dummy-Instagrams - -# Stop app -sudo pm2 stop Dummy-Instagrams - -# Lihat logs real-time -sudo pm2 logs Dummy-Instagrams - -# Lihat logs dengan filter lines -sudo pm2 logs Dummy-Instagrams --lines 50 - -# Delete app dari PM2 -sudo pm2 delete Dummy-Instagrams - -# Monitor resources -sudo pm2 monit -``` - -## ๐ŸŽ‰ DONE! - -Frontend akan otomatis ambil data dari backend production. - -**Total waktu: ~2 menit!** โšก diff --git a/GOOGLE_LOGIN_FIX.md b/GOOGLE_LOGIN_FIX.md deleted file mode 100644 index 5302d54..0000000 --- a/GOOGLE_LOGIN_FIX.md +++ /dev/null @@ -1,171 +0,0 @@ -# Google OAuth Login - Troubleshooting Guide - -## โœ… Perbaikan yang Sudah Dilakukan - -### 1. **Menambahkan File .env** -File `.env` dibuat di folder `client/` dengan konfigurasi: -```env -VITE_GOOGLE_CLIENT_ID=426382311425-flmdrhl6n7tmqcamg1lj8c8cmrkqgtpa.apps.googleusercontent.com -VITE_API_URL=https://dariusjoshua.shop -``` - -### 2. **Update .gitignore** -Menambahkan `.env` ke `.gitignore` agar credential tidak ter-commit: -``` -.env -.env.local -.env.production -``` - -### 3. **Improve Error Handling** -- Menambahkan console.log untuk debugging -- Better error messages dengan Swal styling -- Error parameter di handleGoogleError - -### 4. **File .env.example** -Template untuk developer lain: -```env -VITE_GOOGLE_CLIENT_ID=your-google-client-id-here.apps.googleusercontent.com -VITE_API_URL=http://localhost:3000 -``` - -## ๐Ÿ” Debugging Steps - -Jika Google Login masih error, ikuti langkah berikut: - -### Step 1: Cek Console Browser -1. Buka browser DevTools (F12) -2. Pergi ke tab Console -3. Klik tombol "Sign in with Google" -4. Lihat error message yang muncul - -### Step 2: Verifikasi Google OAuth Setup - -#### Di Google Cloud Console: -1. Buka: https://console.cloud.google.com/apis/credentials -2. Pilih project: "ch2ph2-project" atau yang sesuai -3. Klik Client ID yang digunakan -4. Verifikasi **Authorized JavaScript origins**: - ``` - https://ch2ph2-project.web.app - http://localhost:5173 - http://localhost:3000 - ``` -5. Verifikasi **Authorized redirect URIs**: - ``` - https://ch2ph2-project.web.app - https://ch2ph2-project.web.app/login - http://localhost:5173 - ``` - -### Step 3: Cek Backend Environment - -Di server Biznet Gio, pastikan `.env` memiliki: -```env -GOOGLE_CLIENT_ID=426382311425-flmdrhl6n7tmqcamg1lj8c8cmrkqgtpa.apps.googleusercontent.com -``` - -Atau di `ecosystem.config.js`: -```javascript -env: { - GOOGLE_CLIENT_ID: '426382311425-flmdrhl6n7tmqcamg1lj8c8cmrkqgtpa.apps.googleusercontent.com', - // ... env lainnya -} -``` - -### Step 4: Test Backend Endpoint - -Test endpoint Google Auth di backend: -```bash -curl -X POST https://dariusjoshua.shop/users/auth/google \ - -H "Content-Type: application/json" \ - -d '{"google_token":"SAMPLE_TOKEN"}' -``` - -Expected response (jika token invalid): -```json -{ - "message": "Invalid token" -} -``` - -## ๐Ÿšจ Common Errors - -### Error 1: "Popup closed by user" -**Cause:** User menutup popup Google OAuth -**Solution:** Normal behavior, user harus klik lagi - -### Error 2: "Invalid Google token" -**Cause:** Client ID tidak match antara frontend dan backend -**Solution:** -- Pastikan `VITE_GOOGLE_CLIENT_ID` di frontend sama dengan `GOOGLE_CLIENT_ID` di backend -- Restart backend setelah update .env - -### Error 3: "Origin not allowed" -**Cause:** Domain tidak terdaftar di Google Cloud Console -**Solution:** -1. Pergi ke Google Cloud Console -2. Tambahkan domain ke "Authorized JavaScript origins" -3. Tunggu beberapa menit untuk propagasi - -### Error 4: "Network error" -**Cause:** Backend tidak bisa diakses -**Solution:** -- Cek apakah backend running: `pm2 status` -- Cek logs: `pm2 logs Dummy-Instagrams` -- Test API: `curl https://dariusjoshua.shop/posts` - -## ๐Ÿงช Testing - -### Local Testing (Development) -```bash -cd client -npm run dev -``` -Akses: http://localhost:5173/login - -### Production Testing -Akses: https://ch2ph2-project.web.app/login - -### Test Accounts -Gunakan Google account pribadi Anda untuk test. - -## ๐Ÿ“ Console Logs - -Setelah perbaikan, di browser console akan muncul: -``` -Google Login Success: {credential: "eyJhbG...", clientId: "426382311425..."} -Sending Google token to backend... -Backend response: {access_token: "eyJhbGciOi..."} -``` - -Jika error: -``` -Google Login Error: Error: Request failed with status code 500 -Error response: {message: "Invalid token"} -``` - -## ๐Ÿ”„ Rebuild & Deploy - -Setiap kali update kode: -```bash -cd client -npm run build -firebase deploy -``` - -## โœจ What's Fixed - -โœ… Environment variables (.env file) -โœ… Better error handling with console.log -โœ… Improved error messages -โœ… .gitignore updated -โœ… .env.example for documentation -โœ… Styled Swal alerts - -## ๐Ÿ“ž Next Steps - -Jika masih ada masalah: -1. Share screenshot console error -2. Share screenshot Network tab (XHR request) -3. Cek backend logs: `pm2 logs Dummy-Instagrams --lines 100` diff --git a/READY_TO_DEPLOY.md b/READY_TO_DEPLOY.md deleted file mode 100644 index e2b5dc6..0000000 --- a/READY_TO_DEPLOY.md +++ /dev/null @@ -1,126 +0,0 @@ -# โœ… READY TO DEPLOY! - -## ๐ŸŽฏ Apa yang Sudah Selesai: - -### Backend: -- โœ… Fix error `profilePic` di chatController.js -- โœ… Fix error `profilePic` di postController.js -- โœ… Fix test files -- โœ… File `.env` sudah bersih (tanpa kode JS) -- โœ… Seeders folder sudah ditambahkan -- โœ… Posts data sudah include `isPrivate: false` -- โœ… **Database production SUDAH DI-SEED** dengan 5 posts, 5 users, dll - -### Frontend: -- โœ… Messages page dengan chat features -- โœ… StartChatModal untuk mulai chat dengan users -- โœ… AI Chat modal -- โœ… Premium UI dengan Bootstrap 5 -- โœ… BaseURL dikembalikan ke production: `https://dariusjoshua.shop` - -### Deployment: -- โœ… ecosystem.config.js sudah dikonfigurasi -- โœ… DEPLOY_NOW.md dengan instruksi lengkap -- โœ… DEPLOY_GUIDE.md untuk troubleshooting -- โœ… Semua code sudah di-push ke GitHub - ---- - -## ๐Ÿš€ DEPLOY SEKARANG! - -### Copy command ini di server Biznet Gio: - -```bash -cd /var/www/Dummy-Instagram && \ -git pull origin development && \ -npm install --production && \ -sudo pm2 start ecosystem.config.js -``` - -### Lalu cek logs: -```bash -sudo pm2 logs -``` - -### Save PM2 config (biar auto-start after reboot): -```bash -sudo pm2 save -sudo pm2 startup -``` - ---- - -## ๐ŸŽ‰ Test Setelah Deploy: - -1. **Test API:** - ```bash - curl https://dariusjoshua.shop/posts - ``` - Should return 5 posts! - -2. **Login ke Frontend:** - - URL: https://dariusjoshua.shop (atau domain frontend Anda) - - Email: `john@example.com` - - Password: `password123` - -3. **Test Features:** - - โœ… Feed dengan 5 posts - - โœ… Like posts - - โœ… Create new post - - โœ… Messages (chat dengan users) - - โœ… AI Chat - ---- - -## ๐Ÿ“Š Data yang Tersedia di Production: - -### Users (5): -- john@example.com / password123 -- jane@example.com / password123 -- mike@example.com / password123 -- sarah@example.com / password123 -- alex@example.com / password123 - -### Posts (5): -1. Beautiful sunset at the beach! ๐ŸŒ… -2. Delicious homemade pasta! ๐Ÿ -3. Exploring the streets of Tokyo ๐Ÿ—ผ -4. New collection dropping soon! ๐Ÿ‘— -5. Latest tech gadgets review ๐Ÿ“ฑ - -### Plus: -- 5 Categories -- Sample Likes -- Sample Chats & Messages - ---- - -## ๐Ÿ›Ÿ Jika Ada Masalah: - -### Backend tidak start: -```bash -sudo pm2 logs Dummy-Instagrams -# Lihat error apa yang muncul -``` - -### Port sudah dipakai: -```bash -sudo lsof -i :80 -sudo kill -9 -``` - -### Data tidak muncul: -Database sudah di-seed dari local, jadi seharusnya langsung ada data! - ---- - -## ๐Ÿ’ช You're All Set! - -Tinggal: -1. SSH ke server -2. Run command di atas -3. Done! ๐ŸŽŠ - -**Deployment time: ~2 menit** - -Good luck! ๐Ÿš€ diff --git a/app.js b/app.js index bd28be0..6a3b6a1 100644 --- a/app.js +++ b/app.js @@ -38,23 +38,23 @@ io.on('connection', (socket) => { socket.join(`chat_${chatId}`); }); - socket.on('send_message', (messageData) => { //comment untuk npx jest - io.to(`chat_${messageData.chatId}`).emit('new_message', messageData); - }); + // socket.on('send_message', (messageData) => { //comment untuk npx jest + // io.to(`chat_${messageData.chatId}`).emit('new_message', messageData); + // }); - socket.on('user_typing', (typingData) => { //comment untuk npx jest - io.to(`chat_${typingData.chatId}`).emit('typing_status', typingData); - }); + // socket.on('user_typing', (typingData) => { //comment untuk npx jest + // io.to(`chat_${typingData.chatId}`).emit('typing_status', typingData); + // }); - socket.on('disconnect', () => { //comment untuk npx jest - // console.log('โŒ User disconnected:', socket.id); - }); + // socket.on('disconnect', () => { //comment untuk npx jest + // // console.log('โŒ User disconnected:', socket.id); + // }); }); -if (process.env.NODE_ENV !== 'test') { //comment untuk npx jest - server.listen(port, () => { - console.log(`App listening on port http://localhost:${port}`); - }); -} +// if (process.env.NODE_ENV !== 'test') { //comment untuk npx jest +// server.listen(port, () => { +// console.log(`App listening on port http://localhost:${port}`); +// }); +// } module.exports = app; \ No newline at end of file diff --git a/client/.firebase/hosting.ZGlzdA.cache b/client/.firebase/hosting.ZGlzdA.cache index 62de020..2293ac6 100644 --- a/client/.firebase/hosting.ZGlzdA.cache +++ b/client/.firebase/hosting.ZGlzdA.cache @@ -1,5 +1,5 @@ vite.svg,1760631936123,699a02e0e68a579f687d364bbbe7633161244f35af068220aee37b1b33dfb3c7 -404.html,1760635348044,762bf484ba67404bd1a3b181546ea28d60dfddf18e9dd4795d8d25bcf3c1a890 index.html,1760637804203,ca4b78bd2c4b12b1beec3f63bb67f02a4be08af535e534a63dcfd77c4031a2eb +404.html,1760635348044,762bf484ba67404bd1a3b181546ea28d60dfddf18e9dd4795d8d25bcf3c1a890 assets/index-CIpsl6Aj.css,1760637804203,ec30b7cd4a9d868211d83512ac0b4b2899f1ce907c7981290b698e6c16eadff0 assets/index-BcBqiLfD.js,1760637804203,54dd37fa1f85e1692a72157d0d197ad4b9d652e293ca55f2dd04465c736c18d2 diff --git a/client/src/pages/Login.jsx b/client/src/pages/Login.jsx index 17331fd..3acee47 100644 --- a/client/src/pages/Login.jsx +++ b/client/src/pages/Login.jsx @@ -141,12 +141,10 @@ const Login = () => {
diff --git a/client/src/pages/Profile.jsx b/client/src/pages/Profile.jsx index 72ec052..739d339 100644 --- a/client/src/pages/Profile.jsx +++ b/client/src/pages/Profile.jsx @@ -107,29 +107,8 @@ const Profile = () => { backgroundSize: '400% 400%', animation: 'gradient 15s ease infinite' }}> - - {/* Header */} -
- -

{user?.username || 'Profile'}

- -
- - {/* Profile Info Card */} + + {/* Simple Header with Username */} { borderRadius: '20px', }} > - - - + +
+ +
{user?.username?.charAt(0).toUpperCase() || 'U'}
- - -

{user?.username || 'User'}

-

{user?.email || ''}

- - -
{posts.length}
-
Posts
- - -
0
-
Followers
- - -
0
-
Following
- -
- - +
+
{user?.username || 'My Posts'}
+ {posts.length} posts +
+
+ +
- {/* Tabs */} -
-
+
1 2 @@ -122,132 +122,132 @@

All files / Dummy-Instagram 57 58 59 -60

  -  -  -  -  -  -  +6011x +11x +11x +11x +11x +11x +11x   -  -  -  -  +11x +11x +11x +11x           -  +11x     -  -  -  -  +11x +11x +11x +11x     -  +11x       -  +11x     -  +11x     -  -  +8x +8x     -  -      -  -      -          -  -  -        - 
require('dotenv').config();
-const express = require('express');
-const app = express();
-const port = process.env.PORT || 3000;
-const handleError = require('./helpers/handleError');
-const routes = require('./routes');
-const cors = require('cors'); 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+ 
+11x
require('dotenv').config();
+const express = require('express');
+const app = express();
+const port = process.env.PORT || 3000;
+const handleError = require('./helpers/handleError');
+const routes = require('./routes');
+const cors = require('cors'); 
  
-const http = require('http');
-const server = http.createServer(app);
-const { Server } = require("socket.io");
-const io = new Server(server, {
+const http = require('http');
+const server = http.createServer(app);
+const { Server } = require("socket.io");
+const io = new Server(server, {
   cors: {
     origin: "*", 
   }
 });
  
-app.set('socketio', io); 
+app.set('socketio', io); 
  
 // Middleware
-app.use(cors()); 
-app.use(express.json());
-app.use(express.urlencoded({ extended: true }));
-app.use(express.static('public'));
+app.use(cors()); 
+app.use(express.json());
+app.use(express.urlencoded({ extended: true }));
+app.use(express.static('public'));
  
 // Router
-app.use("/", routes);
+app.use("/", routes);
  
  
 // Error handler
-app.use(handleError);
+app.use(handleError);
  
 // +++ Logika koneksi Socket.IO +++
-io.on('connection', (socket) => {
+io.on('connection', (socket) => {
   // console.log('โœ… User connected:', socket.id); //comment untuk npx jest
  
-  socket.on('join_chat', (chatId) => {
-    socket.join(`chat_${chatId}`);
+  socket.on('join_chat', (chatId) => {
+    socket.join(`chat_${chatId}`);
   });
  
-  socket.on('send_message', (messageData) => { //comment untuk npx jest
-    io.to(`chat_${messageData.chatId}`).emit('new_message', messageData); 
-  });
+  // socket.on('send_message', (messageData) => { //comment untuk npx jest
+  //   io.to(`chat_${messageData.chatId}`).emit('new_message', messageData); 
+  // });
  
-  socket.on('user_typing', (typingData) => { //comment untuk npx jest
-    io.to(`chat_${typingData.chatId}`).emit('typing_status', typingData); 
-  });
+  // socket.on('user_typing', (typingData) => { //comment untuk npx jest
+  //   io.to(`chat_${typingData.chatId}`).emit('typing_status', typingData); 
+  // });
  
-  socket.on('disconnect', () => { //comment untuk npx jest
-    // console.log('โŒ User disconnected:', socket.id); 
-  });
+  // socket.on('disconnect', () => { //comment untuk npx jest
+  //   // console.log('โŒ User disconnected:', socket.id); 
+  // });
 });
  
-if (process.env.NODE_ENV !== 'test') { //comment untuk npx jest
-  server.listen(port, () => {
-    console.log(`App listening on port http://localhost:${port}`);
-  });
-}
+// if (process.env.NODE_ENV !== 'test') { //comment untuk npx jest
+//   server.listen(port, () => {
+//     console.log(`App listening on port http://localhost:${port}`);
+//   });
+// }
  
-module.exports = app;
+module.exports = app;

+ + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/config/index.html b/coverage/lcov-report/config/index.html new file mode 100644 index 0000000..0339b44 --- /dev/null +++ b/coverage/lcov-report/config/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for config + + + + + + + + + +
+
+

All files config

+
+ +
+ 100% + Statements + 4/4 +
+ + +
+ 50% + Branches + 2/4 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 4/4 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
config.js +
+
100%4/450%2/4100%0/0100%4/4
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/controllers/aiController.js.html b/coverage/lcov-report/controllers/aiController.js.html new file mode 100644 index 0000000..af18c9a --- /dev/null +++ b/coverage/lcov-report/controllers/aiController.js.html @@ -0,0 +1,166 @@ + + + + + + Code coverage report for controllers/aiController.js + + + + + + + + + +
+
+

All files / controllers aiController.js

+
+ +
+ 100% + Statements + 12/12 +
+ + +
+ 100% + Branches + 4/4 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 11/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +283x +  +  +  +2x +2x +1x +  +  +1x +1x +  +1x +  +1x +  +  +  +  +  +1x +1x +  +  +  +  +3x + 
const { getAIRecommendations } = require("../helpers/aiRecommendation");
+ 
+class AIController {
+  static async getRecommendations(req, res, next) {
+    try {
+      if (!req.user || !req.user.id) {
+        throw { name: "Unauthorized" };
+      }
+ 
+      const userId = req.user.id;
+      const posts = await getAIRecommendations(userId);
+ 
+      const plainPosts = posts.map(post => post.toJSON());
+ 
+      res.status(200).json({
+        message: "Rekomendasi berhasil dibuat",
+        count: plainPosts.length,
+        data: plainPosts,
+      });
+    } catch (err) {
+      console.error("Error in AIController:", err.message);
+      next(err);
+    }
+  }
+}
+ 
+module.exports = AIController;
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/controllers/chatController.js.html b/coverage/lcov-report/controllers/chatController.js.html new file mode 100644 index 0000000..5ed81c1 --- /dev/null +++ b/coverage/lcov-report/controllers/chatController.js.html @@ -0,0 +1,556 @@ + + + + + + Code coverage report for controllers/chatController.js + + + + + + + + + +
+
+

All files / controllers chatController.js

+
+ +
+ 100% + Statements + 52/52 +
+ + +
+ 100% + Branches + 19/19 +
+ + +
+ 100% + Functions + 5/5 +
+ + +
+ 100% + Lines + 52/52 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +1583x +3x +3x +  +  +  +  +4x +4x +4x +  +4x +1x +  +  +  +3x +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +2x +  +  +  +  +  +2x +2x +2x +  +  +  +  +  +  +  +  +  +  +1x +  +1x +1x +  +  +  +  +  +4x +4x +4x +  +  +4x +3x +2x +  +  +1x +  +  +  +  +  +1x +  +3x +  +  +  +  +3x +3x +3x +  +  +  +  +  +  +  +  +  +  +2x +  +1x +  +  +  +  +  +5x +5x +5x +5x +5x +  +5x +5x +1x +  +  +4x +4x +1x +  +  +  +3x +  +  +  +  +2x +  +  +2x +  +1x +  +  +1x +  +  +  +  +  +  +1x +  +  +1x +  +  +  +1x +  +  +  +3x +  +  +  +  +3x
const { Chat, Message, User, Sequelize } = require("../models");
+const { Op } = Sequelize;
+const { askGemini } = require("../helpers/aiHelper");
+ 
+class ChatController {
+    // Mencegah duplikasi chat
+    static async createOrGetChat(req, res, next) {
+        try {
+            const { partnerId } = req.body;
+            const userId = req.user.id;
+ 
+            if (partnerId == userId) { //  Validasi agar tidak chat dengan diri sendiri
+                throw { name: "BadRequest", message: "You cannot create a chat with yourself." };
+            }
+ 
+            // Cari chat yang sudah ada antara kedua user
+            const [chat, created] = await Chat.findOrCreate({
+                where: {
+                    [Op.or]: [
+                        { UserId: userId, partnerId: partnerId },
+                        { UserId: partnerId, partnerId: userId },
+                    ],
+                    isAIChat: false
+                },
+                defaults: {
+                    UserId: userId,
+                    partnerId: partnerId,
+                },
+            });
+ 
+            res.status(created ? 201 : 200).json(chat);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // Menampilkan semua chat dimana user terlibat
+    static async getUserChats(req, res, next) {
+        try {
+            const userId = req.user.id;
+            const chats = await Chat.findAll({
+                where: {
+                    [Op.or]: [{ UserId: userId }, { partnerId: userId }],
+                },
+                include: [
+                    { model: User, as: "creator", attributes: ["id", "username", "email"], required: false },
+                    { model: User, as: "partner", attributes: ["id", "username", "email"], required: false },
+                ],
+                order: [["updatedAt", "DESC"]],
+            });
+ 
+            res.json(chats);
+        } catch (err) {
+            console.error('Error in getUserChats:', err);
+            next(err);
+        }
+    }
+ 
+    // Menambahkan validasi keamanan
+    static async getChatMessages(req, res, next) {
+        try {
+            const { chatId } = req.params;
+            const userId = req.user.id;
+ 
+            // Validasi: Pastikan user adalah bagian dari chat ini
+            const chat = await Chat.findByPk(chatId);
+            if (!chat || (chat.UserId !== userId && chat.partnerId !== userId)) {
+                throw { name: "Forbidden" };
+            }
+ 
+            const messages = await Message.findAll({
+                where: { ChatId: chatId },
+                include: [{ model: User, as: "sender", attributes: ["id", "username"] }],
+                order: [["createdAt", "ASC"]],
+            });
+ 
+            res.json(messages);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    static async createAIChat(req, res, next) {
+        try {
+            const userId = req.user.id;
+            const [chat, created] = await Chat.findOrCreate({
+                where: {
+                    UserId: userId,
+                    isAIChat: true,
+                },
+                defaults: {
+                    UserId: userId,
+                    isAIChat: true,
+                    partnerId: null, // Tidak ada partner untuk AI chat
+                },
+            });
+            res.status(created ? 201 : 200).json(chat);
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    // Menambahkan validasi keamanan & menyederhanakan
+    static async sendMessage(req, res, next) {
+        try {
+            const { chatId } = req.params;
+            const { content } = req.body;
+            const userId = req.user.id;
+            const io = req.app.get("socketio");
+ 
+            const chat = await Chat.findByPk(chatId);
+            if (!chat) {
+                throw { name: "NotFound", message: "Chat not found" };
+            }
+ 
+            const isAuthorized = chat.UserId === userId || chat.partnerId === userId;
+            if (!isAuthorized) {
+                throw { name: "Forbidden", message: "You are not authorized to access this chat" };
+            }
+ 
+            // Pesan dari user tetap dibuat
+            const userMessage = await Message.create({
+                ChatId: chatId,
+                senderId: userId,
+                content,
+            });
+            io.to(`chat_${chatId}`).emit("receive_message", userMessage);
+ 
+            // --- PERUBAHAN UTAMA UNTUK POSTMAN ---
+            if (chat.isAIChat) {
+                // 1. Panggil Gemini dan TUNGGU (await) sampai ada jawaban
+                const aiResponseText = await askGemini(content);
+ 
+                // 2. Simpan jawaban AI ke database
+                const aiMessage = await Message.create({
+                    ChatId: chatId,
+                    senderId: null, // AI tidak punya ID
+                    content: aiResponseText,
+                });
+ 
+                // 3. Kirim juga jawaban AI via socket untuk klien web
+                io.to(`chat_${chatId}`).emit("receive_message", aiMessage);
+ 
+                // 4. Kirim JAWABAN AI sebagai respons HTTP ke Postman
+                return res.status(201).json(aiMessage);
+ 
+            } else {
+                // Untuk chat biasa, kembalikan pesan user seperti biasa
+                return res.status(201).json(userMessage);
+            }
+ 
+        } catch (err) {
+            next(err);
+        }
+    }
+}
+ 
+module.exports = ChatController;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/controllers/index.html b/coverage/lcov-report/controllers/index.html new file mode 100644 index 0000000..c1e834d --- /dev/null +++ b/coverage/lcov-report/controllers/index.html @@ -0,0 +1,161 @@ + + + + + + Code coverage report for controllers + + + + + + + + + +
+
+

All files controllers

+
+ +
+ 100% + Statements + 159/159 +
+ + +
+ 100% + Branches + 49/49 +
+ + +
+ 100% + Functions + 17/17 +
+ + +
+ 100% + Lines + 154/154 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
aiController.js +
+
100%12/12100%4/4100%2/2100%11/11
chatController.js +
+
100%52/52100%19/19100%5/5100%52/52
postController.js +
+
100%63/63100%18/18100%7/7100%59/59
userController.js +
+
100%32/32100%8/8100%3/3100%32/32
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/controllers/postController.js.html b/coverage/lcov-report/controllers/postController.js.html new file mode 100644 index 0000000..e2e4b15 --- /dev/null +++ b/coverage/lcov-report/controllers/postController.js.html @@ -0,0 +1,535 @@ + + + + + + Code coverage report for controllers/postController.js + + + + + + + + + +
+
+

All files / controllers postController.js

+
+ +
+ 100% + Statements + 63/63 +
+ + +
+ 100% + Branches + 18/18 +
+ + +
+ 100% + Functions + 7/7 +
+ + +
+ 100% + Lines + 59/59 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +1513x +  +  +  +  +3x +3x +3x +  +  +3x +1x +  +  +  +2x +  +  +  +  +  +  +  +  +2x +  +  +  +  +1x +  +1x +  +  +  +  +  +2x +  +  +  +  +  +2x +2x +  +  +  +  +  +  +  +  +  +1x +  +1x +  +  +  +  +  +2x +2x +  +  +  +  +1x +  +1x +  +  +  +  +  +4x +4x +4x +  +4x +4x +3x +  +2x +1x +  +3x +  +  +  +  +  +4x +4x +  +4x +4x +  +4x +4x +1x +1x +  +  +3x +3x +  +  +3x +1x +1x +  +  +2x +1x +1x +  +3x +3x +  +  +  +  +  +4x +4x +4x +3x +  +2x +  +  +  +  +2x +1x +1x +  +1x +1x +  +2x +  +2x +  +  +  +  +3x + 
const { Post, Image, Like, User, Category } = require("../models");
+ 
+class PostController {
+  // CREATE POST 
+  static async createPost(req, res, next) {
+    try {
+      const { content, isPrivate, categoryId } = req.body;
+      const UserId = req.user.id; 
+      // 1. Validasi: pastikan ada setidaknya 1 gambar
+      // Jika upload gagal di Multer (misalnya tidak ada file), error akan di-catch oleh handleError
+      if (!req.files || req.files.length === 0) {
+        throw { name: "BadRequest", message: "At least one image is required to create a post." };
+      }
+ 
+      // 2. Buat postingan baru di database
+      const post = await Post.create({
+        content,
+        // Konversi string 'true'/'false' ke boolean
+        isPrivate: isPrivate === 'true' || isPrivate === true, // handle both string and actual boolean if any
+        CategoryId: categoryId,
+        UserId,
+      });
+ 
+      // 3. Ambil URL gambar dari req.files (yang sudah diunggah oleh multer-storage-cloudinary)
+      const imagesToCreate = req.files.map((file) => ({
+        imageUrl: file.path, 
+        PostId: post.id,
+      }));
+ 
+      await Image.bulkCreate(imagesToCreate);
+ 
+      res.status(201).json({ 
+        message: "Post created successfully", 
+        post, 
+        images: imagesToCreate 
+      }); 
+    } catch (err) {
+      next(err);
+    }
+  }
+ 
+  // READ ALL PUBLIC POSTS
+  static async getAllPublicPosts(req, res, next) {
+    try {
+      const posts = await Post.findAll({
+        where: { isPrivate: false },
+        include: [
+          { model: User, attributes: ["id", "username", "email"] },
+          { model: Image },
+          { model: Category, attributes: ["name"] },
+          { model: Like },
+        ],
+        order: [["createdAt", "DESC"]],
+      });
+      res.json(posts);
+    } catch (err) {
+      next(err);
+    }
+  }
+ 
+  // READ USER'S OWN POSTS
+  static async getMyPosts(req, res, next) {
+    try {
+      const posts = await Post.findAll({
+        where: { UserId: req.user.id },
+        include: [Image, Category, Like],
+        order: [["createdAt", "DESC"]],
+      });
+      res.json(posts);
+    } catch (err) {
+      next(err);
+    }
+  }
+ 
+  // UPDATE POST
+  static async updatePost(req, res, next) {
+    try {
+      const { id } = req.params;
+      const { content, isPrivate, categoryId } = req.body;
+ 
+      const post = await Post.findByPk(id);
+      if (!post) throw { name: "NotFound" };
+      if (post.UserId !== req.user.id) throw { name: "Unauthorized" };
+ 
+      await post.update({ content, isPrivate, CategoryId: categoryId });
+      res.json({ message: "Post updated successfully", post });
+    } catch (err) {
+      next(err);
+    }
+  }
+ 
+  // DELETE POST
+  static async deletePost(req, res, next) {
+    try {
+      const { id } = req.params;
+      
+      console.log('Delete request for post:', id);
+      console.log('User ID from token:', req.user?.id);
+      
+      const post = await Post.findByPk(id);
+      if (!post) {
+        console.log('Post not found:', id);
+        throw { name: "NotFound" };
+      }
+      
+      console.log('Post UserId:', post.UserId, typeof post.UserId);
+      console.log('Request User Id:', req.user.id, typeof req.user.id);
+      
+      // Use == instead of === to handle potential type mismatch
+      if (post.UserId != req.user.id) {
+        console.log('Unauthorized: User does not own this post');
+        throw { name: "Unauthorized" };
+      }
+ 
+      await post.destroy();
+      console.log('Post deleted successfully:', id);
+      res.json({ message: "Post deleted successfully" });
+    } catch (err) {
+      console.error('Error in deletePost:', err);
+      next(err);
+    }
+  }
+ 
+  // LIKE / UNLIKE POST
+  static async toggleLike(req, res, next) {
+    try {
+      const { id } = req.params;
+      const post = await Post.findByPk(id);
+      if (!post) throw { name: "NotFound" };
+ 
+      const existingLike = await Like.findOne({
+        where: { UserId: req.user.id, PostId: id },
+      });
+ 
+      let message;
+      if (existingLike) {
+        await existingLike.destroy();
+        message = "Post unliked";
+      } else {
+        await Like.create({ UserId: req.user.id, PostId: id });
+        message = "Post liked";
+      }
+      res.json({ message });
+    } catch (err) {
+      next(err);
+    }
+  }
+}
+ 
+module.exports = PostController;
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/controllers/userController.js.html b/coverage/lcov-report/controllers/userController.js.html new file mode 100644 index 0000000..ab99bb7 --- /dev/null +++ b/coverage/lcov-report/controllers/userController.js.html @@ -0,0 +1,310 @@ + + + + + + Code coverage report for controllers/userController.js + + + + + + + + + +
+
+

All files / controllers userController.js

+
+ +
+ 100% + Statements + 32/32 +
+ + +
+ 100% + Branches + 8/8 +
+ + +
+ 100% + Functions + 3/3 +
+ + +
+ 100% + Lines + 32/32 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +763x +3x +3x +3x +3x +  +  +  +  +2x +2x +2x +1x +  +  +  +  +  +1x +  +  +  +  +5x +5x +5x +1x +  +  +4x +3x +1x +  +  +2x +2x +1x +  +  +1x +1x +  +4x +  +  +  +  +2x +2x +  +2x +  +  +  +1x +  +1x +  +  +  +  +  +  +  +  +  +1x +1x +  +  +1x +  +  +  +  +3x
const { User } = require('../models');
+const bcrypt = require('bcryptjs');
+const { signToken } = require('../helpers/jwt');
+const { OAuth2Client } = require('google-auth-library');
+const client = new OAuth2Client();
+ 
+ 
+class UserController {
+    static async register(req, res, next) {
+        try {
+            const { username, email, password } = req.body;
+            const newUser = await User.create({ username, email, password });
+            res.status(201).json({
+                id: newUser.id,
+                username: newUser.username,
+                email: newUser.email,
+            });
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    static async login(req, res, next) {
+        try {
+            const { email, password } = req.body;
+            if (!email || !password) {
+                throw { name: 'BadRequest', message: 'Email and password are required' };
+            }
+ 
+            const user = await User.findOne({ where: { email } });
+            if (!user) {
+                throw { name: 'InvalidLogin' };
+            }
+ 
+            const isPasswordValid = bcrypt.compareSync(password, user.password);
+            if (!isPasswordValid) {
+                throw { name: 'InvalidLogin' };
+            }
+ 
+            const token = signToken({ id: user.id });
+            res.status(200).json({ access_token: token });
+        } catch (err) {
+            next(err);
+        }
+    }
+ 
+    static async googleSignIn(req, res, next) {
+        try {
+            const { google_token } = req.body;
+ 
+            const ticket = await client.verifyIdToken({
+                idToken: google_token,
+                audience: process.env.GOOGLE_CLIENT_ID,
+            });
+            const payload = ticket.getPayload();
+ 
+            const [user, created] = await User.findOrCreate({
+                where: { email: payload.email },
+                defaults: {
+                    username: payload.name,
+                    email: payload.email,
+                    password: Math.random().toString(36),
+                },
+                hooks: false
+            });
+ 
+            const access_token = signToken({ id: user.id });
+            res.status(200).json({ access_token });
+ 
+        } catch (err) {
+            next(err);
+        }
+    }
+}
+ 
+module.exports = UserController;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/helpers/aiHelper.js.html b/coverage/lcov-report/helpers/aiHelper.js.html new file mode 100644 index 0000000..1566cf4 --- /dev/null +++ b/coverage/lcov-report/helpers/aiHelper.js.html @@ -0,0 +1,190 @@ + + + + + + Code coverage report for helpers/aiHelper.js + + + + + + + + + +
+
+

All files / helpers aiHelper.js

+
+ +
+ 100% + Statements + 11/11 +
+ + +
+ 100% + Branches + 1/1 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 11/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +368x +  +8x +8x +  +  +  +4x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +3x +3x +2x +2x +  +1x +1x +  +  +  +8x + 
const { GoogleGenerativeAI } = require("@google/generative-ai");
+ 
+const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
+const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash" });
+ 
+// cleaning text function
+function cleanText(text = "") {
+  return text
+    // Hapus seluruh baris heading markdown dan pemisah
+    .replace(/^#+\s?.*$/gm, "")     
+    .replace(/---+/g, " ")         
+    // Hapus bullet dan angka daftar
+    .replace(/^\s*\d+\.\s*/gm, "") 
+    .replace(/^\s*-\s*/gm, "")     
+    .replace(/\*/g, "")            
+    // Hapus kutipan berlebih
+    .replace(/["โ€œโ€โ€˜โ€™]/g, '"')      
+    // Rapikan whitespace
+    .replace(/\r?\n+/g, " ")       
+    .replace(/\s{2,}/g, " ")       
+    .trim();
+}
+ 
+async function askGemini(prompt) {
+  try {
+    const result = await model.generateContent(prompt);
+    const rawText = result.response.text();
+    return cleanText(rawText);
+  } catch (err) {
+    console.error("โŒ Error from Gemini:", err);
+    return "Maaf, saya mengalami kesulitan menjawab saat ini.";
+  }
+}
+ 
+module.exports = { askGemini, cleanText };
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/helpers/aiRecommendation.js.html b/coverage/lcov-report/helpers/aiRecommendation.js.html new file mode 100644 index 0000000..b938f51 --- /dev/null +++ b/coverage/lcov-report/helpers/aiRecommendation.js.html @@ -0,0 +1,430 @@ + + + + + + Code coverage report for helpers/aiRecommendation.js + + + + + + + + + +
+
+

All files / helpers aiRecommendation.js

+
+ +
+ 89.47% + Statements + 34/38 +
+ + +
+ 85.71% + Branches + 12/14 +
+ + +
+ 100% + Functions + 5/5 +
+ + +
+ 89.18% + Lines + 33/37 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +1167x +7x +7x +  +  +4x +4x +4x +  +  +  +  +  +  +  +  +  +4x +  +  +  +  +3x +1x +  +  +  +  +  +  +  +6x +  +2x +2x +4x +4x +  +  +2x +  +  +  +  +  +  +  +  +2x +2x +  +2x +  +2x +  +2x +4x +  +  +2x +  +  +  +  +  +  +  +2x +2x +  +2x +  +  +  +  +2x +  +  +2x +  +  +2x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +2x +  +1x +  +1x +1x +  +  +  +  +  +  +  +  +  +  +  +  +7x + 
const { GoogleGenerativeAI } = require("@google/generative-ai");
+const { Post, Like, Category, User, Image } = require("../models");
+const { Op } = require("sequelize");
+ 
+async function getAIRecommendations(userId) {
+  try {
+    const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
+    const model = genAI.getGenerativeModel({ 
+      model: "gemini-2.0-flash-exp",
+      generationConfig: {
+        temperature: 0.1,
+        topP: 0.9,
+        topK: 10,
+        maxOutputTokens: 50,
+      }
+    });
+ 
+    const likedPosts = await Like.findAll({
+      where: { UserId: userId },
+      include: [{ model: Post, include: [Category] }],
+    });
+ 
+    if (!likedPosts || likedPosts.length < 3) {
+      return await Post.findAll({
+        where: { isPrivate: false },
+        include: [Category, User, Like, Image],
+        order: [["createdAt", "DESC"]],
+        limit: 10,
+      });
+    }
+ 
+    const validPosts = likedPosts.filter(like => like.Post && like.Post.Category);
+    
+    const categoryCount = {};
+    validPosts.forEach(like => {
+      const categoryName = like.Post.Category.name;
+      categoryCount[categoryName] = (categoryCount[categoryName] || 0) + 1;
+    });
+ 
+    Iif (Object.keys(categoryCount).length === 0) {
+      return await Post.findAll({
+        where: { isPrivate: false },
+        include: [Category, User, Like, Image],
+        order: [["createdAt", "DESC"]],
+        limit: 10,
+      });
+    }
+ 
+    const sortedCategories = Object.entries(categoryCount)
+      .sort((a, b) => b[1] - a[1]);
+ 
+    const topCategory = sortedCategories[0][0];
+ 
+    const availableCategories = ["Travel", "Food", "Fashion", "Technology", "Lifestyle"];
+ 
+    const categoryStats = sortedCategories
+      .map(([cat, count]) => `${cat}:${count}`)
+      .join(', ');
+ 
+    const prompt = `User liked these categories with counts: ${categoryStats}
+ 
+Available categories: Travel, Food, Fashion, Technology, Lifestyle
+ 
+Return only 1 most relevant category for recommendations.
+Only use categories from the available list.
+Format: CategoryName`;
+ 
+    const result = await model.generateContent(prompt);
+    const aiResponse = result.response.text().trim();
+    
+    let aiCategory = aiResponse
+      .replace(/['"]/g, '')
+      .trim();
+ 
+    let finalCategory;
+    Iif (aiCategory && availableCategories.includes(aiCategory)) {
+      finalCategory = aiCategory;
+    } else {
+      finalCategory = topCategory;
+    }
+    
+    const recommendedPosts = await Post.findAll({
+      where: {
+        isPrivate: false,
+        UserId: { [Op.ne]: userId },
+      },
+      include: [
+        { model: Category, where: { name: finalCategory } },
+        User,
+        Like,
+        Image
+      ],
+      order: [["createdAt", "DESC"]],
+      limit: 20,
+    });
+    
+    return recommendedPosts;
+  } catch (err) {
+    console.error("Error in AI recommendations:", err.message);
+    
+    try {
+      return await Post.findAll({
+        where: { isPrivate: false },
+        include: [Category, User, Like, Image],
+        order: [["createdAt", "DESC"]],
+        limit: 10,
+      });
+    } catch (fallbackErr) {
+      console.error("Fallback failed:", fallbackErr.message);
+      return [];
+    }
+  }
+}
+ 
+module.exports = { getAIRecommendations };
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/helpers/authMiddleware.js.html b/coverage/lcov-report/helpers/authMiddleware.js.html new file mode 100644 index 0000000..231948a --- /dev/null +++ b/coverage/lcov-report/helpers/authMiddleware.js.html @@ -0,0 +1,169 @@ + + + + + + Code coverage report for helpers/authMiddleware.js + + + + + + + + + +
+
+

All files / helpers authMiddleware.js

+
+ +
+ 100% + Statements + 20/20 +
+ + +
+ 100% + Branches + 10/10 +
+ + +
+ 100% + Functions + 1/1 +
+ + +
+ 100% + Lines + 19/19 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +296x +6x +  +6x +6x +6x +6x +2x +  +  +4x +4x +3x +2x +  +1x +1x +1x +  +5x +3x +2x +1x +  +1x +  +  +  + 
const { verifyToken } = require("./jwt");
+const { User } = require("../models");
+ 
+module.exports = async function authMiddleware(req, res, next) {
+  try {
+    const tokenHeader = req.headers.authorization;
+    if (!tokenHeader || !tokenHeader.startsWith("Bearer ")) {
+      throw { name: "Unauthorized", message: "Please login first" };
+    }
+ 
+    const token = tokenHeader.split(" ")[1];
+    const decoded = verifyToken(token);
+    const user = await User.findByPk(decoded.id);
+    if (!user) throw { name: "Unauthorized", message: "User not found" };
+ 
+    req.user = user;
+    req.userId = decoded.id;
+    next();
+  } catch (err) {
+    if (err.name === "Unauthorized") {
+      next(err);
+    } else if (err.message === "Database error") {
+      next({ name: "Internal Server Error", message: err.message });
+    } else {
+      next({ name: "Unauthorized", message: "Please login first" });
+    }
+  }
+};
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/helpers/cloudinary.js.html b/coverage/lcov-report/helpers/cloudinary.js.html new file mode 100644 index 0000000..04463ce --- /dev/null +++ b/coverage/lcov-report/helpers/cloudinary.js.html @@ -0,0 +1,148 @@ + + + + + + Code coverage report for helpers/cloudinary.js + + + + + + + + + +
+
+

All files / helpers cloudinary.js

+
+ +
+ 100% + Statements + 7/7 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 7/7 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +225x +5x +5x +  +5x +  +  +  +  +  +5x +  +  +  +  +  +  +  +  +5x +  +5x
const cloudinary = require("cloudinary").v2;
+const { CloudinaryStorage } = require("multer-storage-cloudinary");
+const multer = require("multer");
+ 
+cloudinary.config({
+    cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
+    api_key: process.env.CLOUDINARY_API_KEY,
+    api_secret: process.env.CLOUDINARY_API_SECRET,
+});
+ 
+const storage = new CloudinaryStorage({
+    cloudinary,
+    params: {
+        folder: "DummyInstagram_Posts",
+        allowed_formats: ["jpg", "png", "jpeg"],
+        transformation: [{ quality: "auto", fetch_format: "auto" }],
+    },
+});
+ 
+const upload = multer({ storage });
+ 
+module.exports = upload;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/helpers/handleError.js.html b/coverage/lcov-report/helpers/handleError.js.html new file mode 100644 index 0000000..950d4ed --- /dev/null +++ b/coverage/lcov-report/helpers/handleError.js.html @@ -0,0 +1,175 @@ + + + + + + Code coverage report for helpers/handleError.js + + + + + + + + + +
+
+

All files / helpers handleError.js

+
+ +
+ 100% + Statements + 15/15 +
+ + +
+ 100% + Branches + 14/14 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 14/14 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31  +8x +  +8x +1x +  +  +7x +1x +  +  +6x +1x +  +  +5x +2x +  +  +3x +3x +2x +  +  +1x +  +  +  +  +3x + 
function handleError(err, req,res, next) {
+  console.error("Error:", err);
+ 
+  if (err.name === "Unauthorized") {
+    return res.status(401).json({ message: "Unauthorized access" });
+  }
+ 
+  if (err.name === "InvalidLogin") {
+    return res.status(401).json({ message: "Invalid email or password" });
+  }
+ 
+  if (err.name === "NotFound") {
+    return res.status(404).json({ message: "Data not found" });
+  }
+ 
+  if (err.name === "BadRequest") {
+    return res.status(400).json({ message: err.message || "Bad request" });
+  }
+ 
+  if (err.name === "SequelizeValidationError" || err.name === "SequelizeUniqueConstraintError") {
+    const messages = err.errors.map(e => e.message);
+    return res.status(400).json({ message: messages });
+  }
+ 
+  return res.status(500).json({
+    message: "Internal Server Error",
+  });
+}
+ 
+module.exports = handleError;
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/helpers/index.html b/coverage/lcov-report/helpers/index.html new file mode 100644 index 0000000..839cbd2 --- /dev/null +++ b/coverage/lcov-report/helpers/index.html @@ -0,0 +1,191 @@ + + + + + + Code coverage report for helpers + + + + + + + + + +
+
+

All files helpers

+
+ +
+ 95.83% + Statements + 92/96 +
+ + +
+ 94.87% + Branches + 37/39 +
+ + +
+ 100% + Functions + 12/12 +
+ + +
+ 95.69% + Lines + 89/93 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
aiHelper.js +
+
100%11/11100%1/1100%2/2100%11/11
aiRecommendation.js +
+
89.47%34/3885.71%12/14100%5/589.18%33/37
authMiddleware.js +
+
100%20/20100%10/10100%1/1100%19/19
cloudinary.js +
+
100%7/7100%0/0100%0/0100%7/7
handleError.js +
+
100%15/15100%14/14100%2/2100%14/14
jwt.js +
+
100%5/5100%0/0100%2/2100%5/5
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/helpers/jwt.js.html b/coverage/lcov-report/helpers/jwt.js.html new file mode 100644 index 0000000..1c9c217 --- /dev/null +++ b/coverage/lcov-report/helpers/jwt.js.html @@ -0,0 +1,118 @@ + + + + + + Code coverage report for helpers/jwt.js + + + + + + + + + +
+
+

All files / helpers jwt.js

+
+ +
+ 100% + Statements + 5/5 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 5/5 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +1210x +10x +  +  +1x +  +  +  +2x +  +  +10x
const jwt = require('jsonwebtoken');
+const secret = process.env.JWT_SECRET;
+ 
+function signToken(payload) {
+  return jwt.sign(payload, secret);
+}
+ 
+function verifyToken(token) {
+  return jwt.verify(token, secret);
+}
+ 
+module.exports = { signToken, verifyToken };
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/index.html b/coverage/lcov-report/index.html index f68540c..fe4627f 100644 --- a/coverage/lcov-report/index.html +++ b/coverage/lcov-report/index.html @@ -23,9 +23,9 @@

All files

- 98.49% + 98.95% Statements - 393/399 + 379/383
@@ -44,9 +44,9 @@

All files

- 98.46% + 98.92% Lines - 385/391 + 369/373
@@ -114,28 +114,28 @@

All files

100% - 159/159 + 149/149 100% 49/49 100% 17/17 100% - 154/154 + 144/144 Dummy-Instagram/helpers - -
+ +
- 95.83% - 92/96 + 97.77% + 88/90 94.87% 37/39 100% 12/12 - 95.69% - 89/93 + 97.64% + 83/85 @@ -176,7 +176,7 @@

All files

+ + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/chat.js.html b/coverage/lcov-report/models/chat.js.html new file mode 100644 index 0000000..4ee4b5e --- /dev/null +++ b/coverage/lcov-report/models/chat.js.html @@ -0,0 +1,166 @@ + + + + + + Code coverage report for models/chat.js + + + + + + + + + +
+
+

All files / models chat.js

+
+ +
+ 100% + Statements + 7/7 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 7/7 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28  +  +  +12x +12x +  +  +  +  +  +  +  +12x +12x +12x +  +  +  +12x +  +  +  +  +  +  +  +12x + 
'use strict';
+const {
+  Model
+} = require('sequelize');
+module.exports = (sequelize, DataTypes) => {
+  class Chat extends Model {
+    /**
+     * Helper method for defining associations.
+     * This method is not a part of Sequelize lifecycle.
+     * The `models/index` file will call this method automatically.
+     */
+    static associate(models) {
+      Chat.belongsTo(models.User, { as: "creator", foreignKey: "UserId" }); 
+      Chat.belongsTo(models.User, { as: "partner", foreignKey: "partnerId" });
+      Chat.hasMany(models.Message);
+    }
+ 
+  }
+  Chat.init({
+    isAIChat: DataTypes.BOOLEAN,
+    UserId: DataTypes.INTEGER,
+    partnerId: DataTypes.INTEGER
+  }, {
+    sequelize,
+    modelName: 'Chat',
+  });
+  return Chat;
+};
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/image.js.html b/coverage/lcov-report/models/image.js.html new file mode 100644 index 0000000..e9b73cf --- /dev/null +++ b/coverage/lcov-report/models/image.js.html @@ -0,0 +1,157 @@ + + + + + + Code coverage report for models/image.js + + + + + + + + + +
+
+

All files / models image.js

+
+ +
+ 100% + Statements + 5/5 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 5/5 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25  +  +  +12x +12x +  +  +  +  +  +  +  +12x +  +  +  +12x +  +  +  +  +  +  +12x + 
'use strict';
+const {
+  Model
+} = require('sequelize');
+module.exports = (sequelize, DataTypes) => {
+  class Image extends Model {
+    /**
+     * Helper method for defining associations.
+     * This method is not a part of Sequelize lifecycle.
+     * The `models/index` file will call this method automatically.
+     */
+    static associate(models) {
+      Image.belongsTo(models.Post);
+    }
+ 
+  }
+  Image.init({
+    imageUrl: DataTypes.STRING,
+    PostId: DataTypes.INTEGER
+  }, {
+    sequelize,
+    modelName: 'Image',
+  });
+  return Image;
+};
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/index.html b/coverage/lcov-report/models/index.html new file mode 100644 index 0000000..d20e961 --- /dev/null +++ b/coverage/lcov-report/models/index.html @@ -0,0 +1,221 @@ + + + + + + Code coverage report for models + + + + + + + + + +
+
+

All files models

+
+ +
+ 97.18% + Statements + 69/71 +
+ + +
+ 70% + Branches + 7/10 +
+ + +
+ 94.44% + Functions + 17/18 +
+ + +
+ 97.18% + Lines + 69/71 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
category.js +
+
100%5/5100%0/0100%2/2100%5/5
chat.js +
+
100%7/7100%0/0100%2/2100%7/7
image.js +
+
100%5/5100%0/0100%2/2100%5/5
index.js +
+
95.23%20/2170%7/10100%3/395.23%20/21
like.js +
+
100%6/6100%0/0100%2/2100%6/6
message.js +
+
100%7/7100%0/0100%2/2100%7/7
post.js +
+
100%8/8100%0/0100%2/2100%8/8
user.js +
+
91.66%11/12100%0/066.66%2/391.66%11/12
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/index.js.html b/coverage/lcov-report/models/index.js.html new file mode 100644 index 0000000..47e4560 --- /dev/null +++ b/coverage/lcov-report/models/index.js.html @@ -0,0 +1,214 @@ + + + + + + Code coverage report for models/index.js + + + + + + + + + +
+
+

All files / models index.js

+
+ +
+ 95.23% + Statements + 20/21 +
+ + +
+ 70% + Branches + 7/10 +
+ + +
+ 100% + Functions + 3/3 +
+ + +
+ 95.23% + Lines + 20/21 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44  +  +12x +12x +12x +12x +12x +12x +12x +12x +  +  +  +12x +  +  +12x +  +  +12x +  +  +96x +  +  +  +  +  +  +  +84x +84x +  +  +12x +84x +84x +  +  +  +12x +12x +  +12x
'use strict';
+ 
+const fs = require('fs');
+const path = require('path');
+const Sequelize = require('sequelize');
+const process = require('process');
+const basename = path.basename(__filename);
+const env = process.env.NODE_ENV || 'development';
+const config = require(__dirname + '/../config/config.js')[env];
+const db = {};
+ 
+let sequelize;
+// Menggunakan URL dari config.js
+Iif (config.url) {
+  sequelize = new Sequelize(config.url, config);
+} else {
+  sequelize = new Sequelize(config.database, config.username, config.password, config);
+}
+ 
+fs
+  .readdirSync(__dirname)
+  .filter(file => {
+    return (
+      file.indexOf('.') !== 0 &&
+      file !== basename &&
+      file.slice(-3) === '.js' &&
+      file.indexOf('.test.js') === -1
+    );
+  })
+  .forEach(file => {
+    const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
+    db[model.name] = model;
+  });
+ 
+Object.keys(db).forEach(modelName => {
+  Eif (db[modelName].associate) {
+    db[modelName].associate(db);
+  }
+});
+ 
+db.sequelize = sequelize;
+db.Sequelize = Sequelize;
+ 
+module.exports = db;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/like.js.html b/coverage/lcov-report/models/like.js.html new file mode 100644 index 0000000..e8610da --- /dev/null +++ b/coverage/lcov-report/models/like.js.html @@ -0,0 +1,160 @@ + + + + + + Code coverage report for models/like.js + + + + + + + + + +
+
+

All files / models like.js

+
+ +
+ 100% + Statements + 6/6 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 6/6 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26  +  +  +12x +12x +  +  +  +  +  +  +  +12x +12x +  +  +  +12x +  +  +  +  +  +  +12x + 
'use strict';
+const {
+  Model
+} = require('sequelize');
+module.exports = (sequelize, DataTypes) => {
+  class Like extends Model {
+    /**
+     * Helper method for defining associations.
+     * This method is not a part of Sequelize lifecycle.
+     * The `models/index` file will call this method automatically.
+     */
+    static associate(models) {
+      Like.belongsTo(models.User);
+      Like.belongsTo(models.Post);
+    }
+ 
+  }
+  Like.init({
+    UserId: DataTypes.INTEGER,
+    PostId: DataTypes.INTEGER
+  }, {
+    sequelize,
+    modelName: 'Like',
+  });
+  return Like;
+};
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/message.js.html b/coverage/lcov-report/models/message.js.html new file mode 100644 index 0000000..5fa28d6 --- /dev/null +++ b/coverage/lcov-report/models/message.js.html @@ -0,0 +1,172 @@ + + + + + + Code coverage report for models/message.js + + + + + + + + + +
+
+

All files / models message.js

+
+ +
+ 100% + Statements + 7/7 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 7/7 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30  +  +  +12x +12x +  +  +  +  +  +  +  +12x +12x +12x +  +  +  +  +12x +  +  +  +  +  +  +  +  +12x + 
'use strict';
+const {
+  Model
+} = require('sequelize');
+module.exports = (sequelize, DataTypes) => {
+  class Message extends Model {
+    /**
+     * Helper method for defining associations.
+     * This method is not a part of Sequelize lifecycle.
+     * The `models/index` file will call this method automatically.
+     */
+    static associate(models) {
+      Message.belongsTo(models.Chat);
+      Message.belongsTo(models.User, { as: "sender", foreignKey: "senderId" });
+      Message.belongsTo(models.User, { as: "receiver", foreignKey: "receiverId" });
+    }
+ 
+ 
+  }
+  Message.init({
+    ChatId: DataTypes.INTEGER,
+    senderId: DataTypes.INTEGER,
+    receiverId: DataTypes.INTEGER,
+    content: DataTypes.TEXT
+  }, {
+    sequelize,
+    modelName: 'Message',
+  });
+  return Message;
+};
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/post.js.html b/coverage/lcov-report/models/post.js.html new file mode 100644 index 0000000..874ce72 --- /dev/null +++ b/coverage/lcov-report/models/post.js.html @@ -0,0 +1,205 @@ + + + + + + Code coverage report for models/post.js + + + + + + + + + +
+
+

All files / models post.js

+
+ +
+ 100% + Statements + 8/8 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 8/8 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41  +  +  +12x +12x +  +  +  +  +  +  +  +12x +12x +12x +12x +  +  +  +12x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +12x + 
'use strict';
+const {
+  Model
+} = require('sequelize');
+module.exports = (sequelize, DataTypes) => {
+  class Post extends Model {
+    /**
+     * Helper method for defining associations.
+     * This method is not a part of Sequelize lifecycle.
+     * The `models/index` file will call this method automatically.
+     */
+    static associate(models) {
+      Post.belongsTo(models.User);
+      Post.belongsTo(models.Category);
+      Post.hasMany(models.Image);
+      Post.hasMany(models.Like)
+    }
+ 
+  }
+  Post.init({
+    content: {
+      type: DataTypes.TEXT,
+      allowNull: false,
+      validate: {
+        notEmpty: {
+          msg: "Content is required"
+        },
+        notNull: {
+          msg: "Content is required"
+        }
+      }
+    },
+    isPrivate: DataTypes.BOOLEAN,
+    UserId: DataTypes.INTEGER,
+    CategoryId: DataTypes.INTEGER
+  }, {
+    sequelize,
+    modelName: 'Post',
+  });
+  return Post;
+};
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/models/user.js.html b/coverage/lcov-report/models/user.js.html new file mode 100644 index 0000000..99d0c96 --- /dev/null +++ b/coverage/lcov-report/models/user.js.html @@ -0,0 +1,262 @@ + + + + + + Code coverage report for models/user.js + + + + + + + + + +
+
+

All files / models user.js

+
+ +
+ 91.66% + Statements + 11/12 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 66.66% + Functions + 2/3 +
+ + +
+ 91.66% + Lines + 11/12 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60  +12x +  +  +12x +12x +  +  +  +  +  +  +  +12x +12x +12x +12x +12x +12x +  +  +  +12x +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +12x + 
'use strict';
+const bcrypt = require('bcryptjs'); 
+const {
+  Model
+} = require('sequelize');
+module.exports = (sequelize, DataTypes) => {
+  class User extends Model {
+    /**
+     * Helper method for defining associations.
+     * This method is not a part of Sequelize lifecycle.
+     * The `models/index` file will call this method automatically.
+     */
+    static associate(models) {
+      User.hasMany(models.Post);
+      User.hasMany(models.Like);
+      User.hasMany(models.Chat, { foreignKey: "UserId" });
+      User.hasMany(models.Chat, { foreignKey: "partnerId" });
+      User.hasMany(models.Message, { foreignKey: "senderId" });
+      User.hasMany(models.Message, { foreignKey: "receiverId" });
+    }
+ 
+  }
+  User.init({
+    username: {
+      type: DataTypes.STRING,
+      allowNull: false,
+      validate: {
+        notEmpty: { msg: `Username is required` },
+        notNull: { msg: `Username is required` }
+      }
+    },
+    email: {
+      type: DataTypes.STRING,
+      allowNull: false,
+      unique: { msg: `Email is already registered` },
+      validate: {
+        notEmpty: { msg: `Email is required` },
+        notNull: { msg: `Email is required` },
+        isEmail: { msg: `Invalid email format` }
+      }
+    },
+    password: {
+      type: DataTypes.STRING,
+      allowNull: false,
+      validate: {
+        notEmpty: { msg: `Password is required` },
+        notNull: { msg: `Password is required` }
+      }
+    },
+  }, {
+    sequelize,
+    modelName: 'User',
+    hooks: {
+      beforeCreate: async (user) => {
+        user.password = await bcrypt.hash(user.password, 10);
+      }
+    }
+  });
+  return User;
+};
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/routes/aiRouter.js.html b/coverage/lcov-report/routes/aiRouter.js.html new file mode 100644 index 0000000..251dbb8 --- /dev/null +++ b/coverage/lcov-report/routes/aiRouter.js.html @@ -0,0 +1,109 @@ + + + + + + Code coverage report for routes/aiRouter.js + + + + + + + + + +
+
+

All files / routes aiRouter.js

+
+ +
+ 100% + Statements + 6/6 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 6/6 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +92x +2x +2x +2x +  +  +2x +  +2x
const express = require('express');
+const router = express.Router();
+const AIController = require('../controllers/aiController');
+const auth = require('../helpers/authMiddleware');
+ 
+// Endpoint untuk mendapatkan rekomendasi post
+router.get('/recommendations', auth, AIController.getRecommendations);
+ 
+module.exports = router;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/routes/chatRouter.js.html b/coverage/lcov-report/routes/chatRouter.js.html new file mode 100644 index 0000000..64eea6a --- /dev/null +++ b/coverage/lcov-report/routes/chatRouter.js.html @@ -0,0 +1,151 @@ + + + + + + Code coverage report for routes/chatRouter.js + + + + + + + + + +
+
+

All files / routes chatRouter.js

+
+ +
+ 100% + Statements + 11/11 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 11/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +232x +2x +2x +2x +  +2x +  +  +2x +  +  +2x +  +  +2x +  +  +2x +  +  +2x +  +2x
const express = require('express');
+const router = express.Router();
+const ChatController = require('../controllers/chatController');
+const auth = require('../helpers/authMiddleware');
+ 
+router.use(auth);
+ 
+// Membuat chat AI
+router.post('/ai', ChatController.createAIChat);
+ 
+// Membuat atau mendapatkan chat dengan user lain
+router.post('/', ChatController.createOrGetChat);
+ 
+// Mendapatkan semua chat milik user yang sedang login
+router.get('/', ChatController.getUserChats);
+ 
+// Mendapatkan semua pesan dalam sebuah chat
+router.get('/:chatId/messages', ChatController.getChatMessages);
+ 
+// Mengirim pesan ke sebuah chat
+router.post('/:chatId/messages', ChatController.sendMessage);
+ 
+module.exports = router;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/routes/index.html b/coverage/lcov-report/routes/index.html new file mode 100644 index 0000000..55d712c --- /dev/null +++ b/coverage/lcov-report/routes/index.html @@ -0,0 +1,176 @@ + + + + + + Code coverage report for routes + + + + + + + + + +
+
+

All files routes

+
+ +
+ 100% + Statements + 47/47 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 47/47 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
aiRouter.js +
+
100%6/6100%0/0100%0/0100%6/6
chatRouter.js +
+
100%11/11100%0/0100%0/0100%11/11
index.js +
+
100%11/11100%0/0100%0/0100%11/11
postRouter.js +
+
100%12/12100%0/0100%0/0100%12/12
userRouter.js +
+
100%7/7100%0/0100%0/0100%7/7
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/routes/index.js.html b/coverage/lcov-report/routes/index.js.html new file mode 100644 index 0000000..c8917f9 --- /dev/null +++ b/coverage/lcov-report/routes/index.js.html @@ -0,0 +1,145 @@ + + + + + + Code coverage report for routes/index.js + + + + + + + + + +
+
+

All files / routes index.js

+
+ +
+ 100% + Statements + 11/11 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 11/11 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +212x +2x +  +2x +2x +2x +2x +  +  +  +  +  +  +  +  +2x +2x +2x +2x +  +2x
const express = require('express');
+const router = express.Router();
+ 
+const userRouter = require('./userRouter');
+const postRouter = require('./postRouter');
+const chatRouter = require('./chatRouter');
+const aiRouter = require('./aiRouter');
+ 
+// router.get('/', (req, res) => {
+//   res.status(200).json({
+//     status: 'success',
+//     message: 'Welcome to the Dummy Instagram API!'
+//   });
+// });
+ 
+router.use('/users', userRouter);
+router.use('/posts', postRouter);
+router.use('/chats', chatRouter);
+router.use('/ai', aiRouter); 
+ 
+module.exports = router;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/routes/postRouter.js.html b/coverage/lcov-report/routes/postRouter.js.html new file mode 100644 index 0000000..018a801 --- /dev/null +++ b/coverage/lcov-report/routes/postRouter.js.html @@ -0,0 +1,136 @@ + + + + + + Code coverage report for routes/postRouter.js + + + + + + + + + +
+
+

All files / routes postRouter.js

+
+ +
+ 100% + Statements + 12/12 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 12/12 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +182x +2x +2x +2x +2x +  +  +2x +  +2x +2x +  +2x +2x +  +2x +  +2x
const express = require("express");
+const router = express.Router();
+const PostController = require("../controllers/postController");
+const auth = require("../helpers/authMiddleware");
+const upload = require("../helpers/cloudinary"); 
+ 
+// Terapkan middleware upload. 'images' adalah nama field, 5 adalah batas maksimal file.
+router.post("/", auth, upload.array("images", 5), PostController.createPost);
+ 
+router.get("/", PostController.getAllPublicPosts);
+router.get("/me", auth, PostController.getMyPosts);
+ 
+router.put("/:id", auth, PostController.updatePost);
+router.delete("/:id", auth, PostController.deletePost);
+ 
+router.post("/:id/like", auth, PostController.toggleLike);
+ 
+module.exports = router;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov-report/routes/userRouter.js.html b/coverage/lcov-report/routes/userRouter.js.html new file mode 100644 index 0000000..45cd328 --- /dev/null +++ b/coverage/lcov-report/routes/userRouter.js.html @@ -0,0 +1,112 @@ + + + + + + Code coverage report for routes/userRouter.js + + + + + + + + + +
+
+

All files / routes userRouter.js

+
+ +
+ 100% + Statements + 7/7 +
+ + +
+ 100% + Branches + 0/0 +
+ + +
+ 100% + Functions + 0/0 +
+ + +
+ 100% + Lines + 7/7 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +102x +2x +2x +  +2x +2x +2x +  +  +2x
const express = require('express');
+const UserController = require('../controllers/userController');
+const router = express.Router();
+ 
+router.post('/register', UserController.register);
+router.post('/login', UserController.login);
+router.post('/auth/google', UserController.googleSignIn);
+ 
+ 
+module.exports = router;
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/lcov.info b/coverage/lcov.info index 2be157a..03ac225 100644 --- a/coverage/lcov.info +++ b/coverage/lcov.info @@ -69,10 +69,9 @@ DA:11,1 DA:13,1 DA:15,1 DA:21,1 -DA:22,1 -DA:27,3 -LF:11 -LH:11 +DA:26,3 +LF:10 +LH:10 BRDA:6,0,0,1 BRDA:6,0,1,1 BRDA:6,1,0,2 @@ -82,11 +81,11 @@ BRH:4 end_of_record TN: SF:controllers\chatController.js -FN:7,(anonymous_0) -FN:38,(anonymous_1) -FN:60,(anonymous_2) -FN:83,(anonymous_3) -FN:104,(anonymous_4) +FN:6,(anonymous_0) +FN:35,(anonymous_1) +FN:55,(anonymous_2) +FN:77,(anonymous_3) +FN:98,(anonymous_4) FNF:5 FNH:5 FNDA:4,(anonymous_0) @@ -97,88 +96,87 @@ FNDA:5,(anonymous_4) DA:1,3 DA:2,3 DA:3,3 +DA:7,4 DA:8,4 DA:9,4 -DA:10,4 -DA:12,4 -DA:13,1 -DA:17,3 +DA:11,4 +DA:12,1 +DA:15,3 +DA:29,2 DA:31,2 -DA:33,2 -DA:39,2 -DA:40,2 -DA:41,2 -DA:52,1 -DA:54,1 -DA:55,1 -DA:61,4 -DA:62,4 -DA:63,4 -DA:66,4 -DA:67,3 -DA:68,2 +DA:36,2 +DA:37,2 +DA:38,2 +DA:49,1 +DA:51,1 +DA:56,4 +DA:57,4 +DA:58,4 +DA:60,4 +DA:61,3 +DA:62,2 +DA:65,1 DA:71,1 -DA:77,1 +DA:73,3 +DA:78,3 DA:79,3 -DA:84,3 -DA:85,3 -DA:86,3 -DA:97,2 -DA:99,1 +DA:80,3 +DA:91,2 +DA:93,1 +DA:99,5 +DA:100,5 +DA:101,5 +DA:102,5 +DA:103,5 DA:105,5 DA:106,5 -DA:107,5 -DA:108,5 -DA:109,5 -DA:111,5 -DA:112,5 -DA:113,1 -DA:116,4 -DA:117,4 -DA:118,1 -DA:122,3 -DA:127,2 -DA:130,2 -DA:132,1 -DA:135,1 -DA:142,1 -DA:145,1 -DA:149,1 -DA:153,3 -DA:158,3 -LF:52 -LH:52 -BRDA:12,0,0,1 -BRDA:12,0,1,3 -BRDA:31,1,0,1 -BRDA:31,1,1,1 -BRDA:67,2,0,2 -BRDA:67,2,1,1 -BRDA:67,3,0,3 -BRDA:67,3,1,2 -BRDA:67,3,2,1 -BRDA:97,4,0,1 -BRDA:97,4,1,1 -BRDA:112,5,0,1 -BRDA:112,5,1,4 -BRDA:116,6,0,4 -BRDA:116,6,1,1 -BRDA:117,7,0,1 -BRDA:117,7,1,3 -BRDA:130,8,0,1 -BRDA:130,8,1,1 +DA:107,1 +DA:110,4 +DA:111,4 +DA:112,1 +DA:115,3 +DA:120,2 +DA:122,2 +DA:123,1 +DA:124,1 +DA:130,1 +DA:131,1 +DA:133,1 +DA:137,3 +DA:142,3 +LF:51 +LH:51 +BRDA:11,0,0,1 +BRDA:11,0,1,3 +BRDA:29,1,0,1 +BRDA:29,1,1,1 +BRDA:61,2,0,2 +BRDA:61,2,1,1 +BRDA:61,3,0,3 +BRDA:61,3,1,2 +BRDA:61,3,2,1 +BRDA:91,4,0,1 +BRDA:91,4,1,1 +BRDA:106,5,0,1 +BRDA:106,5,1,4 +BRDA:110,6,0,4 +BRDA:110,6,1,1 +BRDA:111,7,0,1 +BRDA:111,7,1,3 +BRDA:122,8,0,1 +BRDA:122,8,1,1 BRF:19 BRH:19 end_of_record TN: SF:controllers\postController.js -FN:5,(anonymous_0) -FN:25,(anonymous_1) -FN:43,(anonymous_2) -FN:62,(anonymous_3) -FN:76,(anonymous_4) -FN:93,(anonymous_5) -FN:125,(anonymous_6) +FN:4,(anonymous_0) +FN:20,(anonymous_1) +FN:37,(anonymous_2) +FN:56,(anonymous_3) +FN:70,(anonymous_4) +FN:87,(anonymous_5) +FN:108,(anonymous_6) FNF:7 FNH:7 FNDA:3,(anonymous_0) @@ -189,84 +187,76 @@ FNDA:4,(anonymous_4) FNDA:4,(anonymous_5) FNDA:4,(anonymous_6) DA:1,3 +DA:5,3 DA:6,3 DA:7,3 -DA:8,3 -DA:11,3 -DA:12,1 -DA:16,2 -DA:25,2 -DA:30,1 -DA:32,1 +DA:9,3 +DA:10,1 +DA:13,2 +DA:20,2 +DA:25,1 +DA:27,1 +DA:33,2 DA:38,2 -DA:44,2 -DA:45,2 -DA:55,1 -DA:57,1 -DA:63,2 -DA:64,2 -DA:69,1 -DA:71,1 -DA:77,4 -DA:78,4 -DA:79,4 -DA:81,4 -DA:82,4 -DA:83,3 -DA:85,2 -DA:86,1 -DA:88,3 -DA:94,4 -DA:95,4 -DA:97,4 -DA:98,4 -DA:100,4 -DA:101,4 -DA:102,1 -DA:103,1 -DA:106,3 -DA:107,3 -DA:110,3 -DA:111,1 -DA:112,1 -DA:115,2 -DA:116,1 -DA:117,1 -DA:119,3 -DA:120,3 -DA:126,4 -DA:127,4 -DA:128,4 -DA:129,3 -DA:131,2 -DA:136,2 -DA:137,1 -DA:138,1 -DA:140,1 -DA:141,1 -DA:143,2 -DA:145,2 -DA:150,3 -LF:59 -LH:59 -BRDA:11,0,0,1 -BRDA:11,0,1,2 -BRDA:11,1,0,3 -BRDA:11,1,1,3 -BRDA:19,2,0,2 -BRDA:19,2,1,2 -BRDA:82,3,0,1 -BRDA:82,3,1,3 -BRDA:83,4,0,1 -BRDA:83,4,1,2 -BRDA:101,5,0,1 -BRDA:101,5,1,3 -BRDA:110,6,0,1 -BRDA:110,6,1,2 -BRDA:129,7,0,1 -BRDA:129,7,1,2 -BRDA:136,8,0,1 -BRDA:136,8,1,1 +DA:39,2 +DA:49,1 +DA:51,1 +DA:57,2 +DA:58,2 +DA:63,1 +DA:65,1 +DA:71,4 +DA:72,4 +DA:73,4 +DA:75,4 +DA:76,4 +DA:77,3 +DA:79,2 +DA:80,1 +DA:82,3 +DA:88,4 +DA:89,4 +DA:91,4 +DA:92,4 +DA:93,1 +DA:96,3 +DA:97,1 +DA:100,2 +DA:101,1 +DA:103,3 +DA:109,4 +DA:110,4 +DA:111,4 +DA:112,3 +DA:114,2 +DA:119,2 +DA:120,1 +DA:121,1 +DA:123,1 +DA:124,1 +DA:126,2 +DA:128,2 +DA:133,3 +LF:51 +LH:51 +BRDA:9,0,0,1 +BRDA:9,0,1,2 +BRDA:9,1,0,3 +BRDA:9,1,1,3 +BRDA:15,2,0,2 +BRDA:15,2,1,2 +BRDA:76,3,0,1 +BRDA:76,3,1,3 +BRDA:77,4,0,1 +BRDA:77,4,1,2 +BRDA:92,5,0,1 +BRDA:92,5,1,3 +BRDA:96,6,0,1 +BRDA:96,6,1,2 +BRDA:112,7,0,1 +BRDA:112,7,1,2 +BRDA:119,8,0,1 +BRDA:119,8,1,1 BRF:18 BRH:18 end_of_record @@ -327,8 +317,8 @@ BRH:8 end_of_record TN: SF:helpers\aiHelper.js -FN:7,cleanText -FN:24,askGemini +FN:6,cleanText +FN:19,askGemini FNF:2 FNH:2 FNDA:4,cleanText @@ -336,27 +326,26 @@ FNDA:3,askGemini DA:1,8 DA:3,8 DA:4,8 -DA:8,4 -DA:25,3 -DA:26,3 -DA:27,2 -DA:28,2 -DA:30,1 -DA:31,1 -DA:35,8 -LF:11 -LH:11 -BRDA:7,0,0,1 +DA:7,4 +DA:20,3 +DA:21,3 +DA:22,2 +DA:23,2 +DA:25,1 +DA:29,8 +LF:10 +LH:10 +BRDA:6,0,0,1 BRF:1 BRH:1 end_of_record TN: SF:helpers\aiRecommendation.js FN:5,getAIRecommendations -FN:32,(anonymous_1) -FN:35,(anonymous_2) -FN:50,(anonymous_3) -FN:57,(anonymous_4) +FN:29,(anonymous_1) +FN:32,(anonymous_2) +FN:46,(anonymous_3) +FN:48,(anonymous_4) FNF:5 FNH:5 FNDA:4,getAIRecommendations @@ -370,53 +359,47 @@ DA:3,7 DA:6,4 DA:7,4 DA:8,4 -DA:18,4 -DA:23,3 -DA:24,1 -DA:32,6 -DA:34,2 -DA:35,2 -DA:36,4 -DA:37,4 -DA:40,2 -DA:41,0 -DA:49,2 +DA:15,4 +DA:20,3 +DA:21,1 +DA:29,6 +DA:30,2 +DA:32,2 +DA:33,4 +DA:34,4 +DA:37,2 +DA:38,0 +DA:46,2 +DA:47,2 +DA:48,4 DA:50,2 -DA:52,2 -DA:54,2 -DA:56,2 -DA:57,4 -DA:60,2 +DA:58,2 +DA:59,2 +DA:61,2 +DA:62,2 +DA:64,2 DA:68,2 -DA:69,2 -DA:71,2 -DA:76,2 -DA:77,0 -DA:79,2 -DA:82,2 -DA:97,2 -DA:99,1 -DA:101,1 -DA:102,1 -DA:109,0 -DA:110,0 -DA:115,7 -LF:37 -LH:33 -BRDA:23,0,0,1 -BRDA:23,0,1,2 -BRDA:23,1,0,3 -BRDA:23,1,1,3 -BRDA:32,2,0,6 -BRDA:32,2,1,6 -BRDA:37,3,0,4 -BRDA:37,3,1,4 -BRDA:40,4,0,0 -BRDA:40,4,1,2 -BRDA:76,5,0,0 -BRDA:76,5,1,2 -BRDA:76,6,0,2 -BRDA:76,6,1,2 +DA:83,2 +DA:85,1 +DA:86,1 +DA:93,0 +DA:98,7 +LF:31 +LH:29 +BRDA:20,0,0,1 +BRDA:20,0,1,2 +BRDA:20,1,0,3 +BRDA:20,1,1,3 +BRDA:29,2,0,6 +BRDA:29,2,1,6 +BRDA:34,3,0,4 +BRDA:34,3,1,4 +BRDA:37,4,0,0 +BRDA:37,4,1,2 +BRDA:64,5,0,0 +BRDA:64,5,1,2 +BRDA:64,6,0,2 +BRDA:64,6,1,2 BRF:14 BRH:12 end_of_record @@ -479,41 +462,40 @@ end_of_record TN: SF:helpers\handleError.js FN:1,handleError -FN:21,(anonymous_1) +FN:19,(anonymous_1) FNF:2 FNH:2 FNDA:8,handleError FNDA:3,(anonymous_1) DA:2,8 -DA:4,8 -DA:5,1 -DA:8,7 -DA:9,1 -DA:12,6 -DA:13,1 -DA:16,5 -DA:17,2 -DA:20,3 -DA:21,3 -DA:22,2 -DA:25,1 -DA:30,3 -LF:14 -LH:14 -BRDA:4,0,0,1 -BRDA:4,0,1,7 -BRDA:8,1,0,1 -BRDA:8,1,1,6 -BRDA:12,2,0,1 -BRDA:12,2,1,5 -BRDA:16,3,0,2 -BRDA:16,3,1,3 -BRDA:17,4,0,2 -BRDA:17,4,1,1 -BRDA:20,5,0,2 -BRDA:20,5,1,1 -BRDA:20,6,0,3 -BRDA:20,6,1,2 +DA:3,1 +DA:6,7 +DA:7,1 +DA:10,6 +DA:11,1 +DA:14,5 +DA:15,2 +DA:18,3 +DA:19,3 +DA:20,2 +DA:23,1 +DA:28,3 +LF:13 +LH:13 +BRDA:2,0,0,1 +BRDA:2,0,1,7 +BRDA:6,1,0,1 +BRDA:6,1,1,6 +BRDA:10,2,0,1 +BRDA:10,2,1,5 +BRDA:14,3,0,2 +BRDA:14,3,1,3 +BRDA:15,4,0,2 +BRDA:15,4,1,1 +BRDA:18,5,0,2 +BRDA:18,5,1,1 +BRDA:18,6,0,3 +BRDA:18,6,1,2 BRF:14 BRH:14 end_of_record diff --git a/helpers/aiRecommendation.js b/helpers/aiRecommendation.js index 0585f06..72d38fc 100644 --- a/helpers/aiRecommendation.js +++ b/helpers/aiRecommendation.js @@ -8,9 +8,6 @@ async function getAIRecommendations(userId) { const model = genAI.getGenerativeModel({ model: "gemini-2.0-flash-exp", generationConfig: { - temperature: 0.1, - topP: 0.9, - topK: 10, maxOutputTokens: 50, } }); From c9080be51927824aa1e4ae3ee8dbc7ef210c9333 Mon Sep 17 00:00:00 2001 From: Joshua080324 Date: Fri, 24 Oct 2025 11:02:21 +0700 Subject: [PATCH 62/62] Readme Update --- README.md | 596 +++++++++++++++++++++++++- client/.firebase/hosting.ZGlzdA.cache | 6 +- client/src/App.jsx | 30 +- 3 files changed, 613 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index e88486a..0f38872 100644 --- a/README.md +++ b/README.md @@ -1 +1,595 @@ -# Individual Project Phase 2 +# ๐Ÿ“ธ Dummy Instagram - AI-Powered Social Media Platform + +![Instagram Clone](https://img.shields.io/badge/Instagram-Clone-E4405F?style=for-the-badge&logo=instagram&logoColor=white) +![Node.js](https://img.shields.io/badge/Node.js-43853D?style=for-the-badge&logo=node.js&logoColor=white) +![React](https://img.shields.io/badge/React-20232A?style=for-the-badge&logo=react&logoColor=61DAFB) +![PostgreSQL](https://img.shields.io/badge/PostgreSQL-316192?style=for-the-badge&logo=postgresql&logoColor=white) +![Redux](https://img.shields.io/badge/Redux-593D88?style=for-the-badge&logo=redux&logoColor=white) + +> A modern social media platform with AI-powered recommendations and real-time messaging capabilities. + +## ๐ŸŒŸ Features + +### ๐Ÿ” Authentication & Authorization +- **Email/Password Authentication** with JWT tokens +- **Google OAuth 2.0** integration for seamless sign-in +- Protected routes with middleware authentication + +### ๐Ÿ“ Post Management +- **Create Posts** with multiple image uploads (via Cloudinary) +- **Public/Private visibility** settings +- **Like/Unlike** posts with real-time updates +- **Delete posts** with cascade deletion of associated data +- **Category-based** organization (Travel, Food, Fashion, Technology, Lifestyle) + +### ๐Ÿค– AI-Powered Features +- **Smart Recommendations**: AI analyzes your liked posts and recommends similar content using Google Gemini AI +- **AI Chat Assistant**: Interactive AI chatbot to answer questions and provide assistance +- **Intelligent Category Matching**: Machine learning-based content discovery + +### ๐Ÿ’ฌ Real-Time Messaging +- **Personal Chat** with Socket.IO real-time communication +- **Chat History** with message persistence +- **User Discovery** to find and connect with new users +- **Start Chat** modal for quick conversations + +### ๐Ÿ‘ค User Profiles +- **Profile Page** with user's post collection +- **User Discovery** modal to browse other users +- **Like tracking** across posts + +### ๐ŸŽจ Modern UI/UX +- **Responsive Design** with React Bootstrap +- **Smooth Animations** and transitions +- **Dark Mode Ready** interface +- **Mobile-Friendly** layout + +--- + +## ๐Ÿš€ Getting Started + +### Prerequisites +- Node.js v16+ +- PostgreSQL 12+ +- npm or yarn +- Cloudinary account +- Google Cloud Console project (for OAuth) +- Google AI Studio API key (for Gemini) + +### ๐Ÿ“ฆ Installation + +1. **Clone the repository** +```bash +git clone https://github.com/Joshua080324/Dummy-Instagram.git +cd Dummy-Instagram +``` + +2. **Install backend dependencies** +```bash +npm install +``` + +3. **Install frontend dependencies** +```bash +cd client +npm install +cd .. +``` + +4. **Setup environment variables** + +Create `.env` file in root directory: +```env +# Database +DATABASE_URL=postgresql://username:password@localhost:5432/dummy_instagram + +# JWT Secret +JWT_SECRET=your_jwt_secret_key_here + +# Cloudinary +CLOUDINARY_CLOUD_NAME=your_cloudinary_cloud_name +CLOUDINARY_API_KEY=your_cloudinary_api_key +CLOUDINARY_API_SECRET=your_cloudinary_api_secret + +# Google OAuth +GOOGLE_CLIENT_ID=your_google_client_id +GOOGLE_CLIENT_SECRET=your_google_client_secret + +# Google Gemini AI +GEMINI_API_KEY=your_gemini_api_key + +# Server +PORT=3000 +``` + +Create `client/.env` file: +```env +VITE_BASE_URL=http://localhost:3000 +VITE_GOOGLE_CLIENT_ID=your_google_client_id +``` + +5. **Setup Database** +```bash +# Create database +npx sequelize-cli db:create + +# Run migrations +npm run migrate + +# Seed sample data +npm run seed +``` + +6. **Run the application** + +Backend: +```bash +npm run dev +``` + +Frontend (in new terminal): +```bash +cd client +npm run dev +``` + +7. **Access the application** +- Frontend: `http://localhost:5173` +- Backend API: `http://localhost:3000` + +--- + +## ๐Ÿ”‘ Sample Accounts + +Use these pre-seeded accounts for testing: + +| Email | Password | +|-------|----------| +| john@example.com | password123 | +| jane@example.com | password123 | +| mike@example.com | password123 | +| sarah@example.com | password123 | +| alex@example.com | password123 | + +--- + +## ๐Ÿ“ฑ Application Flow + +### 1๏ธโƒฃ **User Authentication Flow** + +```mermaid +graph TD + A[Landing Page] -->|New User| B[Register Page] + A -->|Existing User| C[Login Page] + B -->|Email/Password| D[Create Account] + B -->|Google OAuth| E[Google Sign-In] + C -->|Email/Password| F[Verify Credentials] + C -->|Google OAuth| E + D --> G[Generate JWT Token] + E --> G + F --> G + G --> H[Store Token in localStorage] + H --> I[Redirect to Home] +``` + +**Steps:** +1. User visits the application +2. Choose between **Register** or **Login** +3. Option to use **Email/Password** or **Google OAuth** +4. System validates credentials and generates JWT token +5. Token stored in browser's localStorage +6. User redirected to Home feed + +--- + +### 2๏ธโƒฃ **Home Feed & Content Discovery Flow** + +```mermaid +graph TD + A[Home Page] --> B{Authenticated?} + B -->|No| C[Redirect to Login] + B -->|Yes| D[Load Posts] + D --> E[Show All Posts Tab] + D --> F[AI Recommended Posts Tab] + F --> G[Analyze User's Liked Posts] + G --> H[AI Gemini Processing] + H --> I[Return Recommended Posts] + E --> J[Display Posts] + I --> J + J --> K[User Interactions] + K --> L[Like/Unlike Post] + K --> M[View Profile] + K --> N[Start Chat] + K --> O[Delete Own Post] +``` + +**Steps:** +1. User lands on **Home Page** +2. System checks authentication status +3. Loads all public posts in **"All Posts"** tab +4. **"AI Recommended"** tab analyzes user's like history +5. Google Gemini AI processes liked categories +6. Returns personalized recommendations +7. User can interact: Like, Comment, Chat, Delete + +--- + +### 3๏ธโƒฃ **Create Post Flow** + +```mermaid +graph TD + A[Click Create Post Button] --> B[Open Create Post Modal] + B --> C[Fill Post Details] + C --> D[Select Category] + C --> E[Upload Images] + C --> F[Set Privacy] + E --> G[Upload to Cloudinary] + G --> H[Get Image URLs] + F --> I{Privacy Setting?} + I -->|Public| J[Visible to All] + I -->|Private| K[Visible to Owner Only] + H --> L[Submit Post to Server] + L --> M[Save to Database] + M --> N[Update Redux Store] + N --> O[Show in Feed] + O --> P[Success Notification] +``` + +**Steps:** +1. Click **"+"** icon in navigation +2. **Create Post Modal** appears +3. Fill in post details: + - Content/Caption + - Select category (Travel, Food, Fashion, etc.) + - Upload up to 5 images + - Choose visibility (Public/Private) +4. Images uploaded to **Cloudinary CDN** +5. Post data saved to database +6. Redux store updated +7. New post appears in feed instantly + +--- + +### 4๏ธโƒฃ **AI Recommendation Flow** + +```mermaid +graph TD + A[User Likes Posts] --> B[Track Liked Post Categories] + B --> C{Minimum 3 Likes?} + C -->|No| D[Show Recent Public Posts] + C -->|Yes| E[Analyze Category Distribution] + E --> F[Prepare Prompt for Gemini] + F --> G[Google Gemini AI API] + G --> H[AI Returns Best Category Match] + H --> I[Query Posts by Category] + I --> J[Filter User's Own Posts] + J --> K[Order by Recent] + K --> L[Return Top 20 Recommendations] + L --> M[Display in Recommended Tab] +``` + +**Steps:** +1. System tracks all posts liked by user +2. Counts likes per category (Travel: 5, Food: 3, Fashion: 1) +3. If user has liked at least 3 posts, activate AI +4. Send category statistics to **Google Gemini AI** +5. AI analyzes patterns and returns best matching category +6. Query database for posts in that category +7. Exclude user's own posts +8. Display personalized recommendations + +--- + +### 5๏ธโƒฃ **Real-Time Messaging Flow** + +```mermaid +graph TD + A[Click Messages Icon] --> B[Messages Page] + B --> C[Load Chat List] + C --> D{Has Chats?} + D -->|No| E[Show Empty State] + D -->|Yes| F[Display Chat List] + E --> G[Click Start New Chat] + F --> H[Select Chat] + G --> I[User Discovery Modal] + I --> J[Select User] + J --> K[Create/Open Chat] + H --> K + K --> L[Load Message History] + L --> M[Socket.IO Connection] + M --> N[Real-Time Updates] + N --> O[Send/Receive Messages] +``` + +**Steps:** +1. Navigate to **Messages** page +2. View list of existing conversations +3. **Start New Chat** via User Discovery modal +4. Select a user to chat with +5. System creates chat room (or opens existing) +6. Load message history from database +7. **Socket.IO** establishes WebSocket connection +8. Messages sent/received in **real-time** +9. Chat history persisted to database + +--- + +### 6๏ธโƒฃ **AI Chat Assistant Flow** + +```mermaid +graph TD + A[Click AI Chat Icon] --> B[AI Chat Modal Opens] + B --> C[User Types Message] + C --> D[Send to Gemini AI] + D --> E[AI Processing] + E --> F[Clean & Format Response] + F --> G[Display AI Response] + G --> H{Continue Chat?} + H -->|Yes| C + H -->|No| I[Close Modal] +``` + +**Steps:** +1. Click **"AI Chat"** icon (Stars icon) +2. **AI Chat Modal** appears +3. Type your question or message +4. Message sent to **Google Gemini AI** API +5. AI processes and generates response +6. Response cleaned (remove markdown, formatting) +7. Display AI answer in chat interface +8. Continue conversation or close modal + +--- + +### 7๏ธโƒฃ **Profile & User Interaction Flow** + +```mermaid +graph TD + A[View User Profile] --> B{Own Profile?} + B -->|Yes| C[Show All Posts + Private] + B -->|No| D[Show Public Posts Only] + C --> E[Can Delete Posts] + D --> F[Can Like Posts] + D --> G[Can Start Chat] + F --> H[Update Like Count] + G --> I[Open Chat with User] + E --> J[Confirm Delete] + J --> K[Remove from Database] + K --> L[Update Redux Store] + L --> M[Refresh Profile] +``` + +**Steps:** +1. Click on username or profile picture +2. System checks: Is this your profile? +3. **Own Profile**: See all posts (public + private), can delete +4. **Other Profile**: See public posts only, can like/chat +5. **Delete Post**: Confirmation dialog โ†’ Remove from DB โ†’ Update UI +6. **Start Chat**: Create new conversation with user +7. All changes update Redux store for instant UI refresh + +--- + +## ๐Ÿ—๏ธ System Architecture + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ CLIENT SIDE โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ React.js + Redux Toolkit + React Router + Bootstrap โ”‚ +โ”‚ โ”œโ”€โ”€ Pages (Login, Register, Home, Profile, Messages) โ”‚ +โ”‚ โ”œโ”€โ”€ Components (PostCard, Modals, Navigation) โ”‚ +โ”‚ โ”œโ”€โ”€ Redux Store (Auth, Posts, Likes Slices) โ”‚ +โ”‚ โ””โ”€โ”€ HTTP Client (Axios) โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ + โ”‚ REST API + Socket.IO + โ”‚ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ SERVER SIDE โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ Node.js + Express.js + Socket.IO โ”‚ +โ”‚ โ”œโ”€โ”€ Routes (Users, Posts, Chat, AI) โ”‚ +โ”‚ โ”œโ”€โ”€ Controllers (Business Logic) โ”‚ +โ”‚ โ”œโ”€โ”€ Middleware (Authentication, Error Handling) โ”‚ +โ”‚ โ””โ”€โ”€ Helpers (JWT, Cloudinary, AI) โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ + โ”‚ Sequelize ORM + โ”‚ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ DATABASE LAYER โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ PostgreSQL Database โ”‚ +โ”‚ โ”œโ”€โ”€ Users Table โ”‚ +โ”‚ โ”œโ”€โ”€ Posts Table โ”‚ +โ”‚ โ”œโ”€โ”€ Likes Table (Junction) โ”‚ +โ”‚ โ”œโ”€โ”€ Categories Table โ”‚ +โ”‚ โ”œโ”€โ”€ Images Table โ”‚ +โ”‚ โ”œโ”€โ”€ Chats Table โ”‚ +โ”‚ โ””โ”€โ”€ Messages Table โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ EXTERNAL SERVICES โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ ๐Ÿค– Google Gemini AI โ†’ AI Recommendations & Chat โ”‚ +โ”‚ โ˜๏ธ Cloudinary โ†’ Image Storage & CDN โ”‚ +โ”‚ ๐Ÿ” Google OAuth โ†’ Authentication โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +--- + +## ๐Ÿงช Testing + +The project includes comprehensive test coverage (80%+): + +```bash +# Run all tests +npm test + +# Run tests with coverage report +npm run test:coverage + +# Run tests in watch mode +npm run test:watch +``` + +**Test Coverage Includes:** +- Unit tests for controllers +- Integration tests for routes +- Middleware tests +- Helper function tests +- Database model tests + +--- + +## ๐Ÿ“š API Documentation + +Comprehensive API documentation available in [API_DOCUMENTATION.md](./API_DOCUMENTATION.md) + +**Key Endpoints:** + +### Authentication +- `POST /users/register` - Create new account +- `POST /users/login` - Email/password login +- `POST /users/auth/google` - Google OAuth login + +### Posts +- `GET /posts` - Get all posts +- `POST /posts` - Create new post +- `DELETE /posts/:id` - Delete post + +### Likes +- `POST /posts/:id/like` - Like/unlike post + +### Chat +- `POST /chat` - Create/get chat +- `GET /chat` - Get all user's chats +- `GET /chat/:id` - Get chat details +- `POST /chat/:id/messages` - Send message + +### AI Features +- `GET /ai/recommendations` - Get AI-powered recommendations +- `POST /ai/chat` - Chat with AI assistant + +--- + +## ๐Ÿ› ๏ธ Tech Stack + +### Backend +- **Runtime**: Node.js v16+ +- **Framework**: Express.js +- **Database**: PostgreSQL with Sequelize ORM +- **Authentication**: JWT + Google OAuth 2.0 +- **Real-time**: Socket.IO +- **File Upload**: Multer + Cloudinary +- **AI**: Google Generative AI (Gemini) +- **Testing**: Jest + +### Frontend +- **Framework**: React.js 18 +- **State Management**: Redux Toolkit +- **Routing**: React Router v6 +- **UI Library**: React Bootstrap +- **HTTP Client**: Axios +- **OAuth**: @react-oauth/google +- **Notifications**: SweetAlert2 +- **Build Tool**: Vite + +### DevOps & Tools +- **Version Control**: Git & GitHub +- **Environment**: dotenv +- **API Testing**: Thunder Client / Postman +- **Code Quality**: ESLint +- **Database Migrations**: Sequelize CLI + +--- + +## ๐Ÿ“ Project Structure + +``` +Dummy-Instagram/ +โ”œโ”€โ”€ client/ # React frontend +โ”‚ โ”œโ”€โ”€ src/ +โ”‚ โ”‚ โ”œโ”€โ”€ components/ # Reusable components +โ”‚ โ”‚ โ”œโ”€โ”€ pages/ # Page components +โ”‚ โ”‚ โ”œโ”€โ”€ store/ # Redux store & slices +โ”‚ โ”‚ โ”œโ”€โ”€ helpers/ # Utility functions +โ”‚ โ”‚ โ””โ”€โ”€ assets/ # Static assets +โ”‚ โ”œโ”€โ”€ public/ +โ”‚ โ””โ”€โ”€ package.json +โ”œโ”€โ”€ controllers/ # Request handlers +โ”œโ”€โ”€ models/ # Sequelize models +โ”œโ”€โ”€ routes/ # API routes +โ”œโ”€โ”€ helpers/ # Backend utilities +โ”œโ”€โ”€ middleware/ # Express middleware +โ”œโ”€โ”€ migrations/ # Database migrations +โ”œโ”€โ”€ seeders/ # Database seeders +โ”œโ”€โ”€ __tests__/ # Test files +โ”œโ”€โ”€ config/ # Configuration files +โ”œโ”€โ”€ data/ # Sample data +โ”œโ”€โ”€ .env # Environment variables +โ”œโ”€โ”€ app.js # Express app setup +โ”œโ”€โ”€ package.json +โ””โ”€โ”€ README.md +``` + +--- + +## ๐Ÿ”’ Security Features + +- โœ… JWT token authentication +- โœ… Password hashing with bcryptjs +- โœ… Protected routes with middleware +- โœ… Environment variable protection +- โœ… SQL injection prevention (Sequelize ORM) +- โœ… XSS protection +- โœ… CORS configuration + +--- + +## ๐Ÿšง Future Enhancements + +- [ ] Story/Reels feature +- [ ] Comment system on posts +- [ ] Hashtag support +- [ ] Advanced search and filters +- [ ] User follow/following system +- [ ] Push notifications +- [ ] Email verification +- [ ] Password reset functionality +- [ ] Post editing capability +- [ ] Image filters and editing tools + +--- + +## ๐Ÿ‘จโ€๐Ÿ’ป Developer + +**Joshua** +- GitHub: [@Joshua080324](https://github.com/Joshua080324) +- Repository: [Dummy-Instagram](https://github.com/Joshua080324/Dummy-Instagram) + +--- + +## ๐Ÿ“„ License + +This project is for educational purposes as part of Individual Project Phase 2. + +--- + +## ๐Ÿ™ Acknowledgments + +- Google Gemini AI for intelligent recommendations +- Cloudinary for image hosting +- React & Redux community +- Node.js & Express.js ecosystem + +--- + +
+ โญ If you like this project, please give it a star! โญ +
+ Built with โค๏ธ using React, Node.js, and AI +
diff --git a/client/.firebase/hosting.ZGlzdA.cache b/client/.firebase/hosting.ZGlzdA.cache index 5408ccc..2402fd6 100644 --- a/client/.firebase/hosting.ZGlzdA.cache +++ b/client/.firebase/hosting.ZGlzdA.cache @@ -1,5 +1,5 @@ vite.svg,1760631936123,699a02e0e68a579f687d364bbbe7633161244f35af068220aee37b1b33dfb3c7 404.html,1760635348044,762bf484ba67404bd1a3b181546ea28d60dfddf18e9dd4795d8d25bcf3c1a890 -index.html,1760671323173,bbc0fb88a7dd3cf2f1bc3053a2ab789314e3241ab26ed3ad55b6ac96950bef33 -assets/index-CIpsl6Aj.css,1760671323174,ec30b7cd4a9d868211d83512ac0b4b2899f1ce907c7981290b698e6c16eadff0 -assets/index-Dboi_fWA.js,1760671323174,58ffac606df9a4cfce1598dc71ba8b11e33cabb9dedd79e974119ba260ae509f +index.html,1761208311565,90e31f25a3bfc900d9445d3d4a734e013763a2baba7bc16e4f406cc2c62da10e +assets/index-CIpsl6Aj.css,1761208311565,ec30b7cd4a9d868211d83512ac0b4b2899f1ce907c7981290b698e6c16eadff0 +assets/index-Cdr4-Jjl.js,1761208311566,63bcf06e8f1c893dcb257babb6dfa32329248aacb2e484bca228a83756e33d66 diff --git a/client/src/App.jsx b/client/src/App.jsx index 74f7c2f..c74ea17 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -29,45 +29,45 @@ function App() { - - } + } /> - - } + } /> - - } + } /> - - } + } /> - - } + } /> } />