diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..9e5b2bcf Binary files /dev/null and b/.DS_Store differ diff --git a/BACKEND/.DS_Store b/BACKEND/.DS_Store new file mode 100644 index 00000000..38ba1b2d Binary files /dev/null and b/BACKEND/.DS_Store differ diff --git a/BACKEND/.env.sample b/BACKEND/.env.sample new file mode 100644 index 00000000..3d91f9b4 --- /dev/null +++ b/BACKEND/.env.sample @@ -0,0 +1 @@ +SECRET_KEY="" \ No newline at end of file diff --git a/BACKEND/.gitignore b/BACKEND/.gitignore new file mode 100644 index 00000000..d8e69663 --- /dev/null +++ b/BACKEND/.gitignore @@ -0,0 +1,3 @@ +node_modules +.env +note \ No newline at end of file diff --git a/BACKEND/__test__/backend.test.js b/BACKEND/__test__/backend.test.js new file mode 100644 index 00000000..37503d05 --- /dev/null +++ b/BACKEND/__test__/backend.test.js @@ -0,0 +1,269 @@ +const app = require("../app"); +const request = require("supertest"); +const { test, expect, beforeAll, afterAll } = require("@jest/globals"); +const { User, Product, Category, Cart, sequelize } = require("../models"); +const { hashPassword } = require("../helpers/bcrypt"); +const { signToken } = require("../helpers/jwt"); +const { queryInterface } = sequelize; +const fs = require("fs").promises; + +let access_token_admin; +let access_token_user; + +beforeAll(async () => { + try { + const usersData = await fs.readFile("./data/users.json", "utf8"); + const users = JSON.parse(usersData).map((user) => { + if (!user.email) { + throw new Error("User missing email in users.json"); + } + if (!user.password) { + throw new Error("User missing password in users.json"); + } + return { + ...user, + createdAt: new Date(), + updatedAt: new Date(), + password: hashPassword(user.password), + role: user.role || "user", + }; + }); + + const categoriesData = await fs.readFile("./data/categories.json", "utf8"); + const categories = JSON.parse(categoriesData).map((category) => ({ + ...category, + createdAt: new Date(), + updatedAt: new Date(), + })); + + const productsData = await fs.readFile("./data/products.json", "utf8"); + const products = JSON.parse(productsData).map((product) => ({ + ...product, + createdAt: new Date(), + updatedAt: new Date(), + })); + + const cartsData = await fs.readFile("./data/carts.json", "utf8"); + const carts = JSON.parse(cartsData).map((cart) => ({ + ...cart, + createdAt: new Date(), + updatedAt: new Date(), + })); + + await queryInterface.bulkDelete("Carts", null, { + truncate: true, + restartIdentity: true, + cascade: true, + }); + await queryInterface.bulkDelete("Products", null, { + truncate: true, + restartIdentity: true, + cascade: true, + }); + await queryInterface.bulkDelete("Categories", null, { + truncate: true, + restartIdentity: true, + cascade: true, + }); + await queryInterface.bulkDelete("Users", null, { + truncate: true, + restartIdentity: true, + cascade: true, + }); + + await queryInterface.bulkInsert("Users", users); + await queryInterface.bulkInsert("Categories", categories); + await queryInterface.bulkInsert("Products", products); + await queryInterface.bulkInsert("Carts", carts); + + const adminUser = await User.findOne({ + where: { email: "admin@example.com" }, + }); + if (!adminUser) { + throw new Error("Admin user not found in database"); + } + access_token_admin = signToken({ id: adminUser.id }); + + const regularUser = await User.findOne({ + where: { email: "user@example.com" }, + }); + if (!regularUser) { + throw new Error("Regular user not found in database"); + } + access_token_user = signToken({ id: regularUser.id }); + } catch (error) { + console.error("Error in beforeAll:", error); + throw error; + } +}); + +afterAll(async () => { + await queryInterface.bulkDelete("Carts", null, { + truncate: true, + restartIdentity: true, + cascade: true, + }); + await queryInterface.bulkDelete("Products", null, { + truncate: true, + restartIdentity: true, + cascade: true, + }); + await queryInterface.bulkDelete("Categories", null, { + truncate: true, + restartIdentity: true, + cascade: true, + }); + await queryInterface.bulkDelete("Users", null, { + truncate: true, + restartIdentity: true, + cascade: true, + }); +}); + +describe("POST /login", () => { + test("should login successfully and return access_token", async () => { + const requestBody = { + email: "admin@example.com", + password: "admin123", + }; + + const response = await request(app).post("/login").send(requestBody); + expect(response.status).toBe(200); + expect(response.body).toHaveProperty("access_token"); + }); + + test("should fail if email is missing", async () => { + const requestBody = { + password: "admin123", + }; + + const response = await request(app).post("/login").send(requestBody); + expect(response.status).toBe(400); + expect(response.body).toHaveProperty("message", "Email is required"); + }); + + test("should fail if password is missing", async () => { + const requestBody = { + email: "admin@example.com", + }; + + const response = await request(app).post("/login").send(requestBody); + expect(response.status).toBe(400); + expect(response.body).toHaveProperty("message", "Password is required"); + }); + + test("should fail if email is not registered", async () => { + const requestBody = { + email: "nonexistent@example.com", + password: "admin123", + }; + + const response = await request(app).post("/login").send(requestBody); + expect(response.status).toBe(401); + expect(response.body).toHaveProperty("message", "Invalid email/password"); + }); + + test("should fail if password is incorrect", async () => { + const requestBody = { + email: "admin@example.com", + password: "wrongpassword", + }; + + const response = await request(app).post("/login").send(requestBody); + expect(response.status).toBe(401); + expect(response.body).toHaveProperty("message", "Invalid email/password"); + }); +}); + +describe("POST /products", () => { + test("should create a product successfully", async () => { + const product = { + name: "Cubic Lemari Pakaian Minimalis / Wardrobe Baju / LUNA LPM 301 - SonomaBl - Grey", + description: + "Store your favorite clothes in the LUNA LPM 301 wardrobe, equipped with racks, a table, and a beautiful mirror that can be opened.", + price: 1029000, + stock: 587, + imgUrl: + "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522920/hacktiv8/branded/cubic-lemari-pakaian-minimalis-wardrobe-baju-luna-lpm-301-sonomabl-grey-qswxtjtx14i.jpg", + categoryId: 2, + userId: 1, + }; + + const response = await request(app) + .post("/products") + .set("Authorization", `Bearer ${access_token_admin}`) + .send(product); + + expect(response.status).toBe(201); + expect(response.body).toHaveProperty("id"); + expect(response.body).toHaveProperty("name", product.name); + expect(response.body).toHaveProperty("description", product.description); + expect(response.body).toHaveProperty("price", product.price); + expect(response.body).toHaveProperty("stock", product.stock); + expect(response.body).toHaveProperty("imgUrl", product.imgUrl); + expect(response.body).toHaveProperty("categoryId", product.categoryId); + expect(response.body).toHaveProperty("userId", product.userId); + + // Verify product is saved in the database + const savedProduct = await Product.findOne({ + where: { name: product.name }, + }); + expect(savedProduct).toBeTruthy(); + }); + + test("should fail with invalid token", async () => { + const product = { + name: "Kota kembang Bandung", + description: "Tourist attractions and snacks in Bandung", + price: 100000, + stock: 10, + imgUrl: "https://suarautama.id/wp-content/uploads/2024/10/images-15.jpeg", + categoryId: 1, + userId: 2, + }; + + const response = await request(app) + .post("/products") + .set("Authorization", "Bearer invalid_token") + .send(product); + + expect(response.status).toBe(401); + expect(response.body).toHaveProperty("message", "Unauthorized access"); + }); + + test("should fail when required fields are missing", async () => { + const product = { + description: "Tourist attractions and snacks in Bandung", + imgUrl: "https://suarautama.id/wp-content/uploads/2024/10/images-15.jpeg", + categoryId: 1, + }; + + const response = await request(app) + .post("/products") + .set("Authorization", `Bearer ${access_token_admin}`) + .send(product); + + expect(response.status).toBe(400); + expect(response.body).toHaveProperty("message", "Name is required!"); + }); + + test("should fail for non-admin user", async () => { + const product = { + name: "Non-Admin Product", + description: "A product created by a non-admin user", + price: 500000, + stock: 100, + imgUrl: "https://example.com/image.jpg", + categoryId: 1, + userId: 2, + }; + + const response = await request(app) + .post("/products") + .set("Authorization", `Bearer ${access_token_user}`) + .send(product); + + expect(response.status).toBe(403); + expect(response.body).toHaveProperty("message", "Admin access required"); + }); +}); diff --git a/BACKEND/app.js b/BACKEND/app.js new file mode 100644 index 00000000..d783135f --- /dev/null +++ b/BACKEND/app.js @@ -0,0 +1,66 @@ +if(process.env.NODE_ENV !== "production"){ + require("dotenv").config(); +} + +const express = require("express"); +const ProductController = require("./controllers/ProductController"); +const CategoryController = require("./controllers/CategoryController"); +const UserController = require("./controllers/UserController"); +const CartController = require("./controllers/CartController"); +const authentication = require("./middlewares/authentication"); +const { authorizationAdmin } = require("./middlewares/authorization"); +const errorHandler = require("./middlewares/errorHandler"); + + +const app = express(); +const port = process.env.PORT || 3000; + +const cors = require("cors") +app.use(cors()) + +app.use(express.urlencoded({ extended: true })); +app.use(express.json()); + + +// User endpoints +app.post("/register", UserController.register); +app.post("/login", UserController.login); +app.post("/login/google", UserController.googleLogin); + +app.use(authentication); + +// Product endpoints +app.get("/products", ProductController.getProduct); +app.get("/products/:id", ProductController.getProductById); +app.post("/products",authorizationAdmin, ProductController.postProduct); +app.put("/products/:id",authorizationAdmin, ProductController.putProductById); +app.delete("/products/:id",authorizationAdmin, ProductController.deleteProductById); + +// Category endpoints +app.get("/categories", CategoryController.getCategory); +app.get("/categories/:id", CategoryController.getCategorybyId); +app.post("/categories",authorizationAdmin, CategoryController.postCategory); +app.put( + "/categories/:id", + authorizationAdmin, CategoryController.updateCategoryById +); +app.delete( + "/categories/:id", + authorizationAdmin, CategoryController.deleteCategoryById +); + +// Cart endpoints +app.post("/carts", CartController.postCart); +app.get("/carts", CartController.getCart); +app.put("/carts/:id", CartController.updateCartItem); +app.delete("/carts/:id", CartController.deleteCartItem); + +// Error handler middleware +app.use(errorHandler); + +app.listen(port, () => { + console.log(`Example app listening on port ${port}`); +}); + + +module.exports = app \ No newline at end of file diff --git a/BACKEND/config/config.json b/BACKEND/config/config.json new file mode 100644 index 00000000..4c592091 --- /dev/null +++ b/BACKEND/config/config.json @@ -0,0 +1,19 @@ +{ + "development": { + "username": "postgres", + "password": "postgres", + "database": "database_ecommerce", + "host": "127.0.0.1", + "dialect": "postgres" + }, + "test": { + "username": "postgres", + "password": "postgres", + "database": "database_ecommerce", + "host": "127.0.0.1", + "dialect": "postgres" + }, + "production": { + "use_env_variable": "DATABASE_URL" + } +} diff --git a/BACKEND/controllers/CartController.js b/BACKEND/controllers/CartController.js new file mode 100644 index 00000000..73073928 --- /dev/null +++ b/BACKEND/controllers/CartController.js @@ -0,0 +1,130 @@ +const { Cart, Product } = require("../models"); + +module.exports = class CartController { + static async postCart(req, res, next) { + try { + const { productId, quantity } = req.body; + const userId = req.user.id; + + if (!productId || isNaN(productId)) { + throw { name: "ValidationError", message: "Invalid product ID" }; + } + if (!quantity || isNaN(quantity) || quantity <= 0) { + throw { + name: "ValidationError", + message: "Quantity must be greater than 0", + }; + } + + const product = await Product.findByPk(productId); + if (!product) { + throw { name: "NotFoundError", message: "Product not found" }; + } + if (product.stock < quantity) { + throw { name: "ValidationError", message: "Insufficient stock" }; + } + + let cartItem = await Cart.findOne({ + where: { userId, productId }, + }); + + if (cartItem) { + cartItem.quantity += quantity; + await cartItem.save(); + } else { + cartItem = await Cart.create({ + userId, + productId, + quantity, + }); + } + + res.status(201).json({ message: "Item added to cart" }); + } catch (error) { + next(error); + } + } + + static async getCart(req, res, next) { + try { + const userId = req.user.id; + const cartItems = await Cart.findAll({ + where: { userId }, + include: [ + { + model: Product, + attributes: ["id", "name", "price", "imgUrl", "stock"], + }, + ], + }); + + res.status(200).json(cartItems); + } catch (error) { + next(error); + } + } + + static async updateCartItem(req, res, next) { + try { + const id = parseInt(req.params.id); + const { productId, quantity } = req.body; + + if (isNaN(id)) { + throw { name: "ValidationError", message: "Invalid cart ID" }; + } + if (!productId || isNaN(productId)) { + throw { name: "ValidationError", message: "Invalid product ID" }; + } + if (!quantity || isNaN(quantity) || quantity <= 0) { + throw { + name: "ValidationError", + message: "Quantity must be greater than 0", + }; + } + + const cart = await Cart.findByPk(id); + if (!cart) { + throw { + name: "NotFoundError", + message: `Cart with ID ${id} not found` + }; + } + + await cart.update({ productId, quantity }); + res + .status(200) + .json({ message: `Cart with ID ${id} successfully updated` }); + } catch (error) { + next(error); + } + } + + static async deleteCartItem(req, res, next) { + try { + const id = parseInt(req.params.id); + const userId = req.user.id; + + if (isNaN(id)) { + throw { name: "ValidationError", message: "ID Invalid cart" }; + } + + const cartItem = await Cart.findOne({ + where: { id, userId }, + }); + + if (!cartItem) { + throw { + name: "NotFoundError", + message: `Cart with ID ${id} not found`, + }; + } + + await cartItem.destroy(); + res + .status(200) + .json({ message: `Cart with ID ${id} successfully deleted` }); + } catch (error) { + next(error); + } + } +}; diff --git a/BACKEND/controllers/CategoryController.js b/BACKEND/controllers/CategoryController.js new file mode 100644 index 00000000..655a1bcd --- /dev/null +++ b/BACKEND/controllers/CategoryController.js @@ -0,0 +1,93 @@ +const { Category } = require("../models"); + +module.exports = class CategoryController { + static async getCategory(req, res, next) { + try { + const categories = await Category.findAll(); + res.status(200).json(categories); + } catch (error) { + next(error); + } + } + + static async postCategory(req, res, next) { + try { + const { name } = req.body; + if (!name) { + throw { name: "ValidationError", message: "Category name is required" }; + } + const category = await Category.create({ name }); + res.status(201).json(category); + } catch (error) { + next(error); + } + } + + static async getCategorybyId(req, res, next) { + try { + const id = parseInt(req.params.id); + if (isNaN(id)) { + throw { name: "ValidationError", message: "Invalid category ID" }; + } + const category = await Category.findByPk(id); + if (!category) { + throw { + name: "NotFoundError", + message: `Category with ID ${id} not found`, + }; + } + res.status(200).json(category); + } catch (error) { + next(error); + } + } + + static async updateCategoryById(req, res, next) { + try { + const id = parseInt(req.params.id); + if (isNaN(id)) { + throw { name: "ValidationError", message: `Invalid category ${id}` }; + } + const { name } = req.body; + if (!name) { + throw { name: "ValidationError", message: "Category name is required" }; + } + const category = await Category.findByPk(id); + if (!category) { + throw { + name: "NotFoundError", + message: `Category with ID ${id} not found`, + }; + } + await category.update({ name }); + res + .status(200) + .json({ message: `Category with ID ${id} has been successfully updated` }); + } catch (error) { + next(error); + } + } + + static async deleteCategoryById(req, res, next) { + try { + const id = parseInt(req.params.id); + if (isNaN(id)) { + throw { name: "ValidationError", message: "Invalid category ID" }; + } + const category = await Category.findByPk(id); + if (!category) { + throw { + name: "NotFoundError", + message: `Category with ID ${id} not found`, + }; + } + await category.destroy(); + res + .status(200) + .json({ + message: `Category with ID ${id} has been successfully deleted` }); + } catch (error) { + next(error); + } + } +}; diff --git a/BACKEND/controllers/ProductController.js b/BACKEND/controllers/ProductController.js new file mode 100644 index 00000000..b9c6924c --- /dev/null +++ b/BACKEND/controllers/ProductController.js @@ -0,0 +1,143 @@ +const { Product } = require("../models"); + +module.exports = class ProductController { + static async getProduct(req, res, next) { + try { + const products = await Product.findAll(); + res.status(200).json(products); + } catch (error) { + next(error); + } + } + + static async getProductById(req, res, next) { + try { + const id = parseInt(req.params.id); + if (isNaN(id)) { + throw { name: "ValidationError", message: "Invalid product ID" }; + } + const product = await Product.findByPk(id); + if (!product) { + throw { + name: "NotFoundError", + message: `Product with ID ${id} not found`, + }; + } + res.status(200).json(product); + } catch (error) { + next(error); + } + } + + static async postProduct(req, res, next) { + try { + const { name, description, price, stock, imgUrl, categoryId, userId } = + req.body; + if (!name) + throw { name: "ValidationError", message: "Name is required!" }; + if (!description) + throw { name: "ValidationError", message: "Description is required!" }; + if (!price || isNaN(price)) + throw { + name: "ValidationError", + message: "Price is required and must be a number!", + }; + if (!stock || isNaN(stock)) + throw { + name: "ValidationError", + message: "Stock is required and must be a number!", + }; + if (!imgUrl) + throw { name: "ValidationError", message: "Image URL is required!" }; + if (!categoryId || isNaN(categoryId)) + throw { + name: "ValidationError", + message: "Category ID is required and must be a number!", + }; + if (!userId || isNaN(userId)) + throw { + name: "ValidationError", + message: "User ID is required and must be a number!", + }; + + const product = await Product.create(req.body); + res.status(201).json(product); + } catch (error) { + next(error); + } + } + + static async putProductById(req, res, next) { + try { + const id = parseInt(req.params.id); + const { name, description, price, stock, imgUrl, categoryId, userId } = + req.body; + + if (isNaN(id)) { + throw { name: "ValidationError", message: "Invalid product ID" }; + } + if (!name) + throw { name: "ValidationError", message: "Name is required!" }; + if (!description) + throw { name: "ValidationError", message: "Description is required!" }; + if (!price || isNaN(price)) + throw { + name: "ValidationError", + message: "Price is required and must be a number!", + }; + if (!stock || isNaN(stock)) + throw { + name: "ValidationError", + message: "Stock is required and must be a number!", + }; + if (!imgUrl) + throw { name: "ValidationError", message: "Image URL is required!" }; + if (!categoryId || isNaN(categoryId)) + throw { + name: "ValidationError", + message: "Category ID is required and must be a number!", + }; + if (!userId || isNaN(userId)) + throw { + name: "ValidationError", + message: "User ID is required and must be a number!", + }; + + const product = await Product.findByPk(id); + if (!product) { + throw { + name: "NotFoundError", + message: `Product with ID ${id} not found`, + }; + } + await product.update(req.body); + res + .status(200) + .json({ message: `Product with ID ${id} successfully updated` }); + } catch (error) { + next(error); + } + } + + static async deleteProductById(req, res, next) { + try { + const id = parseInt(req.params.id); + if (isNaN(id)) { + throw { name: "ValidationError", message: "Invalid product ID" }; + } + const product = await Product.findByPk(id); + if (!product) { + throw { + name: "NotFoundError", + message: `Product with ID ${id} not found`, + }; + } + await product.destroy(); + res + .status(200) + .json({ message: `Product with ID ${id} successfully deleted` }); + } catch (error) { + next(error); + } + } +}; diff --git a/BACKEND/controllers/UserController.js b/BACKEND/controllers/UserController.js new file mode 100644 index 00000000..028f50f7 --- /dev/null +++ b/BACKEND/controllers/UserController.js @@ -0,0 +1,88 @@ +const { comparePassword } = require("../helpers/bcrypt"); +const { signToken } = require("../helpers/jwt"); +const { User } = require("../models"); +const { OAuth2Client } = require("google-auth-library"); +const client = new OAuth2Client(); + +module.exports = class UserController { + static async googleLogin(res, req, next) { + try { + const { googleToken } = req.body; + const ticket = await client.verifyIdToken({ + idToken: googleToken, + audience: WEB_CLIENT_ID, + }); + const payload = ticket.getPayload(); + + let user = await User.findOne({ where: { email:payload.email } }); + if (!user) { + user = await user.create({ + name: payload.name, + email: payload.email, + phoneNumber: Math.random(), + password: Math.random().toString(), + address: Math.random().toString() + }); + } + + console.log(req.body, "<<< body"); + + res.status(200).json({ message: "Login Success" }); + } catch (error) { + next(error); + } + } + + static async register(req, res, next) { + try { + const { username, email, phoneNumber, password, address, role } = + req.body; + if (!username || !email || !phoneNumber || !password || !address) { + throw { + name: "ValidationError", + message: "All data must be filled.", + }; + } + const user = await User.create({ + username, + email, + phoneNumber, + password, + address, + role, + }); + res.status(201).json({ + username: user.username, + email: user.email, + }); + } catch (error) { + next(error); + } + } + + static async login(req, res, next) { + try { + const { email, password } = req.body; + if (!email) { + throw { name: "ValidationError", message: "Email is required" }; + } + if (!password) { + throw { name: "ValidationError", message: "Password is required" }; + } + const user = await User.findOne({ where: { email } }); + if (!user) { + throw { name: "UnauthorizedError", message: "Invalid email/password" }; + } + const isValidPassword = comparePassword(password, user.password); + if (!isValidPassword) { + throw { name: "UnauthorizedError", message: "Invalid email/password" }; + } + const access_token = signToken({ id: user.id }); + res.status(200).json({ + access_token, + }); + } catch (error) { + next(error); + } + } +}; diff --git a/BACKEND/data/carts.json b/BACKEND/data/carts.json new file mode 100644 index 00000000..84038ac7 --- /dev/null +++ b/BACKEND/data/carts.json @@ -0,0 +1,32 @@ +[ + { + "id": 1, + "userId": 2, + "productId": 24, + "quantity": 2 + }, + { + "id": 2, + "userId": 2, + "productId": 24, + "quantity": 1 + }, + { + "id": 3, + "userId": 2, + "productId": 29, + "quantity": 3 + }, + { + "id": 4, + "userId": 2, + "productId": 37, + "quantity": 1 + }, + { + "id": 5, + "userId": 1, + "productId": 47, + "quantity": 2 + } +] diff --git a/BACKEND/data/categories.json b/BACKEND/data/categories.json new file mode 100644 index 00000000..903fa442 --- /dev/null +++ b/BACKEND/data/categories.json @@ -0,0 +1,106 @@ +[ + { + "id": 1, + "name": "Electronics" + }, + { + "id": 2, + "name": "Furniture" + }, + { + "id": 3, + "name": "Clothing" + }, + { + "id": 4, + "name": "Footwear" + }, + { + "id": 5, + "name": "Beauty & Personal Care" + }, + { + "id": 6, + "name": "Health & Wellness" + }, + { + "id": 7, + "name": "Home Appliances" + }, + { + "id": 8, + "name": "Kitchen & Dining" + }, + { + "id": 10, + "name": "Automotive" + }, + { + "id": 11, + "name": "Toys & Games" + }, + { + "id": 12, + "name": "Books & Stationery" + }, + { + "id": 13, + "name": "Baby Products" + }, + { + "id": 14, + "name": "Jewelry & Accessories" + }, + { + "id": 15, + "name": "Musical Instruments" + }, + { + "id": 16, + "name": "Pet Supplies" + }, + { + "id": 17, + "name": "Office Supplies" + }, + { + "id": 18, + "name": "Garden & Outdoor" + }, + { + "id": 19, + "name": "Tools & Hardware" + }, + { + "id": 20, + "name": "Groceries & Gourmet Food" + }, + { + "id": 21, + "name": "Art & Craft Supplies" + }, + { + "id": 22, + "name": "Movies & TV Shows" + }, + { + "id": 23, + "name": "Video Games" + }, + { + "id": 24, + "name": "Bags & Luggage" + }, + { + "id": 25, + "name": "Watches" + }, + { + "id": 26, + "name": "Halo" + }, + { + "id": 9, + "name": "New Name" + } +] diff --git a/BACKEND/data/products.json b/BACKEND/data/products.json new file mode 100644 index 00000000..4f182e22 --- /dev/null +++ b/BACKEND/data/products.json @@ -0,0 +1,1184 @@ +[ + { + "id": 22, + "name": "Cubic Lemari Pakaian Minimalis / Wardrobe Baju / LUNA LPM 301 - SonomaBl - Grey", + "description": "### Deskripsi Produk\n\nSimpan pakaian kesayanganmu di dalam lemari pakaian LUNA LPM 301 yang dilengkapi dengan rak, meja, dan cermin cantik yang dapat dibuka. Lemari ini menjaga pakaianmu tetap aman dari debu dan serangga.\n\n**Merk:** Cubic \n**Bahan:** Papan partikel ekspor kualitas dengan finishing sheet premium \n\n**Variasi Warna & Motif:** \n- Sonoma Black-Grey \n- Sonoma Oak-White \n\n**Dimensi Produk (MM):** \n1194 X 417.5 X 1843 \n**Dimensi Packing (MM):** \n1831 X 470 X 150 \n**Berat Total:** \n63,5 Kg \n\n**Kelebihan:** \n- Kuat dan kokoh \n- Pintu kaca dapat dibuka \n- Permukaan luas dan halus \n- Menggunakan edging \n- Desain elegan & minimalis \n- Particle board dengan bahan premium (Kualitas Terbaik) \n- Buku perakitan yang mudah dimengerti \n- Dibuat menggunakan mesin modern dari Jerman", + "price": 1029000, + "stock": 587, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522920/hacktiv8/branded/cubic-lemari-pakaian-minimalis-wardrobe-baju-luna-lpm-301-sonomabl-grey-qswxtjtx14i.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 24, + "name": "Rinso Matic Deterjen Cair Mesin Bukaan Depan 1.45L Twin Pack", + "description": "Rinso Matic Deterjen Cair Mesin Cuci Bukaan Depan dengan keharuman tahan lama. Menghilangkan noda membandel 3x lebih efektif, tersedia dalam ukuran 1.45L. Formula ini rendah busa dan tidak meninggalkan residu pada pakaian, serta direkomendasikan oleh mesin cuci terkemuka. Detergen ini mengandung aroma pink rose, jasmine, dan apple, yang tahan hingga 21 hari.\n\n**Cara Pemakaian:**\nCukup gunakan 1 tutup botol untuk cucian Anda (20-25 potong pakaian). Untuk noda membandel, oleskan deterjen pada noda, gosok sebentar, lalu masukkan ke dalam mesin cuci.\n\nDengan tagline \"Berani Kotor Demi Kebaikan\", Rinso Deterjen Mesin Cuci mengajak kamu untuk berani berbuat kebaikan tanpa takut kotor, serta meningkatkan kesadaran akan lingkungan dengan kemasan yang dapat didaur ulang.", + "price": 98800, + "stock": 71, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522930/hacktiv8/branded/rinso-matic-deterjen-cair-mesin-bukaan-depan-1.45l-twin-pack-9tgfl9aox1q.jpg", + "categoryId": 6, + "userId": 1 + }, + { + "id": 25, + "name": "Lemari Pakaian Sliding HPL 200 Putih Glossy - PutihGlossy1", + "description": "Lemari model pintu sliding door dengan finishing HPL dilengkapi kabinet pintu kaca transparan untuk menyimpan koleksi sehingga mudah dilihat. Dikenakan laci dibawah untuk penyimpanan barang kecil. Desain minimalis dan mewah, terbuat dari full panel MDF board 16mm. Produk ini adalah ukuran jumbo (Lebar: 200cm, Tinggi: 200cm, Luas: 60cm) dan merupakan limited edition. Dapat dibongkar pasang (knock down). Pengiriman dan pemasangan gratis untuk area JABODETABEK dan Bandung. Untuk daerah lain, biaya ekspedisi ditanggung pembeli. Pabrikan standar, pintu tidak dilengkapi kunci, tetapi kunci opsional dapat dipesan terpisah. Tersedia paket kabinet tambahan dengan harga spesial hanya untuk pembeli lemari ini. Kunjungi tautan berikut untuk melihat produk terkait kami lainnya seperti lemari pajangan, meja rias, meja TV, dan banyak lagi.", + "price": 4770000, + "stock": 95, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522934/hacktiv8/branded/lemari-pakaian-sliding-hpl-200-putih-glossy-putihglossy1-coscylrfaz.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 26, + "name": "Gerobak Mie Ayam", + "description": "**Gerobak Mie Ayam**\n\nGerobak Kaki Lima adalah industri yang menyediakan berbagai gerobak usaha dan furniture. Menerima pemesanan dalam jumlah kecil maupun besar. Gerobak ini cocok untuk memulai usaha kuliner Anda, dengan desain khas Jawa yang memberi kesan klasik.\n\n**Harga Terjangkau, Kualitas Terbaik.** \n**Ukuran:** \n• Panjang: 120 cm \n• Lebar: 65 cm \n• Tinggi: 190 cm \n• Tinggi Meja dari Bawah: 85 cm \n• Diameter Lubang Dandang: 36 cm \n**Bahan:** \n• Kayu Jati \n• Kayu Mahoni \n\n**Fitur:** \n• Rak Atas \n• Etalase \n• Kaki Lipat \n• Laci dengan Kunci \n• Etalase Bawah \n• Lubang Dandang \n• Tempat Saus Sambal \n\n**Keunggulan:** \n• Harga Hemat \n• Produk Berkualitas \n• Stok Tersedia \n• Banyak Varian Produk \n• Pembayaran di Tempat \n• Pengiriman Kilat \n• Permintaan Desain Diterima \n• Packing Aman \n• Tahan Gores \n\n**Kelengkapan:** \n• Paket Gerobak: Gerobak Mie Ayam Plitur \n• Paket Sederhana: Gerobak Mie Ayam Plitur, Roda Motor \n• Paket Standar: Gerobak Mie Ayam Plitur, Dandang = 1 pcs, Roda Motor = 2 pcs \n\n**Detail:** \n- Gerobak finishing melamine semprot (spray), bukan kuas \n- Bahan gerobak 100% Kayu Jati dan Kayu Mahoni \n- Sambungan gerobak menggunakan paku kayu dan lem \n\n*NB: Pengiriman luar Jawa dikenakan tambahan ongkir. Tanyakan ongkirnya ke admin karena tiap wilayah berbeda-beda. Bisa bayar di tempat (COD).* \n\n**Kontak:** wa.me/6285727578836 \n*Invoice dikirim via JNT / ANTERAJA / SICEPAT / dll terlebih dahulu. Geroabk dikirim via ekspedisi pribadi mengikuti jadwal pengiriman.* \n\n#gerobakbakso #gerobakmieayam #gerobakklasik #gerobakmiesojoglo #gerobakkekinian #gerobakjualan #gerobakangkringansayapbesar #gerobak #gerobakkayu #gerobakusaha #gerobakkuliner #gerobakmurah #gerobaksolo #gerobakklaten #gerobakjogja #gerobakusahamurah #gerobakkulinermurah #jasapembuatangerobak #jasapembuatangerobakkuliner #gerobakmakanan #gerobakjawabarat #gerobakjawatimur #gerobakmakanankekinian #gerobakkekinian #rombongpikul #gerobakbaksobali #gerobaksulawesi #gerobaksumatera", + "price": 2650000, + "stock": 100, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522935/hacktiv8/branded/gerobak-mie-ayam-y36yeppos1.jpg", + "categoryId": 8, + "userId": 1 + }, + { + "id": 46, + "name": "Lemari Pakaian HPL Sliding Transparan-Gamis-longdress-walk in closet - Cokat Tua Kayu", + "description": "Produksi Interior Design, lemari 2 pintu sliding door dengan finishing HPL dan full kaca bening/transparan. Model walk in closet/butik baju untuk gamis, long dress, dan koleksi. Desain eksklusif dengan bahan berkualitas, full MDF panel board 16mm dan kaca bening (non-tempered). Knock down dengan ukuran besar (Lebar: 160cm, Tinggi: 200cm, Dalam: 60cm). Sangat murah! Dipasaran, lemari sejenis harganya 8-10jt. Gratis pengiriman dan pemasangan untuk Jabodetabek. Untuk luar kota, ongkos ekspedisi ditanggung oleh pembeli. Jangan lupa untuk mengunjungi halaman daftar produk untuk model dan pilihan furniture kami lainnya.", + "price": 2650000, + "stock": 987, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522984/hacktiv8/branded/lemari-pakaian-hpl-sliding-transparan-gamis-longdress-walk-in-closet-cokat-tua-kayu-caubqirl86.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 23, + "name": "ANTBOX Lemari Pakaian Plastik 9 Kabinet 1 Hanger Pintu Magnet", + "description": "🌈 Selamat datang di ANTBOX Official Store.\n\nANTBOX menyediakan berbagai produk home furnishing secara global. Kami hadir sebagai solusi cerdas untuk Anda yang menginginkan produk furniture yang mudah dipasang dan berkualitas tinggi. ANTBOX menghadirkan teknologi \"Quickfold Free Decomposition\" yang menciptakan kabinet terpadu bebas perakitan, sehingga dapat dipasang secara mandiri.\n\n### Detail Produk Lemari Pakaian ANTBOX\n- **Merek:** ANTBOX \n- **Material:** Plastik PP (Kabinet), PET (Pintu), ABS, Magnet \n- **Warna:** Transparan \n- **Ukuran dan Berat Produk:** \n - 10 BOX 1 HANGER: Berat Bersih: 15,12 kg; Ukuran: 69 x 50 x 170 cm\n\n### Kenapa Harus Membeli Rak Sepatu ANTBOX?\n⭐ Lemari Pakaian ANTBOX bisa diinstal kurang dari 5 menit, sehingga menghemat waktu Anda. \n⭐ Bahan kokoh dapat menampung beban lebih dari 50 kg. \n⭐ Bagian Pintu dilengkapi magnet, sehingga pintu aman dan tidak mudah terbuka. \n⭐ Terbuat dari bahan yang aman, anti rayap, tidak beracun, tidak berbau, dan bebas formaldehida. \n⭐ Memiliki banyak pilihan ukuran sesuai kebutuhan.\n\n### Catatan:\n✨ Waktu Pengiriman: Pesanan sebelum jam 4 sore akan diproses pada hari yang sama, sedangkan pesanan setelah jam 4 akan diproses pada hari berikutnya. \n✨ Komplain wajib sertakan video unboxing. \n✨ Jika ada pertanyaan, silakan tanyakan terlebih dahulu pada admin kami.", + "price": 1513000, + "stock": 42, + "imgUrl": "https://ik.imagekit.io/3zpysfovqw/phase2/challenge/all-in-one/emily-armstrong_nuf0WhKY-.jpeg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 29, + "name": "Excel 500gr Makanan Kucing Cat Food Dry - Salmon", + "description": "Produk Mudah Penyok, disarankan untuk membeli tambahan packing karena kami menggunakan plastik biasa. Jika ingin menggunakan kardus atau bubble wrap, silakan klik link di bawah ini.\n\n**Bubble Wrap:**\n[Link untuk Bubble Wrap](https://www.tokopedia.com/salanova/packing-tambahan-bubble-wrap)\n\n**Kardus:**\n[Link untuk Kardus](https://www.tokopedia.com/salanova/kardus-tambahan-packing)\n\nEXCEL CAT adalah jajaran produk berkualitas tinggi yang menggunakan bahan baku impor berkualitas 100% alami. Tinggi protein dari daging ayam dan ikan asli, kaya akan taurine, omega 3 dan 6, serta mineral penting bagi kesehatan kucing Anda.\n\n**Keunggulan EXCEL CAT:**\n- Kerenyahan dengan rasa tuna yang lezat.\n- Mengandung serat tumbuhan alami untuk mencegah pembentukan bola rambut.\n- Terbuat dari bahan yang higienis dan alami.\n- Kaya Omega-3 untuk kulit sehat dan bulu berkilau.\n\n**Varian Rasa:**\n- Tuna (Donut)\n- Tuna (Ikan)\n- Ayam & Tuna (Segitiga)\n- Mother & Kitten - Chicken & Tuna (Segitiga)\n\n**Nutrisi untuk Dewasa:**\n- Protein: 30%\n- Fat: 14%\n- Fiber: 3%\n- Moisture: 7%\n- Taurine: 1%\n- Kalsium: 1.3%\n- Fosfor: 1.2%\n- Vit. A: 20.000 IU\n\n**Nutrisi untuk Mother & Kitten:**\n- Protein: 30%\n- Fat: 11%\n- Fiber: 3%\n- Moisture: 8%\n- Taurine: 0.15%\n- Kalsium: 2.5%\n- Fosfor: 1.5%\n- Vit. A: 18.000 IU/kg\n\n**Cara Pemesanan:**\nPilih varian yang diinginkan di menu pilihan rasa. Tidak menerima pilihan rasa melalui chat atau catatan pesanan.", + "price": 11499, + "stock": 1389, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522943/hacktiv8/branded/excel-500gr-makanan-kucing-cat-food-dry-salmon-t15qfiax4w9.jpg", + "categoryId": 16, + "userId": 1 + }, + { + "id": 30, + "name": "Gerobak Soto Lamongan", + "description": "❗ Gerobak Soto Lamongan ❗ Gerobak Kaki Lima yang ideal untuk memulai usaha kuliner. Didesain dengan etalase miring, gerobak ini terbuat dari Kayu Jati dan Kayu Mahoni. \n\n**Ukuran:** \n- Panjang: 170 cm \n- Lebar: 70 cm \n- Tinggi: 190 cm \n- Diameter Lubang Jimbeng: 33 cm \n- Tinggi Meja dari Bawah: 90 cm \n\n**Fitur:** \n- Etalase Bawah \n- Kaki Lipat \n- Rak Atas \n- Lubang Jimbeng \n- Etalase \n\n**Keunggulan:** \n- Harga Hemat \n- Produk berkualitas \n- Stok tersedia \n- Banyak Varian Produk \n- Bisa Bayar di Tempat \n- Pengiriman Kilat \n- Bisa Request Desain \n- Packing aman \n- Tahan Gores \n\n**Paket Gerobak:** \n1. Gerobak Soto Lamongan tanpa roda \n2. Gerobak Soto Lamongan + Roda \n3. Gerobak Soto Lamongan + Roda, 1 Jimbeng \n\nDetail: \n- Gerobak finishing melamine semprot \n- Sambungan menggunakan paku kayu + lem \n\n**Catatan:** Pengiriman luar Jawa ada biaya tambahan. Hubungi admin untuk info ongkir. Pembayaran dapat dilakukan di tempat (COD).", + "price": 2900000, + "stock": 100, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522947/hacktiv8/branded/gerobak-soto-lamongan-gt9wevnewpf.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 31, + "name": "Lemari Pakaian Premium Full Cermin Scandinavian Frameless Sliding - 90x50x180cm", + "description": "### Spesifikasi Produk:\n- **Material:** Kayu MDF \n- **Finishing:** Papersheet \n- **Ukuran (P x L x T):** \n - 90 x 50 x 180 cm \n - 120 x 50 x 180 cm \n - 150 x 50 x 180 cm \n- **Metode Pintu:** Sliding Door (Digeser)\n\n### Informasi:\n- Pre-order -+ 7 hari (tergantung antrian) \n- Dapat request warna dan ukuran furniture (harga menyesuaikan) \n- GRATIS pemasangan & pengiriman untuk wilayah JABODETABEK \n- Dapat custom kompartemen sesuai kebutuhan \n\n### Keunggulan Merakit Ruang:\n1. Menggunakan bahan berkualitas, kokoh dan sudah teruji. \n2. Gratis pengiriman Jabodetabek (untuk pengiriman luar Jabodetabek, silakan chat admin) \n3. Pengiriman oleh kurir pribadi dengan teknisi, barang dirakit/set-up di tempat di hari yang sama \n4. Kurir dan tukang berpengalaman \n5. Harga terjangkau dan terima beres \n6. Custom furniture tanpa ribet \n\n### S&K Komplain:\n1. Sebelum order, tim kami akan konfirmasi. Jika customer sudah ACC, dilarang mengubah atau membatalkan pesanan. \n2. Kesalahan ukuran diluar tanggung jawab kami. \n3. Garansi hanya berlaku saat pengiriman. Jika ada komponen cacat, sampaikan ke teknisi kami saat serah terima. \n4. Kesalahan pemilihan warna Papersheet/HPL diluar tanggung jawab kami. \n5. Untuk request kompartemen, ukuran tidak bisa dipatokan secara baku.", + "price": 2200000, + "stock": 9948, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522957/hacktiv8/branded/lemari-pakaian-premium-full-cermin-scandinavian-frameless-sliding-90x50x180cm-im6roil2mu.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 32, + "name": "Gerobak Soto Pikul Rombong Soto Kudus", + "description": "Gerobak Soto Pikul Kudus adalah gerobak soto model pikul. Gerobak Kaki Lima merupakan industri gerobak usaha yang menyediakan berbagai gerobak dan furniture. Kami menerima pemesanan partai kecil maupun besar. Gerobak ini sangat cocok untuk memulai usaha kuliner Anda, dengan model pikulan khas Jawa yang memberikan nuansa klasik.\n\n**Detail Ukuran:**\n- Panjang: 165 cm\n- Lebar: 85 cm\n- Tinggi: 165 cm\n- Diameter Lubang Jimbeng: 33 cm\n- Tinggi Meja dari Bawah: 75 cm\n\n**Bahan:**\n- Kayu Jati\n- Kayu Mahoni\n\n**Fitur:**\n- Rak Atas\n- Pikulan Rotan\n- Lubang Anglo\n- Etalase\n- Laci dengan Kunci\n\n**Keunggulan:**\n- Harga Hemat\n- Produk Berkualitas\n- Stok Tersedia\n- Banyak Varian Produk\n- Bisa Bayar di Tempat\n- Pengiriman Kilat\n- Bisa Request Desain\n\nGerobak ini menggunakan finishing melamine semprot (spray) dan terbuat 100% dari Kayu Jati & Kayu Mahoni. Sambungan menggunakan paku kayu dan lem. Pengiriman luar Jawa dikenakan tambahan biaya. Untuk bayar di tempat (COD), silakan hubungi admin. Invoice dikirim via JNT/ANTERAJA/SICEPAT terlebih dahulu. GEROBAK dikirim melalui ekspedisi pribadi mengikuti jadwal pengiriman.", + "price": 2650000, + "stock": 50, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522962/hacktiv8/branded/gerobak-soto-pikul-rombong-soto-kudus-46xmt73esbv.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 33, + "name": "COOGER Panda Dual Clean Mop Terbaru 2in1 Spin Mop Pel Otomatis", + "description": "### Deskripsi Produk\n\nCOOGER Panda Dual Clean Mop Terbaru 2in1 Spin Mop adalah alat pel otomatis terbaru yang dapat memisahkan air kotor dan bersih secara otomatis dengan desain menarik seperti Panda.\n\n#### Spesifikasi:\n- **Bahan:** PP + Baja Tahan Karat + ABS\n- **Warna:** Hitam + Putih\n- **Berat:** 1950 gr\n- **Ukuran Pel:** 135 x 20 x 20 cm\n- **Ukuran Ember:** 28.5 x 28.5 x 19 cm\n- **Kelengkapan:** 1 Ember Panda, 1 Batang Pel, 2 Kain Pel\n\n#### Keunggulan:\n1. Desain inovatif yang menyerupai mesin cuci dengan kemampuan memisahkan air secara otomatis.\n2. Desain yang menarik dan nyaman ditempatkan di berbagai ruang.\n3. Dilengkapi gerigi untuk pembersihan kain pel yang sempurna.\n4. Tersedia 2 jenis kain pel untuk membersihkan secara menyeluruh.\n5. Kemampuan berputar 360 derajat untuk menjangkau segala sudut ruangan.\n\nUntuk pertanyaan lebih lanjut, silakan hubungi tim Customer Service kami. Pemesanan dalam jumlah besar dapat menghubungi kami untuk mendapatkan harga spesial! Setiap pengembalian produk yang cacat harus disertai video unboxing. Pesanan yang diterima pada hari Minggu akan diproses pada hari Senin, dan khusus hari libur nasional, pesanan akan diproses sesudah jam operasional.\n\nSelamat berbelanja! COOGER Easy Life! :D", + "price": 299900, + "stock": 57, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522964/hacktiv8/branded/cooger-panda-dual-clean-mop-terbaru-2in1-spin-mop-pel-otomatis-v71xni9ds5s.jpg", + "categoryId": 7, + "userId": 1 + }, + { + "id": 47, + "name": "Reffil Reed Diffuser High Quality - Eng Pear, +Sticks", + "description": "Refill reed diffuser 100ml\n\nHigh quality reed diffuser oil.\nAroma bertahan sampai dengan 60 hari dalam satu kali pemakaian.\n\nTulis di note untuk aroma yang dipilih:\n1. Elizabeth Arden Green Tea\n2. Jo Malone English Pear\n3. Dior Sauvage\n4. Dolce Gab: Light Blue", + "price": 90000, + "stock": 1995, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522987/hacktiv8/branded/reffil-reed-diffuser-high-quality-eng-pear-%2Bsticks-fyvwngk6ch8.jpg", + "categoryId": 5, + "userId": 1 + }, + { + "id": 34, + "name": "Sendal Flat Selop Rumah Slipper Sandal Pria Wanita Karet Jelly HSN150 - 150 PUTIH, 40-41", + "description": "### Deskripsi Produk\n\nSandal Slipper Slip-On dengan alas kaki tebal dan anti licin. Sangat lembut saat digunakan dan tidak membuat kaki nyeri saat berjalan jauh. Desain estetis yang sederhana tetapi elegan, terbuat dari bahan fleksibel sehingga tidak mudah berubah bentuk. Nyaman dan cocok untuk digunakan di rumah atau saat bepergian.\n\n### Keunggulan Produk:\n- Warna modern dan bahan empuk\n- Ringan dengan sol super empuk, tidak membuat kaki lelah saat berjalan, tali belakang tidak membuat sakit saat dipakai\n- Desain menarik pada sol maupun permukaan sandal atas, sangat anti selip\n\n**Varian:**\n- 150: Hitam, Putih, Abu, Beige (warna polos)\n- 151: Hitam (warna gradasi)\n\n**Bahan:** PVC (sedikit bau plastik, tetapi akan hilang setelah penggunaan 2 hari)\n\n**Ukuran:**\n- 36-37 : 23 cm\n- 38-39 : 24 cm\n- 40-41 : 25 cm\n- 42-43 : 26 cm\n- 44-45 : 27 cm\n\n*Untuk jenis kaki dengan punggung tebal dan lebar, disarankan untuk pesan 1 ukuran lebih besar.*\n\n### Catatan Penting:\n- Keluhan tanpa video pembukaan tidak akan dianggap sah.\n- Penjual tidak bertanggung jawab atas segala kerusakan yang terjadi selama pengiriman.\n- Pesanan akan dikirimkan sesuai pilihan saat checkout; tidak ditulis di catatan.\n- Jika barang yang dipesan habis, akan diganti dengan produk atau warna lain.", + "price": 29880, + "stock": 61, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522965/hacktiv8/branded/sendal-flat-selop-rumah-slipper-sandal-pria-wanita-karet-jelly-hsn150-150-putih-40-41-ga1ze6dmma5.jpg", + "categoryId": 4, + "userId": 1 + }, + { + "id": 36, + "name": "ANTBOX Lemari Pakaian Plastik Susun Putih Minimalis Lemari Baju - 6 BOX 1 HANGER", + "description": "### Selamat datang di ANTBOX Official Store\n\nANTBOX menyediakan berbagai produk home furnishing secara global. Kami hadir sebagai solusi cerdas untuk Anda yang menginginkan produk furniture yang mudah dipasang dan berkualitas tinggi. Dengan teknologi \"Quickfold Free Decomposition\", kabinet ini bebas perakitan dan dapat dipasang secara mandiri.\n\n#### Detail Produk Lemari Pakaian ANTBOX\n- **Merek:** ANTBOX\n- **Material:** Plastik PP (Kabinet), PET (Pintu), ABS, Magnet \n- **Warna:** Transparan \n\n#### Ukuran dan Berat Produk:\n- **6 Box:** Berat bersih: 9 kg; Ukuran: 69 x 50 x 18.8 cm, 360L\n\n#### Mengapa Harus Membeli Rak Sepatu ANTBOX?\n- Instalasi dalam kurang dari 5 menit, menghemat waktu Anda.\n- Bahan kokoh mampu menampung beban lebih dari 50 kg.\n- Pintu dilengkapi magnet agar tidak mudah terbuka.\n- Terbuat dari bahan aman, anti rayap, tidak beracun, tidak berbau, dan bebas formaldehida.\n- Tersedia berbagai pilihan ukuran sesuai kebutuhan.\n\n#### Catatan:\n- **Waktu Pengiriman:** Pesanan sebelum jam 4 sore akan diproses pada hari yang sama, setelah jam tersebut akan diproses pada hari berikutnya.\n- **Komplain:** Harap sertakan video unboxing saat mengajukan keluhan.\n- Jika ada pertanyaan, silakan tanyakan terlebih dahulu pada admin kami.", + "price": 1153000, + "stock": 85, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522972/hacktiv8/branded/antbox-lemari-pakaian-plastik-susun-putih-minimalis-lemari-baju-6-box-1-hanger-t1z1uaixj6.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 37, + "name": "Sepatu Casual Nike AF1 MLB White Black Sneakers Kets New - MLB White Black (Size 39)", + "description": "### Bonus: FREE BOX\n\nBarang 100% sesuai foto karena kami foto sendiri!\nMenerima pesanan grosir & ecer. Mohon dibaca dulu sebelum membeli.\n\n**Perkiraan Ukuran:**\n- 36 = 21cm\n- 37 = 22cm\n- 38 = 23cm\n- 39 = 24cm\n- 40 = 25cm\n- 41 = 26cm\n- 42 = 27cm\n- 43 = 28cm\n- 44 = 29cm\n\nTolong dibaca catatan kami mengenai ketentuan barang, karena setelah Anda klik beli, kami anggap Anda menyetujui segala apa yang kami sampaikan pada catatan deskripsi. Terima kasih.", + "price": 349000, + "stock": 998, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522974/hacktiv8/branded/sepatu-casual-nike-af1-mlb-white-black-sneakers-kets-new-mlb-white-black-%28size-39%29-0kn866td4u3.jpg", + "categoryId": 4, + "userId": 1 + }, + { + "id": 38, + "name": "ZACRO Penutup Kaca depan Mobil Pelindung Panas Sun Shield Kaca Mobil - 145cm x 80cm", + "description": "Payung Pelindung Anti Panas untuk Kaca Depan Mobil. \n\n**Ukuran:** 145 x 80 cm (Large) \n\n**Termasuk:** \n1. Anti sunshade untuk Kaca Depan Mobil \n2. Pouch untuk penyimpanan \n\n**Kelebihan:** \n1. Mengurangi panas secara signifikan. \n2. Pemasangan yang sangat mudah, semudah membuka payung! \n3. Bagian dalam: Hitam, Bagian luar: Silver, cocok untuk menangkal panas masuk. \n4. Material Titanium Silver Sunscreen Cloth. \n5. Mudah disimpan, dapat disimpan di holder payung. \n6. Perlindungan UV hingga 90% dari panas matahari. \n7. Waterproof, Windproof, anti-scratch dan tidak berbau. \n8. Melindungi interior mobil agar tidak cepat rusak akibat panas matahari.", + "price": 45000, + "stock": 296, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522975/hacktiv8/branded/zacro-penutup-kaca-depan-mobil-pelindung-panas-sun-shield-kaca-mobil-145cm-x-80cm-ilirx4luour.jpg", + "categoryId": 7, + "userId": 1 + }, + { + "id": 39, + "name": "ZACRO Y80 Intercom Helm Bluetooth Chip Qualcomm Waterproof IPX6", + "description": "1. Chip Qualcomm: Bluetooth 5.0\n\n2. Baterai lithium polimer bawaan 3.7V\n\n3. Kapasitas baterai: 1000mAh, interkom dua orang, jarak interkom 800M (dapat disesuaikan dengan yang ketiga persegi)\n\n4. Kompatibel dengan interkom headset Bluetooth biasa (jarak interkom 10-50 meter)\n\n5. Pengurangan kebisingan CVC, panggilan jernih pada jarak hingga 100 mil\n\n6. Koeksistensi mode ganda: dalam mode interkom, panggilan masuk dijawab terlebih dahulu\n\n7. Jarak transmisi: 10M\n\n8. Waktu siaga: 300 jam\n\n9. Waktu bicara: 25 jam, waktu interkom: 15 jam\n\n10. Asisten suara AI: dukungan\n\n11. Tingkat tahan air: IP67\n\n12. Mendukung menghubungkan dua ponsel sekaligus\n\n13. Mengautomatisasi penjawaban panggilan masuk (mode manual dapat dialihkan)\n\n14. Speaker berkualitas tinggi berdiameter 40㎜\n\n15. Kompatibel dengan Android, Apple, dan Hongmeng\n\n16. Fitur: Bluetooth, tahan air, tahan debu, interkom, pengurangan kebisingan, tampilan daya, kontrol suara, dukungan musik, koneksi multi-titik\n\n17. Saluran stereo dan stereo bilateral.\n\nHelm interkom sepeda motor Y80-2X juga kompatibel dengan headset interkom ZACRO E1, EJEAS V6 PRO, dan EJEAS Q7.", + "price": 342000, + "stock": 499, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522976/hacktiv8/branded/zacro-y80-intercom-helm-bluetooth-chip-qualcomm-waterproof-ipx6-83zrk6ds8wh.jpg", + "categoryId": 1, + "userId": 1 + }, + { + "id": 128, + "name": "Lampu gantung plafon kipas angin minimalis modern body white - TIPE-B", + "description": "### Nama Produk: Lampu Gantung Kipas 2 IN 1\n- **Diameter**: 82 cm x 13 cm \n- **Motor Type**: DC \n- **Jumlah Baling Kipas**: 7 \n- **Type Lampu**: 60*2W Led (3 warna) \n- **Kecepatan Putaran Angin**: 6 tingkat \n- **Frequency**: 50/60 Hz \n- **Net Weight**: 3.5 Kg \n- **Metode Kontrol**: Remote control (termasuk) + sakelar \n- **Tegangan**: 220V \n- **Area Pencahayaan**: 12-18 meter persegi \n- **Lokasi**: Ruang Tamuk/Kamar Tidur/Dapur \n- **Daftar Perangkat Lunak**: fg \n- **Isi Paket**: 1 * Lampu Gantung Kipas", + "price": 995280, + "stock": 13, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523153/hacktiv8/branded/lampu-gantung-plafon-kipas-angin-minimalis-modern-body-white-tipe-b-joqracufb2d.jpg", + "categoryId": 7, + "userId": 1 + }, + { + "id": 40, + "name": "Cuka Apel Organik 1 Liter Apple Cider Vinegar Premium With The Mother - CUKA 2 X 500ML", + "description": "Cuka Apel dibuat dari apel pilihan dengan sistem fermentasi alami, tanpa menggunakan zat kimia, ragi, pewarna, atau pemanis buatan, serta tanpa proses pasteurisasi. Produk ini masih mengandung ‘MOTHER’ yang merupakan bakteri probiotik. Cuka Apel sangat cocok untuk meningkatkan rasa masakan Anda.\n\n-- GARANSI barang pecah/rusak dengan mengirimkan foto dan video unboxing (WAJIB) --\n\nDikirim dalam 2 botol x 500ml atau 4 botol x 250ml (Dapat request di varian produk).\n\nIzin PIRT: 2093671090739-28\nHalal MUI: ID36110015859870124\n\n**Manfaat Cuka Apel:**\n1. Mengurangi radikal bebas dalam tubuh\n2. Mencegah penyakit jantung\n3. Mengurangi berat badan\n4. Meningkatkan sistem imun\n5. Menyehatkan tulang\n6. Meningkatkan kesehatan mata\n7. Mencegah kanker\n8. Meningkatkan kinerja sistem pencernaan\n9. Meningkatkan kesuburan\n10. Membuat kulit lebih halus\n11. Menormalkan kolesterol\n12. Menormalkan tekanan darah\n13. Menormalkan asam urat\n14. Menyembuhkan sariawan\n15. Mengatasi sakit tenggorokan\n\nCuka Apel juga dapat digunakan untuk memperlezat masakan Anda. Bisa dicampur dengan madu, juice, smoothies atau sebagai salad dressing.\n\n**Cara penyimpanan:**\n- Simpan pada suhu ruangan.\n- Hindari paparan sinar matahari langsung.\n- Tidak perlu dikulkas karena mother apel tetap aktif di suhu ruangan.\n\n^^ Langsung Check Out - Selalu Ready Stock!! ^^ \n^^ Pengiriman tetap ada di Hari Sabtu/Minggu/Tanggal Merah (setiap hari) ^^ \n^^ Sameday/Instant diproses maksimal pukul 14.00 WIB, Reguler maksimal diproses pukul 13.00 WIB ^^", + "price": 55000, + "stock": 104, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522977/hacktiv8/branded/cuka-apel-organik-1-liter-apple-cider-vinegar-premium-with-the-mother-cuka-2-x-500ml-j4dhv1t0psh.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 41, + "name": "Crocs Swifwater Mesh Deck - NAVY ORANGE, M10", + "description": "Crocs Swifwater Mesh Deck tersedia dalam warna Hitam Full, Coklat, Hitam Biru, Navy Toska, dan Army.\n\nUkuran yang tersedia: M7,8,9,10,11\n- M7 = 40\n- M8 = 41\n- M9 = 42\n- M10 = 43\n- M11 = 44\n\nSendal ini adalah BEST SELLER, nyaman dipakai, dan mudah dibersihkan. Sangat cocok untuk digunakan di air, dan tidak licin.\n\n**Mengapa belanja di Glory Jaya?**\n1. Keberhasilan dalam menjual banyak barang.\n2. Kepuasan pelanggan yang tinggi.\n3. Pengiriman cepat.\n4. Kualitas barang terjamin meskipun ada harga yang lebih murah.\n5. Cek ketelitian barang sebelum dikirim.\n6. Banyak reseller/dropshipper yang setia.\n7. Banyak pelanggan yang memfavoritkan toko kami.\n\nHati-hati dengan tawaran di bawah harga karena bisa jadi kualitas berbeda atau stok habis.\n\nBelanja di toko kami yang terpercaya dan responsif dijamin tidak akan mengecewakan!", + "price": 287000, + "stock": 3, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522979/hacktiv8/branded/crocs-swifwater-mesh-deck-navy-orange-m10-a4yc97lwdsp.jpg", + "categoryId": 4, + "userId": 1 + }, + { + "id": 42, + "name": "EJ - Mainan Balok Susun Panda Park Nano Block Mainan Anak EdukasI - Panda 1", + "description": "EJ - Mainan Balok Susun Panda Park Kotak Nano Block adalah mainan edukatif untuk anak-anak yang memperkenalkan konsep bangunan. \n\n### Karakteristik:\n- **Blok bangunan pendidikan**: Mampu merangsang kemampuan anak dalam memanipulasi, memvisualisasikan, dan memecahkan masalah.\n- **Meningkatkan interaksi**: Memungkinkan anak-anak untuk membangun, bermain, dan belajar, serta memperkuat interaksi antara orang tua dan anak.\n- **Merangsang imajinasi**: Mengembangkan rasa ruang tiga dimensi dan meningkatkan daya khayal.\n- **Hadiah terbaik**: Bentuk hewan lucu membuatnya sebagai hadiah ideal untuk anak-anak. \n\n### Spesifikasi:\n- **Bahan**: Plastik\n- **Usia yang berlaku**: Lebih dari 14 tahun.\n\n### Catatan: \nHarap di bawah pengawasan orang dewasa saat bermain. Tidak cocok untuk anak di bawah 6 tahun karena bahaya tersedak.", + "price": 27500, + "stock": 12, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522980/hacktiv8/branded/ej-mainan-balok-susun-panda-park-nano-block-mainan-anak-edukasi-panda-1-5n2o0qeg3t4.jpg", + "categoryId": 11, + "userId": 1 + }, + { + "id": 43, + "name": "ANTBOX Smart Display Box Kotak Sepatu Otomatis dengan Remote Control", + "description": "🌈 Selamat datang di ANTBOX Official Store. ANTBOX menyediakan berbagai produk home furnishing secara global dengan solusi cerdas untuk furniture yang mudah dipasang dan berkualitas tinggi. Produk ini menggunakan teknologi 'Quickfold Free Decomposition' untuk kabinet terpadu yang bebas perakitan.\n\n### Detail Produk Rak Sepatu ANTBOX\n- **Merek**: ANTBOX\n- **Warna**: Transparan\n- **Fitur**: Pintu kotak sepatu otomatis dengan touchscreen atau remote control\n\n### Ukuran Produk\n- 4 BOX SEPATU UNTUK 4 PASANG (max. size 44-45)\n\n### Kenapa Harus Membeli Produk ANTBOX?\n- Instalasi dalam waktu kurang dari 3 menit, menghemat waktu.\n- Bahan kokoh bisa menampung beban lebih dari 60 kg.\n- Pintu dilengkapi magnet sehingga aman tidak mudah terbuka.\n- Terbuat dari bahan yang aman, tidak beracun, tidak berbau, dan bebas formaldehida.\n- Tersedia berbagai ukuran sesuai kebutuhan.\n\n### Tips Penggunaan:\n1. Sangat cocok untuk penghuni apartemen, hemat tempat. Mudah dirakit, cukup tarik dan buka.\n2. Cocok untuk ruangan seperti ruang tamu, kamar tidur, kamar mandi, dan lainnya.\n3. Dapat digunakan untuk menyimpan sepatu, pakaian, buku, kosmetik, dan bahan makanan.", + "price": 2386000, + "stock": 18, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522981/hacktiv8/branded/antbox-smart-display-box-kotak-sepatu-otomatis-dengan-remote-control-p6jiolo8k.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 44, + "name": "Nike Airmax 1 Easy On Pulse - Sepatu Anak", + "description": "Nike Airmax 1 Easy On Pulse tersedia dalam 8 warna.\n\n**Size**: 28, 29, 30, 31, 32, 33, 34, 35, 36, 37\n\n**Size Chart**:\n- EUR 28 = Feet Length 17.0cm = 11C\n- EUR 29 = Feet Length 18.0cm = 12C\n- EUR 30 = Feet Length 18.5cm = 12.5C\n- EUR 31 = Feet Length 19.0cm = 13C\n- EUR 32 = Feet Length 20.0cm = 1Y\n- EUR 33 = Feet Length 21.0cm = 2Y\n- EUR 34 = Feet Length 21.5cm = 2.5Y\n- EUR 35 = Feet Length 22.0cm = 3Y\n- EUR 36 = Feet Length 22.5cm = 4Y\n\n**Features**:\n- Lengkap dengan dus.\n- Original, jika KW garansi uang kembali.\n\n**Mengapa Belanja di Glory Jaya**:\n1. Banyak barang yang terjual.\n2. Kepuasan pelanggan yang tinggi.\n3. Pengiriman barang cepat.\n4. Kualitas kami terjamin.\n5. Cek barang secara teliti sebelum kirim.\n6. Banyak reseller/dropshipper setia.\n7. Pelanggan yang memfavoritkan toko kami.\n\nKami terpercaya dengan respons cepat dan memastikan kepuasan konsumen.", + "price": 390000, + "stock": 1, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522982/hacktiv8/branded/nike-airmax-1-easy-on-pulse-sepatu-anak-yc38wxu7i19.jpg", + "categoryId": 4, + "userId": 1 + }, + { + "id": 45, + "name": "ANTBOX Lemari Pakaian Putih 12 Box 2 Hanger Lemari Baju Minimalis", + "description": "🌈 Selamat datang di ANTBOX Official Store\n\nANTBOX menyediakan berbagai produk home furnishing secara global. Sebagai solusi cerdas, ANTBOX menawarkan furniture yang mudah dipasang dan berkualitas tinggi.\n\nANTBOX menghadirkan teknologi \"Quickfold Free Decomposition\" yang memungkinkan pemasangan kabinet terpadu tanpa perakitan. Produk ini memungkinkan instalasi kurang dari 5 menit, sehingga menghemat waktu Anda.\n\n**Detail Produk:**\n- **Merek:** ANTBOX\n- **Material:** Plastik PP (Kabinet), PET (Pintu), ABS, Magnet\n- **Warna:** Transparan\n- **Ukuran dan Berat:** 12 BOX 2 HANGER; Berat Bersih: 17,67 kg; Ukuran: 104 * 50 * 136 cm\n\n**Keunggulan:**\n- Menampung beban lebih dari 50 kg\n- Bagian pintu dilengkapi magnet agar aman dan tidak mudah terbuka\n- Terbuat dari bahan aman, anti rayap, tidak beracun, tidak berbau, dan bebas formaldehida\n- Tersedia banyak pilihan ukuran sesuai kebutuhan\n\n**Catatan:**\n- Waktu Pengiriman: Pesanan sebelum jam 4 sore akan diproses pada hari yang sama. Pesanan setelah jam 4 akan diproses pada hari berikutnya.\n- Komplain wajib sertakan video unboxing.\n- Jika ada pertanyaan, silakan tanyakan pada admin kami.", + "price": 1869000, + "stock": 17, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522983/hacktiv8/branded/antbox-lemari-pakaian-putih-12-box-2-hanger-lemari-baju-minimalis-pwk2qtwipse.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 48, + "name": "ANTBOX Lemari Pakaian Plastik Susun Putih Minimalis Lemari Baju - 6 BOX 1 HANGER", + "description": "🌈 Selamat datang di ANTBOX Official Store.\n\nANTBOX menyediakan berbagai produk home furnishing secara global. Kami hadir sebagai solusi cerdas untuk Anda yang menginginkan produk furniture yang mudah dipasang dan berkualitas tinggi. Dengan teknologi \"Quickfold Free Decomposition\", kami menawarkan kabinet terpadu yang bebas perakitan, sehingga bisa dipasang secara mandiri.\n\n### DETAIL PRODUK LEMARI PAKAIAN ANTBOX\n- **Merek**: ANTBOX\n- **Material**: Plastik PP (Kabinet) + PET (Pintu) + ABS + Magnet\n- **Warna**: Transparan\n\n### Ukuran dan Berat Produk:\n- **6 Box**: berat bersih: 9 kg; ukuran: 69 x 50 x 18.8 cm, 360L\n- **12 Box**: berat bersih: 17,67 kg; ukuran: 104 x 50 x 23.8 cm, 710L\n\n### Kenapa Harus Membeli Lemari Pakaian ANTBOX?\n- Instalasi kurang dari 5 menit, menghemat waktu Anda.\n- Bahan kokoh, dapat menampung beban lebih dari 50 kg.\n- Pintu aman dilengkapi magnet, tidak mudah terbuka.\n- Terbuat dari bahan aman, anti rayap, tidak beracun, tidak berbau, dan bebas formaldehida.\n- Tersedia banyak pilihan ukuran sesuai kebutuhan.\n\n### NOTE:\n- Waktu Pengiriman: Pesanan sebelum jam 16:00 akan diproses pada hari yang sama; setelah jam 16:00 akan diproses pada hari berikutnya.\n- Komplain wajib sertakan video unboxing.\n- Jika ada pertanyaan, silakan bertanya kepada admin kami.", + "price": 1153000, + "stock": 85, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522988/hacktiv8/branded/antbox-lemari-pakaian-plastik-susun-putih-minimalis-lemari-baju-6-box-1-hanger-1h8115w9cta.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 49, + "name": "SAPPORO BOLOGNA - Lemari Pakaian Besi 3 Pintu | Steel Wardrobe 3 Doors - Rainbow", + "description": "SAPPORO BOLOGNA - Lemari Pakaian Besi 3 Pintu adalah produk lemari pakaian berkualitas dari Sapporo Furniture.\n\n**Spesifikasi Produk:**\n- Rangka: Plat Besi Tebal 0.5 mm\n- Finishing Rangka: Powder Coating\n- Jumlah Pintu: 3\n- Model Pintu: Swinging\n- Ukuran Cermin: 84 cm x 25 cm\n- Dimensi Produk: 120 cm x 50 cm x 190 cm\n- Packing: Kardus\n\n**Keunggulan Produk:**\n- Anti jamur\n- Anti rayap\n- Dilengkapi brankas\n- Cermin dibalik pintu\n- Motif gambar eksklusif dan modern pada pintu\n\n**Kegunaan Produk:**\n- Lemari pakaian\n\n**Syarat & Ketentuan:**\n- *Wilayah Jabodetabek Kota*: Pengiriman dalam wilayah ini dapat memilih metode \"Kurir Toko\" untuk mendapatkan gratis biaya kirim dan instalasi.\n- *Wilayah luar Jabodetabek*: Produk dikirim dalam kondisi knock down dan menggunakan kargo. Semua klaim kerusakan produk harus disertakan dengan bukti video unboxing; tanpa itu, klaim akan ditolak. Harus menggunakan Packing Kayu Jumbo.\n- *Wilayah pinggir kota Jabodetabek*: Jika ingin menggunakan jasa pengiriman dan instalasi dari SAPPORO FURNITURE, silakan hubungi admin kami.\n\nHarga sudah termasuk PPN, faktur pajak dapat diterbitkan jika diperlukan.", + "price": 2499900, + "stock": 18, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522990/hacktiv8/branded/sapporo-bologna-lemari-pakaian-besi-3-pintu-or-steel-wardrobe-3-doors-rainbow-lc587d6e0p.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 50, + "name": "REFILL Reed Diffuser OIL Ready To Use 250ml - Hidden Gem", + "description": "Reed Diffuser Refill dapat langsung digunakan dan diletakkan di wadah diffuser Anda.\n\n### Nuansa Aroma:\n- **Michelin:** Suasana super mewah ala hotel berbintang enam yang memberikan relaksasi.\n- **Califia Milk:** Bagi pecinta aroma manis, kamar Anda akan semerbak dengan wangi yang kuat.\n- **Verbena Pakubwn:** Nuansa alami yang memberikan kesan tinggal di apartemen mewah.\n- **Crystal:** Aroma mewah seperti parfum dengan sentuhan manis dan segar.\n- **Marina Trench:** Nuansa akuatik yang segar seperti lautan dalam.\n- **Rose and Love:** Aroma floral dengan sentuhan kasih yang mendalam.\n- **Peony Suede:** Aroma kalem dan segar dari bunga peony.\n- **Madagascar Scent:** Aroma segar dengan sedikit jahe, lembut dan elegan.\n- **Wood Elegant:** Perpaduan kayu yang elegan, cocok bagi pencinta kayu.\n\n### Informasi Tambahan:\n- **Coverage area:** Cocok untuk 1 Kamar Tidur / 1 Kamar Mandi / Ruang tamu kecil.\n- **Harga:** Terjangkau dan baik.\n\n**Catatan:** Mohon tunggu 2 hari untuk hasil yang lebih baik. Produk ini tidak menggunakan alkohol, sehingga penguapannya konsisten dan efektif. Custom aroma tersedia, silakan hubungi tim kami untuk ukuran dan aroma lainnya. Untuk ukuran lebih kecil bisa dilihat [di sini](https://www.tokopedia.com/go-nature/refill-reed-diffuser-oil-ready-to-use-30ml-sample-size).", + "price": 165000, + "stock": 347, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522992/hacktiv8/branded/refill-reed-diffuser-oil-ready-to-use-250ml-hidden-gem-bn9glzla7ok.jpg", + "categoryId": 5, + "userId": 1 + }, + { + "id": 51, + "name": "ANTBOX Lemari Penyimpanan Helm Rak Organizer Serbaguna 14 BOX", + "description": "🌈 Selamat datang di ANTBOX Official Store\n\nANTBOX menyediakan berbagai produk home furnishing secara global. Produk ini adalah solusi cerdas untuk Anda yang menginginkan furniture yang mudah dipasang dan berkualitas tinggi. Dengan teknologi \"Quickfold Free Decomposition\", kabinet ini dapat dipasang tanpa perakitan.\n\n### Detail Produk Lemari ANTBOX\n- **Merek:** ANTBOX\n- **Material:** Plastik PP (Kabinet), PET (Pintu), ABS, Magnet\n- **Warna:** Transparan\n- **Ukuran dan Berat Produk:** 14 BOX : Berat Bersih: 21,8 kg; Ukuran 104 * 50 * 170 cm\n\n### Keunggulan Lemari Pakaian ANTBOX\n- Instalasi dalam kurang dari 5 menit, menghemat waktu\n- Bahan kokoh dapat menampung beban lebih dari 50 kg\n- Pintu dilengkapi magnet, aman dan tidak mudah terbuka\n- Terbuat dari bahan anti rayap, tidak beracun, tidak berbau, dan bebas formaldehida\n- Tersedia banyak pilihan ukuran sesuai kebutuhan\n\n### Catatan\n- Waktu Pengiriman: Pesanan sebelum jam 4 sore diproses pada hari yang sama; setelah jam 4, diproses pada hari berikutnya.\n- Komplain wajib sertakan video unboxing.\n- Jika ada pertanyaan, silahkan tanyakan pada admin kami.", + "price": 2323000, + "stock": 12, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723522995/hacktiv8/branded/antbox-lemari-penyimpanan-helm-rak-organizer-serbaguna-14-box-9idvs30tw9m.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 52, + "name": "Lemari Pakaian HPL Sliding 4 Pintu Putih Glossy+kaca 2 Pintu LPS-402 - Putih Glossy", + "description": "Produksi Interior Design. Lemari 4 pintu sliding door dengan finishing HPL + Kaca full 2 Pintu (30x200cm), full panel board 15mm, knock down, ukuran besar (Lebar: 180cm, Tinggi: 200cm, Dalam: 60cm). Limited edition dan sangat murah! Di pasaran, lemari sejenis harganya 6-8 juta.\n\n**GRATIS PENGIRIMAN DAN PASANG** untuk wilayah Jabodetabek (Jakarta, Bogor, Depok, Tangerang, Bekasi) serta Serang dan Cilegon. Untuk Bandung Kota, jadwal pengiriman mengikuti jadwal kami dan tidak bisa memilih jadwal.\n\n*Diluar kota tersebut, ongkos ekspedisi ditanggung pembeli.*\n\nKunjungi halaman daftar produk untuk model dan pilihan produk furniture kami lainnya.\n\nDapatkan harga spesial! Kabin tambahan di atas lemari khusus dibuat/custom made hanya bagi pembeli Lemari 3 & 4 Pintu Sliding kami. [Link](https://www.tokopedia.com/rocketfurniture/kabin-atas-lemari-4-pintu-tarik?n=1&utm_source=desktop&utm_medium=share&utm_campaign=product_share&utm_content=copy&_branch_match_id=480404596846008234) untuk informasi lebih lanjut.", + "price": 4300000, + "stock": 75, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523000/hacktiv8/branded/lemari-pakaian-hpl-sliding-4-pintu-putih-glossy%2Bkaca-2-pintu-lps-402-putih-glossy-ei3lnsivun.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 129, + "name": "FRISKIES ADULT Meaty Grills Grill 3kg", + "description": "FRISKIES ADULT Meaty Grills Grill 2.5 kg untuk kucing dewasa (di atas 1 tahun). Kemasannya baru, 2.5KG.", + "price": 142465, + "stock": 7, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523156/hacktiv8/branded/friskies-adult-meaty-grills-grill-3kg-hqocr9vil3i.jpg", + "categoryId": 16, + "userId": 1 + }, + { + "id": 53, + "name": "ANTBOX Lemari Pakaian Putih Susun Plastik Minimalis Lemari Baju - 6 BOX FULL", + "description": "🌈 Selamat datang di ANTBOX Official Store.\n\nANTBOX menyediakan berbagai produk home furnishing secara global. Kami hadir sebagai solusi cerdas untuk Anda yang menginginkan produk furniture yang mudah dipasang dan berkualitas tinggi. Dengan teknologi \"Quickfold Free Decomposition\", kabinet terpadu bebas perakitan kami dapat dipasang secara mandiri.\n\n### DETAIL PRODUK LEMARI PAKAIAN ANTBOX\n- **Merek:** ANTBOX\n- **Material:** Plastik PP (Kabinet) + PET (Pintu) + ABS + Magnet\n- **Warna:** Transparan\n- **Ukuran dan Berat Produk:**\n * 15 Box: berat bersih: 21,8 kg; ukuran: 104 x 50 x 28 cm, 890L\n * 12 Box: berat bersih: 17,67 kg; ukuran: 104 x 50 x 23,8 cm, 710L\n * 10 Box: berat bersih: 15,12 kg; ukuran: 69 x 50 x 28.8 cm, 590L\n * 9 Box: berat bersih: 15 kg; ukuran: 104 x 50 x 18 cm, 540L\n * 8 Box: berat bersih: 12,4 kg; ukuran: 69 x 50 x 23,8 cm, 470L\n * 6 Box: berat bersih: 9 kg; ukuran: 69 x 50 x 18.8 cm, 360L\n\n### Kenapa Harus Membeli Rak Sepatu ANTBOX?\n⭐ Lemari Pakaian ANTBOX dapat diinstal dalam kurang dari 5 menit, menghemat waktu Anda.\n⭐ Bahan kokoh dapat menampung beban lebih dari 50 kg.\n⭐ Bagian pintu dilengkapi magnet, menjamin pintu tidak mudah terbuka.\n⭐ Terbuat dari bahan aman, anti rayap, tidak beracun, tidak berbau, dan bebas formaldehida.\n⭐ Tersedia berbagai ukuran sesuai kebutuhan.\n\n### NOTE:\n✨ Waktu Pengiriman: Pesanan sebelum jam 4 sore akan diproses pada hari yang sama. Pesanan setelah jam 4 akan diproses pada hari berikutnya.\n✨ Komplain wajib sertakan video unboxing.\n✨ Jika ada pertanyaan, silakan tanyakan pada admin kami.", + "price": 1202000, + "stock": 5, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523002/hacktiv8/branded/antbox-lemari-pakaian-putih-susun-plastik-minimalis-lemari-baju-6-box-full-ghv1xgxro.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 54, + "name": "Infinix GT 20 Pro 5G 8/256GB", + "description": "💯 Barang Original Imei Terdaftar Garansi Resmi 💯 \nUntuk Produk Infinix, Vivo, Realme, Oppo kami repack semua ya, hanya untuk aktivasi, selebihnya dijamin tidak ada yang ditukar/ganti.\n\n### READY ACCESSORIES SMARTPHONE\n- **Audio**: [Link](https://www.tokopedia.com/gallerygadget/etalase/audio)\n- **Charger**: [Link](https://www.tokopedia.com/gallerygadget/etalase/charger)\n- **Powerbank**: [Link](https://www.tokopedia.com/gallerygadget/etalase/powerbank)\n- **Hydrogel/Anti Gores**: [Link](https://www.tokopedia.com/gallerygadget/hydrogel-anti-gores-jelly-screen-protector-all-type-smartphone)\n\n### Spesifikasi: \n--- **Infinix GT 20 Pro 5G** ---\n\n**Jaringan**: 2G, 3G, 4G, 5G\n- SIM Card: Dual SIM (Slot Khusus) \n- eSIM: Tidak\n\n**Body**:\n- Dimensi: 164.26 x 75.43 x 8.15 mm \n- Berat: 194 gram \n- Ketahanan: IP54, Tahan debu dan percikan air\n\n**LAYAR UTAMA**:\n- Jenis: AMOLED \n- Ukuran: 6.78 inci \n- Refresh Rate: 144 Hz \n- Resolusi: 1080 x 2436 piksel\n\n**HARDWARE**:\n- Chipset: MediaTek Dimensity 8200 Ultimate\n- CPU: Octa-core (1x3.1 GHz Cortex-A78 & 3x3.0 GHz Cortex-A78 & 4x2.0 GHz Cortex-A55)\n- GPU: Mali-G610 MC6\n\n**MEMORI**:\n- RAM: 8 GB \n- Jenis RAM: LPDDR5X \n- Memori Internal: 256 GB \n- Memori Eksternal: Tidak Ada\n\n**KAMERA UTAMA**:\n- 108 MP (wide), f/1.75 \n- 2 MP (macro), f/2.4 \n- 2 MP (depth), f/2.4 \n\n**KAMERA DEPAN**:\n- 32 MP (wide), f/2.2\n\n**KONEKTIVITAS**:\n- WLAN: Wi-Fi 802.11 a/b/g/n/ac/6, dual-band, Wi-Fi Direct \n- Bluetooth: 5.3, A2DP, LE, aptX HD \n- NFC: Ada\n\n**BATERAI**:\n- Kapasitas: 5000 mAh \n- Pengisian cepat: 45W, bypass charging\n\n**OS**: Android 14, XOS 14\n\n**FITUR**:\n- Speaker stereo yang disetel JBL \n- Jaminan upgrade OS 2x dan 3 tahun pembaruan security patch\n", + "price": 3953000, + "stock": 5, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523004/hacktiv8/branded/infinix-gt-20-pro-5g-8256gb-vd9nue4baus.jpg", + "categoryId": 1, + "userId": 1 + }, + { + "id": 55, + "name": "Lemari Pakaian HPL+Kaca Sliding 3 Pintu Putih Glossy", + "description": "Produksi Interior Design, lemari model 3 pintu sliding door dengan finishing HPL dan pintu cermin. Minimalis, mewah, dan menggunakan full panel MDF board 16mm. Desain knock down, dapat dibongkar pasang. Ukuran: Lebar 180 cm, Tinggi 200 cm, Luas 60 cm. Limited edition, sangat murah! Di pasaran, lemari sejenis harganya 5-6 juta. \n\n**GRATIS PENGIRIMAN DAN PASANG!** \n* JABODETABEK (Jakarta, Bogor, Depok, Tangerang, Bekasi), serta Serang dan Cilegon. \n* KOTA BANDUNG dan KARAWANG (Jadwal kirim mengikuti jadwal kirim kami - tidak bisa pilih jadwal) atau gratis ongkos kirim ekspedisi (barang kami kirim dalam dus via ekspedisi dan belum dirakit). \n* Diluar kota tersebut, barang dikirim dalam dus belum dirakit via ekspedisi dan biaya ditanggung pembeli. \n\n* Standar pabrikan lemari sliding, pintu tidak dilengkapi kunci - untuk kunci opsional, dapat diorder terpisah. \n\n* Tersedia paket kabinet tambahan dengan tinggi yang dapat disesuaikan dengan harga spesial hanya untuk pembeli lemari kami dan tidak dijual terpisah. \n\nJangan lewatkan untuk melihat pilihan model dan warna lemari lainnya di etalase produk kami. \n\n[Link lebih lanjut untuk lemari pajangan](https://tokopedia.link/qD98avSxkX) \n[Meja Rias](https://tokopedia.link/AZqCQ12xkX) \n[Meja TV Set](https://tokopedia.link/hgP1hL9xkX)", + "price": 3850000, + "stock": 80, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523006/hacktiv8/branded/lemari-pakaian-hpl%2Bkaca-sliding-3-pintu-putih-glossy-su07yp2nda.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 56, + "name": "IPHONE 12 PRO PACIFIC BLUE 128GB", + "description": "😎😈 SPECIALIST IPHONE SECOND KONDISI PERFECT 😎😈\n\nDsni bisa tukar tambah / beli hp second kalian ya, Lgsg whatsapp aja ges 🤩🤓.\n\n**IPHONE 12 PRO PACIFIC BLUE 128GB**\nBarang 95-96% mulussssss mantap !! 👙🤪\nNamanya barang second sudah pasti ada bekas pemakaian. Tidak recommended untuk perfectionist.\nUnit sudah bisa pake all operator Indonesia, bukan wifi only yaaa 🔥🤓.\n\n### Pilihan untuk garansi sinyal:\n- VARIANT 30 HARI = GARANSI SIGNAL 30 HARI\n- VARIANT 6 BULAN = GARANSI SIGNAL 6 BULAN\n\n✅ 100% ORIGINAL APPLE BUKAN KAWE / HDC / SEJENISNYA\n✅ Battery health 90%+ UP\n✅ Ex International unit terbaik\n✅ Ex pemakaian user luar BUKAN BARANG REKONDISI 👍🏻\n✅ Face ID ON\n✅ True Tone ON\n✅ Sampai tinggal pake ajaa\n✅ Semua fungsi 100% work normal\n✅ Kelengkapan fullset OEM\n✅ iCloud kosong bebas reset\n✅ Bebas update iOS terbaru.\n\n### Kenapa harus beli sama NERDBOSS GADGET?\n1. Semua unit yg dijual dsni adalah unit pilihan dengan kualitas terbaik !!\n\n2. Barang yg anda beli, pasti sesuai deskripsi + sesuai di foto produk.\n\n3. Jualan jujur, barang dengan kondisi apapun pasti akan diinfo.\n\n4. Untuk hp second, ada garansi personal untuk kalian.\n\n5. After sales bukan sampah! Pelayanan dsni sangat komunikatif.\n\n6. BUKAN SELLER baru, sudah jualan sejak 2013 di Kasku, 2015 di Tokopedia tercinta.", + "price": 6850000, + "stock": 3, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523007/hacktiv8/branded/iphone-12-pro-pacific-blue-128gb-yqe0b3bew.jpg", + "categoryId": 1, + "userId": 1 + }, + { + "id": 69, + "name": "Sepatu Formal Pantofel Pria Kulit Slop Kerja Kantor Kuliah ZX AJ - AJ 7504 SGB, 43", + "description": "Sepatu Pantofel Pria oleh Zeintin. \n\n**Merek:** Zeintin \n**Bahan:** Kulit \n**Jenis Sol:** TPR (Thermo Plastic Rubber) Anti Slip \n**Size Tersedia:** 38 s.d 46 \n\n**Size Chart:** \n- 38 = 24 cm \n- 39 = 25 cm \n- 40 = 26 cm \n- 41 = 27 cm \n- 42 = 28 cm \n- 43 = 29 cm \n- 44 = 30 cm \n- 45 = 31 cm \n- 46 = 32 cm \n\n**Catatan:** \n- Ketersediaan stok barang bisa berubah sewaktu-waktu. \n- Sebelum melakukan checkout, tanyakan ketersediaan stok kepada kami. \n- Harap isi detail pesanan pada kolom catatan untuk penjual. \n- Garansi pengembalian atau penukaran berlaku maksimal 7 hari setelah barang diterima. Syarat dan ketentuan berlaku.\n\nTerima kasih telah berkunjung ke toko kami. Semoga Anda puas dengan produk yang kami jual. Selamat berbelanja!", + "price": 249916, + "stock": 6, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523041/hacktiv8/branded/sepatu-formal-pantofel-pria-kulit-slop-kerja-kantor-kuliah-zx-aj-aj-7504-sgb-43-2wmcc74px3n.jpg", + "categoryId": 4, + "userId": 1 + }, + { + "id": 57, + "name": "Lemari Pakaian HPL Sliding Transparan - Gamis - Longdress - Walk-in Closet - Coklat Tua Kayu", + "description": "Produksi Interior Design, lemari 2 pintu sliding door dengan finishing HPL dan full kaca bening/transparan. Model walk-in closet/butik baju untuk baju gamis, long dress, dan koleksi. Desain eksklusif dengan bahan berkualitas full MDF panel board 16mm dan kaca bening (non-tempered). Knock down, ukuran besar (Lebar: 160cm, Tinggi: 200cm, Dalam: 60cm). Sangat murah! Dipasaran, lemari sejenis harganya antara 8-10 juta. GRATIS pengiriman dan pemasangan untuk area Jabodetabek! Luar kota, ongkos ekspedisi ditanggung pembeli.\n\nGRATIS PENGIRIMAN DAN PASANG untuk:\n- Jabodetabek (Jakarta, Bogor, Depok, Tangerang, Bekasi), Serang, Cilegon\n- Bandung Kota (Jadwal dan pengiriman mengikuti jadwal kami, tidak bisa pilih jadwal)\n*Diluar kota tersebut, ongkos ekspedisi ditanggung pembeli.\n\nJangan lupa untuk mengunjungi halaman daftar produk untuk model dan pilihan produk furniture kami lainnya.", + "price": 2650000, + "stock": 987, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523013/hacktiv8/branded/lemari-pakaian-hpl-sliding-transparan-gamis-longdress-walk-in-closet-coklat-tua-kayu-8vrxtv6fcxf.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 58, + "name": "OPPO Reno 11F 5G 8/256 RAM 8GB ROM 256GB - Palm Green", + "description": "BARANG ORIGINAL, GARANSI RESMI IMEI TERDAFTAR! \n\n**Spesifikasi:** \n- Jaringan: GSM / HSPA / LTE / 5G \n- RAM: 8GB (+8GB Extended RAM) \n- Penyimpanan Internal: 256GB \n- Layar: 6,7 Inch AMOLED 120Hz, FHD+ (2412x1080) \n- Chipset: MediaTek Dimensity 7050 \n- GPU: ARM Mali-G68 MC4 \n- Sistem Operasi: ColorOS 14.0 \n- SIM: Dual Nano-SIM \n- Kamera Depan: 32MP \n- Kamera Belakang: 64MP + 2MP + 8MP \n- Biometrik: Sidik jari dan Pengenalan Wajah \n- NFC: Didukung \n- Versi Bluetooth: Bluetooth® v5.2 \n- Baterai: 5.000 mAh Fast Charging 67W \n\n**Catatan:** Untuk produk Infinix, Vivo, Realme, Oppo, kami repack semua ya, hanya untuk aktivasi, selebihnya dijamin tidak ada yang ditukar/ganti.", + "price": 3745000, + "stock": 10, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523014/hacktiv8/branded/oppo-reno-11f-5g-8256-ram-8gb-rom-256gb-palm-green-gi4bz5j7z5c.jpg", + "categoryId": 1, + "userId": 1 + }, + { + "id": 59, + "name": "NGY Tornado Desk Fan / Kipas Angin Meja Lantai Besi 8 inch | NG-8TDF", + "description": "### Deskripsi Produk\n\nKipas Angin Kecil Ini Akan Menyejukkan Cuaca Panas Indonesia.\n\nNikmati udara sejuk dengan **NGY NG8TDF Kipas Angin Meja / Tornado Desk Fan 8 inch**. Anda tidak perlu khawatir dengan cuaca panas di Indonesia lagi. Kipas angin kecil ini dapat menghembuskan angin badai untuk mendinginkan suasana ruangan Anda.\n\n#### Fitur Utama:\n- **Motor Kuat**: Kipas ini dilengkapi dengan motor kuat dan handal, menjadikannya lebih awet dan tahan lama.\n- **Pengaturan Kecepatan**: Memiliki 3 pilihan pengatur kecepatan sesuai dengan kebutuhan Anda.\n- **Desain Portabel**: Kecil namun fungsional, bisa digunakan di lantai atau meja.\n- **ThermoSafe**: Fitur pengaman untuk mencegah overheating pada motor.\n- **Bahan Berkualitas**: Menggunakan bahan berkualitas membuat finishing kipas angin lebih glossy dan elegan.\n\n#### Spesifikasi:\n- Kode Produk: NG-8TDF\n- Daya listrik: 28 Watt\n- Tegangan: 220 Volt / 50 Hz\n- Jenis Motor: Heavyduty Tornado\n- Ukuran Baling: 8 inch / 20 cm\n- Bahan Baling: Aluminium\n- Mode Kipas: 3-speed\n- Berat Barang: 1.4 KG\n- Garansi Resmi NGY Electronics: 1 Tahun", + "price": 149000, + "stock": 77, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523016/hacktiv8/branded/ngy-tornado-desk-fan-kipas-angin-meja-lantai-besi-8-inch-or-ng-8tdf-mkw8o9bcj9n.jpg", + "categoryId": 7, + "userId": 1 + }, + { + "id": 60, + "name": "Citronella / Sereh Wangi Essential Oil 100% Murni", + "description": "Registrasi BPOM TR236080591. Produk Bliss Scents diawasi dan disertifikasi HALAL dengan no sertifikat LPPOM-00240162830922.\n\nCitronella (minyak sereh wangi) essential oil murni (pure oil) ukuran 10ml.\n\n**Nama ilmiah**: Cymbopogon Winterianus Jowitt \n**Negara asal**: Indonesia \n**Karakteristik aroma**: Sereh wangi \n**Tipe aroma (note)**: Middle note \n\n### Manfaat: \n- Menghalau nyamuk / serangga \n- Mengurangi kecemasan / depresi \n- Membantu meredakan kelelahan \n- Meningkatkan suasana hati \n- Mempercepat penyembuhan luka \n- Mengatasi infeksi karena parasit \n- Melancarkan peredaran darah \n- Anti bakterial / anti septic \n\n### Cara Pakai: \n#### Penggunaan di Diffuser \nTeteskan 3-5 tetes pada 100 ml air. Tambahkan tetesan sesuai selera hingga mencapai tingkat kekuatan aroma yang diinginkan. \n\n#### Penggunaan dioles \nDicampur dengan carrier oil dengan rasio 3 - 10% essential oil. \nCarrier oil yang dapat digunakan: [Carrier Oil](https://www.tokopedia.com/bliss-scents/etalase/face-body-oil-carrier-oil-minyak-pembawa). \n\n#### Penggunaan Lainnya \n- Ditambahkan ke bak mandi \n- Dicampurkan dengan sabun, shampoo atau detergen \n\n### Tipe Aroma dan Ketahanan di Udara: \n- **Top note**: 1-2 jam \n- **Middle note**: 2-4 jam \n- **Base note**: 4-6 jam \n\n**PENTING**: Produk Bliss Scents tidak dimaksudkan untuk mengobati atau menggantikan obat. Semua produk hanya untuk penggunaan luar dan tidak dimaksudkan untuk dikonsumsi. Essential oil murni, tanpa penguat aroma atau campuran apapun. Penggunaan essential oil dengan diffuser bertujuan untuk menyebarkan molekul dari essential oil ke udara untuk mendapatkan manfaat terapeutik.", + "price": 28900, + "stock": 707, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523018/hacktiv8/branded/citronella-sereh-wangi-essential-oil-100percent-murni-5n8c2fpwil.jpg", + "categoryId": 6, + "userId": 1 + }, + { + "id": 61, + "name": "Racing Belt SSS for all Vespa 3V & 2V 150CC", + "description": "### Racing Belt SSS\n\n**Nama:** BELT SSS FOR ALL VESPA 2V & 3V 150CC \n**Tipe Motor:** FOR ALL VESPA 2V & 3V 150CC ONLY \n**Deskripsi:** BELT SSS UNTUK SEMUA VESPA 150CC ONLY. PASTIKAN CC VESPA ANDA, KARENA BEDA CC BEDA SIZE.\n\n**Catatan:** \n1. Tanyakan dulu stok barang \n2. Tulis catatan untuk tipe Vespa di keterangan tambahan \n3. Bila ada pilihan warna, tulis di keterangan tambahan \n4. Jika tidak memberikan keterangan tambahan tipe motor, kami akan mengirimkan barang sesuai foto \n5. Jika tidak memberikan keterangan tambahan warna, kami akan mengirimkan barang sesuai stok yang ada \n6. Jika barang dari gudang SHD Jakarta habis, pesanan akan dikirimkan dari gudang SHD Scooter Bandung. Tidak bisa dibatalkan. Membeli berarti dianggap setuju. \nSHD TIDAK BERTANGGUNG JAWAB ATAS PEMASANGAN DI LUAR BENGKEL SHD.", + "price": 256500, + "stock": 9, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523024/hacktiv8/branded/racing-belt-sss-for-all-vespa-3v-and-2v-150cc-gzcr0s0vpv.jpg", + "categoryId": 10, + "userId": 1 + }, + { + "id": 62, + "name": "Lemari Baju Besi - Lemari Pakaian Besi Sliding Motif Marmer - A15", + "description": "Lemari dengan kualitas terbaik 100%.\n\n**Penting:** Harap hubungi admin terlebih dahulu untuk mengecek ongkos kirim dan jasa. Ongkir cargo ditanggung pembeli. Sebelum order, chat kami untuk menanyakan ketersediaan stok barang dan harga ongkir agar tidak terjadi kesalahan paham. Ongkir yang tertera di Tokopedia hanya untuk tracking resi dengan berat 10 gr (ini bahan besi, bukan kertas/kayu).\n\nUntuk pengiriman luar kota, barang akan dikirim menggunakan cargo. Pastikan invoice (resi Tokopedia) dan barang tidak datang bersamaan, namun kami akan terus membantu tracking. Setelah barang dikirim ke ekspedisi, kami hanya bisa membantu tracking saja.\n\n**Happy Shopping!** 😊\n\nPengiriman dapat dilakukan menggunakan kurir dari toko kami. Estimasi packing 1-2 hari setelah pesanan diterima, namun bisa lebih cepat tergantung antrian. Order pada hari Sabtu dan Minggu akan dipacking pada hari kerja dari Senin hingga Sabtu.", + "price": 1690000, + "stock": 80, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523027/hacktiv8/branded/lemari-baju-besi-lemari-pakaian-besi-sliding-motif-marmer-a15-vzhqicqu0or.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 63, + "name": "ANTBOX Lemari Pakaian Plastik Susun Putih Minimalis Lemari Baju - 6 BOX 1 HANGER", + "description": "🌈 Selamat datang di ANTBOX Official Store\n\nANTBOX menyediakan berbagai produk home furnishing secara global. ANTBOX hadir sebagai solusi cerdas untuk Anda yang menginginkan produk furniture yang mudah dipasang dan berkualitas tinggi. ANTBOX menghadirkan teknologi \"Quickfold Free Decomposition\" yang menciptakan kabinet terpadu bebas perakitan, sehingga bisa dipasang secara mandiri.\n\n---\n\n**Detail Produk Lemari Pakaian ANTBOX** \n- **Merek:** ANTBOX \n- **Material:** PLASTIK PP (Kabinet) + PET (pintu) + ABS + Magnet \n- **Warna:** Transparan \n- **Ukuran dan Berat Produk:** \n - **6 Box:** berat bersih: 9 kg; ukuran: 69 x 50 x 18.8 cm, 360L \n - Terdapat pilihan ukuran lainnya seperti 15 Box, 12 Box, 10 Box, 9 Box, dan 8 Box.\n\n---\n\n**Kenapa Harus Membeli Rak Sepatu ANTBOX?** \n⭐ Lemari Pakaian ANTBOX bisa diinstal kurang dari 5 menit, menghemat waktu Anda. \n⭐ Bahan kokoh dapat menampung beban lebih dari 50 kg. \n⭐ Bagian pintu dilengkapi magnet, sehingga aman dan tidak mudah terbuka. \n⭐ Terbuat dari bahan yang aman, anti rayap, tidak beracun, tidak berbau, dan bebas formaldehid. \n⭐ Memiliki banyak pilihan ukuran sesuai kebutuhan.\n\n---\n\n**Note:** \n✨ Waktu Pengiriman: Pesanan sebelum jam 4 sore akan diproses pada hari yang sama; di atas jam 4 akan diproses pada hari berikutnya. \n✨ Komplain wajib sertakan video unboxing. \n✨ Jika ada pertanyaan, silahkan tanyakan terlebih dahulu pada admin kami.", + "price": 1153000, + "stock": 85, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523028/hacktiv8/branded/antbox-lemari-pakaian-plastik-susun-putih-minimalis-lemari-baju-6-box-1-hanger-5ioirjnjsvj.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 64, + "name": "SSS CVT PAKET KIRIAN VBELT ROLLER VESPA S 3V LX125 3V", + "description": "CVT SET SSS RACING\n\n100% ORIGINAL SSS RACING\nPAKET TERDIRI DARI: BELT + ROLLER\n\nUNTUK MOTOR: VESPA S 3V / LX125 3V\n\n- PERFORMA LEBIH BAIK DARI STANDAR\n- DURABILITAS SETARA RACING\n- VARIAN ROLLER YANG BERAGAM\n- BELT EPDM YANG KUAT\n- SLIDER DENGAN UMUR PEMAKAIAN 200% LEBIH BAIK\n\nTERSEDIA BERAT ROLLER: 9, 10, 11, 12 GR\nINFOKAN BERAT ROLLER YANG DIINGINKAN PADA CHAT ATAU CATATAN PEMBELIAN\n\nMOHON TANYAKAN STOK SEBELUM MEMBELI, TERIMAKSIH", + "price": 270000, + "stock": 83, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523031/hacktiv8/branded/sss-cvt-paket-kirian-vbelt-roller-vespa-s-3v-lx125-3v-4a54rqfqepd.jpg", + "categoryId": 10, + "userId": 1 + }, + { + "id": 65, + "name": "Lemari Plastik Lipat Napolly/Lemari Pakaian Lipat Minimalis/POLICABINE 3211", + "description": "## Detail Produk\n- **Ukuran**: P. 92,5 x L. 45 x T. 160 cm \n- **Warna**: Putih \n- **Bahan**: Plastik \n\n## Info Pengiriman \n- Barang kami kirim dalam kondisi bentuk Knock Down (belum dirakit/dalam packing dus) \n- Setiap produk memiliki petunjuk pemasangan dalam dus \n- Setiap produk yang kami kirim telah kami periksa terlebih dahulu \n- Silahkan chat admin untuk info stok, warna, dll \n\n## Pengiriman \n- **Instan** (Estimasi pengiriman 3 Jam; 1 kurir hanya membawa 1 orderan untuk 1 alamat yang sama) \n- **Gocar** (Estimasi pengiriman 3 jam; 1 mobil bisa membawa beberapa orderan sekaligus/barang dalam ukuran BESAR dalam 1 alamat) \n- **Kargo** (Estimasi pengiriman sampai tujuan 1-3 hari tergantung jarak tempuh dan kargo yang dipilih) \nDisarankan untuk menambah asuransi pengiriman guna kebutuhan komplain. \n\n## Syarat/Pengajuan Komplain \n- Komplain bisa diajukan dalam waktu 1x24 jam sejak barang diterima dari tangan kurir. \n- Mohon melampirkan foto & video unboxing tanpa jeda pada saat barang baru dibuka (tidak terima video dengan paket yang telah dikemas ulang) \n- Lakukan klaim/komplain ke admin melalui chat. Klaim dapat diterima dalam bentuk pergantian part/kompensasi, tergantung tingkat kerusakan barang. \n- Pergantian komponen akan dikirimkan sesuai dengan part yang rusak. \n\n**Happy Shopping Dear 🥰**", + "price": 875000, + "stock": 48, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523036/hacktiv8/branded/lemari-plastik-lipat-napollylemari-pakaian-lipat-minimalispolicabine-3211-4k4qvwhlfq3.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 66, + "name": "ANTBOX Lemari Penyimpanan Helm Rak Organizer Serbaguna 14 BOX", + "description": "🌈 Selamat datang di ANTBOX Official Store\n\nANTBOX menyediakan berbagai produk home furnishing secara global. Kami hadir sebagai solusi cerdas untuk Anda yang menginginkan produk furniture yang mudah dipasang dan berkualitas tinggi. ANTBOX menghadirkan teknologi \"Quickfold Free Decomposition\" yang menciptakan kabinet terpadu bebas perakitan, sehingga dapat dipasang secara mandiri.\n\n### Detail Produk Lemari ANTBOX\n- **Merek:** ANTBOX\n- **Material:** Plastik PP (Kabinet), PET (Pintu), ABS, Magnet\n- **Warna:** Transparan\n- **Ukuran dan Berat Produk:** 14 Box - Berat Bersih: 21,8 kg; Ukuran: 104 * 50 * 170 cm\n\n### Kenapa Harus Membeli Rak Sepatu ANTBOX?\n- ⭐ Instalasikan dalam kurang dari 5 menit, menghemat waktu Anda\n- ⭐ Bahan kokoh, menampung beban lebih dari 50 kg\n- ⭐ Pintu dilengkapi magnet agar aman dan tidak mudah terbuka\n- ⭐ Terbuat dari bahan aman, anti rayap, tidak beracun, tidak berbau, dan bebas formaldehida\n- ⭐ Tersedia berbagai ukuran sesuai kebutuhan\n\n### Catatan\n- ✨ **Waktu Pengiriman:** Pesanan sebelum jam 4 sore akan diproses hari yang sama; setelah jam 4 diproses hari berikutnya\n- ✨ **Kompilasi:** Sertakan video unboxing dalam komplain\n- ✨ Jika ada pertanyaan, silakan tanyakan pada admin kami.", + "price": 2323000, + "stock": 12, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523037/hacktiv8/branded/antbox-lemari-penyimpanan-helm-rak-organizer-serbaguna-14-box-skgkirglwc.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 67, + "name": "BUKU Langka GOLA GONG : KUTUNGGU DI YOGYA", + "description": "No. # S-4 1si 133 HAL\nKondisi buku bekas, buku original. Buku sesuai di foto, tidak sobek, tidak rusak, masih kelihatan baru.\n\nStok hanya ada 1. Seluruh penjualan dari buku ini akan disalurkan untuk kegiatan sosial.\n\nBuku ini cocok untuk semua kalangan. Selama barang masih ada dalam daftar kami, barang masih ready.\n\nBisa order: ✍🏻\n\nSIAPA CEPAT DIA DAPAT #bukuberkas #bukuberkualitas #bukuoriginalberkas #bukubermutu #bukupolitik #bukusosialpolitik", + "price": 100000, + "stock": 1, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523038/hacktiv8/branded/buku-langka-gola-gong-:-kutunggu-di-yogya-dsg5s3vuxn.jpg", + "categoryId": 12, + "userId": 1 + }, + { + "id": 68, + "name": "Lemari Pakaian HPL Sliding Transparan-Gamis-longdress-walk in closet - Cokat Tua Kayu", + "description": "Produksi Interior Design, lemari 2 pintu dengan sliding door, finishing HPL dan full kaca bening/transparan. Model walk-in closet untuk baju gamis dan long dress. Desain eksklusif menggunakan bahan berkualitas full MDF panel board 16mm dan kaca bening (non-tempered). Knock down, ukuran besar: Lebar: 160cm, Tinggi: 200cm, Dalam: 60cm. Sangat murah! Di pasaran, lemari sejenis harganya mencapai 8-10 juta IDR. Gratis pengiriman dan pemasangan untuk area Jabodetabek! Untuk luar kota, ongkos ekspedisi ditanggung pembeli. Jangan lupa untuk mengunjungi halaman produk kami untuk model dan pilihan lainnya.", + "price": 2650000, + "stock": 987, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523039/hacktiv8/branded/lemari-pakaian-hpl-sliding-transparan-gamis-longdress-walk-in-closet-cokat-tua-kayu-h3cv8y2wwr.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 70, + "name": "BUKU WACANA MUSIM PANAS 1990", + "description": "No. #223\n1si. 226 HAL\n- Kondisi: buku bekas, buku original. Buku sesuai di foto, tidak sobek, tidak rusak, masih kelihatan baru.\n\nStok hanya ada 1. Seluruh penjualan dan hasil dana buku ini untuk kegiatan sosial.\n\nBuku ini untuk semua kalangan. Selama barang masih ada di list kami, barang masih ready.\n\nBisa order: ✍🏻\nAtau 😁📞📞\n* WA 081282649914\n\nSIAPA CEPAT DIA DAPAT #bukuberkas #bukuberkualitas #bukuoriginalberkas #bukubermutu #bukupolitik #bukusosialpolitik", + "price": 100000, + "stock": 1, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523043/hacktiv8/branded/buku-wacana-musim-panas-1990-qkhmowyc8fb.jpg", + "categoryId": 12, + "userId": 1 + }, + { + "id": 71, + "name": "SAPPORO BOLOGNA - Lemari Pakaian Besi 3 Pintu | Steel Wardrobe 3 Doors - Rainbow", + "description": "### SAPPORO BOLOGNA - Lemari Pakaian Besi 3 Pintu \n\nLemari pakaian berkualitas tinggi dari Sapporo Furniture.\n\n#### Spesifikasi Produk:\n- **Rangka:** Plat Besi Tebal 0.5 mm\n- **Finishing Rangka:** Powder Coating\n- **Jumlah Pintu:** 3\n- **Model Pintu:** Swinging\n- **Ukuran Cermin:** 84 cm x 25 cm\n- **Dimensi Produk:** 120 cm x 50 cm x 190 cm\n- **Packing:** Kardus\n\n#### Keunggulan Produk:\n- Anti jamur\n- Anti rayap\n- Dilengkapi brankas\n- Cermin dibalik pintu\n- Motif gambar eksklusif dan modern pada pintu\n\n#### Kegunaan Produk:\n- Lemari pakaian\n\n#### Syarat & Ketentuan:\n- **Wilayah Jabodetabek Kota:** Untuk pengiriman di dalam Jabodetabek, dapat memilih metode pengiriman 'Kurir Toko' untuk mendapatkan gratis biaya kirim dan instalasi.\n- **Wilayah luar Jabodetabek:** Produk dikirim dalam kondisi knock down.\n - Pengiriman menggunakan kargo, klaim kerusakan produk harus disertakan bukti video unboxing. Tanpa bukti, klaim akan ditolak.\n - Pengiriman wajib menggunakan Packing Kayu Jumbo. [Link Packing Kayu](https://www.tokopedia.com/sapporo-1/sapporo-packing-jumbo)\n- **Wilayah pinggir kota JABODETABEK:** Jika ingin menggunakan JASA PENGIRIMAN & INSTALASI dari SAPPORO FURNITURE, bisa menghubungi admin kami. [Link Pengiriman Kurir Toko](https://www.tokopedia.com/sapporo-1/sapporo-jasa-kirim) | [Link Jasa Instalasi](https://www.tokopedia.com/sapporo-1/sapporo-jasa-instalasi)\n\nHarga sudah termasuk PPN, faktur pajak tersedia jika dibutuhkan.", + "price": 2499900, + "stock": 18, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523046/hacktiv8/branded/sapporo-bologna-lemari-pakaian-besi-3-pintu-or-steel-wardrobe-3-doors-rainbow-bj2nbikq404.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 72, + "name": "Zeintin - Sepatu Pantofel Pria Formal Kerja Kantoran AJ - AJ 7502, 38", + "description": "Sepatu Pantofel Pria Zeintin AJ 7502 SGB\n\n**Merek:** Zeintin \n**Bahan:** Kulit \n**Jenis Sol:** TPR (Thermo Plastic Rubber) \n**Size:** Tersedia 38 - 46 \n\n**Size Chart:** \n- 38 = 24 cm \n- 39 = 25 cm \n- 40 = 26 cm \n- 41 = 27 cm \n- 42 = 28 cm \n- 43 = 29 cm \n- 44 = 30 cm \n- 45 = 31 cm \n- 46 = 32 cm \n\n**Catatan:** \n* Ketersediaan stok barang bisa berubah sewaktu-waktu. \n* Sebelum melakukan checkout, disarankan untuk menanyakan terlebih dahulu ketersediaan stok kepada kami. \n* Harap diisi detail pesanan pada kolom catatan untuk penjual. \n* Garansi pengembalian atau penukaran berlaku maksimal 7 hari setelah barang diterima. Syarat dan ketentuan berlaku.\n\nTerima kasih telah berkunjung ke toko kami. Kami sangat senang Anda berkunjung dan berharap Anda puas dengan produk yang kami jual. Selamat berbelanja di toko online kami!\n\nIngat...!! Yang Dipilih Tetap Zeintin", + "price": 249916, + "stock": 50, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523047/hacktiv8/branded/zeintin-sepatu-pantofel-pria-formal-kerja-kantoran-aj-aj-7502-38-16wzwthab2l.jpg", + "categoryId": 4, + "userId": 1 + }, + { + "id": 73, + "name": "BUKU PEPERANGAN KERAJAAN DI NUSANTARA BY CAPT.R. P.SUYONO", + "description": "Kondisi: Buku bekas, buku original. Buku sesuai di foto, tidak sobek, tidak rusak, masih kelihatan baru.\n\nStok hanya ada 1. Seluruh penjualan dan hasil dana buku ini untuk kegiatan sosial.\n\nBuku ini untuk semua kalangan. Selama barang masih ada di list kami, barang masih ready.\n\nBisa order: ✍🏻 Atau 😁📞📞.\n\nSIAPA CEPAT DIA DAPAT #bukuberkas #bukuberkualitas #bukuoriginalberkas #bukubermutu #bukupolitik #bukusosialpolitik", + "price": 100000, + "stock": 1, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523048/hacktiv8/branded/buku-peperangan-kerajaan-di-nusantara-by-capt.r.-p.suyono-qd6d7s2fxpk.jpg", + "categoryId": 12, + "userId": 1 + }, + { + "id": 74, + "name": "Lemari Pakaian HPL Sliding 4 Pintu Putih Glossy+kaca 2 Pintu LPS-402 - Putih Glossy 1", + "description": "Produksi Interior Design, Lemari 4 pintu sliding door dengan finishing HPL + Kaca full 2 Pintu (30x200cm), full panel board 15mm, knock down, ukuran besar (Lebar: 180cm, Tinggi: 200cm, Dalam: 60cm). Limited edition, sangat murah! Dipasaran, lemari sejenis harganya 6-8 juta.\n\nGRATIS PENGIRIMAN DAN PASANG ke wilayah JABODETABEK (Jakarta, Bogor, Depok, Tangerang, Bekasi) serta Serang dan Cilegon. Untuk Bandung Kota, jadwal pengiriman mengikuti jadwal kami.\n\nDiluar kota di atas, ongkos ekspedisi ditanggung pembeli.\n\nKunjungi halaman daftar produk untuk model dan pilihan furniture lainnya.\n\nDapatkan harga spesial! Kabin tambahan di atas lemari khusus dibuat/custom made hanya bagi pembeli Lemari 3 & 4 Pintu Sliding kami. [Link kabin atas lemari](https://www.tokopedia.com/rocketfurniture/kabin-atas-lemari-4-pintu-tarik?n=1&utm_source=desktop&utm_medium=share&utm_campaign=product_share&utm_content=copy&_branch_match_id=480404596846008234).", + "price": 4300000, + "stock": 75, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523050/hacktiv8/branded/lemari-pakaian-hpl-sliding-4-pintu-putih-glossy%2Bkaca-2-pintu-lps-402-putih-glossy-1-56rvj5h6wvr.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 75, + "name": "Back Rack Vespa LX S GTS Primavera dan Sprint Plus Bantalan Busa, - Crome/CoklatLis, Sprint", + "description": "Silahkan d order aksesoris Vespa Modern Matik.\n\nReady stok Backrack plus bantalan untuk Vespa Lx S Primavera Sprint dan GTS.\n- Bahan dijamin berkualitas dengan ketebalan 1,2 mm.\n- Kuat terhadap perubahan suhu dari hujan maupun panas.\n- Sangat nyaman saat digunakan.\n- Tampilan elegan.\n- Pemasangan plug and play.\n- Tersedia warna chrome/silver dan hitam doff.\n\nBagi yang berminat silakan d order.\n\nTerima Kasih.", + "price": 298000, + "stock": 96, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523053/hacktiv8/branded/back-rack-vespa-lx-s-gts-primavera-dan-sprint-plus-bantalan-busa-cromecoklatlis-sprint-pjelycy3xu.jpg", + "categoryId": 10, + "userId": 1 + }, + { + "id": 76, + "name": "LAPPY Stand Holder Laptop Ergonomic", + "description": "LAPPY stand holder laptop ergonomis yang dapat dilipat dan mudah dibawa ke mana-mana tanpa memakan banyak tempat. \n\n**Fitur:**\n1. Memaksimalkan pembuangan panas dari laptop tanpa perlu fan. \n2. Desain lipat yang mudah dibawa. \n3. Material anti slip, tidak mudah bergeser. \n4. Desain ergonomis yang menjaga postur tubuh saat duduk. \n5. Tinggi dapat disesuaikan dengan kenyamanan (6 posisi). \n6. Tahan beban hingga 15 Kg. \n7. Kualitas premium.\n8. Cocok untuk laptop/notebook ukuran 11-17 inci.\n\n**Warna:** \n- Hitam \n- Putih \n\n**Bahan:** \n- Aluminium alloy \n- Plastik ABS \n- Rubber \n\n**Ukuran:** \n- 24 cm x 16 cm x 6.5 - 11.5 cm", + "price": 73000, + "stock": 232, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523056/hacktiv8/branded/lappy-stand-holder-laptop-ergonomic-09fghv3gbeht.jpg", + "categoryId": 1, + "userId": 1 + }, + { + "id": 77, + "name": "SAPPORO LICATA - Lemari Pakaian Besi 4 Pintu | Steel Wardrobe 4 Doors - Romawi", + "description": "SAPPORO LICATA - Lemari Pakaian Besi 4 Pintu | Steel Wardrobe 4 Doors adalah produk lemari pakaian berkualitas dan terpercaya dari Sapporo Furniture.\n\n**Spesifikasi Produk:**\n- Rangka: Plat Besi Tebal 0.5 mm\n- Finishing Rangka: Powder Coating\n- Jumlah Pintu: 4\n- Model Pintu: Swinging\n- Dimensi Produk: 158 cm x 50 cm x 190 cm\n- Packing: Kardus\n\n**Keunggulan Produk:**\n- Anti jamur\n- Anti rayap\n- Dilengkapi brankas\n- Cermin pada pintu\n- Motif gambar eksklusif dan modern pada pintu\n- Tampilan glossy yang memberikan kesan mewah\n\n**Kegunaan Produk:**\n- Lemari pakaian\n\n**Syarat & Ketentuan:**\n- Untuk wilayah Jabodetabek Kota, pengiriman dapat memilih metode \"Kurir Toko\" untuk mendapatkan gratis biaya kirim dan instalasi.\n- Pengiriman ke luar Jabodetabek dilakukan dalam kondisi knock down melalui kargo. Klaim kerusakan produk harus disertakan dengan video unboxing.\n- Pengiriman wajib menggunakan Packing Kayu Jumbo.\n- Untuk pinggiran kota Jabodetabek, hubungi admin untuk pengiriman dan instalasi.\n\nHarga sudah termasuk PPN, dan faktur pajak dapat diterbitkan jika diperlukan.", + "price": 3299900, + "stock": 18, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523059/hacktiv8/branded/sapporo-licata-lemari-pakaian-besi-4-pintu-or-steel-wardrobe-4-doors-romawi-cy9ljbjgml5.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 79, + "name": "Hook Gantungan Baju Serbaguna Tempel Kuat Dinding Tembok Dapur Magic - Hook B, Silver/ Putih", + "description": "### Hook Gantungan Baju Serbaguna Tempel Kuat Dinding Tembok Dapur Magic\n\nGantungan dinding ini memiliki desain minimalis dengan pemasangan yang mudah tanpa alat tambahan. Terbuat dari bahan berkualitas yang mampu menopang beban berat dan awet untuk penggunaan jangka panjang.\n\n#### Fitur Produk\n- **Mudah Dipasang**: Dilengkapi dengan perekat kuat di belakang, dapat dipasang pada permukaan datar tanpa alat tambahan.\n- **Gantungan Kuat**: Mampu menahan beban hingga **3 kg**, cocok untuk menggantung jaket, pakaian, topi, dan lebih banyak lagi.\n- **Material**: Terbuat dari stainless steel berkualitas, menjamin kekuatan dan ketahanan untuk penggunaan jangka panjang.\n\n#### Spesifikasi\n- **Material**: Stainless Steel\n- **Warna**: Hitam, Silver, Gold\n\n[Link pembelian lem perekat stainless](https://www.tokopedia.com/indigosstore/lem-pasta-perekat-super-kuat-tempel-serbaguna-power-nail-adhesive-glue)", + "price": 6900, + "stock": 250, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523062/hacktiv8/branded/hook-gantungan-baju-serbaguna-tempel-kuat-dinding-tembok-dapur-magic-hook-b-silver-putih-95gyfgnjnn.jpg", + "categoryId": 7, + "userId": 1 + }, + { + "id": 80, + "name": "ANTBOX Lemari Pakaian Putih 6 BOX 1 HANGER Lemari Baju Minimalis", + "description": "🌈 Selamat datang di ANTBOX Official Store.\n\nANTBOX menyediakan berbagai produk home furnishing secara global. Kami hadir sebagai solusi cerdas untuk Anda yang menginginkan produk furniture yang mudah dipasang dan berkualitas tinggi. ANTBOX menghadirkan teknologi \"Quickfold Free Decomposition\" yang menciptakan kabinet terpadu bebas perakitan, sehingga bisa dipasang secara mandiri.\n\n### Detail Produk Lemari Pakaian ANTBOX\n- **Merek:** ANTBOX \n- **Material:** Plastik PP (Kabinet), PET (Pintu), ABS, Magnet \n- **Warna:** Transparan \n- **Ukuran dan Berat Produk:** \n - 6 BOX 1 HANGER: Berat Bersih: 9 kg; Ukuran: 69 x 50 x 104 cm\n\n### Kenapa Harus Membeli Rak Sepatu ANTBOX?\n- Lemari Pakaian ANTBOX dapat diinstal kurang dari 5 menit, menghemat waktu Anda. \n- Bahan kokoh bisa menampung beban lebih dari 50 kg. \n- Pintu dilengkapi magnet, aman dan tidak mudah terbuka. \n- Terbuat dari bahan yang aman, anti rayap, tidak beracun, tidak berbau, dan bebas formaldehida. \n- Memiliki banyak pilihan ukuran sesuai kebutuhan.\n\n### Catatan\n- **Waktu Pengiriman:** Pesanan sebelum jam 4 sore akan diproses pada hari yang sama; setelah jam 4 akan diproses pada hari berikutnya. \n- **Komplain:** Wajib sertakan video unboxing. \n- Jika ada pertanyaan, silahkan tanyakan kepada admin kami.", + "price": 1153000, + "stock": 13, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523063/hacktiv8/branded/antbox-lemari-pakaian-putih-6-box-1-hanger-lemari-baju-minimalis-wl8agiirdrm.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 81, + "name": "Batok Lampu VESPA LXV Ori", + "description": "Batok lampu Vespa LXV Ori Piaggio.", + "price": 445000, + "stock": 2, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523068/hacktiv8/branded/batok-lampu-vespa-lxv-ori-abr5la559sj.jpg", + "categoryId": 10, + "userId": 1 + }, + { + "id": 82, + "name": "Laptop Stand Milenial Aluminium Holder Meja Macbook Alas Notebook IPAD", + "description": "Laptop stand portable yang mudah dilipat dan dibawa kemana-mana tanpa memakan banyak tempat.\n\n### Fitur:\n1. Memaksimalkan Pembuangan Panas dari Laptop melalui bawah (tanpa perlu fan).\n2. Design lipat yang mudah dibawa.\n3. Material anti slip, tidak mudah geser.\n4. Design ergonomis untuk menjaga posisi tubuh tetap tegak saat duduk.\n5. Dapat diatur ketinggiannya sesuai kenyamanan (6 posisi).\n6. Tahan beban hingga 15 kg.\n7. Premium quality.\n8. Cocok untuk laptop/notebook ukuran 11 - 17 inci.\n\n### Warna:\n- Hitam\n- Putih\n\n### Ukuran:\n- 24 cm x 16 cm x 6.5 - 11.5 cm\n\n### Bahan:\n- Aluminium alloy\n- Plastik ABS\n- Rubber", + "price": 73000, + "stock": 232, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523070/hacktiv8/branded/laptop-stand-milenial-aluminium-holder-meja-macbook-alas-notebook-ipad-ag1ium0tuto.jpg", + "categoryId": 1, + "userId": 1 + }, + { + "id": 83, + "name": "OLYMPIC PALAZIO Lemari Pakaian / Baju 2 & 3 Pintu Minimalis Jumbo Dengan Gantungan & Cermin - 2 Pintu", + "description": "### OLYMPIC PALAZIO Lemari Pakaian\n\n**Ukuran Tersedia**: 2 & 3 Pintu \n**Merek**: Olympic Furniture \n**Dimensi**: \n- 2 Pintu: 43 cm x 91.2 cm x 191 cm \n- 3 Pintu: 43 cm x 136.5 cm x 191 cm \n**Warna**: Full White \n**Bahan**: Particle Board \n**Kondisi**: Baru \n\n**Fitur**: \n- Bahan Grade A hardwood particle board (kualitas terbaik). \n- Ketebalan atas: 12+12 mm; Bagian lainnya: 12 mm. \n- Tipe furnitur: Lemari pakaian. \n- Laminasi: Paper. \n- Dilengkapi kunci pada pintu dan laci. \n- Kaca mirror di bagian pintu. \n\n**Pengiriman**: \n- **Free Ongkir** untuk Jakarta, Tangerang*, dan Depok. \n- Untuk Bekasi Kota & Bogor Kota + Rp 50.000 (maks 40 km). \n- Pengiriman dalam 1-3 hari kerja setelah transaksi. \n- Termasuk pemasangan di toko; biaya pemasangan di tempat Rp 50.000. \n\n**Catatan**: \n- Kirim barang dalam kondisi Knock Down. \n- Untuk pertanyaan lebih lanjut, hubungi Toko Meubel Odenpan di Jl. Cirendeu Raya No. B5, Cireundeu, Kec. Ciputat Timur, Kota Tangerang Selatan, Banten. \n- [Tel] 021-7424150 / [WA] 087880051129.", + "price": 1199000, + "stock": 2, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523071/hacktiv8/branded/olympic-palazio-lemari-pakaian-baju-2-and-3-pintu-minimalis-jumbo-dengan-gantungan-and-cermin-2-pint-mjtyt0tpgul.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 84, + "name": "Reed Diffuser Sweet Dew (Geranium) 50ml Essential Oil Aromatherapy - Fiber Hitam", + "description": "Box original READY. Cocok untuk hampers :)\n\nBearspaws Reed Diffuser Essential Oil Aromatherapy.\n\n**Aroma:** Geranium, Lavender, Peppermint \n**Keunggulan:** \n- Essential Oil based \n- Lebih tahan lama dibandingkan water based \n- Tidak membuat pusing \n- Menggunakan essential oil natural \n- Tidak menggunakan fragrance oil/parfum \n- Berfungsi sebagai aroma terapi \n\n**Ukuran:** 50ml, dengan box original, free bubble wrap. \nSangat cocok untuk ruang tamu, ruang keluarga, kamar tidur, kantor, kamar mandi, dll. \n\n**Free stik diffuser (pilihan):** \n- 5 stik lurus, 2 stik gelombang, 2 dried flower (jenis, ukuran, warna bunga dikirim sesuai ketersediaan) \n- 10 stik fiber \n- 10 stik rotan premium \n(Akan kami kirim sesuai persediaan) \n\n**Durabilitas:** 50ml 28-32 hari tergantung banyaknya stik, suhu dan kelembapan, ventilasi, dan sinar matahari langsung. \nSetelah 1 jam dicelupkan, silahkan balikkan stiknya supaya penyerapan lebih cepat merata. Silahkan balik rutin stiknya seminggu sekali. Setelah 1 bulan atau cairan habis/tidak berbau, silahkan ganti stik yang baru. \nGaransi bocor dan pecah, mohon sertakan foto. \n\n**Tersedia varian lainnya:** \n- Sunkissed (orange) \n- Summer Bloom (ylang ylang) \n- Breathe (lemongrass) \n- The Nobles (frankincense) \n- Pillow Talk (lavender) \n- Eucalyptus Dream (Eucalyptus) \n\n*Jika ada yang mau disisipkan sample varian lain dan kartu ucapan untuk keluarga, sahabat, kolega, silahkan ditulis di note ya. Free :)", + "price": 78000, + "stock": 484, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523074/hacktiv8/branded/reed-diffuser-sweet-dew-%28geranium%29-50ml-essential-oil-aromatherapy-fiber-hitam-nvyzwcncd4r.jpg", + "categoryId": 5, + "userId": 1 + }, + { + "id": 85, + "name": "Sandal Selop Pria Gold Pigeon UltraLite WeStep G9385M - Moonrock Brown, 44", + "description": "### Highlights:\n- Boost Cushion\n- UltraLite Technology\n- Adjustable Strap\n- Outsole with Extra Traction\n- Waterproof Material\n\nSandal UltraLite WeStep untuk pria menawarkan desain sporty dan santai. Dengan berbagai fitur fungsional, seperti: \n- **Boost Cushion**: Bantalan yang meningkatkan kenyamanan pijakan, mengurangi energi saat berjalan.\n- **UltraLite Technology**: Material dan desain sol yang ringan namun tahan lama.\n- **Adjustable Strap**: Strap yang dapat disesuaikan untuk memudahkan pemakaian.\n- **Outsole dengan Lepisan Ekstra Traction**: Mencegah tergelincir saat bergerak.\n- **Bahan Anti Air**: Mampu bertahan di area basah dengan penggunaan rutin.\n\nStyle UltraLite WeStep cocok untuk mereka yang ingin tampil santai dan tetap nyaman saat beraktivitas. \n\n### Pilihan:\n- **Hitam Oranye (G9385M-42)**: Ukuran 40-44, panjang sandal 27,2cm - 29,8cm.\n- **Hijau Army (G9385M-60)**: Ukuran 40-44, panjang sandal 27,2cm - 29,8cm.\n- **Moonrock Brown (G9385M-73)**: Ukuran 40-44, panjang sandal 27,2cm - 29,8cm.", + "price": 259000, + "stock": 5, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523075/hacktiv8/branded/sandal-selop-pria-gold-pigeon-ultralite-westep-g9385m-moonrock-brown-44-xl3x63rt2m.jpg", + "categoryId": 4, + "userId": 1 + }, + { + "id": 86, + "name": "PREMIUM 250gr Coffee Latte Fragrance Oil Pengahrum Humidifier Pure", + "description": "### Deskripsi Produk\n\n**WAJIB SLIDE FOTO SAMPAI AKHIR dan BACA DESKRIPSI** \nJudul hanya untuk kepentingan keyword dan tidak menjadi acuan detail produk. \n\nPremium Fragrance Oil untuk produk aromatik. \n\nSemua fragrance oil: \n- BERSERTIFIKASI INTERNASIONAL atau Nasional (berbeda setiap varian) \n- THE IFRA STANDARDS \n- COA \n- MSDS \n- HALAL Internasional \n- ISO 9001 Quality Management \n- ISO 22000 Food Safety Management System \n\nUntuk dokumen bisa di-share (beberapa informasi diblok) dengan minimum pembelian 5kg per variasi dalam 1 transaksi (tidak akumulatif). \n\n**Detail Produk:** \n- Oil Based 100% Pure Fragrance Oil \n- Shelf Life: 1 tahun \n- Liquid mass setiap varian berbeda-beda, mungkin ada botol yang penuh dan ada yang tidak. \n- Kegunaan: Lilin Aromaterapi, Sabun, Reed Diffuse, Paper Fresher, dll (lihat panduan IFRA pada foto produk). \n- Satuan ukuran kami berdasarkan berat (gr), bukan dari volume (ml); silakan ditimbang. \n\n**Aturan Penjual:** \n- Perhatikan ukuran dan varian pada judul yang dipilih sebelum checkout. \n- Untuk komplain, silakan video unboxing. \n- Video unboxing wajib tanpa potongan; proses buka sampai akhir harus jelas (tidak jelas dan terpotong tidak bisa komplain). \n- Sebelum memberikan review buruk, silakan berdiskusi terlebih dahulu jika ada masalah. \n- Tidak bisa membatalkan pesanan yang sudah di-checkout (karena ada cost packing dan repacking produk). Mohon pengertiannya. \n\n**PEMBELIAN DALAM JUMLAH BESAR MINIMUM 5KG PER VARIAN SILAKAN CHAT ADMIN UNTUK HARGA GROSIR.**", + "price": 174500, + "stock": 4, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523076/hacktiv8/branded/premium-250gr-coffee-latte-fragrance-oil-pengahrum-humidifier-pure-lqev8xvfpz.jpg", + "categoryId": 5, + "userId": 1 + }, + { + "id": 87, + "name": "Kipas Angin Plafon NAGOYA (Ceiling Fan) 56\" - Baling Besi - NG56CF - Putih", + "description": "# Solusi Sejuk yang Paling Besar dan Hemat Tempat\n\nNikmati udara sejuk dengan **NAGOYA NG-56CF Kipas Angin Plafon Langit-Langit Gantung / Ceiling Fan 56in**. Anda tidak perlu khawatir dengan cuaca panas di Indonesia lagi. Kipas angin plafon ini dapat menghembuskan udara untuk mendinginkan suasana Anda.\n\nDilengkapi dengan motor yang kuat dan handal, kipas NAGOYA lebih awet dan tahan lama. Kipas angin elegan ini juga memiliki 5 pilihan pengatur kecepatan dan dapat diletakkan di plafon ruangan manapun tanpa mengorbankan area lantai atau dinding.\n\n## ThermoSafe (Sekering Pengaman Panas)\nSemua kipas angin NAGOYA dilengkapi dengan ThermoSafe untuk mencegah overheating pada motor.\n\n## Easy Operational\nKipas angin gantung ini dilengkapi dengan Remote Control (wired) untuk memudahkan pengaturan kecepatan angin.\n\n## Quiet Operational (Anti-Bising)\nJika Anda memiliki pendengaran yang sensitif, kipas angin plafon ini bekerja dengan sunyi (anti-bising), sehingga dapat membuat tidur Anda lebih pulas dan nyaman.\n\n## Finishing Berkualitas\nSemua produk NAGOYA menggunakan material besi dengan coating berkualitas, membuat finishing kipas angin lebih glossy, cantik, dan elegan. #MewahTidakHarusMahal\n\n## Spesifikasi Lainnya\n- Kode Produk: NG-56CF\n- Termasuk Hook Bracket (untuk menggantung Kipas Plafon)\n- Belum Termasuk: Kabel Listrik\n- Daya listrik: ~75 watt\n- Tegangan: 220 Volt / 50 Hz\n- Kecepatan: 107-327 rpm\n- Ukuran Baling: 56\" / 142cm +- \n- Bahan Baling: Besi / Coated-Steel\n- Panjang pipa: 29cm\n- Berat Barang: 4kg\n\n### GARANSI RESMI NAGOYA Electronics: 1 TAHUN*", + "price": 299000, + "stock": 125, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523078/hacktiv8/branded/kipas-angin-plafon-nagoya-%28ceiling-fan%29-56%22-baling-besi-ng56cf-putih-wuizgges8ve.jpg", + "categoryId": 7, + "userId": 1 + }, + { + "id": 88, + "name": "Gosso Kayu Putih Essential Oil Stainless Roll-On Travel Size 10ml", + "description": "Gossō’s Minyak Kayu Putih Blend 10ml Roll On Botol Kaca.\n\nGOSSO Minyak Kayu Putih Blend tersedia dalam ukuran praktis untuk perjalanan dan mudah diaplikasikan ke kulit dengan roll-on stainless berkualitas premium yang tidak mudah bocor.\n\nTerbuat dari Minyak Kayu Putih Murni Asli Pulau Buru Ambon, disempurnakan dengan Caprylic/Capric Triglyceride dari Minyak Kelapa alami untuk menjaga kelembapan kulit dan memperoleh manfaat dari minyak kayu putih.\n\n**Manfaat:**\n1. Aromaterapi yang baik untuk meredakan stres dan kecemasan.\n2. Dipakai sebagai antiseptik untuk mencegah pertumbuhan mikro-organisme dan virus.\n3. Melegakan saluran pernapasan, flu, dan hidung tersumbat.\n4. Membantu mengatasi sakit perut dan perut kembung.\n5. Mengurangi peradangan.\n6. Pengusir serangga alami.\n\n**Cara Penggunaan:**\n1. Tekan bagian atas roller untuk membuka sistem lock dan mengalirkan minyak.\n2. Tekan dan putar searah jarum jam agar minyak dapat mengalir terus-menerus.\n3. Oleskan ke bagian yang diinginkan.\n4. Kembalikan ke posisi lock untuk menghindari kebocoran.\n\n**Penyimpanan:**\nSimpan di tempat yang kering dan sejuk, dan hindari cahaya matahari langsung.\n\n**Harga sudah termasuk Bubble Wrap.**\n\n**Produk Kami yang lain:**\n- [PREMIUM GIFT PACKAGE](https://www.tokopedia.com/gossonature/gosso-minyak-kayu-putih-premium-gift-package)\n- [GOSSO Minyak Kayu Putih Asli Pulau Buru Ambon – 100ml Essential Oil](https://www.tokopedia.com/gossonature/gosso-minyak-kayu-putih-asli-pulau-buru-ambon-100ml-essential-oil)\n- [GOSSO Minyak Kayu Putih Asli Pulau Buru Ambon – 50ml Essential Oil](https://www.tokopedia.com/gossonature/gosso-minyak-kayu-putih-asli-pulau-buru-ambon-50ml-essential-oil)", + "price": 45000, + "stock": 100, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523079/hacktiv8/branded/gosso-kayu-putih-essential-oil-stainless-roll-on-travel-size-10ml-y6egta602c.jpg", + "categoryId": 5, + "userId": 1 + }, + { + "id": 89, + "name": "Citihome Bladeless Stand Cooling Fan Remote Kipas Angin Tanpa Baling - White Silver", + "description": "### Garansi Toko 6 Bulan\n\n**Citihome Bladeless Stand Cooling Fan Remote Kipas Angin Tanpa Baling**\n\n**Product Features:**\n- Natural Wind, No Leaf Safety for kids, Energy Saving, Easy to Clean\n- Creates a Healthy and Quality Life: leafless design with technology offering 10 speed adjustment, schedule timer, brushless motor, and low noise.\n- Delivers a strong cool breeze of 500L of wind per second, effectively circulating indoor airflow.\n- Non-impact, soft as natural wind, comfortable and not harmful.\n- Air Conditioning Companion: quickly balances indoor temperature, promotes air circulation, and helps avoid air conditioning-related diseases.\n\n**How to Clean:**\nWipe the outer body of the fan with a dry/wet towel for easy cleaning.\n\n**Spesifikasi:**\n- **Model:** TP-09 \n- **Tinggi Produk Keseluruhan:** 85cm \n- **Size Bladeless Fan:** P15xL10xT52cm \n- **Diameter Base:** 26cm \n- **Noise Level:** <50db \n- **Motor:** DC Brushless Motor \n- **Voltage:** 220V \n- **Rated Frequency:** 50Hz \n- **Rated Power:** 45W \n- **Wind Supply Method:** Sway \n- **Pitch Angle:** 360 degrees \n- **Color:** Black & White \n\n**Dear Customer:** \n* Barang sudah kami periksa dengan baik sebelum kami kirim, packing sudah termasuk dengan bubble wrap & plastik wrapping. Mohon dilengkapi dengan asuransi untuk barang pecah belah dan video unboxing saat penerimaan. Jika terjadi kerusakan saat pengiriman, bukan tanggung jawab penjual. \n* 100% Barang Impor. Produk Berkualitas Tinggi. HARGA GROSIR \n* Berat barang dihitung dalam volume/KG \n\n**Alamat Showroom:** \nGoogle Map/Waze: Citihome Collection Store \nTikTok: Citihomegp \nIG: Citihome Collection", + "price": 1900000, + "stock": 40, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523082/hacktiv8/branded/citihome-bladeless-stand-cooling-fan-remote-kipas-angin-tanpa-baling-white-silver-f2f8d3wob4v.jpg", + "categoryId": 7, + "userId": 1 + }, + { + "id": 90, + "name": "PREMIUM 50gr Cinnamon Fragrance Oil Panegharum Reed Diffuser Pure", + "description": "WAJIB SLIDE PHOTO SAMPAI AKHIR dan BACA DESKRIPSI. JUDUL HANYA UNTUK KEPENTINGAN KEYWORD TIDAK MENJADI ACUAN DETAIL PRODUCT.\n\nPremium Fragrance Oil for Aromatic Products. Semua fragrance oil:\n- BERSERTIFIKASI INTERNATIONAL atau Nasional (berbeda setiap varian)\n - THE IFRA STANDARDS\n - COA\n - MSDS\n - HALAL International\n - ISO 9001 Quality Management\n - ISO 22000 Food Safety Management System\n\nDetail product:\n- Oil Based 100% pure Fragrance Oil\n- Shelf Life: 1 tahun\n- Kegunaan: Lilin Aromaterapi, Sabun, Reed Diffuse, Paper Fresher, dll. (lihat panduan IFRA pada photo product)\n\nRules Seller:\n- Perhatikan ukuran dan varian pada JUDUL yang dipilih sebeleum checkout. Kesalahan pilih product oleh customer tidak terima komplain.\n- Untuk komplain silakan video unboxing. Video unboxing wajib tidak ada cut, proses buka sampai akhir harus jelas.\n- Tidak bisa cancel pesanan yang sudah di checkout.", + "price": 43000, + "stock": 27, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523084/hacktiv8/branded/premium-50gr-cinnamon-fragrance-oil-panegharum-reed-diffuser-pure-9uxgl0ycaac.jpg", + "categoryId": 5, + "userId": 1 + }, + { + "id": 91, + "name": "CouCou Halycon Wet Food Kaleng 400gr makanan basah kucing - tuna KITTEN", + "description": "Coucou Halcyon Makanan Basah Kaleng 400gr adalah makanan untuk kucing semua usia, dengan varian: \n1. Adult Tuna. \n2. Adult Chicken \n3. Kitten Tuna \n4. Kitten Chicken \n\n**Formula:** Esensi Alami Murni \n\n**Fungsi:** \n1. Suplemen nutrisi dengan penyerapan protein yang tinggi, kalsium, vitamin, taurin, L-lisin, dan nutrisi penting lainnya. \n2. Topping saat makan untuk menambah rasa. \n3. Treats yang sangat baik. \n4. Raw Diet \n\n**Deskripsi Produk:** \n1. Sarat dengan daging asli dan nutrisi yang nyata. \n2. Potongan daging asli yang juicy dan lembut disajikan dengan kuah yang gurih dan bergizi. \n3. Hanya daging segar dan air dengan tambahan nutrisi sehat. \n4. Protein berkualitas tinggi, rendah lemak, tanpa pati, pewarna buatan, perasa, dan pengawet. \n5. Mudah dicerna dan bergizi, cocok untuk kucing yang sulit makan. \n6. Kualitas sangat baik, dijamin kepuasan pelanggan dan kucing mereka. \n7. Kemasan yang elegan dan mewah.", + "price": 18500, + "stock": 91, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523085/hacktiv8/branded/coucou-halycon-wet-food-kaleng-400gr-makanan-basah-kucing-tuna-kitten-vzi1ccg1pq.jpg", + "categoryId": 16, + "userId": 1 + }, + { + "id": 92, + "name": "Makanan Kucing Basah Life Cat 85GR Kitten Adult - Capt Salmon Kit", + "description": "### Deskripsi\n\n**Mohon baca sampai selesai:**\n\n- Mohon untuk mengirim video saat unboxing paket. Semua bentuk keluhan dan klaim TIDAK akan dilayani tanpa video unboxing.\n- Kerusakan selama pengiriman, seperti penyot atau bungkusan pecah, bukan menjadi tanggung jawab penjual. Kami sangat menyarankan untuk membeli asuransi untuk kemudahan proses klaim.\n\n**Terdapat 2 brand:** Life Cat & Captain. Merek berbeda tetapi produksi dari pabrik yang sama.\n\n**Varian rasa:**\n1. Life Cat Kitten Salmon\n2. Life Cat Kitten Tuna\n3. Life Cat Chicken and Tuna\n4. Life Cat Tuna Adult\n5. Life Cat Tuna Kitten\n\n**Varian rasa Captain:**\n1. Tuna Adult\n2. Tuna Chicken Adult\n3. Salmon Adult\n4. Tuna Kitten\n5. Tuna Chicken Kitten\n6. Salmon Kitten\n\n**Keunggulan:**\n- Baik untuk pencernaan kucing\n- Meningkatkan daya tahan tubuh\n- Menyehatkan pertumbuhan otot-otot kucing\n- Menyehatkan kulit kucing dan meningkatkan kekebalan tubuh kucing\n\nCat food premium untuk kucing dengan komposisi ayam dan ikan yang kaya vitamin dan mineral seperti vitamin B12, D, A, dan E. (Komposisi lengkap tertera pada kemasan)", + "price": 3700, + "stock": 1239, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523086/hacktiv8/branded/makanan-kucing-basah-life-cat-85gr-kitten-adult-capt-salmon-kit-nzi00jeat7i.jpg", + "categoryId": 16, + "userId": 1 + }, + { + "id": 93, + "name": "SuperCat Pouch 1 DUS (isi 12) Adult & Kitten ALL VARIANT - TUNA CHICKEN", + "description": "Super Cat Pouch dibuat dengan bahan berkualitas tinggi dan bergizi seimbang dengan rasa yang disukai kucing Anda. Mengandung vitamin, mineral, dan antioksidan untuk mendukung kesehatan kucing secara menyeluruh, termasuk sistem kekebalan tubuh, pencernaan, saluran kemih, serta kulit dan bulu. Nutrisi lengkap dan seimbang untuk kucing sehat dengan kulit dan bulu indah, serta cocok bagi kucing yang sulit makan.\n\n**Variant:**\n1. Tuna Prime Cut\n2. Ocean Fish\n3. Tuna Fish Role\n4. Tuna\n5. Tuna with Fish Liver\n6. Kitten Tuna Chicken\n7. Kitten Ocean Fish\n8. Kitten Tuna Special\n9. Kitten Tuna White Meat\n10. Mother & Baby\n\n**Berat:** 85 Gr", + "price": 54000, + "stock": 23, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523088/hacktiv8/branded/supercat-pouch-1-dus-%28isi-12%29-adult-and-kitten-all-variant-tuna-chicken-ujb6lu9ggq.jpg", + "categoryId": 16, + "userId": 1 + }, + { + "id": 94, + "name": "1 Dus Life Cat 400gr Kaleng Makanan Kucing Basah - Chicken Salmon", + "description": "Dengan tekstur halus yang mudah dicerna, produk ini dapat mengurangi risiko obesitas, menjaga kesehatan sistem pencernaan, menyehatkan jaringan, memperbaiki organ tubuh, serta melebatkan dan mengkilapkan bulu. Tersedia dalam 4 varian: Chicken, Chicken and Salmon, Chicken and Tuna, dan Tuna, serta cocok untuk kucing dewasa dan kitten.", + "price": 324000, + "stock": 9996, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523090/hacktiv8/branded/1-dus-life-cat-400gr-kaleng-makanan-kucing-basah-chicken-salmon-e0qashs5sq7.jpg", + "categoryId": 16, + "userId": 1 + }, + { + "id": 95, + "name": "Makanan Kucing Basah Ori Cat Kaleng Wet Food 400 Gram - TUNA&SHRIMP", + "description": "Makanan Kucing Ori cat Basah Kaleng 400 Gram\nTersedia Varian Rasa :\n1. Pure Tuna\n2. Tuna & Shrimp\n3. Ocean Fish\n\nVarian tambahan:\n1. Master Ocean Fish 425gr\n2. Master Kitten 425gr\n3. Master Tuna 425gr\n\nKelebihan:\n- Baik untuk pencernaan kucing\n- Meningkatkan daya tahan tubuh\n- Menyehatkan pertumbuhan otot-otot kucing\n- Menyehatkan kulit kucing dan meningkatkan kekebalan tubuh kucing", + "price": 11950, + "stock": 0, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523092/hacktiv8/branded/makanan-kucing-basah-ori-cat-kaleng-wet-food-400-gram-tunaandshrimp-79o473xn8hl.jpg", + "categoryId": 16, + "userId": 1 + }, + { + "id": 96, + "name": "Kuvings EVO820 Whole Slow Juicer - Kuvings EVO Matt 820 Dark Red", + "description": "#### Deskripsi Produk\n\n**Kuvings EVO820 Whole Slow Juicer** - Warna Dark Red\n\n**Bonus:**\n- 1 Set Pisau\n- 1 Telenan Mini\n- 1 Botol Minum\n\n**Keunggulan Kuvings Whole Slow Juicer:**\n- Menjaga kandungan nutrisi asli dari buah dan sayur berkat slow speed blending.\n- Rasa jus lebih segar dan lezat tanpa ampas.\n- Feeding Tube yang lebih besar mempercepat proses membuat jus.\n- Mudah dibersihkan dengan mesin yang dilengkapi fitur Self-Cleaning.\n- Didesain dan diproduksi sendiri oleh Kuvings, menjamin kualitas produk.\n\n**Spesifikasi:**\n1. Kecepatan: 60 RPM\n2. Daya: 240 Watt\n3. Bahan Material: Stainless Steel, ABS, PC\n4. Kapasitas: 400 Ml\n5. Garansi Motor: 10 Tahun & Garansi Spare Part: 2 Tahun\n6. Warna: Matt Rose Gold\n\nDengan Slow Juicer Kuvings, Anda dapat dengan mudah, cepat, dan sehat membuat jus sayur.", + "price": 7167000, + "stock": 4, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523093/hacktiv8/branded/kuvings-evo820-whole-slow-juicer-kuvings-evo-matt-820-dark-red-e12hiigywdo.jpg", + "categoryId": 7, + "userId": 1 + }, + { + "id": 97, + "name": "Simbalion Watercolor Cake 36 Warna", + "description": "Simbalion Watercolor Cake adalah cat kering dan padat yang larut saat diberi air. Penggunaan dapat dilakukan dengan kuas tradisional atau water brush. Cocok untuk pemula hingga profesional, dengan desain kemasan praktis sehingga mudah dibawa. Penutup kemasan juga dapat digunakan sebagai mixing tray. Sudah termasuk 1 kuas dalam paket.\n\n**Cara Pakai**:\n1. Basahi kuas dengan air sebelum mengusapkan pada watercolor cake.\n2. Cake berukuran diameter 23mm.\n3. Dimensi: 255mm x 135mm x 14mm.", + "price": 95130, + "stock": 872, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523094/hacktiv8/branded/simbalion-watercolor-cake-36-warna-k9xuq3epb2s.jpg", + "categoryId": 21, + "userId": 1 + }, + { + "id": 98, + "name": "SOMETHINC HANGOVER Voluminous Fiber Lash Smudgeproof Mascara", + "description": "## Hangover Mascara\n\nINSTANT LASH LIFT & FILLER MASCARA WITH VOLUME LOCK & 24 HOUR SLICK CURL TECHNOLOGY!\n\nDapatkan bulu mata yang menawan tanpa clumpy dengan sekali sentuhan dramatis HANGOVER MASCARA! Buat eye look natural & glam sesukamu. Diformulasikan agar tahan air, tidak geser, & tahan minyak sehingga kamu tidak perlu takut luntur setelah seharian.\n\n**Ukuran:** 7gr \n**No BPOM:** NA18211204926 \n\n### FIBER INSTANT LASH FILLER\n- Long-lasting! \n- All Day Slick Curl & Volume Lock Technology \n- Waterproof, Smudgeproof, Sweatproof \n- Not Clumpy \n\n### CARA PEMAKAIAN:\n\nUntuk hasil maskara terbaik, aplikasikan pada bulu mata mulai dari akar sampai ujung. Sapukan maskara dengan gerakan zig-zag. Aplikasikan di atas bulu mata sampai kamu mendapatkan tampilan mata volume ekstra yang kamu suka.\n\n**PAO:** 6 months \n\n**INGREDIENTS LIST:** \nIsododecane, Trimethylsiloxysilicate, Talc, Ceresin, Disteardimonium Hectorite, Microcrystalline Wax, CI 77499, Dextrin Palmitate, Polypropylsilsesquioxane, Propylene Carbonate, VP/Eicosene Copolymer, Hydrogenated Polyisobutene, Nylon-66, Silica, Aluminum Distearate, Polymethylsilsesquioxane, Glyceryl Caprylate, Triethoxycaprylylsilane, CI 77891, BHT", + "price": 85000, + "stock": 125, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523096/hacktiv8/branded/somethinc-hangover-voluminous-fiber-lash-smudgeproof-mascara-5zcurhbzg7l.jpg", + "categoryId": 5, + "userId": 1 + }, + { + "id": 99, + "name": "FLIMEAL BY FLIMTY SUSU SEREAL PENGGANTI MAKANAN DIET PELANGSING - Strawberi", + "description": "FLIMEAL 12 SACHET BY FLIMTY PROMO SUSU SEREAL PENGGANTI MAKANAN DIET PELANGSING BPOM HALAL - KMCR NEXTLEVEL\n\nFlimeal adalah minuman pengganti menu sarapan atau Meal Replacement yang diformulasikan khusus untuk Anda yang sedang mempertahankan atau menurunkan berat badan. Mengandung bahan-bahan tinggi protein dan serat seperti kacang-kacangan, kedelai isolat, dan chia seed. Flimeal berfungsi sebagai minuman pengganti sarapan guna memenuhi kebutuhan nutrisi serta energi harian Anda tanpa berpengaruh terhadap peningkatan berat badan.\n\n**PEMBELIAN:**\n- 2 BOX FLIMEAL + FREE 1 SHAKER\n- 4 BOX FLIMEAL + FREE 3 SHAKER\n_(NB: selama Shaker masih ada)_\n\n**Kandungan FLIMEAL:**\n- **Protein Kedelai Isolat**: Mengandung sekitar 40% protein, 20% minyak, 35% karbohidrat larut (sukrosa, stachyose, rafinosa), dan karbohidrat tidak larut (serat makanan). Selenium mengandung lebih dari 90% protein dibanding susu sapi.\n- **Beras Coklat**: Mengandung serat, GABA, Asam amino esensial Lysine, antioksidan, dan berbagai mineral.\n- **Chia Seed**: Mengandung protein, lemak, karbohidrat, serat, mineral, dan asam lemak omega 3.\n- **Bubuk Flaxseed Oil**: Dapat menurunkan insulin dan meningkatkan kapasitas antioksidan.\n\n**CARA MINUM:**\nTuangkan 1 bungkus Flimeal ke dalam shaker, tambahkan 200ml air dingin, kocok hingga larut, dan segera sajikan. Konsumsi Flimeal 1 sachet sebagai pengganti makanan atau camilan ketika lapar.", + "price": 217550, + "stock": 5, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523098/hacktiv8/branded/flimeal-by-flimty-susu-sereal-pengganti-makanan-diet-pelangsing-strawberi-li3cxvijmr9.jpg", + "categoryId": 6, + "userId": 1 + }, + { + "id": 100, + "name": "Kraft Keju Cake Bolu Keju 16 gr [1 Box Isi 12 pcs]", + "description": "Kraft Keju Cake Bolu Keju 16 gr [1 Box Isi 12 pcs] \n\n**Isi paket:** \n1x Kraft Keju Cake Bolu Keju 16 gr [Box Isi 12 pcs] \n\nKraft Keju Cake Bolu Keju dibuat dengan kebaikan susu dan keju asli yang membuat Keju Cake ini sangat lembut dan lezat, sehingga akan membuat Anda ketagihan. \nKeju bolu ini cocok disajikan sebagai snack untuk berbagai kesempatan. Nikmati kelembutan dan kelezatannya dalam setiap gigitan!", + "price": 24900, + "stock": 677, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523099/hacktiv8/branded/kraft-keju-cake-bolu-keju-16-gr-1-box-isi-12-pcs-uyct66rxitb.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 101, + "name": "MAKANAN KUCING BASAH Lifecat Life Cat Pouch/saset 85G - ADULT, CHICKEN TUNA", + "description": "Untuk varian yang mau dicampur, silakan tuliskan di catatan varian yang diinginkan, bukan di chat atau diskusi. Kami akan mengirimkan varian sesuai opsi yang dipilih atau yang ditulis di catatan.\n\nTersedia dalam beberapa varian antara lain:\n1. Kitten Tuna \n2. Kitten Chicken \n3. Kitten Salmon \n4. Adult Salmon \n5. Adult Chicken Tuna", + "price": 4692, + "stock": 2352, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523100/hacktiv8/branded/makanan-kucing-basah-lifecat-life-cat-pouchsaset-85g-adult-chicken-tuna-1gug3vbgvao.jpg", + "categoryId": 16, + "userId": 1 + }, + { + "id": 102, + "name": "Ikan Dori Fillet Lokal Grade A (1 KG)", + "description": "Selamat Datang Di YC Seafood\n\nNote: Tolong Dubaca Untuk Note Pengiriman Terima kasih 😁\n\n# INSTANT = GOJEK / GRAB #\n(Layanan pengiriman instant dengan durasi pengiriman beberapa jam saja (1-2 jam) sejak SERAH TERIMA paket ke kurir). Bukan dari waktu PEMBELI ORDER.\n\nUNTUK KIRIM ALAMAT KANTOR & BURU” Sangat disarankan menggunakan instant kurir.\n\n# SAME DAY = GOJEK / GRAB / AnterAja #\n(Layanan pengiriman dengan durasi pengiriman beberapa jam saja (5-6 jam) sejak SERAH TERIMA paket ke kurir dan akan sampai di hari yang sama). Bukan dari waktu PEMBELI ORDER.\n\nInfo bahwa PENJUAL di berikan WAKTU OLEH TOKPED 1 x 24 Jam (minimum) untuk melakukan pengiriman ke pembeli.\n\nIkan Dori Fillet Lokal Grade A (1 KG)\n\n- Ikan Dori Fillet isi 3-4 Pcs\n- Glazing 40% - 50%\nProduct IQF\nUntuk Fast Respond WA: 087725111621\n\nYC Seafood Menyediakan Berbagai Makanan Laut Seperti Udang, Cumi Dan Ikan. Silahkan Kontak Admin Untuk Informasi Makanan Yang Anda Butuhkan. Kami Selalu Mengutamakan Kualitas Produk Kami.", + "price": 35000, + "stock": 11848, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523103/hacktiv8/branded/ikan-dori-fillet-lokal-grade-a-%281-kg%29-3rcisv4svy4.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 103, + "name": "ANTBOX Lemari Pakaian Plastik 12 Kabinet 2 Hanger Putih Minimalis", + "description": "🌈 Selamat datang di ANTBOX Official Store\n\nANTBOX menyediakan berbagai produk home furnishing secara global. Solusi cerdas untuk Anda yang menginginkan furniture yang mudah dipasang dan berkualitas tinggi. Dikenal dengan teknologi \"Quickfold Free Decomposition\" yang memungkinkan kabinet terpadu bebas perakitan, sehingga dapat dipasang secara mandiri.\n\n**Detail Produk Lemari Pakaian ANTBOX**\n- **Merek:** ANTBOX\n- **Material:** Plastik PP (Kabinet), PET (pintu), ABS, Magnet\n- **Warna:** Transparan\n- **Ukuran dan Berat Produk:** 12 BOX 2 HANGER: Berat Bersih: 17,67 kg; Ukuran: 104 * 50 * 136 cm\n\n**Keunggulan Lemari Pakaian ANTBOX**\n⭐ Instalasi dalam kurang dari 5 menit, menghemat waktu.\n⭐ Bahan kokoh yang mampu menampung beban lebih dari 50 kg.\n⭐ Pintu dilengkapi magnet untuk menjaga pintu tetap tertutup.\n⭐ Material aman, anti rayap, tidak beracun, tidak berbau, dan bebas formaldehida.\n⭐ Beragam pilihan ukuran sesuai kebutuhan.\n\n**Catatan:**\n✨ Waktu Pengiriman: Pesanan sebelum jam 4 sore akan diproses pada hari yang sama; setelah jam 4 akan diproses keesokan harinya.\n✨ Komplain wajib sertakan video unboxing.\n✨ Jika ada pertanyaan, silakan hubungi admin kami.", + "price": 1869000, + "stock": 138, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523105/hacktiv8/branded/antbox-lemari-pakaian-plastik-12-kabinet-2-hanger-putih-minimalis-ev2if6dop1c.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 104, + "name": "KACANG HITAM 1 KG BLACK BEAN 1KG IMPORT IMPOR", + "description": "**Kacang Hitam Import / Black Bean with Green Kernel**\n\n- **Berat Bersih**: 1 Kg\n- **HALAL!**\n- **Packing**: Dilakukan dalam kondisi higienis dan bersih.\n- **Penyimpanan**: Dalam kondisi kering dan dingin tanpa sinar matahari.\n\n**Nutrisi**: Kacang ini mengandung vitamin dan mineral penting seperti asam folat, magnesium, kalium, zat besi, dan zinc. Selain itu, kaya akan protein dan serat, menjadikannya alternatif sehat untuk protein dengan sedikit lemak. Dalam 172 gr kacang hitam terkandung energi sebesar 227 kkal, karbohidrat 41 gr, protein 15 gr, lemak 1 gr, dan serat 15 gr.\n\n**Antioksidan**: Kacang hitam kaya akan antioksidan, lebih tinggi dibanding 11 jenis kacang lainnya. Pigmen antosianin yang memberikan warna lebih gelap berperan dalam tingginya kandungan antioksidan.\n\n**Kesehatan**: Antioksidan dalam kacang hitam dapat membantu melindungi tubuh dari radikal bebas dan mengurangi risiko penyakit kronis seperti kanker, jantung, Alzheimer, dan diabetes.\n\n**Kecantikan**: Kandungan flavonoid pada kacang hitam baik untuk mencegah tanda-tanda penuaan dini akibat paparan sinar matahari.\n\n**Penggunaan**: Kacang hitam dapat dicampur dalam berbagai masakan seperti sup, salad, atau pasta, dan juga bisa dijadikan camilan sehat karena indeks glikemik (IG) yang rendah.\n\n*Kami melayani jumlah besar. Harga nego. Chat/WA: 0813 8427 5267*", + "price": 55000, + "stock": 175, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523106/hacktiv8/branded/kacang-hitam-1-kg-black-bean-1kg-import-impor-xh1okniyp9m.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 105, + "name": "ANTBOX Lemari Pakaian Putih 10 BOX 1 HANGER Lemari Baju Minimalis", + "description": "🌈Selamat datang di ANTBOX Official Store\n\nANTBOX menyediakan berbagai produk home furnishing secara global. ANTBOX hadir sebagai solusi cerdas untuk Anda yang menginginkan produk furniture yang mudah dipasang dan berkualitas tinggi. Produk ini menggunakan teknologi \"Quickfold Free Decomposition\" yang menciptakan kabinet terpadu tanpa perlu rakitan, sehingga bisa dipasang secara mandiri.\n\n### DETAIL PRODUK LEMARI PAKAIAN ANTBOX\n- **Merek:** ANTBOX \n- **Material:** PLASTIK PP (Kabinet), PET (Pintu), ABS, Magnet \n- **Warna:** Transparan \n- **Ukuran dan Berat Produk:** \n - 10 BOX 1 HANGER: \n - Berat Bersih: 15,12 kg \n - Ukuran: 69 * 50 * 170 cm\n\n### Kenapa Harus Membeli Rak Sepatu ANTBOX?\n- 🛠️ Lemari Pakaian ANTBOX dapat diinstal dalam kurang dari 5 menit, menghemat waktu Anda \n- 💪 Bahan kokoh dapat menampung beban lebih dari 50 kg \n- 🔒 Pintu dilengkapi magnet untuk keamanan \n- 🚫 Terbuat dari bahan yang aman, anti rayap, tidak beracun, tidak berbau, dan bebas formaldehida \n- 📏 Tersedia dalam berbagai pilihan ukuran sesuai kebutuhan\n\n### NOTE:\n- ✨ **Waktu Pengiriman:** Pesanan sebelum jam 4 sore akan diproses pada hari yang sama; setelah jam 4 akan diproses pada hari berikutnya \n- 📦 **KOMPLAIN WAJIB SERTAKAN VIDEO UNBOXING** \n- ❓ Jika ada pertanyaan, silakan tanyakan kepada admin kami.", + "price": 1638000, + "stock": 6, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523107/hacktiv8/branded/antbox-lemari-pakaian-putih-10-box-1-hanger-lemari-baju-minimalis-qd07fp88a2.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 106, + "name": "Herslim dari Herwell Susu Diet", + "description": "Selalu ready, tidak perlu tanya stok, bisa langsung order.\nHarga untuk 1 botol Herslim (isi 20 sachet) rasa Coklat. Rendah lemak dan rendah kalori hanya 120kkal.\nPembelian minimal 2 paket FREE Shaker Herwell (boleh mix Hervibe, Herlean, Herslim).\n\nHerslim adalah suplemen tinggi nutrisi yang membantu program diet dengan memberikan efek kenyang lebih lama. Berikut adalah 4 kandungan Superfood Herslim:\n1. **Multigrains:** Gabungan 10 jenis biji-bijian sebagai sumber nutrisi.\n2. **Susu Kolostrum:** Mengandung Immunoglobulin-G untuk meningkatkan imunitas tubuh.\n3. **L-Carnitine:** Membantu mengubah lemak menjadi sumber energi.\n4. **Casein:** Sumber protein lambat serap yang membuat tubuh kenyang lebih lama.\n\n**Manfaat Herslim:**\n- Mencukupi nutrisi harian saat program weight loss.\n- Membuat tubuh awet kenyang.\n- Meningkatkan imunitas tubuh.\n- Membantu menjaga body goal.\n- Mengubah lemak menjadi energi.\n\n**Cara Minum Herslim:**\n- Minum 2x sehari sebelum makan pagi dan malam.\n- Ambil 1 sachet dan campurkan ke dalam 200 ml air hangat.\nProduk HERSLIM sudah lolos BPOM, HALAL, HACCP, GMP, ISO.", + "price": 290000, + "stock": 9884, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523109/hacktiv8/branded/herslim-dari-herwell-susu-diet-n736v0g8ce.jpg", + "categoryId": 6, + "userId": 1 + }, + { + "id": 107, + "name": "Kipas Angin Berdiri Tornado Besi 3in1 18Inch", + "description": "Kipas Angin Tornado Besi 3in1 18Inch ini memiliki beberapa fungsi: Kipas Berdiri, Kipas Meja, dan Kipas Dinding/Tembok. Terdapat dua ukuran yaitu 12Inch untuk fungsi 2in1 (Kipas Meja dan Dinding) serta 18Inch. Fitur lainnya mencakup:\n- 3 Opsi Kecepatan\n- Hemat Listrik\n- Hembusan Angin Kencang\n- Body Yang Kuat Tidak Mudah Pecah\n- Tegangan: 220 Volt - 50Hz\n\nMohon diperhatikan, barang akan diperiksa sebelum dikirim dan dikemas dengan standar baik. Untuk kerusakan akibat ekspedisi, tidak dapat dikembalikan. Disarankan untuk menggunakan asuransi pengiriman.", + "price": 156000, + "stock": 144, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523111/hacktiv8/branded/kipas-angin-berdiri-tornado-besi-3in1-18inch-n2loglxigtb.jpg", + "categoryId": 7, + "userId": 1 + }, + { + "id": 108, + "name": "Wiper Mobil TOYOTA Innova Reborn 26” + 16” (2pcs) - HELLA Premium 2.0", + "description": "HELLA Wiper Blade Premium 2.0 untuk Toyota Innova Reborn. Wiper Mobil Kanan Kiri / Penyeka / Pembersih Kaca Mobil.\n\nHella Wiper Blade dibuat dengan karet berlapis grafit menggunakan nanoteknologi berkualitas tinggi. Lapisan grafit ini mengurangi gesekan antara bilah penyeka dan kaca depan mobil, memberikan pengoperasian yang halus, senyap, dan tahan lama.\n\nHella Wiper Blade memenuhi standar kualitas tertinggi dari Japanese Industrial Standards (JIS) dan Society of Automotive Engineers (SAE). Dilengkapi dengan Multi Adapter, cocok untuk J/U Hook Arm, Pin Arm, dan Bayonet.\n\n**Spesifikasi:**\n- 100% Original Official Store Hella\n- Warna: Hitam\n- Ukuran Wiper Kanan: 26\"\n- Ukuran Wiper Kiri: 16\"\n- Berat: 1 kg\n\nGunakan wiper berkualitas untuk mobil kesayanganmu.", + "price": 90640, + "stock": 909, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523114/hacktiv8/branded/wiper-mobil-toyota-innova-reborn-26%22-%2B-16%22-%282pcs%29-hella-premium-2.0-z9nbobvv73a.jpg", + "categoryId": 10, + "userId": 1 + }, + { + "id": 109, + "name": "Lampu LED Mobil Headlight H4 H7 60W 9000Lumens 6000K - H7", + "description": "Lampu LED Mobil Headlight ini menghasilkan cahaya terang dengan konsumsi daya rendah, membuatnya efektif untuk penggunaan. \n\n- Harga untuk 1 pasang\n- SUPER TERANG\n\n**Spesifikasi:**\n- Bahan: Aluminium \n- Daya: 60W \n- Tegangan: 9-36V \n- Lumens: 9000 Lumens \n- Warna LED: Putih 6000K \n- Umur pemakaian: 50000 Jam \n\n**Catatan:**\n- Sebelum dikirim, barang akan diperiksa terlebih dahulu. \n- Barang yang dikirim tidak akan cacat atau bekas. \n- Tidak dapat mengubah pesanan atau alamat kecuali dengan melakukan order ulang. \n- Barang sudah dipacking aman. Namun, pembeli bisa meminta ekstra packaging jika diperlukan. \n\n**Komplain & Retur:**\n- Lakukan video unboxing dan pengecekan barang sebelum menekan terima pesanan.\n- Komplain tanpa video unboxing dan foto tidak akan diterima.\n- Ongkos kirim untuk retur ditanggung pembeli setelah pesanan selesai. \n\n**Pengiriman:**\n- Semua pesanan akan dikirim pada hari yang sama jika pembayaran dilakukan sebelum jam 15:00 (Senin - Jumat), dan 13:00 (Sabtu). \n- Kurir akan melakukan pick up antara jam 15:00 - 18:00 (Senin - Sabtu). \n- Pesanan instan dan sameday yang dilakukan sebelum jam 12:00 di hari Minggu akan dikirim di hari yang sama. \n\nMembeli berarti Anda telah membaca keterangan di atas. Jangan lupa untuk follow toko kami untuk update barang baru. Tolong bantu review dan referensikan toko kami kepada teman dan kerabat.\n\n**Jam Operasional:**\n- Senin – Jumat: 08:30 - 17:00\n- Sabtu: 08:30 - 13:00\n- Minggu: 10:00 - 13:00\n", + "price": 189000, + "stock": 44, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523116/hacktiv8/branded/lampu-led-mobil-headlight-h4-h7-60w-9000lumens-6000k-h7-eho5dwjogrb.jpg", + "categoryId": 1, + "userId": 1 + }, + { + "id": 110, + "name": "Kipas Angin Dinding NAGOYA (Wall Fan) Baling Besi 18", + "description": "**Warna baling kipas sesuai dengan foto yang terpajang (warna Silver). Pada saat pengiriman, baling dilapisi plastik berwarna biru (bisa dikupas setelah dipasang).**\n\nSiap Melawan Cuaca Panas Ekstrem Indonesia.\n\nNyalakan kipas angin terkuatmu dari NAGOYA NG-18WF Kipas Angin Dinding / Wall Fan 18in. Anda tidak perlu khawatir dengan cuaca panas di Indonesia lagi. Kipas angin bertenaga besar ini dapat menghembuskan udara kencang ke berbagai arah untuk mendinginkan suasana Anda.\n\nDilengkapi dengan motor tornado yang handal, membuat kipas NAGOYA lebih awet dan tahan lama. Kipas angin dinding ini juga mempunyai baling berbahan aluminum, dengan 3 pilihan pengatur kecepatan yang dapat diatur dengan tali, menghembuskan angin badai dan dapat dipasang di dinding untuk menghemat tempat di ruangan, sesuai dengan keinginan dan kebutuhan Anda.\n\n**Spesifikasi Lainnya:**\n- Kode Produk: NG-18WF\n- Daya listrik: 60 watt\n- Tegangan: 220 Volt / 50 Hz\n- Ukuran Baling: 18” / 45cm\n- Berat Barang: 8.61 kg\n\nGARANSI RESMI NAGOYA Electronics: 1 TAHUN*", + "price": 239000, + "stock": 218, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523117/hacktiv8/branded/kipas-angin-dinding-nagoya-%28wall-fan%29-baling-besi-18-dmdw0b5kd37.jpg", + "categoryId": 10, + "userId": 1 + }, + { + "id": 111, + "name": "Aki Mobil Hella XCELERATE PRO AMS 46B19L - Aki Mobil Kering", + "description": "Aki Mobil Hella XCELERATE PRO AMS 46B19L - Aki Mobil Kering\n\n- Bebas perawatan & cocok untuk iklim tropis Indonesia\n- Memiliki daya start tinggi karena dapat menyimpan energi listrik lebih lama dan bebas korosi/karat\n- Anti bocor dan praktis\n\n**Spesifikasi:** \n- 100% Original Official Store Hella \n- Tipe: Aki Mobil MF / Aki Mobil Kering \n- CCA: 360 A \n- Tegangan: 12V, 38AH \n- Ukuran Aki: P 187 mm, L 127 mm, T 226 mm \n- Aplikasi: Toyota Corolla, Corona, Daihatsu, Sirion, Ceria, YRV, Classy, Suzuki Aerio, Baleno, New Baleno, Karimun, Karimun Estilo, Swift, Ertiga, All New Jazz (S/SR), Jazz, All New City, City, Freed, Mitsubishi T-120SS-MPI, Hyundai i10, Isuzu Travera, KIA Visto, Picanto, Grand Livina 1.8, Ertiga, Innova E/J, All New Altis, Hilux", + "price": 851400, + "stock": 6, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523118/hacktiv8/branded/aki-mobil-hella-xcelerate-pro-ams-46b19l-aki-mobil-kering-ik7ruq2ulxm.jpg", + "categoryId": 10, + "userId": 1 + }, + { + "id": 112, + "name": "LED Autovision Xandway 30 Watt H4 H7 H11 H16 H8 H27 HB3 HB4 - Kuning 2800K, H27", + "description": "LED Autovision XAND Dan Xandway 6500K (Garansi 1 Tahun)\n\n**Spesifikasi:**\n- Tipe lampu: H4, H7, H11/H16/H8/H9, HB3, HB4, H27\n- Tegangan: DC 12 volt\n- Daya: 30 Watt\n- Temperatur warna: 6000K Putih\n- Cahaya: 3000 Lumens (1 Lampu), 6000 Lumens (2 Lampu)\n- LED: Advance CSP LED Chips\n\n**Garansi:** Resmi 1 Tahun\n\n**Kelebihan XANDWAY LED:**\n- Warna cahaya putih/kuning terang\n- Cahaya lebih terang 350% dibanding lampu standar\n- Terang cahaya 6000 Lumens\n- Menggunakan Advance CSP Chips LED sebagai sumber cahaya\n- Menggunakan bahan pelepas panas Kisi Alumunium\n- Awet dan tahan lama (Ekspektasi di atas 30.000 jam)\n- Bisa beroperasional pada suhu -40 sampai 80 derajat Celcius\n- Pemasangan gampang, tinggal plug and play sambung soket\n\n**Noted:** Khusus H11 kuning masih seri xand 27 watt", + "price": 342000, + "stock": 10, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523125/hacktiv8/branded/led-autovision-xandway-30-watt-h4-h7-h11-h16-h8-h27-hb3-hb4-kuning-2800k-h27-n6vzfpddgk8.jpg", + "categoryId": 1, + "userId": 1 + }, + { + "id": 113, + "name": "Lemari Baju Besi - Lemari Pakaian Besi Sliding / 2 Pintu / 3 Pintu - SL 202C", + "description": "Lemari dengan kualitas terbaik. HARAP HUBUNGI ADMIN UNTUK CEK ONGKOS KIRIM DAN JASA PASANG DI DAERAH JABODETABEK.\n\nPENTING: Ongkir Cargo di TANGGUNG PEMBELI sebelum Order. Chat Kami untuk menanyakan ketersediaan STOK dan harga Ongkir. Ongkir yg di TOKPED hanya untuk Tracking Resi kirim INVOICE dengan Berat 10 gr, karena ini bahan besi bukan kertas/kayu. Kiriman barang untuk luar kota kami kirim pakai cargo, jadi Invoice dan barang mungkin datang tidak bersamaan tetapi pasti sampai. Kami akan bantu Tracking setelah barang di ekspedisi. HAPPY SHOPPING! \n\nBisa dikirim menggunakan kurir dari toko kami. Estimasi packing 1-2 hari setelah pesanan diterima, tetapi bisa lebih cepat tergantung antrian. Order akhir pekan akan dipacking saat hari kerja, dari Senin hingga Sabtu.", + "price": 1590000, + "stock": 8, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523128/hacktiv8/branded/lemari-baju-besi-lemari-pakaian-besi-sliding-2-pintu-3-pintu-sl-202c-29m7jm1vagn.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 114, + "name": "Wiper Mobil HONDA Brio, BR-V, Mobilio 22\"+16\"(2pcs) - HELLA Premium 2.0", + "description": "HELLA Wiper Blade Premium 2.0 untuk Honda Satya, Brio, BR-V, dan Mobilio - Wiper Mobil Kanan Kiri / Penyeka / Pembersih Kaca Mobil. \n\nHella Wiper Blade dibuat dengan karet berlapis grafit menggunakan teknologi nanoteknologi berkualitas tinggi. Lapisan grafit ini sangat efektif dalam mengurangi gesekan antara bilah penyeka dan kaca depan mobil, menghasilkan operasional yang halus dan tanpa suara, serta performa yang lebih tahan lama. \n\nHella Wiper Blade memenuhi persyaratan kualitas tertinggi berdasarkan standar pengujian Japanese Industrial Standards (JIS) dan Society of Automotive Engineers (SAE). \n\n**Spesifikasi:**\n- 100% Original Official Store Hella\n- Warna: Hitam\n- Ukuran Wiper Kanan: 22\"\n- Ukuran Wiper Kiri: 16\"\n- Berat: 1 kg\n\nGunakan wiper berkualitas untuk mobil kesayanganmu.", + "price": 77000, + "stock": 806, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523129/hacktiv8/branded/wiper-mobil-honda-brio-br-v-mobilio-22%22%2B16%22%282pcs%29-hella-premium-2.0-xub7aka5l5n.jpg", + "categoryId": 10, + "userId": 1 + }, + { + "id": 115, + "name": "Pristine Maldives Villa Reed Diffuser 180ml - Hotel Series", + "description": "### PRISTINE AROMA\n\n- **100% Produk Import** \n- Brand No.1 di Singapore\n\n**Aroma bertahan hingga 6-10 Minggu** (bergantung kondisi ruangan)\n\n#### Include:\n- 1 Botol Diffuser varian Maldives Villa (180ml)\n- 5 Reed Stick polyester berwarna cream\n- Kemasan dengan desain minimalis\n- Umur simpan produk adalah 12 bulan setelah kemasan dibuka\n\n#### Fungsi:\n- Aroma yang tahan lama karena dibuat dengan campuran minyak esensial premium\n- Cocok untuk hadiah karena dikemas dalam kotak cream yang elegan\n- Aman untuk hewan peliharaan & anak-anak karena bebas dari campuran bahan-bahan kimia\n- Reed Diffuser yang cocok untuk dekorasi interior yang modern\n\n#### Note Aroma:\n- Jeruk Bali, Apel, Bunga Yakut\n\n#### Petunjuk Pemakaian:\n1. Buka tutup botol.\n2. Masukkan stick reed diffuser ke dalam botol.\n3. Stik tersebut akan menyerap minyak dan menyebarkan aromanya ke ruangan.\n4. Diffuser akan mencapai hasil maksimal dalam 12 jam.\n5. Jika aroma mulai memudar, balik reed stick diffuser secara berkala selama 3-4 hari sekali.\n\n#### Perhatian:\n- Letakan reed diffuser di ruangan yang tertutup.\n- Jangan meletakan dekat sinar matahari/Bawah AC.\n- Gunakan reed stick seperlunya. Jika ingin aroma lebih kuat, gunakan lebih banyak reed stick.\n- Letakan tisu di bawah reed diffuser untuk menghindari tetesan minyak wangi.\n- Agar lebih hemat, gunakan reed diffuser saat diperlukan.\n\n**PERHATIAN:** Tanpa Video Unboxing, segala jenis komplain kerusakan/kekurangan tidak akan dilayani (Video direkam sebelum & sampai selesai pembukaan paket disertai dengan resi). \n\n#pristine #pristinelife #reeddiffuser #balldiffuser #refill #essentialoil #roomspray #waxmelt #candle #pengharumruangan", + "price": 395000, + "stock": 178, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523131/hacktiv8/branded/pristine-maldives-villa-reed-diffuser-180ml-hotel-series-c18sts5j7ng.jpg", + "categoryId": 5, + "userId": 1 + }, + { + "id": 116, + "name": "MiLife Turbo High Speed Fan Semiconductor Cooling With Phone Stand 100 Speed 4800mah Rechargeable Portable Kipas Angin Turbo Mini - Phantom Black", + "description": "Halo, TikTokers! Sudah siap untuk menjadikan rumah atau kantormu lebih sejuk dan nyaman dengan Kipas Angin MiLife Turbo High Speed Fan? 🌬️💨 Dengan kapasitas baterai besar 4800mAh, kipas angin portable ini mudah dibawa ke mana saja!\n\nDilengkapi dengan fitur ice cooler, kipas ini memiliki 100 level kecepatan yang dapat disesuaikan sesuai kebutuhanmu.\n\nDengan putaran kipas yang cepat, udara kencang akan langsung terasa. Kipas ini juga dilengkapi dengan phone stand, memungkinkanmu menonton video TikTok favorit sambil menikmati udara segar.\n\n**Fitur:**\n- **Digital Display:** Kipas mini ini memiliki tampilan digital dan baterai 4800mAh untuk cepat mendinginkan di cuaca panas.\n- **Kompak dan Portable:** Ukuran kecil 7.8cmx6cmx17.9cm, mudah dibawa ke mana saja.\n- **Pengaturan yang Dapat Disesuaikan:** Menawarkan kecepatan angin yang dapat disesuaikan untuk kenyamananmu.\n- **Desain Phone Stand:** Memungkinkan kamu menonton sambil tetap sejuk.\n- **Aplikasi Luas:** Cocok untuk kegiatan luar ruangan, perjalanan, rumah, kantor, camping, pesta, dan lainnya.\n\n**Size Chart:**\n7.8cmx6cmx17.9cm\n\n**Paket Termasuk:**\n1 Turbo High Speed Portable Fan\n1 USB Cable\n1 Lanyar\n1 Phone Base\n1 Manual", + "price": 249000, + "stock": 19, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523133/hacktiv8/branded/milife-turbo-high-speed-fan-semiconductor-cooling-with-phone-stand-100-speed-4800mah-rechargeable-po-3xxaeehfb5m.jpg", + "categoryId": 7, + "userId": 1 + }, + { + "id": 117, + "name": "PURE Freesiae Pyrus Fragrance LIMITED EDITION for BloomAire", + "description": "**PURE Freesiae Pyrus Fragrance Oil - 100ml Bottle** \n\n**Notes:** Aroma pear dan melon memberikan wewangian manis dan segar, dibantu dengan bunga Fresia yang lembut dan bunga mawar romantis, menciptakan suasana mewah di ruangan Anda. \n\n**Ambience:** Floral, Soft, Powdery \n**Rooms:** Living Room, Study Room, Fashion Boutique \n\nGunakan PURE Fragrance Oil kami dengan diffuser yang Anda miliki! Cocok untuk BloomAire CROWN, CRUISE, dan TOWER. \nFragrance Oil kami adalah Cosmetic Grade perfume tanpa campuran, aman digunakan di rumah setiap hari. Diformulasikan khusus untuk BloomAire nano-tech pump agar dapat tersebar merata dan tahan lama! \nJika menggunakan Ultrasonic Diffuser dan Humidifier, teteskan 3-5 tetes saja dan pastikan air tidak habis.", + "price": 297000, + "stock": 72, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523135/hacktiv8/branded/pure-freesiae-pyrus-fragrance-limited-edition-for-bloomaire-mmawvegid3.jpg", + "categoryId": 5, + "userId": 1 + }, + { + "id": 118, + "name": "Rak botol essential oil & diffuser - Sparkle Brown", + "description": "Susun botol essential oils Anda dengan dudukan botol yang cantik dan unik dari kami. (up to 9 botol essential oils).\n\n**Material:** MDF diproses dengan mesin CNC\n**Warna:** Silver anodized & Gloss White\n**Ukuran:** 25x13x1.8cm\n\n**Catatan:** essential oils and diffuser are not included.\n\nCek dan tinjau produk kami di Instagram: [@propfactoryid](https://www.instagram.com/propfactoryid)", + "price": 149000, + "stock": 6, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523136/hacktiv8/branded/rak-botol-essential-oil-and-diffuser-sparkle-brown-u4wiim4d8r.jpg", + "categoryId": 7, + "userId": 1 + }, + { + "id": 119, + "name": "Sambal Sambel Geprek Monsera 140gr - level 5", + "description": "### Sambal Geprek Monsera\n\nSambal Geprek Monsera menawarkan citarasa khas Jawa Tengah dengan tekstur yang terjaga. Sambal ini memiliki rasa pedas yang khas dan sangat cocok sebagai pendamping lauk makanan sehari-hari. Diproduksi menggunakan mesin modern, sambal ini memiliki citarasa tinggi yang khas Indonesia dan dijamin higienis karena diambil langsung dari pertanian di Malang, dengan greenhouse seluas 10 hektar yang menjamin kualitasnya standar Eropa. Terbukti laku keras di Eropa dan Amerika.\n\n#### Cocok disajikan dengan:\n- Ayam krispi\n- Tahu dan tempe krispi\n- Daging sapi\n- Nugget\n- Terong goreng\n- Usus\n- Mie goreng\n- Telur dadar\n\n#### Cara Penyimpanan:\nUmur simpan sambal Monsera adalah 18 bulan selama kaleng belum dibuka. Jika sudah dibuka, umur simpan sambal ini adalah 3 hari pada suhu ruangan dan 1 bulan di dalam lemari es.\n\n#### Operasional Pengiriman:\n- Order sebelum jam 13.00 WIB akan dikirim di hari yang sama.\n- Order di atas jam 13.00 WIB akan dikirim keesokan harinya.\n- Pada hari Sabtu, Minggu, dan tanggal merah tidak ada pengiriman; akan dikirim keesokan harinya.\n\nMonsera sambal juga membuka kesempatan bagi reseller. Untuk informasi lebih lanjut tentang menjadi reseller, silakan hubungi admin kami melalui chat.\n\n#### Alasan untuk membeli Monsera Sambal:\n- Dibuat dengan bahan pilihan yang segar dan berkualitas.\n- Menggunakan minyak bunga matahari yang kaya manfaat.\n- Diproduksi menggunakan mesin dan dikemas dalam kondisi vakum yang higienis.\n- Tahan lama dan tidak menggunakan bahan pengawet.\n- Higienis dan terjamin kebersihannya.\n- Fresh langsung dari pertanian.\n- Memiliki greenhouse seluas 10 hektar untuk menjaga kualitas produk.\n- Kualitas ekspor yang sudah terbukti laku di Eropa dan Amerika.\n- Mengikuti standarisasi produksi Eropa.\n- Sambal dengan cita rasa internasional.", + "price": 28000, + "stock": 500, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523139/hacktiv8/branded/sambal-sambel-geprek-monsera-140gr-level-5-pps7e6x8qlf.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 127, + "name": "Philips TAUH202 Black Wireless On-Ear Headphones with Mic / TAUH 202", + "description": "## Philips TAUH202 Wireless On-Ear Headphones\n\n### Features:\n- **Drivers:** 32mm neodymium for crisp sound and punchy bass\n- **Playtime:** Enjoy **15 hours** of playtime, great for day or night use.\n- **Charging Time:** Fully charges in **2-3 hours**.\n- **Design:** Flat-fold design for easy storage in pockets or bags.\n- **Weight:** Lightweight at **195 g** for long-lasting comfort.\n- **Microphone:** Built-in mic with echo cancellation for clear audio.\n- **Controls:** Multi-function button for music and calls, easy track skipping and call management.\n- **Comfort:** Soft ear cups that can be angled for optimal comfort.\n\n### Technical Specifications:\n- **Acoustic System:** Closed\n- **Magnet Type:** NdFeB\n- **Frequency Response:** 20 - 20,000 Hz\n- **Impedance:** 32 Ohm\n- **Speaker Diameter:** 32mm\n- **Maximum Power Input:** 10mW\n- **Diaphragm:** PET\n- **Sensitivity:** 102dB\n- **Type:** Dynamic\n- **Bluetooth Profiles:** A2DP, AVRCP, HFP, HSP", + "price": 299000, + "stock": 18, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523151/hacktiv8/branded/philips-tauh202-black-wireless-on-ear-headphones-with-mic-tauh-202-w8cmievay3.jpg", + "categoryId": 1, + "userId": 1 + }, + { + "id": 120, + "name": "Reed Diffuser Classic 100ml by Le Havre - Osmanthus&Green", + "description": "### THE CLASSIC COLLECTION: REED DIFFUSER BY LE HAVRE\n\n- Volume: 100ml\n- Fiber sticks (8 pcs) - Use 4 sticks for small to medium rooms; for larger rooms or a stronger aroma, add more sticks or use multiple diffusers.\n\n**Aromas:**\n- Sakura & Pear: Floral, green, and fruity.\n- Apple & Fig: Fresh, fruity, and herbal.\n- Pine & Cedarwood: Fruity, herb, and woody.\n- Osmanthus & Green Tea: Green, citrus, and fresh.\n- White Jasmine & Freesia: Floral, green, and musky.\n- Eucalyptus & Rainwater: Herbal, fresh, and aqua.\n- Bulgarian Rose & Lychee: Sweet, floral, and woody.\n\nIf there are any damages or discrepancies with the package, please contact the seller via chat first.\n\n**Additional Greeting Card:** \nIf you want a greeting card, we provide a free plain card. During checkout, please include a note indicating you want the card. If you want a message written, include it there as well; do not mention it in the chat as the chat and shipping admin are different. The message on the card can be a maximum of 3-4 short sentences and should not contain emoticons, as these will not be printed.\n\n### SHIPPING:\n- Shipping is available Monday to Friday (no deliveries on weekends or holidays).\n- Orders will be shipped as soon as possible, sometimes even earlier than scheduled.\n- Please note that you cannot request a specific shipping date.\n\n**EXPRESS DELIVERY**:\n- For same-day delivery, if payment is made before 12 PM, the item will be shipped on the same day; orders after this time will be sent out in the next batch.\n- For instant delivery, if payment is made before 4 PM, it will also be shipped on the same day, with later payments going out in the following batch.", + "price": 228000, + "stock": 191, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523140/hacktiv8/branded/reed-diffuser-classic-100ml-by-le-havre-osmanthusandgreen-zi7cb58v6fd.jpg", + "categoryId": 5, + "userId": 1 + }, + { + "id": 121, + "name": "By NCC Sambal Cumi Pedas 160gr", + "description": "Hi Bun! Selamat datang di By NCC Official Shop!\n\n**Sambal Cumi By NCC** \nNetto: 160gr \nBPOM: MD 220971001300032 \nHalal: ID31110000433530722 \n\nSambal Cumi menghadirkan cita rasa pedas dengan sentuhan gurih dari cumi. Sambal ini adalah pilihan sempurna untuk pecinta makanan pedas.\n\n**Penyimpanan:** \n- Suhu freezer: -18°C hingga -23°C (tahan selama 18 bulan). \n- Suhu chiller: 1°C hingga 4°C (tahan selama 12 bulan). \n- Suhu ruang: 23°C hingga 27°C (tahan selama 6 bulan). \n\n**FAQ** \n1. **Bagaimana cara menyimpan Sambal By NCC setelah dibuka?** \n Disarankan untuk menyimpan Sambal By NCC di chiller setelah dibuka untuk mempertahankan kualitasnya.\n \n2. **Apakah Sambal By NCC mengandung bahan pengawet atau pewarna buatan?** \n Tidak, Sambal By NCC tidak mengandung bahan pengawet atau pewarna buatan. Kami menggunakan bahan-bahan alami untuk mempertahankan keaslian produk.\n \nIkuti dan kunjungi kami di: \n[@by.ncc](https://www.instagram.com/by.ncc) \n[by-ncc.com](http://by-ncc.com)", + "price": 49000, + "stock": 9859, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523141/hacktiv8/branded/by-ncc-sambal-cumi-pedas-160gr-sxh99k49l2.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 122, + "name": "Dahlia Heritage Series Reed Diffuser Refill Teh Keraton - 30 ML", + "description": "Dahlia Red Diffuser Teh Keraton memberikan sensasi kesegaran dan keharuman di setiap ruangan. Cara penggunaan: 1. Putar & buka tutup botol. 2. Lepaskan penyumbat botol. 3. Putar dan tutup kembali botol. 4. Masukkan 5 batang stik. 5. Letakkan reed diffuser di tempat yang diinginkan. \n\n**Perhatian:** Hindarkan dari panas api, jangkauan anak-anak, dan binatang peliharaan. \n\n**Pertolongan Pertama:** Jika terkena mata atau kulit, segera basuh dengan air mengalir. Jika iritasi berlanjut, hubungi dokter. \n\n**Variant:** Teh Keraton \n**Kode:** F610TK (30ml) \n**Shelf Life:** 36 bulan", + "price": 31000, + "stock": 127, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523142/hacktiv8/branded/dahlia-heritage-series-reed-diffuser-refill-teh-keraton-30-ml-8hfw2zkd1rh.jpg", + "categoryId": 5, + "userId": 1 + }, + { + "id": 123, + "name": "PRO PLAN Proplan Indoor Hairball Control Cat 3kg", + "description": "PRO PLAN indoor with OPTIRENAL is specifically formulated for the healthy maintenance of indoor cats. This unique formula includes all the essential nutrients, a natural prebiotic, and insoluble fiber to support a healthy digestive and intestinal system while helping to reduce litterbox odors.", + "price": 394684, + "stock": 5, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523144/hacktiv8/branded/pro-plan-proplan-indoor-hairball-control-cat-3kg-46yfubi5bhw.jpg", + "categoryId": 16, + "userId": 1 + }, + { + "id": 124, + "name": "Nuphy Halo 96 Wireless Hot-swappable Mechanical Keyboard - Ionic White, Rose Glacier", + "description": "- Garansi Resmi Nuphy Indonesia 1 Tahun\n- Barang Original Nuphy\n- Brand New In Box (BNIB)\n\nBisa langsung ambil di toko juga ya! Mampir langsung ke GeekyTech Offline Store\nJl. Pluit Karang Utara Raya No. 89, Penjaringan, Jakarta Utara 14450\nCS: 0819-9228-3947 (WA Only)\n\n### Varian:\n1. Ionic White (Red, Brown, Baby Kangaroo, Baby Raccoon, Rose Glacier, Night Breeze)\n2. Matte Black (Red, Brown, Baby Kangaroo, Baby Raccoon, Rose Glacier, Night Breeze)\n\n### Nuphy Halo 96 Wireless Mechanical Keyboard\n- ANSI 96% Layout\n- Aluminum Frame\n- Hot-Swap PCB\n- KOP PBT Keycaps\n- RGB Halolit\n- RGB Sidelit & Backlit\n- 2.4GHz Bluetooth & Wired\n- Nuphy Console Programmable\n- 4000mAh built-in battery\n- 18 extra keycaps\n- Compatible with Mac and Windows\n- Multitasking between up to 4 different devices\n- Multimedia keys for MacOS/Windows\n\n### Introducing GhostBar\nThe world's first noise suppression space keycap, a result of extensive engineering.\n\n### Technical Specifications\n- **Layout:** ANSI 96%\n- **Number of Keys:** 99 keys\n- **Hot-swappable support:** Yes\n- **N-key rollover support:** Yes\n- **Backlight & Sidelight:** RGB-LED\n- **Backlight modes:** 10\n- **Sidelight modes:** 4\n- **Halolight modes:** 4\n- **Mode:** 2.4G wireless, Bluetooth 5.0, or wired\n- **Connection type:** USB Type-C\n- **Compatible systems:** macOS/Windows/Android/iOS\n- **Angle:** 5.5º/8.5º/11º\n- **Operating environment:** -10 to 50℃\n\n### Power & Battery\n- **Battery Capacity:** 4000mAh\n- **Working time (all lights on):** 5–10 hours\n- **Working time (all lights off):** Up to 205 hours\n\n### Materials\n- **Frame:** Aluminum\n- **Bottom Case:** ABS\n- **Keycap:** Double-shot PBT\n\n### Dimensions\n- **Size:** 377 mm x 135 mm x 41 mm\n- **Weight:** 1500 grams\n\n### In The Box:\n- 1 x Halo96 wireless mechanical keyboard\n- 1 x USB-C to USB-A cable (1.5 m)\n- 1 x 2.4G receiver\n- 1 x Keycap/switch puller\n- 18 x Extra keycaps\n- 7 x Extra switches\n- 1 x Quick guide/poster\n- 1 x Stickers", + "price": 2499000, + "stock": 3, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523147/hacktiv8/branded/nuphy-halo-96-wireless-hot-swappable-mechanical-keyboard-ionic-white-rose-glacier-zv05gywof1e.jpg", + "categoryId": 1, + "userId": 1 + }, + { + "id": 125, + "name": "Citihome Bladeless Stand Cooling Fan Remote Kipas Angin Tanpa Baling - White Silver", + "description": "Garansi Toko 6 Bulan\n\nCitihome Bladeless Stand Cooling Fan Remote Kipas Angin Tanpa Baling\n\n**Product Features:**\n- Natural Wind, No Leaf Safety for kids, Energy Saving, Easy to Clean\n- Create a Healthy and Quality Life. Not only leafless, but also technology with 10 speed adjustment, Schedule timer, Brushless Motor, Low Noise.\n- Strong Cool breeze 500L of wind per second, Effectively circulating indoor airflow.\n- Non-impact, as soft as natural wind, comfortable and not harmful.\n- Air Conditioning Companion, quickly balance the indoor temperature, promote air circulation, and avoid air conditioning diseases.\n\n**How to Clean:**\nWipe with a dry/wet towel the outer body of the fan, it will be as clean as new.\n\n**Specifications:**\n- Model: TP-09\n- Height: 85 cm\n- Size Bladeless Fan: P15xL10xT52 cm\n- Diameter Base: 26 cm\n- Noise: <50 db\n- Motor: DC Brushless Motor\n- Voltage: 220V\n- Rated Frequency: 50Hz\n- Rated Power: 45W\n- Wind Supply Method: Sway\n- Pitch Angle: 360 degrees\n- Color: Black & White\n\n**Dear Customer:**\n- Barang sudah kami periksa dengan baik sebelum kami kirim, packing sudah termasuk dengan bubble wrap & plastik wrapping. Mohon dilengkapi dengan asuransi untuk barang pecah belah dan video unboxing saat penerimaan. Jika terjadi kerusakan saat pengiriman, bukan tanggung jawab penjual.\n- 100% Barang Impor. Produk Berkualitas Tinggi. HARGA GROSIR\n- Berat barang dihitung dalam volume/KG.\n\n**Alamat Showroom:**\nGoogle Map/Waze: Citihome Collection Store\nTikTok: Citihomegp\nIG: Citihome Collection", + "price": 1900000, + "stock": 40, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523149/hacktiv8/branded/citihome-bladeless-stand-cooling-fan-remote-kipas-angin-tanpa-baling-white-silver-qf5d6vwp7yb.jpg", + "categoryId": 7, + "userId": 1 + }, + { + "id": 126, + "name": "Pasir Kucing Gumpal Top 25L - Lavender, Tanpa Plastik", + "description": "Tersedia dalam 4 varian (moho pilih sesuai opsi varian/tulis di catatan):\n\n1. Apel\n2. Lemon\n3. Lavender\n4. Kopi\n\n**Catatan:** Kami hanya tempel nama di kemasan pasir. Bila ingin menggunakan plastik, mohon klik opsi \"Pakai Plastik\". Penggunaan plastik adalah tambahan plastik hitam supaya tidak kena hujan.", + "price": 107100, + "stock": 8, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523151/hacktiv8/branded/pasir-kucing-gumpal-top-25l-lavender-tanpa-plastik-ngvykmodrh.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 130, + "name": "SONY WF-C700N White Noise Cancelling Truly Wireless / WFC700N", + "description": "Hanya kamu dan musikmu. Blokir kebisingan latar belakang dengan Teknologi Sensor Kebisingan atau gunakan Mode Suara Ambient untuk tetap terhubung dengan lingkungan alami Anda. Sesuaikan suara ambient dengan aplikasi Sony | Headphones Connect untuk mengontrol pengalaman mendengarkan Anda.\n\nNikmati musik sepanjang hari. Anda dapat menikmati pengisian daya hingga 7.5 jam pada headphone Anda dan menyimpannya hingga 7.5 jam lagi dalam wadahnya sehingga total mendengarkan hingga 15 jam setiap kali Anda meninggalkan rumah. Pengisian cepat 3 menit akan memberi Anda waktu bermain hingga 60 menit.\n\nDirancang dengan kenyamanan sebagai prioritas. Headphone kecil dan ringan ini memiliki desain permukaan ergonomis untuk kenyamanan sepanjang hari.\n\nDengar setiap ketukan dengan kualitas tinggi. Digital Sound Enhancement Engine (DSEE) dan driver unik Sony mereproduksi musik Anda dengan vokal autentik dan bass yang kuat. Ubah musik Anda sesuai dengan selera Anda dengan pengaturan EQ di aplikasi Sony | Headphones Connect.\n\n### Fitur Umum\n- **Tipe Headphone**: Closed\n- **Driver Unit**: 5mm\n- **Kisaran Frekuensi (Bluetooth®)**: 20 Hz - 20,000 Hz (44.1 kHz sampling)\n- **Kontrol Volume**: Ya\n- **Tahan Air**: Ya (IPX4)\n- **DSEE**: Ya\n\n### Baterai\n- **Waktu Pengisian**: Approx. 1.5 hrs\n- **Metode Pengisian**: USB Charge (dengan case)\n- **Umur Baterai**: Max. 7.5 hrs (NC ON) / Max. 10 hrs (NC OFF)\n\n### Spesifikasi Bluetooth®\n- **Versi Bluetooth®**: 5.2\n- **Jarak Efektif**: 10 m\n\n### Isi Dalam Kotak\n- Charging Case\n- Hybrid silicone", + "price": 1429000, + "stock": 55, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523159/hacktiv8/branded/sony-wf-c700n-white-noise-cancelling-truly-wireless-wfc700n-d2omy0kiy6r.jpg", + "categoryId": 1, + "userId": 1 + }, + { + "id": 131, + "name": "FLIMEAL BY FLIMTY SUSU SEREAL PENGGANTI MAKANAN DIET PELANGSING - Strawberi", + "description": "FLIMEAL 12 SACHET BY FLIMTY PROMO SUSU SEREAL PENGGANTI MAKANAN DIET PELANGSING BPOM HALAL - KMCR NEXTLEVEL.\n\nFlimeal adalah minuman pengganti menu sarapan yang diformulasikan khusus untuk Anda yang sedang mempertahankan atau menurunkan berat badan. Mengandung bahan tinggi protein dan serat seperti kacang-kacangan, kedelai isolat, dan chia seed. Flimeal berfungsi sebagai minuman pengganti sarapan untuk memenuhi kebutuhan nutrisi dan energi harian tanpa meningkatkan berat badan.\n\n**PEMBELIAN:**\n- 2 BOX FLIMEAL + FREE 1 SHAKER\n- 4 BOX FLIMEAL + FREE 3 SHAKER\n*NB: selama Shaker masih ada*\n\n**Kandungan FLIMEAL:**\n- **Protein kedelai isolat:** Mengandung sekitar 40% protein, 20% minyak, 35% karbohidrat larut, serta lebih dari 90% protein dibanding susu sapi.\n- **Beras coklat:** Mengandung serat, GABA, asam amino, antioksidan, dan mineral lainnya.\n- **Chia seed:** Mengandung protein, lemak, karbohidrat, serat, dan asam lemak omega 3.\n- **Bubuk flaxseed oil:** Dapat menurunkan insulin dan meningkatkan kapasitas antioksidan.\n\n**CARA MINUM:**\nTuangkan 1 bungkus Flimeal ke dalam shaker, tambahkan 200ml air dingin, kocok hingga larut, dan segera sajikan. Konsumsi Flimeal 1 sachet sebagai pengganti makanan atau camilan saat lapar.", + "price": 217550, + "stock": 5, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523160/hacktiv8/branded/flimeal-by-flimty-susu-sereal-pengganti-makanan-diet-pelangsing-strawberi-luy61tyihk8.jpg", + "categoryId": 6, + "userId": 1 + }, + { + "id": 132, + "name": "Kraft Keju Cake Bolu Keju 16 gr [1 Box Isi 12 pcs]", + "description": "Kraft Keju Cake Bolu Keju 16 gr [1 Box Isi 12 pcs].\n\n**Isi paket:**\n1x Kraft Keju Cake Bolu Keju 16 gr [Box Isi 12 pcs].\n\nKraft Keju Cake Bolu Keju terbuat dari susu dan keju asli, menjadikannya lembut dan lezat, serta membuat Anda ketagihan. Keju bolu ini cocok disajikan sebagai snack untuk berbagai kesempatan. Nikmati kelembutan dan kelezatannya dalam setiap gigitan!", + "price": 24900, + "stock": 677, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523161/hacktiv8/branded/kraft-keju-cake-bolu-keju-16-gr-1-box-isi-12-pcs-p2fxf1ft29f.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 133, + "name": "MAKANAN KUCING BASAH Lifecat Life Cat Pouch/saset 85G - ADULT, CHICKEN TUNA", + "description": "Untuk varian yang mau dicampur, mohon tuliskan di catatan varian yang diinginkan, bukan di chat atau diskusi. Kami akan mengirimkan varian sesuai opsi yang dipilih atau yang ditulis di catatan.\n\nTersedia dalam beberapa varian antara lain:\n1. Kitten Tuna \n2. Kitten Chicken \n3. Kitten Salmon \n4. Adult Salmon \n5. Adult Chicken Tuna", + "price": 4692, + "stock": 2352, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523163/hacktiv8/branded/makanan-kucing-basah-lifecat-life-cat-pouchsaset-85g-adult-chicken-tuna-09s54op8fhs7.jpg", + "categoryId": 16, + "userId": 1 + }, + { + "id": 134, + "name": "Ikan Dori Fillet Lokal Grade A (1 KG)", + "description": "Selamat Datang Di YC Seafood\n\n**Catatan**: Tolong dibaca untuk note pengiriman, terima kasih! 😁\n\n### Layanan Pengiriman\n- **Instant**: GOJEK / GRAB (Pengiriman dalam 1-2 jam setelah serah terima paket ke kurir, bukan dari waktu pembeli order).\n- **Same Day**: GOJEK / GRAB / AnterAja (Pengiriman dalam 5-6 jam setelah serah terima, sampai di hari yang sama, bukan dari waktu pembeli order).\n\n### Info Penting\nPenjual diberikan waktu oleh Tokopedia 1x24 jam (minimum) untuk melakukan pengiriman ke pembeli.\n\n**Detail Produk**:\n- Ikan Dori Fillet isi 3-4 Pcs\n- Glazing 40% - 50% \n- Product IQF\n\nUntuk respons cepat, silahkan hubungi WA: 087725111621.\n\nYC Seafood menyediakan berbagai makanan laut seperti udang, cumi, dan ikan. Silahkan kontak admin untuk informasi lebih lanjut.", + "price": 35000, + "stock": 11848, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523164/hacktiv8/branded/ikan-dori-fillet-lokal-grade-a-%281-kg%29-wcz0qo10vxi.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 135, + "name": "ANTBOX Lemari Pakaian Plastik 12 Kabinet 2 Hanger Putih Minimalis", + "description": "🌈Selamat datang di ANTBOX Official Store.\n\nANTBOX menyediakan berbagai produk home furnishing secara global. Antbox menjadi solusi cerdas untuk Anda yang menginginkan furniture yang mudah dipasang dan berkualitas tinggi. Antbox menghadirkan teknologi \"Quickfold Free Decomposition\" yang menciptakan kabinet terpadu tanpa perlu perakitan dan dapat dipasang sendiri.\n\n### Detail Produk Lemari Pakaian ANTBOX\n- **Merek:** ANTBOX\n- **Material:** Plastik PP (Kabinet), PET (Pintu), ABS, Magnet\n- **Warna:** Transparan\n- **Ukuran dan Berat Produk:** 12 BOX 2 HANGER: Berat Bersih: 17,67 kg; Ukuran: 104 * 50 * 136 cm\n\n### Kenapa Harus Membeli Rak Sepatu ANTBOX?\n⭐ Instalasi kurang dari 5 menit, menghemat waktu. \n⭐ Bahan kokoh, mampu menampung beban lebih dari 50 kg. \n⭐ Pintu dilengkapi magnet untuk keamanan. \n⭐ Terbuat dari bahan yang aman, anti rayap, tidak beracun, tidak berbau, bebas formaldehida. \n⭐ Pilihan ukuran beragam sesuai kebutuhan.\n\n### Catatan:\n✨ Waktu Pengiriman: Pesanan sebelum jam 4 sore akan diproses pada hari yang sama, setelah jam 4 akan diproses keesokan harinya. \n✨ Komplain wajib sertakan video unboxing. \n✨ Jika ada pertanyaan, silakan tanyakan pada admin kami.", + "price": 1869000, + "stock": 138, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523165/hacktiv8/branded/antbox-lemari-pakaian-plastik-12-kabinet-2-hanger-putih-minimalis-wq1ne7vh44d.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 136, + "name": "KACANG HITAM 1 KG BLACK BEAN 1KG IMPORT IMPOR", + "description": "Kacang Hitam Import / Black Bean with Green Kernel.\n\n- Berat Bersih: 1 Kg\n- HALAL!\n- Packing dilakukan dalam kondisi higienis dan bersih.\n- Penyimpanan dalam kondisi kering dan dingin tanpa sinar matahari.\n\nKacang ini mengandung vitamin dan mineral penting seperti asam folat, magnesium, kalium, zat besi, dan zinc, serta protein dan serat. Kacang hitam adalah alternatif sehat untuk protein dengan jumlah lemak yang sedikit. Dalam 172 g kacang hitam terdapat:\n- Energi: 227 kkal\n- Karbohidrat: 41 g\n- Protein: 15 g\n- Lemak: 1 g\n- Serat: 15 g\n\nKacang hitam kaya akan antioksidan; penelitian menunjukkan kandungan antioksidan kacang hitam paling tinggi dibandingkan dengan 11 jenis kacang lain.\n\nKacang hitam yang tinggi antioksidan dapat melindungi tubuh dari radikal bebas, mengurangi risiko penyakit kronis seperti kanker, jantung, Alzheimer, dan diabetes. Selain itu, kandungan flavonoid dalam kacang hitam baik untuk kecantikan, dapat mencegah tanda-tanda penuaan dini akibat paparan sinar matahari.\n\nKacang hitam dapat dicampur dalam berbagai olahan masakan seperti sup, salad, atau pasta, dan juga bisa dijadikan camilan sehat karena kandungan indeks glikemik (IG) yang rendah.\n\nKami melayani jumlah besar. Harga nego. Chat/WA 0813 8427 5267.", + "price": 55000, + "stock": 175, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523166/hacktiv8/branded/kacang-hitam-1-kg-black-bean-1kg-import-impor-czyspdexldi.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 137, + "name": "ANTBOX Lemari Pakaian Putih 10 BOX 1 HANGER Lemari Baju Minimalis", + "description": "🌈 Selamat datang di ANTBOX Official Store.\n\nANTBOX menyediakan produk home furnishing secara global dan hadir sebagai solusi cerdas bagi Anda yang menginginkan furniture yang mudah dipasang dan berkualitas tinggi. Dengan teknologi \"Quickfold Free Decomposition\", kabinet ini bebas perakitan dan dapat dipasang sendiri.\n\n### Detail Produk Lemari Pakaian ANTBOX\n- **Merek:** ANTBOX\n- **Material:** Plastik PP (Kabinet), PET (Pintu), ABS, Magnet\n- **Warna:** Transparan\n- **Ukuran dan Berat Produk:**\n - 10 BOX 1 HANGER: Berat Bersih: 15,12 kg; Ukuran: 69 * 50 * 170 cm\n\n### Kenapa Harus Membeli Rak Sepatu ANTBOX?\n- Lemari Pakaian ANTBOX bisa diinstal kurang dari 5 menit, menghemat waktu Anda.\n- Bahan kokoh bisa menampung beban lebih dari 50 kg.\n- Pintu dilengkapi magnet untuk keamanan.\n- Terbuat dari bahan yang aman, anti rayap, tidak beracun, tidak berbau, dan bebas formaldehida.\n- Memiliki banyak pilihan ukuran sesuai kebutuhan.\n\n### Notes:\n- **Waktu Pengiriman:** Pesanan sebelum jam 4 sore diproses pada hari yang sama, setelah jam 4 akan diproses pada hari berikutnya.\n- **KOMPLAIN:** Wajib sertakan video unboxing.\n- **Pertanyaan:** Silakan tanyakan kepada admin kami.", + "price": 1638000, + "stock": 6, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523167/hacktiv8/branded/antbox-lemari-pakaian-putih-10-box-1-hanger-lemari-baju-minimalis-4migpn8fcat.jpg", + "categoryId": 2, + "userId": 1 + }, + { + "id": 138, + "name": "Herslim dari herwell susu diet", + "description": "Selalu ready, tidak perlu tanya stok, bisa langsung order. Official Store.\n\nHarga untuk 1 botol Herslim (isi 20 sachet) rasa Coklat. Rendah Lemak dan Rendah Kalori hanya 120kkal.\n\nPembelian minimal 2 paket FREE Shaker Herwell (boleh mix Hervibe Herlean Herslim) ✅\n\nBerhenti siksa tubuhmu dengan cara yang tidak sehat. Herwell paham kalau kamu butuh asupan nutrisi yang cukup saat diet tanpa merusak plan diet kamu. Herslim adalah suplemen tinggi nutrisi yang bisa membantu program diet dengan memberikan efek kenyang lebih lama.\n\n**Kandungan Superfood Herslim:**\n1. Multigrains ~ Gabungan 10 jenis biji-bijian sebagai sumber nutrisi yang paling dibutuhkan oleh tubuh sehingga mampu menghasilkan energi.\n2. Susu Kolostrum ~ Susu pertama dari induk sapi setelah melahirkan yang mengandung Immunoglobulin-G untuk meningkatkan imunitas tubuh.\n3. L-Carnitine ~ Asam amino yang fungsi utamanya membantu mengubah lemak dalam tubuh menjadi sumber energi.\n4. Casein ~ Sumber protein lambat serap yang membuat tubuh kenyang lebih lama.\n\n**Manfaat Herslim:**\n* Mencukupi nutrisi harian saat program weight loss.\n* Membuat tubuh awet kenyang.\n* Meningkatkan imunitas tubuh.\n* Membantu program maintain body goal.\n* Membantu mengubah lemak menjadi energi.\n\n**Cara Minum Herslim:**\n* Minum 2x sehari sebelum makan pagi dan makan malam.\n* Ambil 1 sachet dan campurkan ke dalam 200 ml air hangat.\n\nProduk HERSLIM sudah lolos BPOM, HALAL, HACCP, GMP, ISO.", + "price": 290000, + "stock": 9884, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523168/hacktiv8/branded/herslim-dari-herwell-susu-diet-hl0cotsagl.jpg", + "categoryId": 6, + "userId": 1 + }, + { + "id": 139, + "name": "Sepatu Basket NIKE LEBRON WITNESS VII EP DM1122500 ORI - 42.5", + "description": "Brand New In Box - Fullset\nOriginal Guarantee 100%\n\n**Size**\n(Tertera di variant product)\n\nUntuk menjaga agar dus sepatumu tetap aman, silahkan gunakan Additional Double Box dari Sneakersdept. Cuman 10rb!\n\nIt's totally worth to buy, so what are you waiting for? Contact us!\n\n**Customer Service:**\nSenin - Minggu: 09.00-18.00 WIB\n\n**Note:**\nApabila terjadi kerusakan pada produk yang diorder, silahkan chat ke customer service kami dengan melampirkan bukti video unboxing. Tim kami dengan senang hati akan membantu setiap prosesnya :)", + "price": 1099000, + "stock": 4, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523169/hacktiv8/branded/sepatu-basket-nike-lebron-witness-vii-ep-dm1122500-ori-42.5-bd4ynpr4zgq.jpg", + "categoryId": 4, + "userId": 1 + }, + { + "id": 140, + "name": "Kraft Keju Cake Bolu Keju 16 gr [1 Box Isi 12 pcs]", + "description": "Kraft Keju Cake Bolu Keju 16 gr [1 Box Isi 12 pcs] \n \n**Isi paket:** \n1x Kraft Keju Cake Bolu Keju 16 gr [Box Isi 12 pcs] \n \nKraft Keju Cake Bolu dibuat dengan kebaikan susu dan keju asli. Keju Cake ini sangat lembut dan lezat, membuat Anda ketagihan. \n \nKeju bolu ini cocok disajikan sebagai snack untuk berbagai kesempatan. Nikmati kelembutan dan kelezatannya dalam setiap gigitan!", + "price": 24900, + "stock": 677, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523170/hacktiv8/branded/kraft-keju-cake-bolu-keju-16-gr-1-box-isi-12-pcs-kzgotrud09.jpg", + "categoryId": 20, + "userId": 1 + }, + { + "id": 141, + "name": "MAKANAN KUCING BASAH Lifecat Life Cat Pouch 85G - ADULT, CHICKEN TUNA", + "description": "Untuk varian yang mau dicampur, mohon tuliskan di catatan varian yang diinginkan, bukan di chat atau diskusi. Kami akan mengiriskan varian sesuai opsi yang dipilih. Tersedia dalam beberapa varian: \n1. Kitten Tuna \n2. Kitten Chicken \n3. Kitten Salmon \n4. Adult Salmon \n5. Adult Chicken Tuna", + "price": 4692, + "stock": 2352, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523171/hacktiv8/branded/makanan-kucing-basah-lifecat-life-cat-pouch-85g-adult-chicken-tuna-0ie8n6wtegeo.jpg", + "categoryId": 16, + "userId": 1 + }, + { + "id": 142, + "name": "Sepatu Basket ADIDAS ADIZERO SELECT IG5336 ORIGINAL - 40.5", + "description": "Brand New In Box - Fullset\nOriginal Guarantee 100%\n\n**Size:**\n(Tertera di variant product)\n\nUntuk menjaga agar dus sepatumu tetap aman, silahkan gunakan Additional Double Box dari Sneakersdept. Hanya 10rb!\n\nIt's totally worth to buy,\nso what are you waiting for? Contact us!\n\n**Customer Service:**\nSenin - Minggu: 09.00-18.00 WIB\n\n**Note:**\nApabila terjadi kerusakan pada produk yang dipesan, silahkan chat ke customer service kami dengan melampirkan bukti video unboxing. Tim kami dengan senang hati akan membantu setiap prosesnya :)", + "price": 1299000, + "stock": 1, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523174/hacktiv8/branded/sepatu-basket-adidas-adizero-select-ig5336-original-40.5-7oiy4qbhf4b.jpg", + "categoryId": 4, + "userId": 1 + }, + { + "id": 144, + "name": "Sepatu Basket CURRY 11 FUTURE 3027416100 ORIGINAL - 46", + "description": "Brand New In Box - Fullset\nOriginal Guarantee 100%\n\nSize (Tertera di variant product)\n\nUntuk menjaga agar dus sepatumu tetap aman, silahkan gunakan Additional Double Box dari Sneakersdept. Cuman 10rb!\n\nIt's totally worth to buy, so what are you waiting for? Contact us!\n\nCustomer Service : Senin - Minggu : 09.00-18.00 WIB\n\nNote : Apabila terjadi kerusakan pada produk yang diorder, silahkan chat ke customer service kami dengan melampirkan bukti video unboxing. Tim kami dengan senang hati akan membantu setiap prosesnya :)", + "price": 1849000, + "stock": 1, + "imgUrl": "https://res.cloudinary.com/dpjqm8kkk/image/upload/v1723523176/hacktiv8/branded/sepatu-basket-curry-11-future-3027416100-original-46-lw0nzc2vgr.jpg", + "categoryId": 4, + "userId": 1 + + } + ] + diff --git a/BACKEND/data/users.json b/BACKEND/data/users.json new file mode 100644 index 00000000..1b2e58bb --- /dev/null +++ b/BACKEND/data/users.json @@ -0,0 +1,20 @@ +[ + { + "id": 1, + "username": "admin", + "email": "admin@example.com", + "phoneNumber": "081234567890", + "password": "admin123", + "address": "Jl. Merdeka No. 123, Jakarta", + "role": "admin" + }, + { + "id": 2, + "username": "user", + "email": "user@example.com", + "phoneNumber": "081298765432", + "password": "user123", + "address": "Jl. Sudirman No. 456, Bandung", + "role": "user" + } +] diff --git a/BACKEND/helpers/bcrypt.js b/BACKEND/helpers/bcrypt.js new file mode 100644 index 00000000..5a5000bf --- /dev/null +++ b/BACKEND/helpers/bcrypt.js @@ -0,0 +1,14 @@ +const bcrypt = require("bcryptjs"); + + +const hashPassword = (password) => { + const salt = bcrypt.genSaltSync(10); + return bcrypt.hashSync(password, salt); +}; + + +const comparePassword = (password, hashedPassword) => { + return bcrypt.compareSync(password, hashedPassword); +}; + +module.exports = { hashPassword, comparePassword }; diff --git a/BACKEND/helpers/jwt.js b/BACKEND/helpers/jwt.js new file mode 100644 index 00000000..ff1c0ca0 --- /dev/null +++ b/BACKEND/helpers/jwt.js @@ -0,0 +1,15 @@ +const jwt = require("jsonwebtoken"); + +const SECRET = process.env.SECRET_KEY || "SHHHHH"; + + +const signToken = (payload) => { + return jwt.sign(payload, SECRET); +}; + + +const verifyToken = (token) => { + return jwt.verify(token, SECRET); +}; + +module.exports = { signToken, verifyToken }; diff --git a/BACKEND/middlewares/authentication.js b/BACKEND/middlewares/authentication.js new file mode 100644 index 00000000..a736c27b --- /dev/null +++ b/BACKEND/middlewares/authentication.js @@ -0,0 +1,30 @@ +const { User } = require("../models"); +const { verifyToken } = require("../helpers/jwt"); + +const authentication = async (req, res, next) => { + try { + const bearerToken = req.headers.authorization; + if (!bearerToken) { + throw { name: "UnauthorizedError", message: "Unauthorized access" }; + } + const accessToken = bearerToken.split(" ")[1]; + if (!accessToken) { + throw { name: "UnauthorizedError", message: "Unauthorized access" }; + } + const data = verifyToken(accessToken); + const user = await User.findByPk(data.id); + if (!user) { + throw { name: "UnauthorizedError", message: "Unauthorized access" }; + } + + req.user = { + id: user.id, + email: user.email, + }; + next(); + } catch (error) { + next(error); + } +}; + +module.exports = authentication; diff --git a/BACKEND/middlewares/authorization.js b/BACKEND/middlewares/authorization.js new file mode 100644 index 00000000..059f30a3 --- /dev/null +++ b/BACKEND/middlewares/authorization.js @@ -0,0 +1,17 @@ +const { User } = require("../models"); + +const authorizationAdmin = async (req, res, next) => { + try { + const user = await User.findByPk(req.user.id); + if (!user || user.role !== "admin") { + throw { name: "ForbiddenError", message: "Admin access required" }; + } + next(); + } catch (error) { + next(error); + console.log(error,"<< e.message).join(", "); + } else if (error.name === "ValidationError") { + status = 400; + message = error.message; + } else if (error.name === "BadRequest" || error.name === "BadRequestError") { + status = 400; + message = error.message; + } else if ( + error.name === "NotFound" || + error.name === "NotFoundError" || + (!error.name && error.message.includes("not found")) + ) { + status = 404; + message = error.message; + } else if (error.name === "Forbidden" || error.name === "ForbiddenError") { + status = 403; + message = error.message || "Admin access required"; + } else if ( + error.name === "Unauthorized" || + error.name === "UnauthorizedError" || + error.name === "JsonWebTokenError" || + error.name === "TokenExpiredError" + ) { + status = 401; + message = error.message || "Unauthorized access"; + } + + res.status(status).json({ message }); +} + +module.exports = errorHandler; diff --git a/BACKEND/migrations/20250429082453-create-user.js b/BACKEND/migrations/20250429082453-create-user.js new file mode 100644 index 00000000..529b2eee --- /dev/null +++ b/BACKEND/migrations/20250429082453-create-user.js @@ -0,0 +1,51 @@ +"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, + allowNull: false, + }, + email: { + type: Sequelize.STRING, + allowNull: false, + unique: true, + }, + phoneNumber: { + type: Sequelize.STRING, + allowNull: false, + }, + password: { + type: Sequelize.STRING, + allowNull: false, + }, + address: { + type: Sequelize.STRING, + allowNull: false, + }, + role: { + type: Sequelize.STRING, + allowNull: false, + defaultValue: "user", + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE, + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE, + }, + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable("Users"); + }, +}; diff --git a/BACKEND/migrations/20250429082548-create-category.js b/BACKEND/migrations/20250429082548-create-category.js new file mode 100644 index 00000000..f20ff440 --- /dev/null +++ b/BACKEND/migrations/20250429082548-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/BACKEND/migrations/20250429220809-create-product.js b/BACKEND/migrations/20250429220809-create-product.js new file mode 100644 index 00000000..41f18fac --- /dev/null +++ b/BACKEND/migrations/20250429220809-create-product.js @@ -0,0 +1,60 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable("Products", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + name: { + type: Sequelize.STRING, + }, + description: { + type: Sequelize.TEXT, + }, + price: { + type: Sequelize.INTEGER, + }, + stock: { + type: Sequelize.INTEGER, + }, + imgUrl: { + type: Sequelize.STRING, + }, + categoryId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: "Categories", + key: "id", + }, + onUpdate: "cascade", + onDelete: "cascade", + }, + userId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: "Users", + key: "id", + }, + onUpdate: "cascade", + onDelete: "cascade", + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE, + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE, + }, + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('Products'); + } +}; \ No newline at end of file diff --git a/BACKEND/migrations/20250429221822-create-cart.js b/BACKEND/migrations/20250429221822-create-cart.js new file mode 100644 index 00000000..9fdc2979 --- /dev/null +++ b/BACKEND/migrations/20250429221822-create-cart.js @@ -0,0 +1,48 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable("Carts", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER, + }, + userId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: "Users", + key: "id", + }, + onUpdate: "cascade", + onDelete: "cascade", + }, + productId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: "Products", + key: "id", + }, + onUpdate: "cascade", + onDelete: "cascade", + }, + quantity: { + type: Sequelize.INTEGER, + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE, + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE, + }, + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('Carts'); + } +}; \ No newline at end of file diff --git a/BACKEND/models/cart.js b/BACKEND/models/cart.js new file mode 100644 index 00000000..23f5f1dc --- /dev/null +++ b/BACKEND/models/cart.js @@ -0,0 +1,41 @@ +"use strict"; +const { Model } = require("sequelize"); +module.exports = (sequelize, DataTypes) => { + class Cart extends Model { + static associate(models) { + Cart.belongsTo(models.User, { foreignKey: "userId" }); + Cart.belongsTo(models.Product, { foreignKey: "productId" }); + } + } + Cart.init( + { + userId: { + type: DataTypes.INTEGER, + allowNull: false, + validate: { + notNull: { msg: "User ID is required" }, + }, + }, + productId: { + type: DataTypes.INTEGER, + allowNull: false, + validate: { + notNull: { msg: "Product ID is required" }, + }, + }, + quantity: { + type: DataTypes.INTEGER, + allowNull: false, + validate: { + notNull: { msg: "Quantity is required" }, + min: { args: 1, msg: "Quantity must be greater than 0" }, + }, + }, + }, + { + sequelize, + modelName: "Cart", + } + ); + return Cart; +}; diff --git a/BACKEND/models/category.js b/BACKEND/models/category.js new file mode 100644 index 00000000..af423330 --- /dev/null +++ b/BACKEND/models/category.js @@ -0,0 +1,26 @@ +"use strict"; +const { Model } = require("sequelize"); +module.exports = (sequelize, DataTypes) => { + class Category extends Model { + static associate(models) { + Category.hasMany(models.Product, { foreignKey: "categoryId" }); + } + } + Category.init( + { + name: { + type: DataTypes.STRING, + allowNull: false, + validate: { + notNull: { msg: "Category name is required" }, + notEmpty: { msg: "Category name cannot be empty" }, + }, + }, + }, + { + sequelize, + modelName: "Category", + } + ); + return Category; +}; diff --git a/BACKEND/models/index.js b/BACKEND/models/index.js new file mode 100644 index 00000000..0b8e58dc --- /dev/null +++ b/BACKEND/models/index.js @@ -0,0 +1,50 @@ +"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/BACKEND/models/product.js b/BACKEND/models/product.js new file mode 100644 index 00000000..e587bc68 --- /dev/null +++ b/BACKEND/models/product.js @@ -0,0 +1,73 @@ +"use strict"; +const { Model } = require("sequelize"); +module.exports = (sequelize, DataTypes) => { + class Product extends Model { + static associate(models) { + Product.belongsTo(models.Category, { foreignKey: "categoryId" }); + Product.belongsTo(models.User, { foreignKey: "userId" }); + Product.hasMany(models.Cart, { foreignKey: "productId" }); + } + } + Product.init( + { + name: { + type: DataTypes.STRING, + allowNull: false, + validate: { + notNull: { msg: "Name is required" }, + notEmpty: { msg: "Name cannot be empty" }, + }, + }, + description: { + type: DataTypes.TEXT, + allowNull: false, + validate: { + notNull: { msg: "Description is required" }, + notEmpty: { msg: "Description cannot be empty" }, + }, + }, + price: { + type: DataTypes.INTEGER, + allowNull: false, + validate: { + notNull: { msg: "Price is required" }, + }, + }, + stock: { + type: DataTypes.INTEGER, + allowNull: false, + validate: { + notNull: { msg: "Stock is required" }, + + }, + }, + imgUrl: { + type: DataTypes.STRING, + allowNull: false, + validate: { + notNull: { msg: "Image URL is required" }, + notEmpty: { msg: "Image URL cannot be empty" }, + }, + }, + categoryId: { + type: DataTypes.INTEGER, + allowNull: false, + validate: { + notNull: { msg: "Category ID is required" }, + }, + }, + userId: { + type: DataTypes.INTEGER, + allowNull: false, + validate: { + notNull: { msg: "User ID is required" }, + }, + }, + }, + { + sequelize, + modelName: "Product", + } + ); + return Product; +}; diff --git a/BACKEND/models/user.js b/BACKEND/models/user.js new file mode 100644 index 00000000..b6576320 --- /dev/null +++ b/BACKEND/models/user.js @@ -0,0 +1,81 @@ +"use strict"; +const { Model } = require("sequelize"); +const { hashPassword } = require("../helpers/bcrypt"); +module.exports = (sequelize, DataTypes) => { + class User extends Model { + static associate(models) { + User.hasMany(models.Product, { foreignKey: "userId" }); + User.hasMany(models.Cart, { foreignKey: "userId" }); + } + } + User.init( + { + username: { + type: DataTypes.STRING, + allowNull: false, + unique: { args: true, msg: "Username already exists" }, + validate: { + notNull: { msg: "Username is required!" }, + notEmpty: { msg: "Username cannot be empty" }, + }, + }, + email: { + type: DataTypes.STRING, + allowNull: false, + unique: { args: true, msg: "Email already exists" }, + validate: { + notNull: { msg: "Email is required!" }, + notEmpty: { msg: "Email cannot be empty" }, + isEmail: { msg: "Invalid email format" }, + }, + }, + phoneNumber: { + type: DataTypes.STRING, + allowNull: false, + validate: { + notNull: { msg: "Phone number is required!" }, + notEmpty: { msg: "Phone number cannot be empty" }, + len: { + args: [8], + msg: "Phone number must be at least 8 characters long", + }, + isNumeric: { msg: "Phone number must be a number" }, + }, + }, + password: { + type: DataTypes.STRING, + allowNull: false, + validate: { + notNull: { msg: "Password is required!" }, + notEmpty: { msg: "Password cannot be empty" }, + len: { + args: [6], + msg: "Password must be at least 6 characters long", + }, + }, + }, + address: { + type: DataTypes.STRING, + allowNull: false, + validate: { + notNull: { msg: "Address is required!" }, + notEmpty: { msg: "Address cannot be empty" }, + }, + }, + role: { + type: DataTypes.STRING, + allowNull: false, + defaultValue: "user", + }, + }, + { + sequelize, + modelName: "User", + } + ); + + User.beforeCreate((user) => { + user.password = hashPassword(user.password); + }); + return User; +}; diff --git a/BACKEND/note.js b/BACKEND/note.js new file mode 100644 index 00000000..d2a683f1 --- /dev/null +++ b/BACKEND/note.js @@ -0,0 +1,107 @@ +const { Cart, Product } = require("../models"); + +module.exports = class CartController { + static async postCart(req, res, next) { + try { + const { productId, quantity } = req.body; + const userId = req.user.id; + const products = await Product.findByPk(productId); + + if (!products) { + throw { message: "Product not found" }; + } + if (products.stock < quantity) { + throw { message: "plese insert stock" }; + } + + let cartItem = await Cart.findOne({ + where: { userId, productId }, + }); + + if (cartItem) { + cartItem.quantity += quantity; + await cartItem.save(); + } else { + cartItem = await Cart.create({ + userId, + productId, + quantity, + }); + } + + res.status(201).json({ message: "Item added to cart" }); + } catch (error) { + next(error); + } + } + + static async getCart(req, res, next) { + try { + const userId = req.user.id; + const cartItems = await Cart.findAll({ + where: { userId }, + include: [ + { + model: Product, + attributes: ["id", "name", "price", "imgUrl", "stock"], + }, + ], + }); + + res.status(200).json(cartItems); + } catch (error) { + next(error); + } + } + + static async updateCartItem(req, res, next) { + try { + const id = req.params.id; + if (!req.body.productId) { + throw { name: "ValidationError", message: "product is required!" }; + } + if (!req.body.quantity) { + throw { name: "ValidationError", message: "quantity is required!" }; + } + const carts = await Cart.findByPk(id); + if (!carts) { + throw { message: `Cart id:${id} not found` }; + } + if (!req.user.id === 4) { + throw { name: "ForbiddenError" }; + } + await carts.update(req.body); + res.status(200).json({ message: `Cart item id:${id} updated` }); + } catch (error) { + console.log(error, "ERROR"); + + next(error); + } + } + + static async deleteCartItem(req, res, next) { + try { + const id = req.params.id; + const userId = req.user.id; + + if (isNaN(id)) { + throw { message: "Invalid cart item ID" }; + } + + const cartItem = await Cart.findOne({ + where: { id, userId }, + }); + + if (!cartItem) { + throw { + message: `Cart item id:${id} not found`, + }; + } + + await cartItem.destroy(); + res.status(200).json({ message: `Cart item id:${id} deleted` }); + } catch (error) { + next(error); + } + } +}; diff --git a/BACKEND/package-lock.json b/BACKEND/package-lock.json new file mode 100644 index 00000000..5044732b --- /dev/null +++ b/BACKEND/package-lock.json @@ -0,0 +1,6837 @@ +{ + "name": "backend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "backend", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "bcryptjs": "^3.0.2", + "cors": "^2.8.5", + "express": "^5.1.0", + "google-auth-library": "^9.15.1", + "jsonwebtoken": "^9.0.2", + "node-fetch": "^3.3.2", + "nodemon": "^3.1.10", + "pg": "^8.15.6", + "sequelize": "^6.37.7", + "supertest": "^7.1.0" + }, + "devDependencies": { + "dotenv": "^16.5.0", + "jest": "^29.7.0", + "sequelize-cli": "^6.6.2" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", + "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", + "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.10", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.10", + "@babel/parser": "^7.26.10", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.10", + "@babel/types": "^7.26.10", + "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/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/@babel/generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", + "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.0", + "@babel/types": "^7.27.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz", + "integrity": "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.26.8", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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": { + "yallist": "^3.0.2" + } + }, + "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-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz", + "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.0", + "@babel/types": "^7.27.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", + "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.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-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "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.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "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.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", + "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.27.0", + "@babel/types": "^7.27.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", + "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.27.0", + "@babel/parser": "^7.27.0", + "@babel/template": "^7.27.0", + "@babel/types": "^7.27.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", + "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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/@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/@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": ">=8" + } + }, + "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": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/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/@jest/core/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/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/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/@jest/reporters/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@jest/reporters/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/@jest/reporters/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/@jest/reporters/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/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "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==", + "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==", + "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/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "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": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.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.20.7", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", + "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "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/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "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/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": "22.15.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.3.tgz", + "integrity": "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.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.0", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.0.tgz", + "integrity": "sha512-nh7nrWhLr6CBq9ldtw0wx+z9wKnnv/uTVLA9g/3/TcOYxbpOSZE+MhKPmWqU+K0NvThjhv12uD8MuqijB0WzEA==", + "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/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.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "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.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "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==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "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==", + "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==", + "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": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/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-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", + "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", + "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" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.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==", + "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/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.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz", + "integrity": "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==", + "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==", + "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": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.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==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "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": { + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" + }, + "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==", + "dev": true, + "license": "MIT" + }, + "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.30001715", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001715.tgz", + "integrity": "sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==", + "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==", + "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": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-color": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.4.tgz", + "integrity": "sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.64", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.15", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.10" + } + }, + "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/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==", + "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==", + "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==", + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "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/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.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==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/d": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "dev": true, + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", + "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==", + "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==", + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", + "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "dev": true, + "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/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.145", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.145.tgz", + "integrity": "sha512-pZ5EcTWRq/055MvSBgoFEyKf2i4apwfoqJbK/ak2jnFq8oHjZ+vzc3AhRcz37Xn+ZJfL58R666FLJx0YOK9yTw==", + "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/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "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==", + "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/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "dev": true, + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "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/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "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/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "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": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.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/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } + }, + "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==", + "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==", + "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.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "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==", + "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==", + "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==", + "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==", + "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": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gaxios/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/gaxios/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "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==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/google-auth-library": { + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", + "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-auth-library/node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "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": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", + "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": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "license": "MIT", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/gtoken/node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "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==", + "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==", + "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/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/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": "Apache-2.0", + "engines": { + "node": ">=10.17.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==", + "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==", + "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": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "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/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==", + "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==", + "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-generator-fn": { + "version": "2.1.0", + "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==", + "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==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true, + "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==", + "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": ">=8" + } + }, + "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": "BSD-3-Clause", + "dependencies": { + "@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": ">=10" + } + }, + "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": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "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": ">=8" + } + }, + "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": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "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==", + "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/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "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", + "engines": { + "node": ">=8" + } + }, + "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": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "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" + }, + "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": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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": { + "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/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": { + "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/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": ">=12" + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jest-config/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/jest-config/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/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jest-runtime/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/jest-runtime/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/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/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/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": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "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/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", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "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.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "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.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "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/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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", + "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/lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es5-ext": "~0.10.2" + } + }, + "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", + "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/memoizee": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", + "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "es5-ext": "^0.10.64", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.12" + } + }, + "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/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==", + "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==", + "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", + "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/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": "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/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/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/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", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true, + "license": "ISC" + }, + "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": ">=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==", + "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/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.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nodemon": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", + "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "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/nodemon/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nodemon/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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==", + "license": "MIT", + "engines": { + "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/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/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", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "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", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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", + "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.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/pg": { + "version": "8.15.6", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.15.6.tgz", + "integrity": "sha512-yvao7YI3GdmmrslNVsZgx9PfntfWrnXwtR+K/DjI0I/sTKif4Z623um+sjVZ1hk5670B+ODjvHDAckKdjmPTsg==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.8.5", + "pg-pool": "^3.9.6", + "pg-protocol": "^1.9.5", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.2.5" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.5.tgz", + "integrity": "sha512-OOX22Vt0vOSRrdoUPKJ8Wi2OpE/o/h9T8X1s4qSkCedbNah9ei2W2765be8iMVxQUsvgT7zIAT2eIa9fs5+vtg==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.8.5.tgz", + "integrity": "sha512-Ni8FuZ8yAF+sWZzojvtLE2b03cqjO5jNULcHFfM9ZZ0/JXrgom5pBREbtnAw7oxsxJqHw9Nz/XWORUEL3/IFow==", + "license": "MIT" + }, + "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.9.6", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.9.6.tgz", + "integrity": "sha512-rFen0G7adh1YmgvrmE5IPIqbb+IgEzENUm+tzm6MLLDSlPRoZVhzU1WdML9PV2W5GOdRA9qBKURlbt1OsXOsPw==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.9.5.tgz", + "integrity": "sha512-DYTWtWpfd5FOro3UnAfwvhD8jh59r2ig8bPtc9H8Ds7MscE/9NYruUQWFAOuraRl29jwcT2kyMFQ3MxeaVjUhg==", + "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==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "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", + "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/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.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/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "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.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.6.3", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "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/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/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "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/router/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/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.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "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.2", + "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-6.6.2.tgz", + "integrity": "sha512-V8Oh+XMz2+uquLZltZES6MVAD+yEnmMfwfn+gpXcDiwE3jyQygLt4xoI0zG8gKt6cRcs84hsKnXAKDQjG/JAgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-color": "^2.0.3", + "fs-extra": "^9.1.0", + "js-beautify": "^1.14.5", + "lodash": "^4.17.21", + "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==", + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "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/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", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "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.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/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", + "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.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "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/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": "9.0.2", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-9.0.2.tgz", + "integrity": "sha512-xuW7dzkUpcJq7QnhOsnNUgtYp3xRwpt2F7abdRYIpCsAt0hhUqia0EdxyXZQQpNmGtsCzYHryaKSV3q3GJnq7w==", + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^3.5.1", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/supertest": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.0.tgz", + "integrity": "sha512-5QeSO8hSrKghtcWEoPiO036fxH0Ii2wVQfFZSP0oqQhmjk8bOLhDFXr4JrvaFmPuEWUoq4znY3uSi8UzLKxGqw==", + "license": "MIT", + "dependencies": { + "methods": "^1.1.2", + "superagent": "^9.0.1" + }, + "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", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "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/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/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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/test-exclude/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/timers-ext": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.8.tgz", + "integrity": "sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==", + "dev": true, + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "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", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "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==", + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/type": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==", + "dev": true, + "license": "ISC" + }, + "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", + "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/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==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "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/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/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/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.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.0.tgz", + "integrity": "sha512-36B2ryl4+oL5QxZ3AzD0t5SsMNGvTtQHpjgFO5tbNxfXbMFkY822ktCDe1MnlqV3301QQI9SLHDNJokDI+Z9pA==", + "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/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", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.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/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/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/write-file-atomic/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/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/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", + "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" + } + }, + "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/BACKEND/package.json b/BACKEND/package.json new file mode 100644 index 00000000..8035d116 --- /dev/null +++ b/BACKEND/package.json @@ -0,0 +1,30 @@ +{ + "name": "backend", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "jest --verbose --detectOpenHandles --forceExit --runInBand", + "dev": "npx nodemon app" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "devDependencies": { + "dotenv": "^16.5.0", + "jest": "^29.7.0", + "sequelize-cli": "^6.6.2" + }, + "dependencies": { + "bcryptjs": "^3.0.2", + "cors": "^2.8.5", + "express": "^5.1.0", + "google-auth-library": "^9.15.1", + "jsonwebtoken": "^9.0.2", + "node-fetch": "^3.3.2", + "nodemon": "^3.1.10", + "pg": "^8.15.6", + "sequelize": "^6.37.7", + "supertest": "^7.1.0" + } +} diff --git a/BACKEND/seeders/20250429144527-seeding-category.js b/BACKEND/seeders/20250429144527-seeding-category.js new file mode 100644 index 00000000..77f7ac46 --- /dev/null +++ b/BACKEND/seeders/20250429144527-seeding-category.js @@ -0,0 +1,35 @@ +'use strict'; +const fs = require("fs").promises; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + const user = JSON.parse( + await fs.readFile("./data/users.json", "utf8") + ).map((el) => { + delete el.id; + el.createdAt = new Date(); + el.updatedAt = new Date(); + return el; + }); + + await queryInterface.bulkInsert("Users", user, {}); + + const category = JSON.parse( + await fs.readFile("./data/categories.json", "utf8") + ).map((el) => { + delete el.id; + el.createdAt = new Date(); + el.updatedAt = new Date(); + return el; + }); + + await queryInterface.bulkInsert("Categories", category, {}); + }, + + async down(queryInterface, Sequelize) { + + await queryInterface.bulkDelete("Users", null, {}); + await queryInterface.bulkDelete("Categories", null, {});x`` + + }, +}; diff --git a/BACKEND/seeders/20250429144546-seeding-product.js b/BACKEND/seeders/20250429144546-seeding-product.js new file mode 100644 index 00000000..8240b8d7 --- /dev/null +++ b/BACKEND/seeders/20250429144546-seeding-product.js @@ -0,0 +1,33 @@ +"use strict"; +const fs = require("fs").promises; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + const data = JSON.parse( + await fs.readFile("./data/products.json", "utf8") + ).map((el) => { + delete el.id; + el.createdAt = new Date(); + el.updatedAt = new Date(); + return el; + }); + + await queryInterface.bulkInsert("Products", data, {}); + + const cart = JSON.parse( + await fs.readFile("./data/carts.json", "utf8") + ).map((el) => { + delete el.id; + el.createdAt = new Date(); + el.updatedAt = new Date(); + return el; + }); + + await queryInterface.bulkInsert("Carts", cart, {}); + }, + + async down(queryInterface, Sequelize) { + await queryInterface.bulkDelete("Products", null, {}); + await queryInterface.bulkDelete("Carts", null, {}); + }, +}; diff --git a/FRONTEND/.DS_Store b/FRONTEND/.DS_Store new file mode 100644 index 00000000..4840063d Binary files /dev/null and b/FRONTEND/.DS_Store differ diff --git a/FRONTEND/ecommerce/.gitignore b/FRONTEND/ecommerce/.gitignore new file mode 100644 index 00000000..ffef9de8 --- /dev/null +++ b/FRONTEND/ecommerce/.gitignore @@ -0,0 +1,28 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + + + +Carousel.jsx \ No newline at end of file diff --git a/FRONTEND/ecommerce/README.md b/FRONTEND/ecommerce/README.md new file mode 100644 index 00000000..7059a962 --- /dev/null +++ b/FRONTEND/ecommerce/README.md @@ -0,0 +1,12 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/FRONTEND/ecommerce/eslint.config.js b/FRONTEND/ecommerce/eslint.config.js new file mode 100644 index 00000000..ec2b712d --- /dev/null +++ b/FRONTEND/ecommerce/eslint.config.js @@ -0,0 +1,33 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' + +export default [ + { ignores: ['dist'] }, + { + files: ['**/*.{js,jsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...js.configs.recommended.rules, + ...reactHooks.configs.recommended.rules, + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, + }, +] diff --git a/FRONTEND/ecommerce/index.html b/FRONTEND/ecommerce/index.html new file mode 100644 index 00000000..f170a2d8 --- /dev/null +++ b/FRONTEND/ecommerce/index.html @@ -0,0 +1,20 @@ + + + + + + + E-commerce + + + + +
+ + + diff --git a/FRONTEND/ecommerce/package-lock.json b/FRONTEND/ecommerce/package-lock.json new file mode 100644 index 00000000..e5aeaf33 --- /dev/null +++ b/FRONTEND/ecommerce/package-lock.json @@ -0,0 +1,3126 @@ +{ + "name": "ecommerce", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ecommerce", + "version": "0.0.0", + "dependencies": { + "@react-oauth/google": "^0.12.1", + "axios": "^1.9.0", + "bootstrap": "^5.3.5", + "google-auth-library": "^9.15.1", + "jwt-decode": "^4.0.0", + "prop-types": "^15.8.1", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-icons": "^5.5.0", + "react-router": "^7.5.3", + "react-router-dom": "^7.5.3", + "sweetalert2": "^11.19.1" + }, + "devDependencies": { + "@eslint/js": "^9.22.0", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react-swc": "^3.8.0", + "eslint": "^9.22.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^16.0.0", + "vite": "^6.3.1" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.3.tgz", + "integrity": "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.3.tgz", + "integrity": "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.3.tgz", + "integrity": "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.3.tgz", + "integrity": "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.3.tgz", + "integrity": "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.3.tgz", + "integrity": "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.3.tgz", + "integrity": "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.3.tgz", + "integrity": "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.3.tgz", + "integrity": "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.3.tgz", + "integrity": "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.3.tgz", + "integrity": "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.3.tgz", + "integrity": "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.3.tgz", + "integrity": "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.3.tgz", + "integrity": "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.3.tgz", + "integrity": "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.3.tgz", + "integrity": "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.3.tgz", + "integrity": "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.3.tgz", + "integrity": "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.3.tgz", + "integrity": "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.3.tgz", + "integrity": "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.3.tgz", + "integrity": "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.3.tgz", + "integrity": "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.3.tgz", + "integrity": "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.3.tgz", + "integrity": "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz", + "integrity": "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.1.tgz", + "integrity": "sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==", + "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.20.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", + "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", + "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.2.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", + "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", + "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "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.25.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz", + "integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "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.2.8", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", + "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.13.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.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@react-oauth/google": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@react-oauth/google/-/google-0.12.1.tgz", + "integrity": "sha512-qagsy22t+7UdkYAiT5ZhfM4StXi9PPNvw0zuwNmabrWyMKddczMtBIOARflbaIj+wHiQjnMAsZmzsUYuXeyoSg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.1.tgz", + "integrity": "sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.1.tgz", + "integrity": "sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.1.tgz", + "integrity": "sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.1.tgz", + "integrity": "sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.1.tgz", + "integrity": "sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.1.tgz", + "integrity": "sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.1.tgz", + "integrity": "sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.1.tgz", + "integrity": "sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.1.tgz", + "integrity": "sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.1.tgz", + "integrity": "sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.1.tgz", + "integrity": "sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.1.tgz", + "integrity": "sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.1.tgz", + "integrity": "sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.1.tgz", + "integrity": "sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.1.tgz", + "integrity": "sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.1.tgz", + "integrity": "sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.1.tgz", + "integrity": "sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.1.tgz", + "integrity": "sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.1.tgz", + "integrity": "sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.1.tgz", + "integrity": "sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@swc/core": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.11.21.tgz", + "integrity": "sha512-/Y3BJLcwd40pExmdar8MH2UGGvCBrqNN7hauOMckrEX2Ivcbv3IMhrbGX4od1dnF880Ed8y/E9aStZCIQi0EGw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.21" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.11.21", + "@swc/core-darwin-x64": "1.11.21", + "@swc/core-linux-arm-gnueabihf": "1.11.21", + "@swc/core-linux-arm64-gnu": "1.11.21", + "@swc/core-linux-arm64-musl": "1.11.21", + "@swc/core-linux-x64-gnu": "1.11.21", + "@swc/core-linux-x64-musl": "1.11.21", + "@swc/core-win32-arm64-msvc": "1.11.21", + "@swc/core-win32-ia32-msvc": "1.11.21", + "@swc/core-win32-x64-msvc": "1.11.21" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.11.21.tgz", + "integrity": "sha512-v6gjw9YFWvKulCw3ZA1dY+LGMafYzJksm1mD4UZFZ9b36CyHFowYVYug1ajYRIRqEvvfIhHUNV660zTLoVFR8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.11.21.tgz", + "integrity": "sha512-CUiTiqKlzskwswrx9Ve5NhNoab30L1/ScOfQwr1duvNlFvarC8fvQSgdtpw2Zh3MfnfNPpyLZnYg7ah4kbT9JQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.11.21.tgz", + "integrity": "sha512-YyBTAFM/QPqt1PscD8hDmCLnqPGKmUZpqeE25HXY8OLjl2MUs8+O4KjwPZZ+OGxpdTbwuWFyMoxjcLy80JODvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.11.21.tgz", + "integrity": "sha512-DQD+ooJmwpNsh4acrftdkuwl5LNxxg8U4+C/RJNDd7m5FP9Wo4c0URi5U0a9Vk/6sQNh9aSGcYChDpqCDWEcBw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.11.21.tgz", + "integrity": "sha512-y1L49+snt1a1gLTYPY641slqy55QotPdtRK9Y6jMi4JBQyZwxC8swWYlQWb+MyILwxA614fi62SCNZNznB3XSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.11.21.tgz", + "integrity": "sha512-NesdBXv4CvVEaFUlqKj+GA4jJMNUzK2NtKOrUNEtTbXaVyNiXjFCSaDajMTedEB0jTAd9ybB0aBvwhgkJUWkWA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.11.21.tgz", + "integrity": "sha512-qFV60pwpKVOdmX67wqQzgtSrUGWX9Cibnp1CXyqZ9Mmt8UyYGvmGu7p6PMbTyX7vdpVUvWVRf8DzrW2//wmVHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.11.21.tgz", + "integrity": "sha512-DJJe9k6gXR/15ZZVLv1SKhXkFst8lYCeZRNHH99SlBodvu4slhh/MKQ6YCixINRhCwliHrpXPym8/5fOq8b7Ig==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.11.21.tgz", + "integrity": "sha512-TqEXuy6wedId7bMwLIr9byds+mKsaXVHctTN88R1UIBPwJA92Pdk0uxDgip0pEFzHB/ugU27g6d8cwUH3h2eIw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.11.21.tgz", + "integrity": "sha512-BT9BNNbMxdpUM1PPAkYtviaV0A8QcXttjs2MDtOeSqqvSJaPtyM+Fof2/+xSwQDmDEFzbGCcn75M5+xy3lGqpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/types": { + "version": "0.1.21", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.21.tgz", + "integrity": "sha512-2YEtj5HJVbKivud9N4bpPBAyZhj4S2Ipe5LkUG94alTpr7in/GU/EARgPAd3BwU+YOmFVJC2+kjqhGRi3r0ZpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "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.1.2", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz", + "integrity": "sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.1.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.2.tgz", + "integrity": "sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@vitejs/plugin-react-swc": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.9.0.tgz", + "integrity": "sha512-jYFUSXhwMCYsh/aQTgSGLIN3Foz5wMbH9ahb0Zva//UzwZYbMiZd7oT3AU9jHT9DLswYDswsRwPU9jVF3yA48Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@swc/core": "^1.11.21" + }, + "peerDependencies": { + "vite": "^4 || ^5 || ^6" + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "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/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "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.9.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "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/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/bignumber.js": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz", + "integrity": "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/bootstrap": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.5.tgz", + "integrity": "sha512-ct1CHKtiobRimyGzmsSldEtM03E8fcEX4Tb3dGXz1V8faRwM50+vfHwTzOxB3IlKO7m+9vTH3s/3C6T2EAPeTA==", + "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.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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/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/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/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/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "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/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/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/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.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz", + "integrity": "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.3", + "@esbuild/android-arm": "0.25.3", + "@esbuild/android-arm64": "0.25.3", + "@esbuild/android-x64": "0.25.3", + "@esbuild/darwin-arm64": "0.25.3", + "@esbuild/darwin-x64": "0.25.3", + "@esbuild/freebsd-arm64": "0.25.3", + "@esbuild/freebsd-x64": "0.25.3", + "@esbuild/linux-arm": "0.25.3", + "@esbuild/linux-arm64": "0.25.3", + "@esbuild/linux-ia32": "0.25.3", + "@esbuild/linux-loong64": "0.25.3", + "@esbuild/linux-mips64el": "0.25.3", + "@esbuild/linux-ppc64": "0.25.3", + "@esbuild/linux-riscv64": "0.25.3", + "@esbuild/linux-s390x": "0.25.3", + "@esbuild/linux-x64": "0.25.3", + "@esbuild/netbsd-arm64": "0.25.3", + "@esbuild/netbsd-x64": "0.25.3", + "@esbuild/openbsd-arm64": "0.25.3", + "@esbuild/openbsd-x64": "0.25.3", + "@esbuild/sunos-x64": "0.25.3", + "@esbuild/win32-arm64": "0.25.3", + "@esbuild/win32-ia32": "0.25.3", + "@esbuild/win32-x64": "0.25.3" + } + }, + "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.25.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz", + "integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.13.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.25.1", + "@eslint/plugin-kit": "^0.2.8", + "@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.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.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.20", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz", + "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "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.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "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.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "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/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-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.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "dev": true, + "license": "MIT", + "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.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "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.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "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/gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", + "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^6.1.1", + "google-logging-utils": "^0.0.2", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "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.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", + "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/google-auth-library": { + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", + "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-logging-utils": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", + "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", + "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/gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "license": "MIT", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "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/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/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/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "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/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/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/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/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "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": "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/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "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/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==", + "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-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "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.8", + "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/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.1.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", + "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", + "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/react-icons": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", + "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, + "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-router": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.5.3.tgz", + "integrity": "sha512-3iUDM4/fZCQ89SXlDa+Ph3MevBrozBAI655OAfWQlTm9nBR0IKlrmNwFow5lPHttbwvITZfkeeeZFP6zt3F7pw==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.5.3.tgz", + "integrity": "sha512-cK0jSaTyW4jV9SRKAItMIQfWZ/D6WEZafgHuuCb9g+SjhLolY78qc+De4w/Cz9ybjvLzShAmaIMEXt8iF1Cm+A==", + "license": "MIT", + "dependencies": { + "react-router": "7.5.3" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "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.40.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.1.tgz", + "integrity": "sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.7" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.40.1", + "@rollup/rollup-android-arm64": "4.40.1", + "@rollup/rollup-darwin-arm64": "4.40.1", + "@rollup/rollup-darwin-x64": "4.40.1", + "@rollup/rollup-freebsd-arm64": "4.40.1", + "@rollup/rollup-freebsd-x64": "4.40.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.40.1", + "@rollup/rollup-linux-arm-musleabihf": "4.40.1", + "@rollup/rollup-linux-arm64-gnu": "4.40.1", + "@rollup/rollup-linux-arm64-musl": "4.40.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.40.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.40.1", + "@rollup/rollup-linux-riscv64-gnu": "4.40.1", + "@rollup/rollup-linux-riscv64-musl": "4.40.1", + "@rollup/rollup-linux-s390x-gnu": "4.40.1", + "@rollup/rollup-linux-x64-gnu": "4.40.1", + "@rollup/rollup-linux-x64-musl": "4.40.1", + "@rollup/rollup-win32-arm64-msvc": "4.40.1", + "@rollup/rollup-win32-ia32-msvc": "4.40.1", + "@rollup/rollup-win32-x64-msvc": "4.40.1", + "fsevents": "~2.3.2" + } + }, + "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/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "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/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.19.1", + "resolved": "https://registry.npmjs.org/sweetalert2/-/sweetalert2-11.19.1.tgz", + "integrity": "sha512-+8yws3Sc1srAZbrgdhmEIZny1I1UOYhJOIOdtOlv4TYaP5kkwQ9Zm8/BT23Qg+KdByCNOazltxEJAHzXVu8mhA==", + "license": "MIT", + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/limonte" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/turbo-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==", + "license": "ISC" + }, + "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/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/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vite": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.3.tgz", + "integrity": "sha512-5nXH+QsELbFKhsEfWLkHrvgRpTdGJzqOZ+utSdmPTvwHmvU6ITTm3xx+mRusihkcI8GeC7lCDyn3kDtiki9scw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "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/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.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/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/FRONTEND/ecommerce/package.json b/FRONTEND/ecommerce/package.json new file mode 100644 index 00000000..f6b8492f --- /dev/null +++ b/FRONTEND/ecommerce/package.json @@ -0,0 +1,37 @@ +{ + "name": "ecommerce", + "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.1", + "axios": "^1.9.0", + "bootstrap": "^5.3.5", + "google-auth-library": "^9.15.1", + "jwt-decode": "^4.0.0", + "prop-types": "^15.8.1", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-icons": "^5.5.0", + "react-router": "^7.5.3", + "react-router-dom": "^7.5.3", + "sweetalert2": "^11.19.1" + }, + "devDependencies": { + "@eslint/js": "^9.22.0", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react-swc": "^3.8.0", + "eslint": "^9.22.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^16.0.0", + "vite": "^6.3.1" + } +} diff --git a/FRONTEND/ecommerce/public/ecommerce-svgrepo-com.svg b/FRONTEND/ecommerce/public/ecommerce-svgrepo-com.svg new file mode 100644 index 00000000..226450ab --- /dev/null +++ b/FRONTEND/ecommerce/public/ecommerce-svgrepo-com.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/FRONTEND/ecommerce/public/vite.svg b/FRONTEND/ecommerce/public/vite.svg new file mode 100644 index 00000000..e7b8dfb1 --- /dev/null +++ b/FRONTEND/ecommerce/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/FRONTEND/ecommerce/src/App.css b/FRONTEND/ecommerce/src/App.css new file mode 100644 index 00000000..b9d355df --- /dev/null +++ b/FRONTEND/ecommerce/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/FRONTEND/ecommerce/src/App.jsx b/FRONTEND/ecommerce/src/App.jsx new file mode 100644 index 00000000..1efa00a4 --- /dev/null +++ b/FRONTEND/ecommerce/src/App.jsx @@ -0,0 +1,45 @@ +import Navbar from "./components/Navbar"; +import { + BrowserRouter as Router, + Routes, + Route, + Outlet, +} from "react-router-dom"; +import Login from "./pages/LoginPage"; +import RegisterPage from "./pages/RegisterPage"; +import HomePage from "./pages/HomePage"; +import AdminCategoryPage from "./pages/AdminCategoryPage"; +import AdminProductPage from "./pages/AdminProductPage"; +import AdminPage from "./pages/AdminPage" +import CartPage from "./pages/CartPage"; +import EditProfilePage from "./pages/EditProfile"; + +function App() { + const baseUrl = "http://localhost:3000"; + + return ( + + + } /> + } /> + } /> + } /> + } /> + + + + + } + > + } /> + }/> + } /> + + + + ); +} + +export default App; diff --git a/FRONTEND/ecommerce/src/assets/IKEA_logo (1).svg b/FRONTEND/ecommerce/src/assets/IKEA_logo (1).svg new file mode 100644 index 00000000..14a58330 --- /dev/null +++ b/FRONTEND/ecommerce/src/assets/IKEA_logo (1).svg @@ -0,0 +1,28 @@ + + + + + + + + + + diff --git a/FRONTEND/ecommerce/src/assets/images.png b/FRONTEND/ecommerce/src/assets/images.png new file mode 100644 index 00000000..44b963f9 Binary files /dev/null and b/FRONTEND/ecommerce/src/assets/images.png differ diff --git a/FRONTEND/ecommerce/src/assets/react.svg b/FRONTEND/ecommerce/src/assets/react.svg new file mode 100644 index 00000000..6c87de9b --- /dev/null +++ b/FRONTEND/ecommerce/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/FRONTEND/ecommerce/src/assets/style.css b/FRONTEND/ecommerce/src/assets/style.css new file mode 100644 index 00000000..a512b8b5 --- /dev/null +++ b/FRONTEND/ecommerce/src/assets/style.css @@ -0,0 +1,4 @@ + +* { + font-family: initial !important; +} \ No newline at end of file diff --git a/FRONTEND/ecommerce/src/components/CategoryFilter.jsx b/FRONTEND/ecommerce/src/components/CategoryFilter.jsx new file mode 100644 index 00000000..6244f7bd --- /dev/null +++ b/FRONTEND/ecommerce/src/components/CategoryFilter.jsx @@ -0,0 +1,51 @@ +import { useState, useEffect } from "react"; +import PropTypes from "prop-types"; +import axios from "axios"; + +function CategoryFilter({ onCategoryChange, baseUrl }) { + const [categories, setCategories] = useState([]); + const [activeCategory, setActiveCategory] = useState(null); + + useEffect(() => { + const fetchCategories = async () => { + try { + const response = await axios.get(`${baseUrl}/categories`); + setCategories(response.data); + } catch (err) { + console.error("Gagal mengambil kategori:", err); + } + }; + fetchCategories(); + }, [baseUrl]); + + const handleCategoryChange = (e) => { + const categoryId = e.target.value === "all" ? null : Number(e.target.value); + setActiveCategory(categoryId); + onCategoryChange(categoryId); + }; + + return ( +
+

Select Category

+ +
+ ); +} + +CategoryFilter.propTypes = { + onCategoryChange: PropTypes.func.isRequired, + baseUrl: PropTypes.string.isRequired, +}; + +export default CategoryFilter; diff --git a/FRONTEND/ecommerce/src/components/Navbar.jsx b/FRONTEND/ecommerce/src/components/Navbar.jsx new file mode 100644 index 00000000..d34d7479 --- /dev/null +++ b/FRONTEND/ecommerce/src/components/Navbar.jsx @@ -0,0 +1,95 @@ +import axios from "axios"; +import { useEffect, useState } from "react"; +import { BsCart2, BsPersonCircle } from "react-icons/bs"; +import { Link, useNavigate } from "react-router"; +import Swal from "sweetalert2"; + +export default function Navbar({baseUrl}) { + const navigate = useNavigate(); + const [carts, setCarts] = useState() + const handleLogout = () => { + localStorage.removeItem("access_token"); + navigate("/"); + Swal.fire({ + position: "center", + icon: "success", + title: "Bye!", + showConfirmButton: false, + timer: 1500, + }); + }; + +const fetchCart = async () => { + try { + const response = await axios.get( + `${baseUrl}/carts`, + { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + } + ); + setCarts(response.data) + // console.log(response.data, "<<<<"); + } catch (err) { + console.error("Gagal mengambil produk:", err); + Swal.fire({ + title: "Error!", + text: "Gagal memuat daftar produk", + icon: "error", + confirmButtonText: "OK", + }); + } +}; + +useEffect(() => { + fetchCart(); + }, []); + + + + return ( + + ); + +} \ No newline at end of file diff --git a/FRONTEND/ecommerce/src/components/ProductCard.jsx b/FRONTEND/ecommerce/src/components/ProductCard.jsx new file mode 100644 index 00000000..8163454c --- /dev/null +++ b/FRONTEND/ecommerce/src/components/ProductCard.jsx @@ -0,0 +1,46 @@ +import PropTypes from "prop-types"; + +function ProductCard({ product, onAddToCart }) { + return ( +
+
+ {product.name} +
+
{product.name}
+

+ Rp {product.price.toLocaleString("id-ID")} +

+ +
+
+
+ ); +} + +ProductCard.propTypes = { + product: PropTypes.shape({ + id: PropTypes.number.isRequired, + name: PropTypes.string.isRequired, + description: PropTypes.string, + price: PropTypes.number.isRequired, + stock: PropTypes.number.isRequired, + imgUrl: PropTypes.string, + }).isRequired, + onAddToCart: PropTypes.func.isRequired, +}; + +export default ProductCard; diff --git a/FRONTEND/ecommerce/src/index.css b/FRONTEND/ecommerce/src/index.css new file mode 100644 index 00000000..95c417c4 --- /dev/null +++ b/FRONTEND/ecommerce/src/index.css @@ -0,0 +1,17 @@ + +body { + font-family: 'Poppins', sans-serif; + background-color: #f8f9fa; +} + +.card { + transition: transform 0.2s; +} + +.card:hover { + transform: translateY(-5px); +} + +.navbar { + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} diff --git a/FRONTEND/ecommerce/src/main.jsx b/FRONTEND/ecommerce/src/main.jsx new file mode 100644 index 00000000..2ed39d46 --- /dev/null +++ b/FRONTEND/ecommerce/src/main.jsx @@ -0,0 +1,11 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import App from './App.jsx' +import "./assets/style.css"; + +createRoot(document.getElementById("root")).render( + + + + +); diff --git a/FRONTEND/ecommerce/src/pages/AdminCategoryPage.jsx b/FRONTEND/ecommerce/src/pages/AdminCategoryPage.jsx new file mode 100644 index 00000000..5c53f2c5 --- /dev/null +++ b/FRONTEND/ecommerce/src/pages/AdminCategoryPage.jsx @@ -0,0 +1,281 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; +import Swal from "sweetalert2"; +import PropTypes from "prop-types"; +import { useNavigate } from "react-router"; + +function AdminCategoryPage({ baseUrl }) { + const navigate = useNavigate(); + const [categories, setCategories] = useState([]); + const [newCategory, setNewCategory] = useState(""); + const [isLoading, setIsLoading] = useState(false); + + useEffect(() => { + const fetchCategories = async () => { + setIsLoading(true); + try { + const response = await axios.get(`${baseUrl}/categories`, { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + }); + setCategories(response.data); + } catch (error) { + Swal.fire({ + title: "Error!", + text: error.response?.data?.message || "Failed to load categories", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Error fetching categories:", error); + } finally { + setIsLoading(false); + } + }; + fetchCategories(); + }, [baseUrl]); + + const handleAddCategory = async (e) => { + e.preventDefault(); + if (!newCategory.trim()) { + Swal.fire({ + title: "Error!", + text: "Category name cannot be empty", + icon: "error", + confirmButtonText: "OK", + }); + return; + } + try { + const response = await axios.post( + `${baseUrl}/categories`, + { name: newCategory.trim() }, + { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + } + ); + setCategories([...categories, response.data]); + setNewCategory(""); + Swal.fire({ + position: "top-center", + icon: "success", + title: "Category added successfully", + showConfirmButton: false, + timer: 1500, + }); + } catch (error) { + Swal.fire({ + title: "Error!", + text: error.response?.data?.message || "Failed to add category", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Error adding category:", error); + } + }; + + const handleUpdateCategory = async (id, name) => { + if (!name.trim()) { + Swal.fire({ + title: "Error!", + text: "Category name cannot be empty", + icon: "error", + confirmButtonText: "OK", + }); + return; + } + try { + await axios.put( + `${baseUrl}/categories/${id}`, + { name: name.trim() }, + { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + } + ); + setCategories( + categories.map((c) => (c.id === id ? { ...c, name: name.trim() } : c)) + ); + Swal.fire({ + position: "top-center", + icon: "success", + title: "Category updated successfully", + showConfirmButton: false, + timer: 1500, + }); + } catch (error) { + Swal.fire({ + title: "Error!", + text: error.response?.data?.message || "Failed to update category", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Error updating category:", error); + } + }; + + const handleDeleteCategory = async (id) => { + const result = await Swal.fire({ + title: "Are you sure?", + text: "This category will be permanently deleted!", + icon: "warning", + showCancelButton: true, + confirmButtonText: "Delete", + cancelButtonText: "Cancel", + }); + if (result.isConfirmed) { + try { + await axios.delete(`${baseUrl}/categories/${id}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + }); + setCategories(categories.filter((c) => c.id !== id)); + Swal.fire({ + position: "top-center", + icon: "success", + title: "Category deleted successfully", + showConfirmButton: false, + timer: 1500, + }); + } catch (error) { + Swal.fire({ + title: "Error!", + text: error.response?.data?.message || "Failed to delete category", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Error deleting category:", error); + } + } + }; + + return ( +
+
+

+ {isLoading ? ( +
+
+ Loading... +
+
+ ) : ( + <> + {/* Add Category Form */} +
+

+ Add Category +

+
+
+ setNewCategory(e.target.value)} + required + aria-label="Category Name" + /> + +
+
+
+ +
+ + + + + + + + + {categories.map((category) => ( + + + + + ))} + +
Category Name
+ + handleUpdateCategory(category.id, e.target.value) + } + onChange={(e) => + setCategories( + categories.map((c) => + c.id === category.id + ? { ...c, name: e.target.value } + : c + ) + ) + } + aria-label={`Edit category name ${category.name}`} + /> + + +
+
+ + )} +
+ +
+
+
+ ); +} + +AdminCategoryPage.propTypes = { + baseUrl: PropTypes.string.isRequired, +}; + +export default AdminCategoryPage; diff --git a/FRONTEND/ecommerce/src/pages/AdminPage.jsx b/FRONTEND/ecommerce/src/pages/AdminPage.jsx new file mode 100644 index 00000000..2adcbd45 --- /dev/null +++ b/FRONTEND/ecommerce/src/pages/AdminPage.jsx @@ -0,0 +1,59 @@ +import { Link, useNavigate } from "react-router"; +import Swal from "sweetalert2"; + +export default function AdminProductPage() { + const navigate = useNavigate() + + const handleLogout = () => { + localStorage.removeItem("access_token"); + navigate("/"); + Swal.fire({ + position: "center", + icon: "success", + title: "Bye!", + showConfirmButton: false, + timer: 1500, + }); + }; + return ( +
+
+

+ WellCome Admin! +

+
+ + UPDATE PRODUCTS + +
+
+ + UPDATE CATEGORY + +
+
+ + LOGOUT + +
+
+
+ ); +} diff --git a/FRONTEND/ecommerce/src/pages/AdminProductPage.jsx b/FRONTEND/ecommerce/src/pages/AdminProductPage.jsx new file mode 100644 index 00000000..c88f52e1 --- /dev/null +++ b/FRONTEND/ecommerce/src/pages/AdminProductPage.jsx @@ -0,0 +1,553 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; +import Swal from "sweetalert2"; +import PropTypes from "prop-types"; +import { useNavigate } from "react-router"; + +function AdminProductPage({ baseUrl }) { + const navigate = useNavigate(); + const [products, setProducts] = useState([]); + const [categories, setCategories] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [newProduct, setNewProduct] = useState({ + name: "", + description: "", + price: "", + stock: "", + imgUrl: "", + categoryId: "", + userId: localStorage.getItem("userId"), + }); + const [editProduct, setEditProduct] = useState(null); + + useEffect(() => { + const fetchData = async () => { + setIsLoading(true); + try { + const [productResponse, categoryResponse] = await Promise.all([ + axios.get(`${baseUrl}/products`, { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + }), + axios.get(`${baseUrl}/categories`, { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + }), + ]); + setProducts(productResponse.data); + setCategories(categoryResponse.data); + } catch (error) { + Swal.fire({ + title: "Error!", + text: + error.response?.data?.message || + "Failed to load products or categories", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Error fetching data:", error); + } finally { + setIsLoading(false); + } + }; + fetchData(); + }, [baseUrl]); + + const handleAddProduct = async (e) => { + e.preventDefault(); + const { name, description, price, stock, imgUrl, categoryId } = newProduct; + if ( + !name.trim() || + !description.trim() || + !price || + !stock || + !imgUrl.trim() || + !categoryId + ) { + Swal.fire({ + title: "Error!", + text: "All fields must be filled out correctly", + icon: "error", + confirmButtonText: "OK", + }); + return; + } + try { + const response = await axios.post( + `${baseUrl}/products`, + { + ...newProduct, + price: parseInt(price), + stock: parseInt(stock), + categoryId: parseInt(categoryId), + }, + { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + } + ); + setProducts([...products, response.data]); + setNewProduct({ + name: "", + description: "", + price: "", + stock: "", + imgUrl: "", + categoryId: "", + userId: localStorage.getItem("userId"), + }); + Swal.fire({ + position: "top-center", + icon: "success", + title: "Product successfully added", + showConfirmButton: false, + timer: 1500, + }); + } catch (error) { + Swal.fire({ + title: "Error!", + text: error.response?.data?.message || "Failed to add product", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Error adding product:", error); + } + }; + + const handleUpdateProduct = async (e) => { + e.preventDefault(); + if (!editProduct) return; + const { id, name, description, price, stock, imgUrl, categoryId } = + editProduct; + if ( + !name.trim() || + !description.trim() || + !price || + !stock || + !imgUrl.trim() || + !categoryId + ) { + Swal.fire({ + title: "Error!", + text: "All fields must be filled out correctly", + icon: "error", + confirmButtonText: "OK", + }); + navigate('/admin/product') + return; + } + try { + await axios.put( + `${baseUrl}/products/${id}`, + { + ...editProduct, + price: price, + stock: stock, + categoryId: categoryId, + }, + { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + } + ); + setProducts(products.map((p) => (p.id === id ? { ...editProduct } : p))); + setEditProduct(null); + Swal.fire({ + position: "top-center", + icon: "success", + title: "Product successfully updated", + showConfirmButton: false, + timer: 1500, + }); + } catch (error) { + Swal.fire({ + title: "Error!", + text: error.response?.data?.message || "Failed to update product", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Error updating product:", error); + } + }; + + const handleDeleteProduct = async (id) => { + const result = await Swal.fire({ + title: "Are you sure?", + text: "This product will be permanently deleted!", + icon: "warning", + showCancelButton: true, + confirmButtonText: "Delete", + cancelButtonText: "Cancel", + }); + if (result.isConfirmed) { + try { + await axios.delete(`${baseUrl}/products/${id}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + }); + setProducts(products.filter((p) => p.id !== id)); + Swal.fire({ + position: "top-center", + icon: "success", + title: "Product successfully deleted", + showConfirmButton: false, + timer: 1500, + }); + } catch (error) { + Swal.fire({ + title: "Error!", + text: error.response?.data?.message || "Failed to delete product", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Error deleting product:", error); + } + } + }; + + return ( +
+
+

+ Your Are Admin! +

+ {isLoading ? ( +
+
+ Loading... +
+
+ ) : ( + <> +
+

+ Add New Product +

+
+
+
+ + setNewProduct({ ...newProduct, name: e.target.value }) + } + required + aria-label="Product Name" + /> +
+
+ + setNewProduct({ + ...newProduct, + description: e.target.value, + }) + } + required + aria-label="Description" + /> +
+
+ + setNewProduct({ ...newProduct, price: e.target.value }) + } + min="0" + required + aria-label="Price" + /> +
+
+ + setNewProduct({ ...newProduct, stock: e.target.value }) + } + min="0" + required + aria-label="Stock" + /> +
+
+ + setNewProduct({ ...newProduct, imgUrl: e.target.value }) + } + required + aria-label="Image URL" + /> +
+
+ +
+
+ +
+
+
+
+ + {editProduct && ( +
+

+ Edit Product +

+
+
+
+ + setEditProduct({ + ...editProduct, + name: e.target.value, + }) + } + required + aria-label="Product Name" + /> +
+
+ + setEditProduct({ + ...editProduct, + description: e.target.value, + }) + } + required + aria-label="Description" + /> +
+
+ + setEditProduct({ + ...editProduct, + price: e.target.value, + }) + } + min="0" + required + aria-label="Price" + /> +
+
+ + setEditProduct({ + ...editProduct, + stock: e.target.value, + }) + } + min="0" + required + aria-label="Stock" + /> +
+
+ + setEditProduct({ + ...editProduct, + imgUrl: e.target.value, + }) + } + required + aria-label="Image URL" + /> +
+
+ +
+
+ + +
+
+
+
+ )} + +
+ + + + + + + + + + + + {products.map((product) => ( + + + + + + + + ))} + +
NamePriceStockCategory
{product.name}Rp {product.price.toLocaleString()}{product.stock} + {categories.find((c) => c.id === product.categoryId).name} + + +
+ +
+
+
+ + )} +
+ +
+
+
+ ); +} + +AdminProductPage.propTypes = { baseUrl: PropTypes.string.isRequired }; +export default AdminProductPage; diff --git a/FRONTEND/ecommerce/src/pages/CartPage.jsx b/FRONTEND/ecommerce/src/pages/CartPage.jsx new file mode 100644 index 00000000..a2685130 --- /dev/null +++ b/FRONTEND/ecommerce/src/pages/CartPage.jsx @@ -0,0 +1,168 @@ +import { useState, useEffect } from "react"; +import PropTypes from "prop-types"; +import { Link, useNavigate } from "react-router-dom"; +import Swal from "sweetalert2"; +import axios from "axios"; + +function CartPage({ baseUrl, setCartCount }) { + const [cartItems, setCartItems] = useState([]); + const navigate = useNavigate(); + + useEffect(() => { + const userId = localStorage.getItem("userId"); + if (!userId) { + navigate("/login"); + return; + } + + const fetchCart = async () => { + try { + const response = await axios.get(`${baseUrl}/carts`, { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + }); + setCartItems(response.data); + } catch (err) { + console.error("Failed to fetch cart:", err); + Swal.fire({ + title: "Error!", + text: "Failed to load cart", + icon: "error", + confirmButtonText: "OK", + }); + } + }; + fetchCart(); + }, [baseUrl, navigate]); + + const handleUpdateQuantity = async (id, productId, quantity) => { + if (quantity <= 0) { + Swal.fire({ + title: "Error!", + text: "Quantity must be greater than 0", + icon: "error", + confirmButtonText: "OK", + }); + return; + } + try { + await axios.put( + `${baseUrl}/carts/${id}`, + { productId, quantity }, + { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + } + ); + setCartItems( + cartItems.map((item) => (item.id === id ? { ...item, quantity } : item)) + ); + } catch (err) { + console.error("Failed to update cart:", err); + } + }; + + const handleDeleteItem = async (id) => { + try { + await axios.delete(`${baseUrl}/carts/${id}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + }); + setCartItems(cartItems.filter((item) => item.id !== id)); + setCartCount((prev) => prev - 1); + } catch (err) { + console.error("Failed to delete item:", err); + } + }; + + return ( +
+

Shopping Cart

+ {cartItems.length === 0 ? ( +

Your cart is empty

+ ) : ( +
+
+
+ + + + + + + + + + + + {cartItems.map((item) => ( + + + + + + + + ))} + +
ProductPriceQuantityTotalAction
{item.Product?.name || "Product not found"} + Rp {item.Product?.price?.toLocaleString("id-ID") || 0} + + + handleUpdateQuantity( + item.id, + item.productId, + parseInt(e.target.value) + ) + } + className="form-control" + style={{ width: "80px" }} + /> + + Rp{" "} + {(item.Product?.price * item.quantity)?.toLocaleString( + "id-ID" + ) || 0} + + +
+
+
+
+ )} +
+ + Back + + + Buy + +
+
+ ); +} + +CartPage.propTypes = { + baseUrl: PropTypes.string.isRequired, + setCartCount: PropTypes.func.isRequired, +}; + +export default CartPage; diff --git a/FRONTEND/ecommerce/src/pages/EditProfile.jsx b/FRONTEND/ecommerce/src/pages/EditProfile.jsx new file mode 100644 index 00000000..01b252aa --- /dev/null +++ b/FRONTEND/ecommerce/src/pages/EditProfile.jsx @@ -0,0 +1,197 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; +import Swal from "sweetalert2"; +import PropTypes from "prop-types"; +import { useNavigate } from "react-router-dom"; + +export default function EditProfilePage({ baseUrl }) { + const [formData, setFormData] = useState({ + username: "", + email: "", + phoneNumber: "", + address: "", + }); + const navigate = useNavigate(); + + useEffect(() => { + const fetchProfile = async () => { + try { + const userId = localStorage.getItem("userId"); + if (!userId) throw new Error("User ID not found"); + + const response = await axios.get(`${baseUrl}/users/${userId}`, { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + }); + + setFormData({ + username: response.data.username || "", + email: response.data.email || "", + phoneNumber: response.data.phoneNumber || "", + address: response.data.address || "", + }); + } catch (err) { + console.error("Failed to fetch profile data:", err); + Swal.fire({ + title: "Error!", + text: + err.response?.data?.message || + "Failed to load profile data. Please try again.", + icon: "error", + confirmButtonText: "OK", + }); + } + }; + + fetchProfile(); + }, [baseUrl]); + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData((prev) => ({ + ...prev, + [name]: value, + })); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + + if ( + !formData.username || + !formData.email || + !formData.phoneNumber || + !formData.address + ) { + Swal.fire({ + title: "Error!", + text: "All fields are required.", + icon: "error", + confirmButtonText: "OK", + }); + return; + } + + try { + const userId = localStorage.getItem("userId"); + if (!userId) throw new Error("User ID not found"); + + const payload = { ...formData }; + + await axios.put(`${baseUrl}/users/${userId}`, payload, { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + }); + + Swal.fire({ + position: "center", + icon: "success", + title: "Profile updated successfully!", + showConfirmButton: false, + timer: 1500, + }); + + navigate("/"); + } catch (err) { + console.error("Failed to update profile:", err); + Swal.fire({ + title: "Error!", + text: + err.response?.data?.message || + "Failed to update profile. Please try again.", + icon: "error", + confirmButtonText: "OK", + }); + } + }; + + return ( +
+

Edit Profile

+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+ ); +} + +EditProfilePage.propTypes = { + baseUrl: PropTypes.string.isRequired, +}; diff --git a/FRONTEND/ecommerce/src/pages/HomePage.jsx b/FRONTEND/ecommerce/src/pages/HomePage.jsx new file mode 100644 index 00000000..84571c57 --- /dev/null +++ b/FRONTEND/ecommerce/src/pages/HomePage.jsx @@ -0,0 +1,128 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; +import Swal from "sweetalert2"; +import PropTypes from "prop-types"; +import ProductCard from "../components/ProductCard"; +import CategoryFilter from "../components/CategoryFilter"; + +export default function HomePage({ baseUrl, setCartCount }) { + const [products, setProducts] = useState([]); + const [searchQuery, setSearchQuery] = useState(""); + const [selectedCategory, setSelectedCategory] = useState(null); + const [isLoading, setIsLoading] = useState(false); + + const fetchProducts = async () => { + setIsLoading(true); + try { + const response = await axios.get(`${baseUrl}/products`, { + params: { + search: searchQuery || "", + }, + }); + setProducts(response.data); + } catch (err) { + console.error("Failed to fetch products:", err); + Swal.fire({ + title: "Error!", + text: "Failed to load product list", + icon: "error", + confirmButtonText: "OK", + }); + } finally { + setIsLoading(false); + } + }; + + const handleAddToCart = async (productId) => { + try { + const response = await axios.post( + `${baseUrl}/carts`, + { productId, quantity: 1 }, + { + headers: { + Authorization: `Bearer ${localStorage.getItem("access_token")}`, + }, + } + ); + console.log(response.data, "RESPONSE"); + + Swal.fire({ + position: "top-center", + icon: "success", + title: "Item added to cart", + showConfirmButton: false, + timer: 1500, + }); + } catch (err) { + console.error("Failed to add to cart:", err); + Swal.fire({ + title: "Error!", + text: "Could not add item to cart. Please try again.", + icon: "error", + confirmButtonText: "OK", + }); + } + }; + + const handleSearchSubmit = (e) => { + e.preventDefault(); + fetchProducts(); + }; + + useEffect(() => { + fetchProducts(); + }, []); + + const filteredProducts = selectedCategory + ? products.filter((product) => product.categoryId === selectedCategory) + : products; + + return ( +
+ +
+ setSearchQuery(e.target.value)} + /> + +
+
+ {isLoading ? ( +

Loading products...

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

No products found

+ ) : ( + filteredProducts.map((product) => ( +
+ +
+ )) + )} +
+
+ ); +} + +HomePage.propTypes = { + baseUrl: PropTypes.string.isRequired, + setCartCount: PropTypes.func.isRequired, +}; diff --git a/FRONTEND/ecommerce/src/pages/LoginPage.jsx b/FRONTEND/ecommerce/src/pages/LoginPage.jsx new file mode 100644 index 00000000..74977c18 --- /dev/null +++ b/FRONTEND/ecommerce/src/pages/LoginPage.jsx @@ -0,0 +1,178 @@ +import { useEffect, useState } from "react"; +import axios from "axios"; +import { Link, useNavigate } from "react-router-dom"; +import Swal from "sweetalert2"; +import PropTypes from "prop-types"; + +export default function LoginPage({ baseUrl }) { + const navigate = useNavigate(); + const [email, setEmail] = useState("admin1@example.com"); + const [password, setPassword] = useState("admin123"); + + const handleLogin = async (event) => { + event.preventDefault(); + try { + const response = await axios.post(`${baseUrl}/login`, { + email, + password, + }); + localStorage.setItem("access_token", response.data.access_token); + localStorage.setItem("userId", response.data.userId); + console.log(response.data.role, "APA INI ROLE"); + + if (response.data.role === "admin") { + navigate("/admin"); + } else { + navigate("/"); + } + Swal.fire({ + position: "top-center", + icon: "success", + title: "Login successful", + showConfirmButton: false, + timer: 1500, + }); + } catch (error) { + Swal.fire({ + title: "Error!", + text: error.response?.data?.message || "Invalid email or password", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Login failed:", error.response?.data || error); + if (error.response?.status === 401) { + localStorage.removeItem("access_token"); + localStorage.removeItem("userId"); + navigate("/login"); + } + } + }; + + const handleCredentialResponse = async (response) => { + try { + const { data } = await axios.post(`${baseUrl}/login/google`, { + googleToken: response.credential, + }); + localStorage.setItem("access_token", data.access_token); + localStorage.setItem("userId", data.userId); + if (data.role === "admin") { + navigate("/admin/products"); + } else { + navigate("/"); + } + Swal.fire({ + position: "top-center", + icon: "success", + title: "Logged in with Google successfully", + showConfirmButton: false, + timer: 1500, + }); + } catch (error) { + Swal.fire({ + title: "Error!", + text: error.response?.data?.message || "Failed to log in with Google", + icon: "error", + confirmButtonText: "OK", + }); + console.error("Google login failed:", error.response?.data || error); + } + }; + + useEffect(() => { + if (!import.meta.env.VITE_GOOGLE_CLIENT_ID) { + console.error("Google Client ID not found. Check your .env file."); + return; + } + if (!window.google) { + console.error("Google SDK not loaded. Check the script in index.html."); + return; + } + window.google.accounts.id.initialize({ + client_id: import.meta.env.VITE_GOOGLE_CLIENT_ID, + callback: handleCredentialResponse, + }); + window.google.accounts.id.renderButton( + document.getElementById("buttonDiv"), + { theme: "outline", size: "large" } + ); + }, []); + + return ( +
+
+

+ Login +

+
+
+ + setEmail(event.target.value)} + required + aria-label="Email" + /> +
+
+ + setPassword(event.target.value)} + required + aria-label="Password" + /> +
+
+ +
+
+
+

+ Don't have an account?{" "} + + Register + +

+
+
+ ); +} + +LoginPage.propTypes = { + baseUrl: PropTypes.string.isRequired, +}; diff --git a/FRONTEND/ecommerce/src/pages/RegisterPage.jsx b/FRONTEND/ecommerce/src/pages/RegisterPage.jsx new file mode 100644 index 00000000..919f2cac --- /dev/null +++ b/FRONTEND/ecommerce/src/pages/RegisterPage.jsx @@ -0,0 +1,185 @@ +import { useState } from "react"; +import { Link, useNavigate } from "react-router-dom"; +import axios from "axios"; +import Swal from "sweetalert2"; + +export default function RegisterPage({baseUrl}) { + const [username, setUsername] = useState("user"); + const [email, setEmail] = useState("user@mail.com"); + const [password, setPassword] = useState("user123"); + const [phoneNumber, setPhoneNumber] = useState("000000"); + const [address, setAddress] = useState("jalan user"); + const [isLoading, setIsLoading] = useState(false); + const navigate = useNavigate(); + + const handleRegister = async (e) => { + e.preventDefault(); + setIsLoading(true); + try { + await axios.post(`${baseUrl}/register`, { + username, + email, + password, + phoneNumber, + address, + }); + Swal.fire({ + position: "top-center", + icon: "success", + title: "Registration Successful", + showConfirmButton: false, + timer: 1500, + }); + navigate("/login"); + } catch (error) { + console.error("Registration error:", error); + Swal.fire({ + title: "Error!", + text: error.response?.data?.message || "Registration failed", + icon: "error", + confirmButtonText: "OK", + }); + } finally { + setIsLoading(false); + } + }; + + return ( +
+
+

+ Register +

+
+
+ + setUsername(e.target.value)} + required + aria-label="Username" + /> +
+
+ + setEmail(e.target.value)} + required + aria-label="Email address" + /> +
+
+ + setPassword(e.target.value)} + required + aria-label="Password" + /> +
+
+ + setPhoneNumber(e.target.value)} + required + aria-label="Phone number" + /> +
+
+ + setAddress(e.target.value)} + required + aria-label="Address" + /> +
+
+ +
+
+

+ Already have an account?{" "} + + Login + +

+
+
+ ); +} diff --git a/FRONTEND/ecommerce/vite.config.js b/FRONTEND/ecommerce/vite.config.js new file mode 100644 index 00000000..2328e170 --- /dev/null +++ b/FRONTEND/ecommerce/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react()], +}) diff --git a/Plan.md b/Plan.md new file mode 100644 index 00000000..e2c0d62b --- /dev/null +++ b/Plan.md @@ -0,0 +1,10 @@ +theme : ecommerece +overview : aplikasi e-commerce modern dengan fitur chatbot otomatis untuk bantu customer cek order, stok, refund, dll +main featurenya : Login/ SignUp (Google OAuth ) + Admin (CRUD) + +3rd Party API : midtrans (transaksis) + Dialogflow use: Membantu customer tracking order, cek stok, refund otomatis. + Cloudinary +tabel : user, product, order, orderItem, payment, cart, + diff --git a/Screenshot 2025-04-29 at 11.14.45.png b/Screenshot 2025-04-29 at 11.14.45.png new file mode 100644 index 00000000..253fdbcd Binary files /dev/null and b/Screenshot 2025-04-29 at 11.14.45.png differ