diff --git a/controller/abonemments/AbonemmentController.js b/controller/abonemments/AbonemmentController.js
index b68d468..a8031c2 100644
--- a/controller/abonemments/AbonemmentController.js
+++ b/controller/abonemments/AbonemmentController.js
@@ -1,4 +1,5 @@
const AbonemmentService = require('../../services/abonemments/AbonemmentService');
+const PermissionService = require('../../services/permissions/PermissionService');
const service = new AbonemmentService();
module.exports = {
@@ -9,12 +10,22 @@ module.exports = {
const actorUser = { ...rawUser, id: rawUser.id ?? rawUser.userId ?? null };
console.log('[CONTROLLER SUBSCRIBE] Normalized actorUser:', { id: actorUser.id, email: actorUser.email, role: actorUser.role });
+ // Permission check: user must have can_subscribe
+ const hasPermission = await PermissionService.userHasPermission(actorUser.id, 'can_subscribe');
+ if (!hasPermission) {
+ return res.status(403).json({ success: false, message: 'You do not have permission to complete a subscription.' });
+ }
+
const result = await service.subscribeOrder({
userId: actorUser.id || null,
items: req.body.items,
billingInterval: req.body.billing_interval,
intervalCount: req.body.interval_count,
isAutoRenew: req.body.is_auto_renew,
+ isForSelf: req.body.is_for_self,
+ recipientName: req.body.recipient_name,
+ recipientEmail: req.body.recipient_email,
+ recipientNotes: req.body.recipient_notes,
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
@@ -70,6 +81,28 @@ module.exports = {
}
},
+ async updateContent(req, res) {
+ try {
+ const rawUser = req.user || {};
+ const actorUser = { ...rawUser, id: rawUser.id ?? rawUser.userId ?? null };
+ const data = await service.updateContent({
+ abonementId: req.params.id,
+ actorUser,
+ items: req.body.items,
+ });
+ return res.json({ success: true, data });
+ } catch (err) {
+ console.error('[ABONEMENT UPDATE CONTENT]', err);
+ if (err?.message === 'Not found') {
+ return res.status(404).json({ success: false, message: 'Abonement not found' });
+ }
+ if (err?.message === 'Forbidden') {
+ return res.status(403).json({ success: false, message: 'Forbidden' });
+ }
+ return res.status(400).json({ success: false, message: err.message });
+ }
+ },
+
async renew(req, res) {
try {
const rawUser = req.user || {};
@@ -86,6 +119,9 @@ module.exports = {
try {
const rawUser = req.user || {};
const id = rawUser.id ?? rawUser.userId;
+ if (!id) {
+ return res.status(401).json({ success: false, message: 'Unauthorized: missing user id' });
+ }
console.log('[CONTROLLER GET MINE] Using user id:', id);
const data = await service.getMyAbonements({ userId: id });
return res.json({ success: true, data });
@@ -95,6 +131,42 @@ module.exports = {
}
},
+ async getMineStatus(req, res) {
+ try {
+ const rawUser = req.user || {};
+ const id = rawUser.id ?? rawUser.userId;
+ if (!id) {
+ return res.status(401).json({ success: false, message: 'Unauthorized: missing user id' });
+ }
+ const data = await service.getMyAbonementStatus({ userId: id });
+ return res.json({ success: true, data });
+ } catch (err) {
+ console.error('[ABONEMENT MINE STATUS]', err);
+ return res.status(500).json({ success: false, message: 'Internal error' });
+ }
+ },
+
+ async getInvoices(req, res) {
+ try {
+ const rawUser = req.user || {};
+ const actorUser = { ...rawUser, id: rawUser.id ?? rawUser.userId ?? null };
+ const data = await service.getInvoicesForAbonement({
+ abonementId: req.params.id,
+ actorUser,
+ });
+ return res.json({ success: true, data });
+ } catch (err) {
+ console.error('[ABONEMENT INVOICES]', err);
+ if (err?.message === 'Not found') {
+ return res.status(404).json({ success: false, message: 'Abonement not found' });
+ }
+ if (err?.message === 'Forbidden') {
+ return res.status(403).json({ success: false, message: 'Forbidden' });
+ }
+ return res.status(400).json({ success: false, message: err.message });
+ }
+ },
+
async getHistory(req, res) {
try {
return res.json({ success: true, data: await service.getHistory({ abonementId: req.params.id }) });
diff --git a/controller/admin/CompanySettingsController.js b/controller/admin/CompanySettingsController.js
new file mode 100644
index 0000000..b6b88eb
--- /dev/null
+++ b/controller/admin/CompanySettingsController.js
@@ -0,0 +1,26 @@
+const CompanySettingsRepository = require('../../repositories/settings/CompanySettingsRepository');
+
+const repo = new CompanySettingsRepository();
+
+class CompanySettingsController {
+ static async get(req, res) {
+ try {
+ const settings = await repo.get();
+ return res.json(settings || { company_name: '', company_street: '', company_postal_city: '', company_country: '' });
+ } catch (err) {
+ return res.status(500).json({ message: 'Failed to load company settings' });
+ }
+ }
+
+ static async update(req, res) {
+ try {
+ const { company_name, company_street, company_postal_city, company_country } = req.body;
+ const updated = await repo.update({ company_name, company_street, company_postal_city, company_country });
+ return res.json(updated);
+ } catch (err) {
+ return res.status(500).json({ message: 'Failed to update company settings' });
+ }
+ }
+}
+
+module.exports = CompanySettingsController;
diff --git a/controller/invoice/InvoiceController.js b/controller/invoice/InvoiceController.js
index c7b81f9..d4a7628 100644
--- a/controller/invoice/InvoiceController.js
+++ b/controller/invoice/InvoiceController.js
@@ -45,4 +45,28 @@ module.exports = {
return res.status(400).json({ success: false, message: e.message });
}
},
+
+ async updateStatus(req, res) {
+ try {
+ const { status } = req.body;
+ if (!status) return res.status(400).json({ success: false, message: 'status is required' });
+ const data = await service.updateStatus(req.params.id, status);
+ const poolResult = data?._poolResult ?? null;
+ if (data?._poolResult) delete data._poolResult;
+ return res.json({ success: true, data, poolResult });
+ } catch (e) {
+ console.error('[INVOICE UPDATE STATUS]', e);
+ return res.status(400).json({ success: false, message: e.message });
+ }
+ },
+
+ async getDetail(req, res) {
+ try {
+ const data = await service.getInvoiceDetail(req.params.id);
+ return res.json({ success: true, data });
+ } catch (e) {
+ console.error('[INVOICE DETAIL]', e);
+ return res.status(400).json({ success: false, message: e.message });
+ }
+ },
};
diff --git a/controller/pool/PoolController.js b/controller/pool/PoolController.js
index 360f53d..02985e2 100644
--- a/controller/pool/PoolController.js
+++ b/controller/pool/PoolController.js
@@ -1,17 +1,29 @@
-const { createPool, listPools, updatePoolState } = require('../../services/pool/PoolService');
+const { createPool, listPools, updatePoolState, updatePoolSubscription } = require('../../services/pool/PoolService');
const PoolMemberService = require('../../services/pool/PoolMemberService');
+const PoolInflowService = require('../../services/pool/PoolInflowService');
module.exports = {
async create(req, res) {
try {
- const { pool_name, description, price, pool_type, is_active } = req.body || {};
+ const { pool_name, description, price, price_net, subscription_coffee_id, pool_type, is_active } = req.body || {};
+ const normalizedNetPrice = Number(price_net ?? price);
const actorUserId = req.user && req.user.userId;
if (!pool_name) return res.status(400).json({ success: false, message: 'Pool name is required' });
- if (!price || price < 0) return res.status(400).json({ success: false, message: 'Valid price is required' });
+ if (!Number.isFinite(normalizedNetPrice) || normalizedNetPrice < 0) {
+ return res.status(400).json({ success: false, message: 'Valid net price per capsule is required' });
+ }
if (pool_type && !['coffee', 'other'].includes(pool_type)) {
return res.status(400).json({ success: false, message: 'Invalid pool_type. Allowed: coffee, other' });
}
- const pool = await createPool({ pool_name, description, price, pool_type, is_active, created_by: actorUserId });
+ const pool = await createPool({
+ pool_name,
+ description,
+ price: Number(normalizedNetPrice.toFixed(2)),
+ subscription_coffee_id,
+ pool_type,
+ is_active,
+ created_by: actorUserId
+ });
return res.status(201).json({ success: true, data: pool });
} catch (e) {
if (e && (e.code === 'ER_DUP_ENTRY' || e.errno === 1062)) {
@@ -57,6 +69,28 @@ module.exports = {
}
},
+ async updateSubscription(req, res) {
+ try {
+ const { id } = req.params || {};
+ const { subscription_coffee_id } = req.body || {};
+ const actorUserId = req.user && req.user.userId;
+ if (!id) return res.status(400).json({ success: false, message: 'id is required' });
+
+ const updated = await updatePoolSubscription({
+ id,
+ subscription_coffee_id,
+ actorUserId,
+ });
+ return res.status(200).json({ success: true, data: updated });
+ } catch (e) {
+ if (e && e.status === 400) {
+ return res.status(400).json({ success: false, message: e.message });
+ }
+ console.error('[PoolController.updateSubscription]', e);
+ return res.status(500).json({ success: false, message: 'Internal server error' });
+ }
+ },
+
async listMembers(req, res) {
try {
const { id } = req.params || {};
@@ -101,5 +135,62 @@ module.exports = {
console.error('[PoolController.removeMembers]', e);
return res.status(500).json({ success: false, message: 'Internal server error' });
}
+ },
+
+ async inflowDiagnostics(req, res) {
+ try {
+ const invoiceId = Number(req.query?.invoiceId);
+ if (!Number.isFinite(invoiceId) || invoiceId <= 0) {
+ return res.status(400).json({ success: false, message: 'invoiceId is required and must be a positive number' });
+ }
+
+ const data = await PoolInflowService.getInvoiceInflowDiagnostics({
+ invoiceId,
+ paidAt: req.query?.paidAt,
+ });
+
+ return res.status(200).json({ success: true, data });
+ } catch (e) {
+ console.error('[PoolController.inflowDiagnostics]', e);
+ return res.status(500).json({ success: false, message: 'Internal server error' });
+ }
+ },
+
+ async poolStats(req, res) {
+ try {
+ const poolId = Number(req.params?.id);
+ if (!Number.isFinite(poolId) || poolId <= 0) {
+ return res.status(400).json({ success: false, message: 'Invalid pool ID' });
+ }
+
+ const db = require('../../database/database');
+ const now = new Date();
+ const yearStart = new Date(now.getFullYear(), 0, 1).toISOString().slice(0, 10);
+ const monthStart = new Date(now.getFullYear(), now.getMonth(), 1).toISOString().slice(0, 10);
+
+ const [[totals]] = await db.query(
+ `SELECT
+ COALESCE(SUM(amount_net), 0) AS total_amount,
+ COALESCE(SUM(CASE WHEN created_at >= ? THEN amount_net ELSE 0 END), 0) AS amount_this_year,
+ COALESCE(SUM(CASE WHEN created_at >= ? THEN amount_net ELSE 0 END), 0) AS amount_this_month,
+ COUNT(*) AS total_inflows
+ FROM pool_inflows
+ WHERE pool_id = ?`,
+ [yearStart, monthStart, poolId]
+ );
+
+ return res.status(200).json({
+ success: true,
+ data: {
+ total_amount: Number(totals?.total_amount ?? 0),
+ amount_this_year: Number(totals?.amount_this_year ?? 0),
+ amount_this_month: Number(totals?.amount_this_month ?? 0),
+ total_inflows: Number(totals?.total_inflows ?? 0),
+ },
+ });
+ } catch (e) {
+ console.error('[PoolController.poolStats]', e);
+ return res.status(500).json({ success: false, message: 'Internal server error' });
+ }
}
};
\ No newline at end of file
diff --git a/controller/referral/ReferralRegistrationController.js b/controller/referral/ReferralRegistrationController.js
index d3de7dd..e922ab1 100644
--- a/controller/referral/ReferralRegistrationController.js
+++ b/controller/referral/ReferralRegistrationController.js
@@ -1,7 +1,10 @@
const UnitOfWork = require('../../database/UnitOfWork');
const ReferralService = require('../../services/referral/ReferralService');
+const AbonemmentService = require('../../services/abonemments/AbonemmentService');
const { logger } = require('../../middleware/logger');
+const abonemmentService = new AbonemmentService();
+
class ReferralRegistrationController {
static async getReferrerInfo(req, res) {
const { token } = req.params;
@@ -53,6 +56,7 @@ class ReferralRegistrationController {
{ ...registrationData, lang }, refToken, unitOfWork
);
await unitOfWork.commit();
+ await abonemmentService.linkGiftFlagsToUser(user.email, user.id);
logger.info('ReferralRegistrationController:registerPersonalReferral:success', { userId: user.id, email: user.email });
res.json({ success: true, userId: user.id, email: user.email });
} catch (error) {
@@ -97,6 +101,7 @@ class ReferralRegistrationController {
lang
}, refToken, unitOfWork);
await unitOfWork.commit();
+ await abonemmentService.linkGiftFlagsToUser(user.email, user.id);
logger.info('ReferralRegistrationController:registerCompanyReferral:success', { userId: user.id, email: user.email });
res.json({ success: true, userId: user.id, email: user.email });
} catch (error) {
diff --git a/controller/register/CompanyRegisterController.js b/controller/register/CompanyRegisterController.js
index 1ac6615..d07e59e 100644
--- a/controller/register/CompanyRegisterController.js
+++ b/controller/register/CompanyRegisterController.js
@@ -1,6 +1,9 @@
const CompanyUserService = require('../../services/user/company/CompanyUserService');
+const AbonemmentService = require('../../services/abonemments/AbonemmentService');
const { logger } = require('../../middleware/logger'); // add logger import
+const abonemmentService = new AbonemmentService();
+
class CompanyRegisterController {
static async register(req, res) {
logger.info('CompanyRegisterController.register:start');
@@ -69,6 +72,8 @@ class CompanyRegisterController {
contactPersonPhone,
password
});
+
+ await abonemmentService.linkGiftFlagsToUser(companyEmail, newCompany.id);
logger.info('CompanyRegisterController.register:success', { companyId: newCompany.id });
console.log('✅ Company user created successfully:', {
diff --git a/controller/register/GuestRegisterController.js b/controller/register/GuestRegisterController.js
new file mode 100644
index 0000000..ad9174d
--- /dev/null
+++ b/controller/register/GuestRegisterController.js
@@ -0,0 +1,77 @@
+const GuestUserService = require('../../services/user/guest/GuestUserService');
+const AbonemmentService = require('../../services/abonemments/AbonemmentService');
+const { logger } = require('../../middleware/logger');
+
+const abonemmentService = new AbonemmentService();
+
+class GuestRegisterController {
+ static async register(req, res) {
+ logger.info('GuestRegisterController.register:start');
+ try {
+ const {
+ firstName,
+ lastName,
+ email,
+ confirmEmail,
+ password,
+ confirmPassword,
+ referralEmail,
+ lang,
+ } = req.body;
+
+ if (!email || !password || !firstName || !lastName) {
+ return res.status(400).json({
+ success: false,
+ message: 'firstName, lastName, email, and password are required',
+ });
+ }
+
+ if (email !== confirmEmail) {
+ return res.status(400).json({
+ success: false,
+ message: 'Email and confirm email do not match',
+ });
+ }
+
+ if (password !== confirmPassword) {
+ return res.status(400).json({
+ success: false,
+ message: 'Password and confirm password do not match',
+ });
+ }
+
+ const newUser = await GuestUserService.createGuestUser({
+ email,
+ password,
+ firstName,
+ lastName,
+ referralEmail,
+ lang,
+ });
+
+ logger.info('GuestRegisterController.register:success', { userId: newUser.id });
+
+ res.status(201).json({
+ success: true,
+ message: 'Guest user registered successfully',
+ userId: newUser.id,
+ });
+ } catch (error) {
+ logger.error('GuestRegisterController.register:error', { error: error.message });
+
+ if (error.message === 'User already exists') {
+ return res.status(400).json({
+ success: false,
+ message: 'User already exists',
+ });
+ }
+
+ res.status(500).json({
+ success: false,
+ message: 'Internal server error',
+ });
+ }
+ }
+}
+
+module.exports = GuestRegisterController;
diff --git a/controller/register/PersonalRegisterController.js b/controller/register/PersonalRegisterController.js
index 6bd43c6..8bad8a9 100644
--- a/controller/register/PersonalRegisterController.js
+++ b/controller/register/PersonalRegisterController.js
@@ -1,6 +1,9 @@
const PersonalUserService = require('../../services/user/personal/PersonalUserService');
+const AbonemmentService = require('../../services/abonemments/AbonemmentService');
const { logger } = require('../../middleware/logger'); // add logger import
+const abonemmentService = new AbonemmentService();
+
class PersonalRegisterController {
static async register(req, res) {
logger.info('PersonalRegisterController.register:start');
@@ -69,6 +72,8 @@ class PersonalRegisterController {
password,
referralEmail
});
+
+ await abonemmentService.linkGiftFlagsToUser(email, newUser.id);
logger.info('PersonalRegisterController.register:success', { userId: newUser.id });
console.log('✅ Personal user created successfully:', {
diff --git a/database/createDb.js b/database/createDb.js
index 2968827..eae39d3 100644
--- a/database/createDb.js
+++ b/database/createDb.js
@@ -54,6 +54,14 @@ if (NODE_ENV === 'development') {
const allowCreateDb = String(process.env.DB_ALLOW_CREATE_DB || 'false').toLowerCase() === 'true';
+const SYSTEM_POOLS = [
+ { pool_name: 'ABO 60', description: 'System pool for ABO 60 capsule distribution', price: 0.01, pool_type: 'coffee', price_per_capsule_gross: 0.01 },
+ { pool_name: 'ABO 120', description: 'System pool for ABO 120 capsule distribution', price: 0.01, pool_type: 'coffee', price_per_capsule_gross: 0.01 },
+ { pool_name: 'Business', description: 'System pool for Business capsule distribution', price: 0.02, pool_type: 'other', price_per_capsule_gross: 0.02 },
+ { pool_name: 'Gigantea', description: 'System pool for Gigantea capsule distribution', price: 0.02, pool_type: 'other', price_per_capsule_gross: 0.02 },
+ { pool_name: 'Core', description: 'Every member receives 1 cent per capsule sold — the amount multiplies with each member, not divided.', price: 0.01, pool_type: 'other', price_per_capsule_gross: 0.01 },
+];
+
// --- Performance Helpers ---
async function ensureIndex(conn, table, indexName, indexDDL) {
const [rows] = await conn.query(`SHOW INDEX FROM \`${table}\` WHERE Key_name = ?`, [indexName]);
@@ -160,7 +168,7 @@ const createDatabase = async () => {
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
user_type ENUM('personal', 'company') NOT NULL,
- role ENUM('user', 'admin', 'super_admin') DEFAULT 'user',
+ role ENUM('user', 'admin', 'super_admin', 'guest') DEFAULT 'user',
iban VARCHAR(34),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
@@ -172,6 +180,17 @@ const createDatabase = async () => {
`);
console.log('✅ Users table created/verified');
+ // Migrate existing role ENUM to include 'guest'
+ try {
+ await connection.query(`
+ ALTER TABLE users
+ MODIFY COLUMN role ENUM('user', 'admin', 'super_admin', 'guest') DEFAULT 'user'
+ `);
+ console.log('✅ Updated users.role column to include guest');
+ } catch (err) {
+ console.warn('⚠️ Could not modify users.role column:', err.message);
+ }
+
// 2. personal_profiles table: Details specific to personal users
await connection.query(`
CREATE TABLE IF NOT EXISTS personal_profiles (
@@ -418,6 +437,22 @@ const createDatabase = async () => {
`);
console.log('✅ Document templates table created/verified');
+ await connection.query(`
+ CREATE TABLE IF NOT EXISTS no_user_abo_mails (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ email VARCHAR(255) NOT NULL,
+ abonement_id INT NOT NULL,
+ status ENUM('pending','linked') DEFAULT 'pending',
+ source VARCHAR(50) DEFAULT 'subscribe',
+ created_by_user_id INT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ UNIQUE KEY uq_no_user_abo_email_abonement (email, abonement_id),
+ INDEX idx_no_user_abo_email_status (email, status)
+ );
+ `);
+ console.log('✅ no_user_abo_mails table created/verified');
+
// 8b. user_id_documents table: Stores ID-specific metadata (front/back object storage IDs)
await connection.query(`
CREATE TABLE IF NOT EXISTS user_id_documents (
@@ -681,6 +716,24 @@ const createDatabase = async () => {
`);
console.log('✅ User settings table created/verified');
+ // --- Company Settings (single-row, global invoice / company info) ---
+ await connection.query(`
+ CREATE TABLE IF NOT EXISTS company_settings (
+ id INT PRIMARY KEY DEFAULT 1,
+ company_name VARCHAR(200) NOT NULL DEFAULT 'ProfitPlanet GmbH',
+ company_street VARCHAR(255) NOT NULL DEFAULT '',
+ company_postal_city VARCHAR(255) NOT NULL DEFAULT '',
+ company_country VARCHAR(100) NOT NULL DEFAULT 'Germany',
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CHECK (id = 1)
+ );
+ `);
+ // Seed default row if missing
+ await connection.query(`
+ INSERT IGNORE INTO company_settings (id) VALUES (1);
+ `);
+ console.log('✅ Company settings table created/verified');
+
// --- Rate Limiting Table ---
await connection.query(`
CREATE TABLE IF NOT EXISTS rate_limit (
@@ -836,6 +889,38 @@ const createDatabase = async () => {
`);
console.log('✅ Coffee abonements table updated');
+ // Ownership columns for "self" and "gift" subscriptions
+ await addColumnIfMissing(
+ connection,
+ 'coffee_abonements',
+ 'user_id',
+ `INT NULL AFTER referred_by`
+ );
+ await addColumnIfMissing(
+ connection,
+ 'coffee_abonements',
+ 'purchaser_user_id',
+ `INT NULL AFTER user_id`
+ );
+
+ await ensureIndex(connection, 'coffee_abonements', 'idx_abon_user_id', '`user_id`');
+ await ensureIndex(connection, 'coffee_abonements', 'idx_abon_purchaser_user_id', '`purchaser_user_id`');
+
+ await addForeignKeyIfMissing(
+ connection,
+ 'coffee_abonements',
+ 'fk_abon_user',
+ `ALTER TABLE \`coffee_abonements\`
+ ADD CONSTRAINT \`fk_abon_user\` FOREIGN KEY (\`user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE SET NULL ON UPDATE CASCADE`
+ );
+ await addForeignKeyIfMissing(
+ connection,
+ 'coffee_abonements',
+ 'fk_abon_purchaser_user',
+ `ALTER TABLE \`coffee_abonements\`
+ ADD CONSTRAINT \`fk_abon_purchaser_user\` FOREIGN KEY (\`purchaser_user_id\`) REFERENCES \`users\`(\`id\`) ON DELETE SET NULL ON UPDATE CASCADE`
+ );
+
// --- Coffee Abonement History ---
await connection.query(`
CREATE TABLE IF NOT EXISTS coffee_abonement_history (
@@ -1013,6 +1098,7 @@ const createDatabase = async () => {
pool_name VARCHAR(255) NOT NULL,
description TEXT NULL,
price DECIMAL(10,2) NOT NULL DEFAULT 0.00,
+ subscription_coffee_id BIGINT NULL,
pool_type ENUM('coffee','other') NOT NULL DEFAULT 'other',
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_by INT NULL,
@@ -1020,14 +1106,96 @@ const createDatabase = async () => {
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT uq_pools_name UNIQUE (pool_name),
+ CONSTRAINT fk_pools_subscription_coffee FOREIGN KEY (subscription_coffee_id) REFERENCES coffee_table(id) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT fk_pools_created_by FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT fk_pools_updated_by FOREIGN KEY (updated_by) REFERENCES users(id) ON DELETE SET NULL ON UPDATE CASCADE,
INDEX idx_pools_active (is_active),
- INDEX idx_pools_type (pool_type)
+ INDEX idx_pools_type (pool_type),
+ INDEX idx_pools_subscription_coffee (subscription_coffee_id)
);
`);
console.log('✅ Pools table created/verified');
+ // Backward-compatible migration for existing pools table
+ await addColumnIfMissing(connection, 'pools', 'subscription_coffee_id', `BIGINT NULL`);
+ await ensureIndex(connection, 'pools', 'idx_pools_subscription_coffee', '`subscription_coffee_id`');
+ await addForeignKeyIfMissing(
+ connection,
+ 'pools',
+ 'fk_pools_subscription_coffee',
+ `
+ ALTER TABLE pools
+ ADD CONSTRAINT fk_pools_subscription_coffee FOREIGN KEY (subscription_coffee_id)
+ REFERENCES coffee_table(id) ON DELETE SET NULL ON UPDATE CASCADE
+ `
+ );
+
+ await connection.query(`
+ CREATE TABLE IF NOT EXISTS pool_capsule_rules (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ pool_id INT NOT NULL,
+ price_per_capsule_gross DECIMAL(10,4) NOT NULL,
+ applies_to_all_capsules TINYINT(1) NOT NULL DEFAULT 1,
+ is_active TINYINT(1) NOT NULL DEFAULT 1,
+ created_by INT NULL,
+ updated_by INT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CONSTRAINT uq_pool_capsule_rules_pool UNIQUE (pool_id),
+ CONSTRAINT fk_pool_capsule_rules_pool FOREIGN KEY (pool_id) REFERENCES pools(id) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT fk_pool_capsule_rules_created_by FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT fk_pool_capsule_rules_updated_by FOREIGN KEY (updated_by) REFERENCES users(id) ON DELETE SET NULL ON UPDATE CASCADE,
+ INDEX idx_pool_capsule_rules_active (is_active)
+ );
+ `);
+ console.log('✅ pool_capsule_rules table created/verified');
+
+ for (const cfg of SYSTEM_POOLS) {
+ await connection.query(
+ `INSERT INTO pools (pool_name, description, price, subscription_coffee_id, pool_type, is_active, created_by, updated_by)
+ VALUES (?, ?, ?, NULL, ?, 1, NULL, NULL)
+ ON DUPLICATE KEY UPDATE
+ description = VALUES(description),
+ price = VALUES(price),
+ subscription_coffee_id = NULL,
+ pool_type = VALUES(pool_type),
+ is_active = 1,
+ updated_by = NULL,
+ updated_at = NOW()`,
+ [cfg.pool_name, cfg.description, cfg.price, cfg.pool_type]
+ );
+
+ const [poolRows] = await connection.query(
+ `SELECT id FROM pools WHERE pool_name = ? LIMIT 1`,
+ [cfg.pool_name]
+ );
+ const poolId = poolRows?.[0]?.id;
+ if (!poolId) continue;
+
+ await connection.query(
+ `INSERT INTO pool_capsule_rules (pool_id, price_per_capsule_gross, applies_to_all_capsules, is_active, created_by, updated_by)
+ VALUES (?, ?, 1, 1, NULL, NULL)
+ ON DUPLICATE KEY UPDATE
+ price_per_capsule_gross = VALUES(price_per_capsule_gross),
+ applies_to_all_capsules = 1,
+ is_active = 1,
+ updated_by = NULL,
+ updated_at = NOW()`,
+ [poolId, cfg.price_per_capsule_gross]
+ );
+ }
+
+ const systemPoolNames = SYSTEM_POOLS.map((x) => x.pool_name);
+ const systemPoolPlaceholders = systemPoolNames.map(() => '?').join(',');
+ await connection.query(
+ `UPDATE pools
+ SET is_active = 0,
+ updated_at = NOW()
+ WHERE pool_name NOT IN (${systemPoolPlaceholders})`,
+ systemPoolNames
+ );
+ console.log('✅ System pools synchronized (ABO 60, ABO 120, Business, Gigantea, Core)');
+
await connection.query(`
CREATE TABLE IF NOT EXISTS pool_members (
id INT AUTO_INCREMENT PRIMARY KEY,
@@ -1046,6 +1214,94 @@ const createDatabase = async () => {
`);
console.log('✅ pool_members table created/verified');
+ // Track sold capsules per paid invoice as calculation basis for pools
+ await connection.query(`
+ CREATE TABLE IF NOT EXISTS capsule_sales (
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
+ invoice_id BIGINT NOT NULL,
+ abonement_id BIGINT NOT NULL,
+ coffee_table_id BIGINT NOT NULL,
+ capsules_count INT NOT NULL,
+ sold_at DATETIME NOT NULL,
+ currency CHAR(3) NOT NULL DEFAULT 'EUR',
+ details JSON NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ CONSTRAINT fk_capsule_sales_invoice FOREIGN KEY (invoice_id) REFERENCES invoices(id) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT fk_capsule_sales_abon FOREIGN KEY (abonement_id) REFERENCES coffee_abonements(id) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT fk_capsule_sales_coffee FOREIGN KEY (coffee_table_id) REFERENCES coffee_table(id) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT uq_capsule_sales_invoice_coffee UNIQUE (invoice_id, coffee_table_id),
+ INDEX idx_capsule_sales_invoice (invoice_id),
+ INDEX idx_capsule_sales_abon (abonement_id),
+ INDEX idx_capsule_sales_sold_at (sold_at)
+ );
+ `);
+ console.log('✅ capsule_sales table created/verified');
+
+ // Track money inflow into pools from subscriptions/invoices
+ await connection.query(`
+ CREATE TABLE IF NOT EXISTS pool_inflows (
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
+ pool_id INT NOT NULL,
+ invoice_id BIGINT NULL,
+ abonement_id BIGINT NOT NULL,
+ coffee_table_id BIGINT NOT NULL,
+ event_type ENUM('invoice_paid','subscription_created','renewal_paid','manual_adjustment') NOT NULL DEFAULT 'invoice_paid',
+ capsules_count INT NOT NULL,
+ price_per_capsule_net DECIMAL(10,4) NOT NULL,
+ amount_net DECIMAL(12,2) NOT NULL,
+ currency CHAR(3) NOT NULL DEFAULT 'EUR',
+ details JSON NULL,
+ created_by_user_id INT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ CONSTRAINT fk_pool_inflows_pool FOREIGN KEY (pool_id) REFERENCES pools(id) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT fk_pool_inflows_invoice FOREIGN KEY (invoice_id) REFERENCES invoices(id) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT fk_pool_inflows_abon FOREIGN KEY (abonement_id) REFERENCES coffee_abonements(id) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT fk_pool_inflows_coffee FOREIGN KEY (coffee_table_id) REFERENCES coffee_table(id) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT fk_pool_inflows_created_by FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT uq_pool_inflow_invoice_event UNIQUE (pool_id, invoice_id, coffee_table_id, event_type),
+ INDEX idx_pool_inflows_pool_created (pool_id, created_at),
+ INDEX idx_pool_inflows_abon (abonement_id),
+ INDEX idx_pool_inflows_invoice (invoice_id)
+ );
+ `);
+ console.log('✅ pool_inflows table created/verified');
+
+ // Backward-compatible migration for existing pool_inflows table
+ await addColumnIfMissing(connection, 'pool_inflows', 'invoice_id', `BIGINT NULL`);
+ await ensureIndex(connection, 'pool_inflows', 'idx_pool_inflows_invoice', '`invoice_id`');
+ await addForeignKeyIfMissing(
+ connection,
+ 'pool_inflows',
+ 'fk_pool_inflows_invoice',
+ `
+ ALTER TABLE pool_inflows
+ ADD CONSTRAINT fk_pool_inflows_invoice FOREIGN KEY (invoice_id)
+ REFERENCES invoices(id) ON DELETE CASCADE ON UPDATE CASCADE
+ `
+ );
+ try {
+ await connection.query(`
+ ALTER TABLE pool_inflows
+ MODIFY COLUMN event_type ENUM('invoice_paid','subscription_created','renewal_paid','manual_adjustment') NOT NULL DEFAULT 'invoice_paid'
+ `);
+ } catch (e) {
+ console.log('ℹ️ pool_inflows.event_type enum alignment skipped:', e.message);
+ }
+ try {
+ await connection.query(`ALTER TABLE pool_inflows DROP INDEX uq_pool_inflow_event`);
+ } catch (e) {
+ console.log('ℹ️ old pool inflow unique index drop skipped:', e.message);
+ }
+ try {
+ await connection.query(`
+ ALTER TABLE pool_inflows
+ ADD CONSTRAINT uq_pool_inflow_invoice_event UNIQUE (pool_id, invoice_id, coffee_table_id, event_type)
+ `);
+ } catch (e) {
+ console.log('ℹ️ new pool inflow unique index creation skipped:', e.message);
+ }
+
// --- user_matrix_metadata: add matrix_instance_id + alter PK ---
await connection.query(`
CREATE TABLE IF NOT EXISTS user_matrix_metadata (
diff --git a/debug-pdf/template_1_html_full.html b/debug-pdf/template_1_html_full.html
new file mode 100644
index 0000000..2765e05
--- /dev/null
+++ b/debug-pdf/template_1_html_full.html
@@ -0,0 +1,155 @@
+
+
+
+
+
+ Invoice {{invoiceNumber}}
+
+
+
+
+
+
+
+
+
+
+
+
+ | Item |
+ Qty |
+ Unit Net |
+ Line Net |
+
+
+
+ {{itemsHtml}}
+
+
+
+
+
+ Total Net
+ {{totalNet}}
+
+
+ Total Tax
+ {{totalTax}}
+
+
+ Total Gross
+ {{totalGross}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/debug-pdf/template_1_html_raw.bin b/debug-pdf/template_1_html_raw.bin
new file mode 100644
index 0000000..2765e05
--- /dev/null
+++ b/debug-pdf/template_1_html_raw.bin
@@ -0,0 +1,155 @@
+
+
+
+
+
+ Invoice {{invoiceNumber}}
+
+
+
+
+
+
+
+
+
+
+
+
+ | Item |
+ Qty |
+ Unit Net |
+ Line Net |
+
+
+
+ {{itemsHtml}}
+
+
+
+
+
+ Total Net
+ {{totalNet}}
+
+
+ Total Tax
+ {{totalTax}}
+
+
+ Total Gross
+ {{totalGross}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/debug-pdf/template_1_sanitized_preview.html b/debug-pdf/template_1_sanitized_preview.html
new file mode 100644
index 0000000..b77f2f2
--- /dev/null
+++ b/debug-pdf/template_1_sanitized_preview.html
@@ -0,0 +1,209 @@
+
+
+
+
+
+ VERTRIEBSPARTNER / BUSINESSPARTNER / AFFILIATE - VERTRAG
+
+
+
+
+
+
VERTRIEBSPARTNER / BUSINESSPARTNER / AFFILIATE - VERTRAG
+
idF 21.05.2025
+
abgeschlossen zwischen
+
Profit Planet GmbH (kurz PROFIT PLANET)
FN 649474i
Liebenauer Hauptstraße 82c
A-8041 Graz
+
und
+
Vertriebspartner / Businesspartner / Affiliate (kurz VP)
+
+
1. Präambel und Vertragsgegenstand
+
1.1. Dieser Vertrag regelt die Zusammenarbeit zwischen PROFIT PLANET und VP als Grundlage einer fairen, langfristigen und erfolgreichen Kooperation. Die VP unterstützen einander im Sinne der Ziele der Zusammenarbeit und unterrichten sich gegenseitig über alle Vorgänge, die für ihre Leistungen im Rahmen der Kooperation von Interesse sind.
+
1.2. PROFIT PLANET bietet über ein Vertriebspartner / Businesspartner / Affiliate-Netzwerk den Vertrieb verschiedener Dienstleistungen und Produkte, vornehmlich aus den Bereichen Nachhaltigkeit, Energie, Handel sowie Consulting und Coaching an.
+
1.3. Der VP vermittelt die jeweiligen Dienstleistungen, Produkte oder qualifizierten Leads, die zu einem Abschluss führen, und erhält dafür eine Provision. Für die Tätigkeit als VP ist es nicht erforderlich, weitere VP zu werben.
+
1.4. Der VP ist berechtigt, weitere Vertriebspartner / Businesspartner / Affiliate für den Vertrieb der Dienstleistungen und Produkte zu gewinnen. Für die Vermittlung und Betreuung der von ihm akquirierten Vertriebspartner / Businesspartner / Affiliate erhält der werbende VP eine Provision, die sich aus den erwirtschafteten Umsätzen der geworbenen VP ermittelt. Die Höhe der Provision ergibt sich aus der Provisionsübersicht.
+
1.5. Die Vertragsabschlüsse kommen nur zwischen dem Endkunden und dem jeweiligen Dienstleister und/oder Produktgeber (Energieversorgungs-, Handels-, Dienstleistungs- oder Coachingunternehmen) zustande, ohne dass dadurch eine Vertragsbeziehung zwischen dem VP und dem Endkunden entsteht. Ein Anspruch auf Abschluss des jeweiligen Vertrags seitens des Endkunden gegenüber PROFIT PLANET oder dem VP entsteht nicht; der Vertragsabschluss ist von der Annahme des entsprechenden Antrags durch den Dienstleister bzw. Produktgeber abhängig. PROFIT PLANET hat darauf keinen Einfluss.
+
1.6. PROFIT PLANET behält sich vor, die angebotenen Produkte zurückzuziehen, zu ändern, neue hinzuzufügen oder sonstige Anpassungen des Produktangebots vorzunehmen. PROFIT PLANET wird den VP über Änderungen von Produkten oder Tarifen nach Maßgabe der Möglichkeiten rechtzeitig vor Wirksamkeit der Änderungen informieren.
+
1.7. Die genauen Produktbestandteile und Konditionen ergeben sich aus dem jeweiligen Produktpartnerinformationsblatt, welches auf der Online-Plattform hinterlegt wird.
+
1.8. PROFIT PLANET ist berechtigt, nach eigenem Ermessen andere Personen und Unternehmen mit der Vermittlung von Produkten und Dienstleistungen von PROFIT PLANET bzw. Produktpartnern von PROFIT PLANET zu beauftragen. Es bestehen grundsätzlich keine Alleinvermittlungsaufträge und keine Exklusivität.
+
+
2. Vertriebspartner / Businesspartner / Affiliate werden
+
2.1. Kapitalgesellschaften, Personengesellschaften und volljährige natürliche Personen können Vertriebspartner / Businesspartner / Affiliate des PROFIT PLANET werden; pro Entität ist die Registrierung nur eines VP-Vertrags vorgesehen. Natürliche Personen, die bloß als Verbraucher handeln (wollen), können nicht Vertriebspartner / Businesspartner / Affiliate von PROFIT PLANET werden.
+
2.2. Kapitalgesellschaften müssen ihrem VP-Antrag die Firmenbuchnummer und gegebenenfalls die Umsatzsteuer-Identifikationsnummer (UID) beilegen. Der Antrag muss von allen Zeichnungsbereichten der Gesellschaft derart gezeichnet werden, dass eine rechtwirksame Vertretung sichergestellt ist. Die Gesellschafter haften gegenüber PROFIT PLANET jeweils persönlich für das Verhalten der Gesellschaft.
+
2.3. Absatz 2.2 gilt inhaltsgemäß auch für Personengesellschaften.
+
2.4. Der VP ist verpflichtet, Änderungen seiner unternehmens- oder personenbezogenen Daten unverzüglich an PROFIT PLANET zu melden.
+
2.5. Für die Verwendung des Online-Systems gelten die allgemeinen Geschäftsbedingungen.
+
2.6. PROFIT PLANET kann Vertriebspartner / Businesspartner / Affiliate ohne Angabe von Gründen ablehnen.
+
+
3. Leistungen / Pflichten des VP
+
3.1. Der VP handelt unabhängig als selbständiger Unternehmer, er ist weder Arbeitnehmer noch Handelsvertreter oder Makler von PROFIT PLANET. Er ist bei der Vermittlung von Produktverträgen eigenverantwortlich tätig, handelt abgesehen von den Pflichten aus diesem Vertrag frei von Weisungen und ist nicht mit der ständigen Vermittlung von Geschäften betraut. Es bestehen seitens PROFIT PLANET keine Umsatzvorgaben und keine Abnahme- oder Vertriebspflichten. Der VP trägt alle mit der Kundenakquisition verbundenen Kosten und Risiken selbst und verwendet eigene Betriebsmittel. Er stellt im geschäftlichen Verkehr klar, dass er nicht im Auftrag oder im Namen von PROFIT PLANET handelt, sondern als unabhängiger Vertriebspartner / Businesspartner / Affiliate.
+
3.2. Der VP betreibt sein Unternehmen mit der Sorgfalt eines ordentlichen Kaufmanns und ist für die Einhaltung aller gesetzlichen sowie der steuer- und sozialrechtlichen Vorgaben selbst verantwortlich.
+
3.3. Der VP hält sich insbesondere auch an das Wettbewerbsrecht und nimmt Abstand von ungenehmigter, irreführender oder sonst unlauterer Werbung. Der VP verpflichtet sich auch, falsche oder irreführende Aussagen über Dienstleistungen, Produkte und Vertriebssystem der PROFIT PLANET zu unterlassen.
+
3.4. Grundsätzlich steht es dem VP frei, Produkte / Dienstleistungen auch für andere Unternehmen zu vertreiben. Falls es allerdings in der Zusammenarbeit mit einem anderen Dienstleister oder Produktgeber in räumlicher oder zeitlicher Nähe zu Überschneidungen im Vertrieb, insbesondere bei Terminisierungen, Promotion-Auftritten (POS) oder anderen dienstleistungs- oder produktspezifischen Werbetätigkeiten kommen, so wäre dies nur nach ausdrücklicher Zustimmung durch PROFIT PLANET zulässig.
+
3.5. Beim Abschluss von Kundenverträgen ist der VP verpflichtet, die von PROFIT PLANET zur Verfügung gestellten Originalunterlagen (zB Antragsformulare, AGB, sonstige Unterlagen der Dienstleister oder Produktgeber) in der jeweils aktuellen Version zu verwenden und dem Kunden bei Vertragsabschluss vorzulegen bzw. auszuhändigen. Die Originalunterlagen sind durch den VP nicht zu verändern, missbräuchliche Verwendung ist zu verhindern.
+
3.6. Kundenverträge in Papierform sind vom VP unverzüglich, spätestens jedoch binnen 1 Woche nach Aufforderung durch PROFIT PLANET oder den Produktgeber an PROFIT PLANET auszuhändigen.
+
3.7. Sämtliche Präsentations-, Werbe- und Schulungsmaterialien sowie label von PROFIT PLANET sind urheberrechtlich geschützt und dürfen ohne ausdrückliches Einverständnis von PROFIT PLANET weder ganz noch teilweise vervielfältigt, verbreitet oder öffentlich zugänglich gemacht werden. Die Herstellung, Verwendung und Verbreitung eigener Werbemittel, Schulungsmaterialien oder Produktbroschüren ist nur nach schriftlicher Genehmigung und Freigabe durch PROFIT PLANET gestattet.
+
3.8. Der VP ist während der Dauer dieser Vereinbarung und für die Dauer von 36 Monaten nach Beendigung dieses Vertrags aus welchem Grund immer, nicht berechtigt, unmittelbar selbst bzw. mittelbar über Dritte Kunden von PROFIT PLANET und ihrer Produktpartner, einschließlich der vom VP vermittelten Endkunden, durch direkte Ansprache abzuwerben. Als Abwerben gilt jede Form des direkten Herantretens an den Kunden mit der Absicht, ihn zum Wechsel zu einem anderen Energieversorgungs-, Dienstleistungs-, Handels-, und/oder Coachingunternehmen zu bewegen (beispielsweise etwa durch Anrufe beim Kunden, Direktmailing mit Absicht der Abwerbung, Haustürgeschäfte etc.).
+
4. Geheimhaltung
+
4.1. Der VP verpflichtet sich, Geschäfts- und Betriebsgeheimnisse und sonstige vertrauliche Informationen von PROFIT PLANET und dessen Struktur, Geschäftspartner, Vertriebspartner / Businesspartner / Affiliate, Produktgeber, Provisionen und Endkunden unter äußerster Geheimhaltung zu behandeln und zu verwahren und diese Daten nur nach erfolgter schriftlicher Zustimmung durch den PROFIT PLANET an Dritte weiterzugeben.
+
4.2. Diese Verpflichtung gilt auch für Mitarbeiter und Unter-Vertriebspartner / Businesspartner / Affiliate des VP. Der VP hat für das Verhalten allfälliger Erfüllungsgehilfen und/oder Subpartner einzustehen.
+
4.3. Zu den Geschäftsgeheimnissen gehören insbesondere auch Informationen zu internen Betriebsabläufen, Provisionen und Provisionsstrukturen, Produkt- und Preiskalkulationen, Vertriebspartner / Businesspartner / Affiliate-strukturen und -aktivitäten.
+
4.4. Dem VP ist es nicht gestattet, auf Presseanfragen zu PROFIT PLANET, dessen Provisionspläne, Produkte oder andere Leistungen zu antworten. Presseanfragen sind immer an PROFIT PLANET weiterzuleiten.
+
5. Datenschutz
+
5.1. Die Vertragspartner sind verpflichtet, die gesetzlichen Datenschutzbestimmungen vollumfänglich einzuhalten. Für Verstöße gegen datenschutzrechtliche Schutzbestimmungen haftet ausschließlich der jeweils die Bestimmung verletzende Vertragspartner, dieser wird den schuldlos handelnden Vertragspartner von allen entsprechenden Ansprüchen freistellen und schad- und klaglos halten.
+
5.2. Im Regelfall ist der VP ist hinsichtlich der Daten der von ihm vermittelten Endkunden und Akquisitionskontakte Subauftragsverarbeiter im Sinne der Datenschutzgesetze (DSG, DSGVO); PROFIT PLANET ist Auftragsverarbeiter im Sinne der DSGVO. Soweit durch die gesetzlichen Bestimmungen vorgesehen, werden zu dieser Vereinbarung entsprechende datenschutzrechtliche Zusatzverträge abgeschlossen.
+
5.3. PROFIT PLANET ist bezüglich der Daten des VP auf Datenschutz verpflichtet. Die Datenschutzerklärung ist Online jederzeit abrufbar.
+
6. VP-Schutz
+
6.1. Ein neu geworbener VP wird in die Struktur desjenigen VP zugewiesen, der ihn geworben hat (VP-Schutz). Wenn mehrere VP denselben VP neu melden, wird seitens PROFIT PLANET nur die zuerst erfolgte Meldung berücksichtigt, wobei das Eingangsdatum des Registrierungsantrags bei PROFIT PLANET für die Zuteilung maßgeblich ist.
+
6.2. Der meldende VP ist verantwortlich dafür, die Daten des geworbenen VP vollständig und ordentlich zu übermitteln. PROFIT PLANET ist berechtigt, die Daten eines geworbenen VP aus ihrem System zu löschen, wenn von diesem innerhalb einer angemessenen Frist keine Umsätze oder Rückmeldungen kommen.
+
6.3. Ein Wechsel von der Struktur eines VP in die eines anderen ist grundsätzlich ausgeschlossen und nur ausnahmsweise möglich, wenn der wechselwillige VP nachweist, dass der in der Struktur über ihm stehende VP versucht hat, ihn zu einem gesetzes- oder vertragswidrigen Verhalten zu veranlassen oder sonst schwerwiegende Vorfälle die weitere Zusammenarbeit in der Struktur dieses VP untragbar machen. Über einen entsprechenden schriftlichen Antrag entscheidet PROFIT PLANET nach freiem Ermessen.
+
6.4. Ein VP, der innerhalb der letzten 12 Monate bereits einen VP-Vertrag mit PROFIT PLANET hatte, kann nicht geworben werden.
+
6.5. Eine Umgehung des VP-Schutzes etwa durch Verwendung der Namen von Strohnamen, -personen oder -firmen ist untersagt.
+
6.6. PROFIT PLANET räumt ihren VP ausdrücklich keinen Gebietsschutz ein. Alle VP können europaweit ohne Einschränkungen tätig sein.
+
7. Provision
+
7.1. Für jedes vom VP erfolgreich vermittelte Vertragsverhältnis zwischen Produktgeber und Endkunden erwirbt der VP Anspruch auf Provision als Bearbeitungs- und Aufwandspauschale
+
7.2. Die Höhe der Provision richtet sich nach der jeweils aktuell gültigen Provisionsübersicht laut Marketingkonzept. Die jeweils gültige Fassung dieser Provisionsübersicht ist jederzeit auf der Website von PROFIT PLANET (www.profit-planet.com) im internen Bereich abrufbar, einsehbar, downloadbar und kann dort auch auf Anfrage zur Verfügung gestellt werden. Änderungen der Provisionsübersicht werden dem VP rechtzeitig bekannt gegeben. Es gelten jeweils die zum Zeitpunkt der Vermittlung gültigen Provisionssätze.
+
7.3. Als erfolgreiche Vermittlung im Sinne dieses Vertrages gilt, wenn das Vertragsverhältnis zwischen Endkunden und Produktpartner tatsächlich zustande gekommen ist. Insbesondere entsteht kein Provisionsanspruch, wenn
+
+ - der Kunde von seinen Widerrufs- oder Rücktrittsrechten Gebrauch macht,
+ - der Vertrag rechtswirksam angefochten wird,
+ - der Kunde vom Dienstleister oder Produktpartner aus welchem Grund auch immer nicht angenommen wird,
+ - fehlerhafte oder unvollständige Kundenanträge eingereicht werden,
+ - der Vertrag widerrechtlich zustande gekommen ist oder
+ - der Dienstleister oder Produktgeber die Auszahlung der Provision an PROFIT PLANET aus Gründen, die nicht von PROFIT PLANET zu verantworten sind, verweigert.
+
+
7.4. Anspruch auf Auszahlung der Provision entsteht gegenüber PROFIT PLANET grundsätzlich erst dann, wenn die Zahlungen seitens des Geschäftspartners / Produktgebers bei PROFIT PLANET eingelangt sind und alle sonstigen Auszahlungsvoraussetzungen vorliegen. Der VP nimmt zur Kenntnis, dass die exakten Zahlungsmodalitäten bei den verschiedenen Dienstleistern oder Produktgebern voneinander abweichen können und PROFIT PLANET diese Unterschiede bei der Auszahlung berücksichtigt. Die unterschiedlichen Zeitspannen divergieren je nach Partnerunternehmen derzeit durchschnittlich zwischen 30 bis 100 Tage. Die genauen Anforderungen und Konditionen ergeben sich aus dem jeweiligen Produktpartnerinformationsblatt und dem Marketingkonzept.
+
7.5. Die Auszahlung durch PROFIT PLANET erfolgt einmal monatlich, ungefähr um den 20. des auf den Zahlungseingang bei PROFIT PLANET folgenden Monats. Die Auszahlung erfolgt bargeldlos per Überweisung auf das vom VP genannte Konto. PROFIT PLANET kann Zahlungen bis zu einer Höhe von EUR 100,00 von der Auszahlung ausschließen (Mindestauszahlungshöhe); die nicht ausbezahlten Provisionsansprüche werden auf dem Provisionskonto des VP rechnerisch fortgeführt und im Folgemonat nach Erreichen der Mindestauszahlungshöhe ausbezahlt. Beträge unterhalb der Mindestauszahlungshöhe werden einmal jährlich zur Auszahlung gebracht.
+
7.6. Der Provisionsanspruch entfällt rückwirkend, wenn PROFIT PLANET, Provisionen an einen Produktgeber zurückzahlen muss, etwa weil ein Kunde den Vertrag widerruft oder andere Ausschlusskriterien seitens des Produktgebers vorliegen (Stornohaftung etc.). PROFIT PLANET ist berechtigt, Forderungen, die dem PROFIT PLANET gegen den VP zustehen, mit dessen Provisionsansprüchen ganz oder teilweise aufzurechnen.
+
7.7. Mit dieser Provision sind sämtliche Tätigkeiten des VP einschließlich aller ihm in Zusammenhang mit dieser Vereinbarung entstandenen Kosten, Auslagen und Aufwendungen, wie beispielsweise Fahrt- und Reisekosten, Bürokosten, Porto und Telefongebühren, abgegolten. Dasselbe gilt für Leistungen des VP in Hinblick auf Pflege und Herstellung eines VP-Bestandes und/oder Kundenstocks, sodass im Fall der Beendigung des Vertrags unbeachtet des Grundes der Auflösung keinesfalls Ansprüche auf Abfindungen oder Ausgleiche jedweder Art gegen PROFIT PLANET bestehen.
+
7.8. Fehlerhafte Provisionszahlungen oder sonstige Zahlungen sind vom VP binnen 60 Tagen schriftlich einzumahnen. Danach gelten die Zahlungen als genehmigt.
+
7.9. Wenn vom VP keine UID-Nummer bekannt gegeben wird, erfolgen alle Auszahlungen netto.
+
8. Vertragsstrafe, Schadenersatz
+
8.1. Bei einem ersten Verstoß gegen die in diesem Vertrag geregelten Pflichten durch den VP erfolgt eine schriftliche Abmahnung durch PROFIT PLANET. Die Pflichtverletzung ist unmittelbar zu beenden bzw. gegebenenfalls zu beheben.
+
8.2. Kommt es erneut zu einem Verstoß gegen diesen Vertrag oder wird der zuerst gemahnte Zustand nicht beseitigt, so verpflichtet sich der VP zur Zahlung einer verschuldensunabhängigen Vertragsstrafe für jeden jeweiligen Verstoß in Höhe von EUR 5.000,00.
+
8.3. Bei Verstößen gegen die Geheimhaltungs- und Datenschutzpflichten, sowie bei besonders schwerwiegenden Verstößen, insbesondere gegen Punkt 10.2 dieses Vertrags, ist PROFIT PLANET auch ohne vorhergehende Abmahnung zur Geltendmachung der jeweiligen Vertragsstrafe berechtigt.
+
8.4. Für jede Zuwiderhandlung gegen Punkt 3.8 verpflichtet sich der VP zur Zahlung einer verschuldens- und schadensunabhängigen Konventionalstrafe an den PROFIT PLANET von EUR 5.000,00 pro Verstoß (z.B. pro an ein anderes Unternehmen oder sonstigen Dritten vermittelten Vertrags oder pro abgeworbenen Kunden). Die Geltendmachung darüber hinausgehender sonstiger Schadenersatzansprüche, der Vertragsstrafe nach 8.2 oder etwa von Erfüllungsansprüchen bleibt dadurch unberührt.
+
8.5. Für jeden Verstoß gegen die in Punkt 4. dieses Vertrags (Geheimhaltungsverpflichtung) normierten Pflichten, verpflichtet sich der VP zur Zahlung einer verschuldensunabhängigen Vertragsstrafe in Höhe von EUR 7.000,00 pro Verstoß. Die Geltendmachung weitergehender zivilrechtlicher Ansprüche – insbesondere auf Unterlassung und Schadenersatz – bleibt davon unberührt.
+
8.6. Bei Handlungen, die dem Katalog außerordentlicher Kündigungsgründe gemäß Punkt 10.2 entsprechen, insbesondere bei treuwidrigem Verhalten im Sinne der dort beschriebenen Fallgruppen (z. B. unautorisierte Kaltakquise, rufschädigendes Verhalten, unbefugtes Auftreten im Namen von PROFIT PLANET), verpflichtet sich der VP zur Zahlung einer verschuldensunabhängigen Vertragsstrafe in Höhe von EUR 10.000,00 pro Verstoß. Auch in diesen Fällen bleiben darüber hinausgehende Ansprüche – insbesondere Schadenersatz oder außerordentliche Kündigung – ausdrücklich vorbehalten.
+
+
9. Haftungsausschluss
+
9.1. Der VP führt seine Tätigkeiten nach bestem Wissen und Gewissen und in eigener Verantwortung, insbesondere auch in Bezug auf die korrekte Beratung der Endkunden aus. Eine Haftungsübernahme von PROFIT PLANET für Falschberatungen oder sonstiges Fehlverhalten des VP ist explizit ausgeschlossen.
+
9.2. Für Schäden haftet PROFIT PLANET nur, soweit diese auf Vorsatz oder grober Fahrlässigkeit oder auf grob schuldhafter Verletzung einer wesentlichen Vertragspflicht durch PROFIT PLANET, ihrer Mitarbeiter oder Erfüllungsgehilfen beruhen.
+
9.3. Eine Haftung von PROFIT PLANET für mittelbare Schäden, Folgeschäden, entgangenen Gewinn oder erwartete Ersparnis ist jedenfalls ausgeschlossen.
+
9.4. PROFIT PLANET übernimmt keine Haftung für Schäden, die durch Datenverlust auf den Servern auftreten, außer der Schaden beruht auf Vorsatz oder grober Fahrlässigkeit seitens PROFIT PLANET, ihrer Mitarbeiter oder Erfüllungsgehilfen.
+
9.5. Der Eintritt eines Schadens ist PROFIT PLANET unverzüglich mitzuteilen.
+
10. Vertragsdauer & Kündigung
+
10.1. Der Vertrag tritt mit Unterzeichnung oder im Fall einer Online-Registrierung, Online mit der Annahme des Vertrags durch PROFIT PLANET in Kraft und wird auf unbestimmte Zeit geschlossen. Er kann von beiden Parteien unter Einhaltung einer Frist von drei Monaten zum Ende jedes Kalendermonats schriftlich gekündigt werden.
+
10.2. Dessen ungeachtet kann der Vertrag seitens PROFIT PLANET aus wichtigem Grund ohne Einhaltung einer Kündigungsfrist gekündigt werden. Das Recht zur außerordentlichen Kündigung besteht ungeachtet weiterer Ansprüche. Folgende Gründe berechtigen insbesondere zur außerordentlichen Kündigung, die Aufzählung ist nicht abschließend:
+
+ - Akte treuwidrigen Verhaltens, die eine weitere Zusammenarbeit zw. den Vertragspartnern unzumutbar machen;
+ - ein solches treuwidriges Verhalten liegt insbesondere etwa dann vor, wenn ein VP ohne ausdrückliche Zustimmung eines vertretungs- und zeichnungsbefugten Organs von PROFIT PLANET Handlungen setzt, welche nach außen den Anschein erwecken, im Namen oder Auftrag von PROFIT PLANET zu erfolgen – insbesondere etwa durch Kaltakquise, Verwendung von Geschäftsdrucksorten oder -signaturen, Auftritt unter Verwendung der Marke PROFIT PLANET oder vergleichbare ruf- bzw. imageschädigende Aktivitäten.
+ - die Anwendung unlauterer Praktiken oder ein grober oder wiederholter Verstoß gegen diesen Vertrag sowie der Verstoß gegen zwingende Rechtsnormen;
+ - wenn über das Vermögen des jeweils anderen Vertragspartners die Einleitung eines Insolvenzverfahrens beantragt oder wenn die Eröffnung eines Insolvenzverfahrens mangels Masse abgelehnt wird;
+ - Verletzung der vereinbarten oder gesetzlichen Datenschutz- oder Geheimhaltungspflichten;
+ - wenn die Kooperation durch das Verhalten eines Vertragspartners oder dessen Ruf in der Öffentlichkeit den anderen Vertragspartnern einen Imageschaden zufügen würde;
+ - wenn die Kooperation aufgrund der Gesetzeslage oder von dritter Seite als unzulässig untersagt wird;
+ - Unzulässige Nebenabsprachen mit am Vertrieb beteiligten Dritten;
+
+
10.3. Abgesehen von 10.2 kann PROFIT PLANET den VP auch außerordentlich kündigen, wenn dieser in den letzten 6 Monaten keine neuen Umsätze erzielt hat oder bei den durch seine Vermittlung zustande gekommenen Verträgen zwischen Endkunden und Produktgebern über einen Zeitraum von 2 Monaten überdurchschnittliche Stornoquoten von mehr als 30% der vermittelten Verträge bestehen. PROFIT PLANET wird den VP vor einer außerordentlichen Kündigung nach diesem Passus einmalig schriftlich verwarnen, so dass der VP die Möglichkeit hat, innerhalb einer Frist von 30 Tagen die erforderlichen neuen Umsätze zu generieren oder seine Stornoquote zu verbessern.
+
10.4. Mit der Beendigung des Vertrags steht dem VP mit Ausnahme der Provision für zu diesem Zeitpunkt bereits erfolgreich vermittelte Verträge, kein Recht auf Provision mehr zu. Ein Anspruch auf Handelsvertreterausgleich ist ausdrücklich ausgeschlossen, da der VP nicht als Handelsvertreter für den PROFIT PLANET tätig wird. Etwaige Ansprüche auf Folgeprovisionen für vermittelte Produkte bestehen für 12 Monate nach Vertragsbeendigung fort; im Falle einer außerordentlichen Kündigung verfallen Ansprüche auf Folgeprovisionen unmittelbar mit der Vertragsbeendigung.
+
10.5. Nach Beendigung des Vertrags sind vom VP sämtliche überlassenen Unterlagen und Werbematerialien unaufgefordert binnen einem Monat an PROFIT PLANET zurückzugeben. Die Verwendung der Marke PROFIT PLANET und entsprechender Logos etwa auf Briefpapier oder in E-Mail-Signaturen ist nach Beendigung des Vertrags untersagt.
+
11. Übertragung
+
11.1. PROFIT PLANET ist jederzeit berechtigt, den Geschäftsbetrieb ganz oder teilweise auf Dritte zu übertragen.
+
11.2. Der VP ist nur mit ausdrücklicher Zustimmung von PROFIT PLANET berechtigt, seine Vertriebsstruktur an einen Dritten zu übertragen.
+
11.3. Wenn eine als VP registrierte Kapital- oder Personengesellschaft einen neuen Gesellschafter aufnimmt, hat dies auf diesen Vertrag keine Auswirkung, sofern der/die Gesellschafter, die den VP-Antrag ursprünglich unterzeichnet haben, als Gesellschafter in der Gesellschaft verbleiben. Wenn ein Gesellschafter aus einer registrierten Gesellschaft ausscheidet oder seine Anteile an einen Dritten überträgt, so ist dies in Bezug auf diesen Vertrag zulässig, sofern er dies PROFIT PLANET schriftlich unter Vorlage der entsprechenden rechtsgültigen Urkunden anzeigt, und der Vorgang keinen anderen Bestimmungen dieses Vertrags widerspricht; anderenfalls behält PROFIT PLANET sich das Recht vor, den VP-Vertrag der betreffenden Kapital- oder Personengesellschaft aufzukündigen.
+
11.4. Bei Auflösung einer als VP registrierten Gemeinschaft (Kapital- oder Personengesellschaft, aber auch z.B. Ehepartnerschaften oder ähnliches, die einen gemeinsamen VP-Vertrag haben), bleibt nur ein VP-Vertrag bestehen. Die Mitglieder der aufzulösenden Gemeinschaft haben sich intern zu einigen, durch welches Mitglied/Gesellschafter die Vertriebspartner / Businesspartner / Affiliateschaft fortgesetzt werden soll, und dies PROFIT PLANET schriftlich anzuzeigen. Falls sich die Mitglieder der Gemeinschaft in Bezug auf die Fortsetzung des VP-vertrags nicht gütlich einigen können, behält sich PROFIT PLANET das Recht einer außerordentlichen Kündigung vor, insbesondere, wenn es durch die Uneinigkeit über die Folgen zur Vernachlässigung der Pflichten des VP, einem Verstoß gegen diesen Vertrag oder geltendes Recht oder zu einer übermäßigen Belastung der Vertriebsstruktur des VP kommt.
+
+
+
+
12. Schlussbestimmungen
+
12.1. Änderungen und Ergänzungen dieser Vereinbarung bedürfen der Schriftform. Dies gilt auch für das Abgehen der Schriftformerfordernis. Mündliche Nebenabreden bestehen nicht.
+
12.2. Sollte eine Bestimmung dieser Vereinbarung unwirksam sein oder werden, gilt anstelle der unwirksamen Bestimmung jene Bestimmung als vereinbart, die dem wirtschaftlichen Zweck der unwirksamen Bestimmung am nächsten kommt.
+
12.3. Vereinbarter Gerichtsstand für alle Streitigkeiten aus oder in Zusammenhang mit dieser Vereinbarung ist das für Graz sachlich zuständige Gericht. Diese Vereinbarung unterliegt österreichischem Recht, nicht jedoch den nichtzwingenden Verweisungsnormen des IPR. Weiter- bzw. Rückverweisungen sind ausgeschlossen. Darüber hinaus steht es PROFIT PLANET frei, den VP auch seinem allgemeinen Gerichtsstand zu klagen.
+
+
+
Für PROFIT PLANET (Auftraggeber)
+
+
+
{{profitplanetSignature}}
+
{{currentDate}}
+
+
Datum, Unterschrift
+
+
+
Für den VP (Auftragnehmer)
+
+
Name, Datum, Unterschrift
+
+
+
+
+
+
\ No newline at end of file
diff --git a/debug-pdf/template_2_html_full.html b/debug-pdf/template_2_html_full.html
new file mode 100644
index 0000000..4df6877
--- /dev/null
+++ b/debug-pdf/template_2_html_full.html
@@ -0,0 +1,229 @@
+
+
+
+
+
+ SUB-AUFTRAGSVERARBEITUNGS-VERTRAG
+
+
+
+
+
+
+
+
+
+
SUB-AUFTRAGSVERARBEITUNGS-VERTRAG
+
i.S.d. Art. 28 Abs. 3 Datenschutz-Grundverordnung (DS-GVO)
+
+
+
abgeschlossen zwischen
+
Profit Planet GmbH (kurz Auftraggeber)
+ FN 649474i
+ Liebenauer Hauptstraße 82c
+ A-8041 Graz
+
und
+
Vertriebspartner (kurz Auftragnehmer)
+
+
+
+
+
1. PRÄAMBEL
+
+
1.1. Diese Anlage konkretisiert die Verpflichtungen der Vertragsparteien zum Datenschutz, die sich aus der im bestehenden Vertriebspartner-Vertrag („Hauptvertrag“) und seinen Anlagen in ihren Einzelheiten beschriebenen Auftragsverarbeitung ergeben. Sie findet Anwendung auf alle Tätigkeiten, die mit dem Vertrag in Zusammenhang stehen, und bei denen Beschäftigte des Auftragnehmers oder durch den Auftragnehmer Beauftragte personenbezogene Daten („Daten“) des Auftraggebers verarbeiten.
+
1.2. Der Auftragnehmer ist sich bewusst, dass der Auftraggeber als Auftragsverarbeiter für Dritte („Verantwortliche“ im Sinne des Art. 4 Nr. 7 DS-GVO) tätig ist. Im Rahmen des vorbezeichneten Hauptvertrags nimmt der Auftraggeber die Dienste des Auftragnehmers als „weiteren Auftragsverarbeiter“ im Sinne von Art. 28 Nr. 4 DS-GVO in Anspruch, um bestimmte Verarbeitungstätigkeiten im Namen des Dritten („Verantwortlicher“ iSd Art. 4 Nr. 7 DS-GVO) auszuführen.
+
1.3. Der Auftragnehmer ist sich bewusst, dass der Auftraggeber gegenüber Dritten für die Einhaltung der Pflichten des Auftragnehmers haftet, falls der Auftragnehmer seinen Datenschutzpflichten nach diesem Vertrag und nach dem Gesetz nicht nachkommt.
+
1.4. Die Laufzeit dieser Anlage richtet sich nach der Laufzeit des Vertriebspartner-Vertrages, sofern sich aus den Bestimmungen dieser Anlage nicht darüber hinausgehende Verpflichtungen ergeben.
+
+
+
+
+
2. DAUER, GEGENSTAND UND SPEZIFIZIERUNG DER AUFTRAGSVERARBEITUNG
+
+
2.1. Alle Daten dürfen nur so lange verarbeitet werden, als das durch die Vertragserfüllung oder den Zweck der Datenverarbeitung erforderlich ist.
+
2.2. Aus dem Vertrag ergeben sich Gegenstand und Dauer des Auftrags sowie Art und Zweck der Verarbeitung.
+
2.3. Im Einzelnen sind insbesondere die folgenden Daten Bestandteil der Datenverarbeitung:
+
+
+
+
+
+
+
+
+
+
+ | Art der Daten |
+ Interessenten- und Kundendaten; Kontaktdaten beim Auftraggeber; Kontaktdaten des jeweiligen Datenverantwortlichen |
+
+
+ | Art und Zweck der Datenverarbeitung |
+ Datenerfassung beim Interessenten (potenziellen Kunden); Datenübermittlung (auch elektronisch via E-Mail bzw. falls vorhanden über elektronische Schnittstellen der Verantwortlichen) an Auftraggeber bzw. Datenverantwortliche zur Legung eines Angebots bzw. zur Verwirklichung der Kundenbestellung; ggf. telefonischer Nachkontakt zur Qualitätskontrolle |
+
+
+ | Kategorien betroffener Daten |
+ Name, Vorname, Adresse, Geburtsdatum, SV-Nr., E-Mail, Kontodaten Ausweiskopie; Daten zur Energieversorgung (z.B. Zählpunkt, Zählernummer, Kilowattprognose, Jahresverbrauch); Aufzeichnung etwaiger Qualitätskontrollen; Aufzeichnung etwaiger Interessensgebiete im Bereich Versicherung, Kreditwirtschaft, Telekommunikation, Energieeffizienz (PV, Speicher, LED, Infrarotheizung, Kalkschutz…). |
+
+
+
+
+
3. ANWENDUNGSBEREICH UND VERANTWORTLICHKEIT
+
+
3.1. Der Auftragnehmer verarbeitet personenbezogene Daten im Auftrag des Auftraggebers. Dies umfasst Tätigkeiten, die im Vertrag und in der Leistungsbeschreibung konkretisiert sind.
+
3.2. Der Auftraggeber ist gegenüber dem/den Dritten als („Verantwortliche Person“ iSd Art. 4 Nr. 7 DS-GVO) für die Einhaltung der gesetzlichen Bestimmungen der Datenschutzgesetze, insbesondere für die Rechtmäßigkeit der Datenweitergabe an den Auftragnehmer sowie für die Rechtmäßigkeit der Datenverarbeitung verantwortlich.
+
3.3. Der Auftragnehmer ist gegenüber dem Auftraggeber im Rahmen dieses Vertrages für die Einhaltung der gesetzlichen Bestimmungen der Datenschutzgesetze, insbesondere für die Rechtmäßigkeit der Datenweitergabe sowie der Datenverarbeitung verantwortlich.
+
3.4. Die Weisungen werden anfänglich durch diese Vertragsanlage festgelegt und können vom Auftraggeber danach in schriftlicher Form oder in einem elektronischen Format (Textform) an die vom Auftragnehmer bezeichnete Stelle durch einzelne Weisungen geändert, ergänzt oder ersetzt werden (Einzelweisung). Weisungen, die in der Vertragsanlage nicht vorgesehen sind, werden als Antrag auf Leistungsänderung behandelt. Mündliche Weisungen sind unverzüglich schriftlich oder in Textform zu bestätigen.
+
+
+
+
+
4. PFLICHTEN DES AUFTRAGNEHMERS
+
+
4.1. Der Auftragnehmer darf Daten von betroffenen Personen nur im Rahmen des Auftrages und der Weisungen des Auftraggebers verarbeiten, außer es liegt ein Ausnahmefall iSd Art 28 Abs. 3 a) DS-GVO vor. Der Auftragnehmer informiert den Auftraggeber unverzüglich, wenn er der Auffassung ist, dass eine Weisung gegen anwendbare Gesetze verstößt. Der Auftragnehmer darf die Umsetzung der Weisung solange aussetzen, bis sie vom Auftraggeber bestätigt oder abgeändert wurde.
+
4.2. Der Auftragnehmer wird in seinem Verantwortungsbereich die innerbetriebliche Organisation so gestalten, dass sie den besonderen Anforderungen des Datenschutzes gerecht wird. Er wird technische und organisatorische Maßnahmen zum angemessenen Schutz der Daten des Auftraggebers treffen, die den Anforderungen der Datenschutz- Grundverordnung (Art. 32 DS-GVO) genügen. Der Auftragnehmer hat technische und organisatorische Maßnahmen zu treffen, die die Vertraulichkeit, Integrität, Verfügbarkeit und Belastbarkeit der Systeme und Dienste im Zusammenhang mit der Verarbeitung auf Dauer sicherstellen. Der Auftraggeber ist berechtigt, diese technischen und organisatorischen Maßnahmen dahingehend zu überprüfen, ob sie für die Risiken der zu verarbeitenden Daten ein angemessenes Schutzniveau bieten. Eine Änderung der getroffenen Sicherheitsmaßnahmen bleibt dem Auftragnehmer vorbehalten, wobei jedoch sichergestellt sein muss, dass das vertraglich vereinbarte Schutzniveau nicht unterschritten wird.
+
4.3. Der Auftragnehmer gewährleistet, seinen Pflichten nach Art. 32 Abs. 1 lit. d) DS-GVO nachzukommen, ein Verfahren zur regelmäßigen Überprüfung der Wirksamkeit der technischen und organisatorischen Maßnahmen zur Gewährleistung der Sicherheit der Verarbeitung einzusetzen.
+
4.4. Der Auftragnehmer unterstützt den Auftraggeber im Rahmen seiner Möglichkeiten bei der Erfüllung der Anfragen und Ansprüche betroffener Personen gem. Kapitel III der DS-GVO sowie bei der Einhaltung der in Art. 33 bis 36 DS-GVO genannten Pflichten.
+
4.5. Der Auftragnehmer gewährleistet, dass es den mit der Verarbeitung der Daten des Auftraggebers befassten Mitarbeiter und andere für den Auftragnehmer tätigen Personen untersagt ist, die Daten außerhalb der Weisung zu verarbeiten. Ferner gewährleistet der Auftragnehmer, dass sich die zur Verarbeitung der personenbezogenen Daten befugten Personen zur Vertraulichkeit verpflichtet haben oder einer angemessenen gesetzlichen Verschwiegenheitspflicht unterliegen. Die Vertraulichkeits-/ Verschwiegenheitspflicht besteht auch nach Beendigung des Auftrages fort.
+
+
+
+
+
+
+
4.6. Der Auftragnehmer unterrichtet den Auftraggeber unverzüglich, wenn ihm Verletzungen des Schutzes personenbezogener Daten des Auftraggebers bekannt werden. Der Auftragnehmer trifft die erforderlichen Maßnahmen zur Sicherung der Daten und zur Minderung möglicher nachteiliger Folgen der betroffenen Personen und spricht sich hierzu unverzüglich mit dem Auftraggeber ab.
+
4.7. Der Auftragnehmer nennt dem Auftraggeber den Ansprechpartner für im Rahmen des Vertrages anfallende Datenschutzfragen.
+
4.8. Der Auftragnehmer berichtigt oder löscht die vertragsgegenständlichen Daten, wenn der Auftraggeber dies anweist und dies vom Weisungsrahmen umfasst ist. Ist eine datenschutzkonforme Löschung oder eine entsprechende Einschränkung der Datenverarbeitung nicht möglich, übernimmt der Auftragnehmer die datenschutzkonforme Vernichtung von Datenträgern und sonstigen Materialien auf Grund einer Einzelbeauftragung durch den Auftraggeber oder gibt diese Datenträger an den Auftraggeber zurück, sofern nicht im Vertrag bereits vereinbart.
+
4.9. Daten, Datenträger sowie sämtliche sonstige Materialien sind nach Auftragsende auf Verlangen des Auftraggebers entweder herauszugeben oder zu löschen.
+
4.10. Im Falle einer Inanspruchnahme des Auftraggebers oder des Dritten durch eine betroffene Person hinsichtlich etwaiger Ansprüche nach Art. 82 DS-GVO, verpflichtet sich der Auftragnehmer den Auftraggeber bei der Abwehr des Anspruches im Rahmen seiner Möglichkeiten zu unterstützen.
+
4.11. Im Falle einer Inanspruchnahme des Auftraggebers durch den Dritten, verpflichtet sich der Auftragnehmer den Auftraggeber bei der Abwehr des Anspruches im Rahmen seiner Möglichkeiten zu unterstützen.
+
+
+
+
+
5. PFLICHTEN DES AUFTRAGGEBERS
+
+
5.1. Der Auftraggeber hat den Auftragnehmer unverzüglich und vollständig zu informieren, wenn er in den Auftragsergebnissen Fehler oder Unregelmäßigkeiten bzgl. datenschutzrechtlicher Bestimmungen feststellt.
+
5.2. Im Falle einer Inanspruchnahme des Auftraggebers oder des Dritten durch eine betroffene Person hinsichtlich etwaiger Ansprüche nach Art. 82 DS-GVO, gilt §3 Abs. 10 entsprechend.
+
5.3. Der Auftraggeber nennt dem Auftragnehmer den Ansprechpartner für im Rahmen des Vertrages anfallende Datenschutzfragen.
+
+
+
+
+
6. ANFRAGEN BETROFFENER PERSONEN
+
+
6.1. Wendet sich eine betroffene Person mit Forderungen zur Berichtigung, Löschung oder Auskunft an den Auftragnehmer, wird der Auftragnehmer die betroffene Person an den Auftraggeber verweisen und ggf. den Antrag der betroffenen Person unverzüglich an den Auftraggeber weiterleiten. Der Auftragnehmer unterstützt den Auftraggeber im Rahmen seiner Möglichkeiten bei der Erfüllung der jeweiligen Forderung.
+
6.2. Der Auftragnehmer haftet nicht, wenn das Ersuchen der betroffenen Person vom Auftraggeber nicht, nicht richtig oder nicht fristgerecht beantwortet wird.
+
6.3. Der Auftraggeber haftet nicht für Forderungen betroffener Personen, die dadurch entstehen, dass der Auftragnehmer das entsprechende Anliegen nicht zeitgerecht an den Auftraggeber übermittelt hat.
+
+
+
+
+
7. NACHWEISMÖGLICHKEITEN
+
+
7.1. Der Auftragnehmer weist dem Auftraggeber die Einhaltung der in diesem Vertrag niedergelegten Pflichten mit geeigneten Mitteln nach.
+
7.2. Sollten im Einzelfall Inspektionen durch den Auftraggeber oder einen von diesem beauftragten Prüfer erforderlich sein, werden diese zu den üblichen Geschäftszeiten ohne Störung des Betriebsablaufs nach Anmeldung unter Berücksichtigung einer angemessenen Vorlaufzeit durchgeführt. Der Auftragnehmer darf diese von der Unterzeichnung einer Verschwiegenheitserklärung hinsichtlich der Daten anderer Kunden und der eingerichteten technischen und organisatorischen Maßnahmen abhängig machen. Sollte der durch den Auftraggeber beauftragte Prüfer in einem Wettbewerbsverhältnis zu dem Auftragnehmer stehen, hat der Auftragnehmer gegen diesen ein Einspruchsrecht
+
+
+
+
+
+
8. SUBUNTERNEHMER (WEITERE AUFTRAGSVERARBEITER)
+
+
8.1. Der Einsatz von Subunternehmern als weitere Auftragsverarbeiter ist nur zulässig, wenn der Auftraggeber vorher zugestimmt hat.
+
8.2. Ein zustimmungspflichtiges Subunternehmerverhältnis liegt vor, wenn der Auftragnehmer weitere Auftragnehmer mit der ganzen oder einer Teilleistung der im Vertrag vereinbarten Leistung beauftragt. Der Auftragnehmer wird mit diesen Dritten im erforderlichen Umfang Vereinbarungen treffen, um angemessene Datenschutz- und Informationssicherheitsmaßnahmen zu gewährleisten.
+
8.3. Erteilt der Auftragnehmer Aufträge an Subunternehmer, so obliegt es dem Auftragnehmer, seine datenschutzrechtlichen Pflichten aus diesem Vertrag dem Subunternehmer zu überbinden.
+
+
+
+
+
9. INFORMATIONSPFLICHTEN, SCHRIFTFORMKLAUSEL, RECHTSWAHL
+
+
9.1. Sollten die Daten des Auftraggebers beim Auftragnehmer durch Pfändung oder Beschlagnahme, durch ein Insolvenz- oder Vergleichsverfahren oder durch sonstige Ereignisse oder Maßnahmen Dritter gefährdet werden, so hat der Auftragnehmer den Auftraggeber unverzüglich darüber zu informieren. Der Auftragnehmer wird alle in diesem Zusammenhang Verantwortlichen unverzüglich darüber informieren, dass die Hoheit und das Eigentum an den Daten ausschließlich beim Dritten als verantwortliche Person im Sinne der Datenschutz-Grundverordnung liegen.
+
9.2. Änderungen und Ergänzungen dieser Anlage und aller ihrer Bestandteile – einschließlich etwaiger Zusicherungen des Auftragnehmers – bedürfen einer schriftlichen Vereinbarung, die auch in einem elektronischen Format (Textform) erfolgen kann, und des ausdrücklichen Hinweises darauf, dass es sich um eine Änderung bzw. Ergänzung dieser Bedingungen handelt. Dies gilt auch für den Verzicht auf dieses Formerfordernis.
+
9.3. Bei etwaigen Widersprüchen gehen Regelungen dieser Anlage zum Datenschutz den Regelungen des Vertrages vor. Sollten einzelne Teile dieser Anlage unwirksam sein, so berührt dies die Wirksamkeit der Anlage im Übrigen nicht.
+
9.4. Es gilt das auf dem Hauptvertrag anwendbare Recht sowie Gerichtsstand.
+
+
+
+
+
+
Für PROFIT PLANET (Auftraggeber)
+
+
+
{{profitplanetSignature}}
+
{{currentDate}}
+
+
Datum, Unterschrift
+
+
+
Für den VP (Auftragnehmer)
+
+
{{signatureImage}}
+
{{fullName}}
+
{{currentDate}}
+
+
Name, Datum, Unterschrift
+
+
+
+
+
+
\ No newline at end of file
diff --git a/debug-pdf/template_2_html_raw.bin b/debug-pdf/template_2_html_raw.bin
new file mode 100644
index 0000000..4df6877
--- /dev/null
+++ b/debug-pdf/template_2_html_raw.bin
@@ -0,0 +1,229 @@
+
+
+
+
+
+ SUB-AUFTRAGSVERARBEITUNGS-VERTRAG
+
+
+
+
+
+
+
+
+
+
SUB-AUFTRAGSVERARBEITUNGS-VERTRAG
+
i.S.d. Art. 28 Abs. 3 Datenschutz-Grundverordnung (DS-GVO)
+
+
+
abgeschlossen zwischen
+
Profit Planet GmbH (kurz Auftraggeber)
+ FN 649474i
+ Liebenauer Hauptstraße 82c
+ A-8041 Graz
+
und
+
Vertriebspartner (kurz Auftragnehmer)
+
+
+
+
+
1. PRÄAMBEL
+
+
1.1. Diese Anlage konkretisiert die Verpflichtungen der Vertragsparteien zum Datenschutz, die sich aus der im bestehenden Vertriebspartner-Vertrag („Hauptvertrag“) und seinen Anlagen in ihren Einzelheiten beschriebenen Auftragsverarbeitung ergeben. Sie findet Anwendung auf alle Tätigkeiten, die mit dem Vertrag in Zusammenhang stehen, und bei denen Beschäftigte des Auftragnehmers oder durch den Auftragnehmer Beauftragte personenbezogene Daten („Daten“) des Auftraggebers verarbeiten.
+
1.2. Der Auftragnehmer ist sich bewusst, dass der Auftraggeber als Auftragsverarbeiter für Dritte („Verantwortliche“ im Sinne des Art. 4 Nr. 7 DS-GVO) tätig ist. Im Rahmen des vorbezeichneten Hauptvertrags nimmt der Auftraggeber die Dienste des Auftragnehmers als „weiteren Auftragsverarbeiter“ im Sinne von Art. 28 Nr. 4 DS-GVO in Anspruch, um bestimmte Verarbeitungstätigkeiten im Namen des Dritten („Verantwortlicher“ iSd Art. 4 Nr. 7 DS-GVO) auszuführen.
+
1.3. Der Auftragnehmer ist sich bewusst, dass der Auftraggeber gegenüber Dritten für die Einhaltung der Pflichten des Auftragnehmers haftet, falls der Auftragnehmer seinen Datenschutzpflichten nach diesem Vertrag und nach dem Gesetz nicht nachkommt.
+
1.4. Die Laufzeit dieser Anlage richtet sich nach der Laufzeit des Vertriebspartner-Vertrages, sofern sich aus den Bestimmungen dieser Anlage nicht darüber hinausgehende Verpflichtungen ergeben.
+
+
+
+
+
2. DAUER, GEGENSTAND UND SPEZIFIZIERUNG DER AUFTRAGSVERARBEITUNG
+
+
2.1. Alle Daten dürfen nur so lange verarbeitet werden, als das durch die Vertragserfüllung oder den Zweck der Datenverarbeitung erforderlich ist.
+
2.2. Aus dem Vertrag ergeben sich Gegenstand und Dauer des Auftrags sowie Art und Zweck der Verarbeitung.
+
2.3. Im Einzelnen sind insbesondere die folgenden Daten Bestandteil der Datenverarbeitung:
+
+
+
+
+
+
+
+
+
+
+ | Art der Daten |
+ Interessenten- und Kundendaten; Kontaktdaten beim Auftraggeber; Kontaktdaten des jeweiligen Datenverantwortlichen |
+
+
+ | Art und Zweck der Datenverarbeitung |
+ Datenerfassung beim Interessenten (potenziellen Kunden); Datenübermittlung (auch elektronisch via E-Mail bzw. falls vorhanden über elektronische Schnittstellen der Verantwortlichen) an Auftraggeber bzw. Datenverantwortliche zur Legung eines Angebots bzw. zur Verwirklichung der Kundenbestellung; ggf. telefonischer Nachkontakt zur Qualitätskontrolle |
+
+
+ | Kategorien betroffener Daten |
+ Name, Vorname, Adresse, Geburtsdatum, SV-Nr., E-Mail, Kontodaten Ausweiskopie; Daten zur Energieversorgung (z.B. Zählpunkt, Zählernummer, Kilowattprognose, Jahresverbrauch); Aufzeichnung etwaiger Qualitätskontrollen; Aufzeichnung etwaiger Interessensgebiete im Bereich Versicherung, Kreditwirtschaft, Telekommunikation, Energieeffizienz (PV, Speicher, LED, Infrarotheizung, Kalkschutz…). |
+
+
+
+
+
3. ANWENDUNGSBEREICH UND VERANTWORTLICHKEIT
+
+
3.1. Der Auftragnehmer verarbeitet personenbezogene Daten im Auftrag des Auftraggebers. Dies umfasst Tätigkeiten, die im Vertrag und in der Leistungsbeschreibung konkretisiert sind.
+
3.2. Der Auftraggeber ist gegenüber dem/den Dritten als („Verantwortliche Person“ iSd Art. 4 Nr. 7 DS-GVO) für die Einhaltung der gesetzlichen Bestimmungen der Datenschutzgesetze, insbesondere für die Rechtmäßigkeit der Datenweitergabe an den Auftragnehmer sowie für die Rechtmäßigkeit der Datenverarbeitung verantwortlich.
+
3.3. Der Auftragnehmer ist gegenüber dem Auftraggeber im Rahmen dieses Vertrages für die Einhaltung der gesetzlichen Bestimmungen der Datenschutzgesetze, insbesondere für die Rechtmäßigkeit der Datenweitergabe sowie der Datenverarbeitung verantwortlich.
+
3.4. Die Weisungen werden anfänglich durch diese Vertragsanlage festgelegt und können vom Auftraggeber danach in schriftlicher Form oder in einem elektronischen Format (Textform) an die vom Auftragnehmer bezeichnete Stelle durch einzelne Weisungen geändert, ergänzt oder ersetzt werden (Einzelweisung). Weisungen, die in der Vertragsanlage nicht vorgesehen sind, werden als Antrag auf Leistungsänderung behandelt. Mündliche Weisungen sind unverzüglich schriftlich oder in Textform zu bestätigen.
+
+
+
+
+
4. PFLICHTEN DES AUFTRAGNEHMERS
+
+
4.1. Der Auftragnehmer darf Daten von betroffenen Personen nur im Rahmen des Auftrages und der Weisungen des Auftraggebers verarbeiten, außer es liegt ein Ausnahmefall iSd Art 28 Abs. 3 a) DS-GVO vor. Der Auftragnehmer informiert den Auftraggeber unverzüglich, wenn er der Auffassung ist, dass eine Weisung gegen anwendbare Gesetze verstößt. Der Auftragnehmer darf die Umsetzung der Weisung solange aussetzen, bis sie vom Auftraggeber bestätigt oder abgeändert wurde.
+
4.2. Der Auftragnehmer wird in seinem Verantwortungsbereich die innerbetriebliche Organisation so gestalten, dass sie den besonderen Anforderungen des Datenschutzes gerecht wird. Er wird technische und organisatorische Maßnahmen zum angemessenen Schutz der Daten des Auftraggebers treffen, die den Anforderungen der Datenschutz- Grundverordnung (Art. 32 DS-GVO) genügen. Der Auftragnehmer hat technische und organisatorische Maßnahmen zu treffen, die die Vertraulichkeit, Integrität, Verfügbarkeit und Belastbarkeit der Systeme und Dienste im Zusammenhang mit der Verarbeitung auf Dauer sicherstellen. Der Auftraggeber ist berechtigt, diese technischen und organisatorischen Maßnahmen dahingehend zu überprüfen, ob sie für die Risiken der zu verarbeitenden Daten ein angemessenes Schutzniveau bieten. Eine Änderung der getroffenen Sicherheitsmaßnahmen bleibt dem Auftragnehmer vorbehalten, wobei jedoch sichergestellt sein muss, dass das vertraglich vereinbarte Schutzniveau nicht unterschritten wird.
+
4.3. Der Auftragnehmer gewährleistet, seinen Pflichten nach Art. 32 Abs. 1 lit. d) DS-GVO nachzukommen, ein Verfahren zur regelmäßigen Überprüfung der Wirksamkeit der technischen und organisatorischen Maßnahmen zur Gewährleistung der Sicherheit der Verarbeitung einzusetzen.
+
4.4. Der Auftragnehmer unterstützt den Auftraggeber im Rahmen seiner Möglichkeiten bei der Erfüllung der Anfragen und Ansprüche betroffener Personen gem. Kapitel III der DS-GVO sowie bei der Einhaltung der in Art. 33 bis 36 DS-GVO genannten Pflichten.
+
4.5. Der Auftragnehmer gewährleistet, dass es den mit der Verarbeitung der Daten des Auftraggebers befassten Mitarbeiter und andere für den Auftragnehmer tätigen Personen untersagt ist, die Daten außerhalb der Weisung zu verarbeiten. Ferner gewährleistet der Auftragnehmer, dass sich die zur Verarbeitung der personenbezogenen Daten befugten Personen zur Vertraulichkeit verpflichtet haben oder einer angemessenen gesetzlichen Verschwiegenheitspflicht unterliegen. Die Vertraulichkeits-/ Verschwiegenheitspflicht besteht auch nach Beendigung des Auftrages fort.
+
+
+
+
+
+
+
4.6. Der Auftragnehmer unterrichtet den Auftraggeber unverzüglich, wenn ihm Verletzungen des Schutzes personenbezogener Daten des Auftraggebers bekannt werden. Der Auftragnehmer trifft die erforderlichen Maßnahmen zur Sicherung der Daten und zur Minderung möglicher nachteiliger Folgen der betroffenen Personen und spricht sich hierzu unverzüglich mit dem Auftraggeber ab.
+
4.7. Der Auftragnehmer nennt dem Auftraggeber den Ansprechpartner für im Rahmen des Vertrages anfallende Datenschutzfragen.
+
4.8. Der Auftragnehmer berichtigt oder löscht die vertragsgegenständlichen Daten, wenn der Auftraggeber dies anweist und dies vom Weisungsrahmen umfasst ist. Ist eine datenschutzkonforme Löschung oder eine entsprechende Einschränkung der Datenverarbeitung nicht möglich, übernimmt der Auftragnehmer die datenschutzkonforme Vernichtung von Datenträgern und sonstigen Materialien auf Grund einer Einzelbeauftragung durch den Auftraggeber oder gibt diese Datenträger an den Auftraggeber zurück, sofern nicht im Vertrag bereits vereinbart.
+
4.9. Daten, Datenträger sowie sämtliche sonstige Materialien sind nach Auftragsende auf Verlangen des Auftraggebers entweder herauszugeben oder zu löschen.
+
4.10. Im Falle einer Inanspruchnahme des Auftraggebers oder des Dritten durch eine betroffene Person hinsichtlich etwaiger Ansprüche nach Art. 82 DS-GVO, verpflichtet sich der Auftragnehmer den Auftraggeber bei der Abwehr des Anspruches im Rahmen seiner Möglichkeiten zu unterstützen.
+
4.11. Im Falle einer Inanspruchnahme des Auftraggebers durch den Dritten, verpflichtet sich der Auftragnehmer den Auftraggeber bei der Abwehr des Anspruches im Rahmen seiner Möglichkeiten zu unterstützen.
+
+
+
+
+
5. PFLICHTEN DES AUFTRAGGEBERS
+
+
5.1. Der Auftraggeber hat den Auftragnehmer unverzüglich und vollständig zu informieren, wenn er in den Auftragsergebnissen Fehler oder Unregelmäßigkeiten bzgl. datenschutzrechtlicher Bestimmungen feststellt.
+
5.2. Im Falle einer Inanspruchnahme des Auftraggebers oder des Dritten durch eine betroffene Person hinsichtlich etwaiger Ansprüche nach Art. 82 DS-GVO, gilt §3 Abs. 10 entsprechend.
+
5.3. Der Auftraggeber nennt dem Auftragnehmer den Ansprechpartner für im Rahmen des Vertrages anfallende Datenschutzfragen.
+
+
+
+
+
6. ANFRAGEN BETROFFENER PERSONEN
+
+
6.1. Wendet sich eine betroffene Person mit Forderungen zur Berichtigung, Löschung oder Auskunft an den Auftragnehmer, wird der Auftragnehmer die betroffene Person an den Auftraggeber verweisen und ggf. den Antrag der betroffenen Person unverzüglich an den Auftraggeber weiterleiten. Der Auftragnehmer unterstützt den Auftraggeber im Rahmen seiner Möglichkeiten bei der Erfüllung der jeweiligen Forderung.
+
6.2. Der Auftragnehmer haftet nicht, wenn das Ersuchen der betroffenen Person vom Auftraggeber nicht, nicht richtig oder nicht fristgerecht beantwortet wird.
+
6.3. Der Auftraggeber haftet nicht für Forderungen betroffener Personen, die dadurch entstehen, dass der Auftragnehmer das entsprechende Anliegen nicht zeitgerecht an den Auftraggeber übermittelt hat.
+
+
+
+
+
7. NACHWEISMÖGLICHKEITEN
+
+
7.1. Der Auftragnehmer weist dem Auftraggeber die Einhaltung der in diesem Vertrag niedergelegten Pflichten mit geeigneten Mitteln nach.
+
7.2. Sollten im Einzelfall Inspektionen durch den Auftraggeber oder einen von diesem beauftragten Prüfer erforderlich sein, werden diese zu den üblichen Geschäftszeiten ohne Störung des Betriebsablaufs nach Anmeldung unter Berücksichtigung einer angemessenen Vorlaufzeit durchgeführt. Der Auftragnehmer darf diese von der Unterzeichnung einer Verschwiegenheitserklärung hinsichtlich der Daten anderer Kunden und der eingerichteten technischen und organisatorischen Maßnahmen abhängig machen. Sollte der durch den Auftraggeber beauftragte Prüfer in einem Wettbewerbsverhältnis zu dem Auftragnehmer stehen, hat der Auftragnehmer gegen diesen ein Einspruchsrecht
+
+
+
+
+
+
8. SUBUNTERNEHMER (WEITERE AUFTRAGSVERARBEITER)
+
+
8.1. Der Einsatz von Subunternehmern als weitere Auftragsverarbeiter ist nur zulässig, wenn der Auftraggeber vorher zugestimmt hat.
+
8.2. Ein zustimmungspflichtiges Subunternehmerverhältnis liegt vor, wenn der Auftragnehmer weitere Auftragnehmer mit der ganzen oder einer Teilleistung der im Vertrag vereinbarten Leistung beauftragt. Der Auftragnehmer wird mit diesen Dritten im erforderlichen Umfang Vereinbarungen treffen, um angemessene Datenschutz- und Informationssicherheitsmaßnahmen zu gewährleisten.
+
8.3. Erteilt der Auftragnehmer Aufträge an Subunternehmer, so obliegt es dem Auftragnehmer, seine datenschutzrechtlichen Pflichten aus diesem Vertrag dem Subunternehmer zu überbinden.
+
+
+
+
+
9. INFORMATIONSPFLICHTEN, SCHRIFTFORMKLAUSEL, RECHTSWAHL
+
+
9.1. Sollten die Daten des Auftraggebers beim Auftragnehmer durch Pfändung oder Beschlagnahme, durch ein Insolvenz- oder Vergleichsverfahren oder durch sonstige Ereignisse oder Maßnahmen Dritter gefährdet werden, so hat der Auftragnehmer den Auftraggeber unverzüglich darüber zu informieren. Der Auftragnehmer wird alle in diesem Zusammenhang Verantwortlichen unverzüglich darüber informieren, dass die Hoheit und das Eigentum an den Daten ausschließlich beim Dritten als verantwortliche Person im Sinne der Datenschutz-Grundverordnung liegen.
+
9.2. Änderungen und Ergänzungen dieser Anlage und aller ihrer Bestandteile – einschließlich etwaiger Zusicherungen des Auftragnehmers – bedürfen einer schriftlichen Vereinbarung, die auch in einem elektronischen Format (Textform) erfolgen kann, und des ausdrücklichen Hinweises darauf, dass es sich um eine Änderung bzw. Ergänzung dieser Bedingungen handelt. Dies gilt auch für den Verzicht auf dieses Formerfordernis.
+
9.3. Bei etwaigen Widersprüchen gehen Regelungen dieser Anlage zum Datenschutz den Regelungen des Vertrages vor. Sollten einzelne Teile dieser Anlage unwirksam sein, so berührt dies die Wirksamkeit der Anlage im Übrigen nicht.
+
9.4. Es gilt das auf dem Hauptvertrag anwendbare Recht sowie Gerichtsstand.
+
+
+
+
+
+
Für PROFIT PLANET (Auftraggeber)
+
+
+
{{profitplanetSignature}}
+
{{currentDate}}
+
+
Datum, Unterschrift
+
+
+
Für den VP (Auftragnehmer)
+
+
{{signatureImage}}
+
{{fullName}}
+
{{currentDate}}
+
+
Name, Datum, Unterschrift
+
+
+
+
+
+
\ No newline at end of file
diff --git a/debug-pdf/template_2_sanitized_preview.html b/debug-pdf/template_2_sanitized_preview.html
new file mode 100644
index 0000000..4a93851
--- /dev/null
+++ b/debug-pdf/template_2_sanitized_preview.html
@@ -0,0 +1,229 @@
+
+
+
+
+
+ SUB-AUFTRAGSVERARBEITUNGS-VERTRAG
+
+
+
+
+
+
+
+
+
+
SUB-AUFTRAGSVERARBEITUNGS-VERTRAG
+
i.S.d. Art. 28 Abs. 3 Datenschutz-Grundverordnung (DS-GVO)
+
+
+
abgeschlossen zwischen
+
Profit Planet GmbH (kurz Auftraggeber)
+ FN 649474i
+ Liebenauer Hauptstraße 82c
+ A-8041 Graz
+
und
+
Vertriebspartner (kurz Auftragnehmer)
+
+
+
+
+
1. PRÄAMBEL
+
+
1.1. Diese Anlage konkretisiert die Verpflichtungen der Vertragsparteien zum Datenschutz, die sich aus der im bestehenden Vertriebspartner-Vertrag („Hauptvertrag“) und seinen Anlagen in ihren Einzelheiten beschriebenen Auftragsverarbeitung ergeben. Sie findet Anwendung auf alle Tätigkeiten, die mit dem Vertrag in Zusammenhang stehen, und bei denen Beschäftigte des Auftragnehmers oder durch den Auftragnehmer Beauftragte personenbezogene Daten („Daten“) des Auftraggebers verarbeiten.
+
1.2. Der Auftragnehmer ist sich bewusst, dass der Auftraggeber als Auftragsverarbeiter für Dritte („Verantwortliche“ im Sinne des Art. 4 Nr. 7 DS-GVO) tätig ist. Im Rahmen des vorbezeichneten Hauptvertrags nimmt der Auftraggeber die Dienste des Auftragnehmers als „weiteren Auftragsverarbeiter“ im Sinne von Art. 28 Nr. 4 DS-GVO in Anspruch, um bestimmte Verarbeitungstätigkeiten im Namen des Dritten („Verantwortlicher“ iSd Art. 4 Nr. 7 DS-GVO) auszuführen.
+
1.3. Der Auftragnehmer ist sich bewusst, dass der Auftraggeber gegenüber Dritten für die Einhaltung der Pflichten des Auftragnehmers haftet, falls der Auftragnehmer seinen Datenschutzpflichten nach diesem Vertrag und nach dem Gesetz nicht nachkommt.
+
1.4. Die Laufzeit dieser Anlage richtet sich nach der Laufzeit des Vertriebspartner-Vertrages, sofern sich aus den Bestimmungen dieser Anlage nicht darüber hinausgehende Verpflichtungen ergeben.
+
+
+
+
+
2. DAUER, GEGENSTAND UND SPEZIFIZIERUNG DER AUFTRAGSVERARBEITUNG
+
+
2.1. Alle Daten dürfen nur so lange verarbeitet werden, als das durch die Vertragserfüllung oder den Zweck der Datenverarbeitung erforderlich ist.
+
2.2. Aus dem Vertrag ergeben sich Gegenstand und Dauer des Auftrags sowie Art und Zweck der Verarbeitung.
+
2.3. Im Einzelnen sind insbesondere die folgenden Daten Bestandteil der Datenverarbeitung:
+
+
+
+
+
+
+
+
+
+
+ | Art der Daten |
+ Interessenten- und Kundendaten; Kontaktdaten beim Auftraggeber; Kontaktdaten des jeweiligen Datenverantwortlichen |
+
+
+ | Art und Zweck der Datenverarbeitung |
+ Datenerfassung beim Interessenten (potenziellen Kunden); Datenübermittlung (auch elektronisch via E-Mail bzw. falls vorhanden über elektronische Schnittstellen der Verantwortlichen) an Auftraggeber bzw. Datenverantwortliche zur Legung eines Angebots bzw. zur Verwirklichung der Kundenbestellung; ggf. telefonischer Nachkontakt zur Qualitätskontrolle |
+
+
+ | Kategorien betroffener Daten |
+ Name, Vorname, Adresse, Geburtsdatum, SV-Nr., E-Mail, Kontodaten Ausweiskopie; Daten zur Energieversorgung (z.B. Zählpunkt, Zählernummer, Kilowattprognose, Jahresverbrauch); Aufzeichnung etwaiger Qualitätskontrollen; Aufzeichnung etwaiger Interessensgebiete im Bereich Versicherung, Kreditwirtschaft, Telekommunikation, Energieeffizienz (PV, Speicher, LED, Infrarotheizung, Kalkschutz…). |
+
+
+
+
+
3. ANWENDUNGSBEREICH UND VERANTWORTLICHKEIT
+
+
3.1. Der Auftragnehmer verarbeitet personenbezogene Daten im Auftrag des Auftraggebers. Dies umfasst Tätigkeiten, die im Vertrag und in der Leistungsbeschreibung konkretisiert sind.
+
3.2. Der Auftraggeber ist gegenüber dem/den Dritten als („Verantwortliche Person“ iSd Art. 4 Nr. 7 DS-GVO) für die Einhaltung der gesetzlichen Bestimmungen der Datenschutzgesetze, insbesondere für die Rechtmäßigkeit der Datenweitergabe an den Auftragnehmer sowie für die Rechtmäßigkeit der Datenverarbeitung verantwortlich.
+
3.3. Der Auftragnehmer ist gegenüber dem Auftraggeber im Rahmen dieses Vertrages für die Einhaltung der gesetzlichen Bestimmungen der Datenschutzgesetze, insbesondere für die Rechtmäßigkeit der Datenweitergabe sowie der Datenverarbeitung verantwortlich.
+
3.4. Die Weisungen werden anfänglich durch diese Vertragsanlage festgelegt und können vom Auftraggeber danach in schriftlicher Form oder in einem elektronischen Format (Textform) an die vom Auftragnehmer bezeichnete Stelle durch einzelne Weisungen geändert, ergänzt oder ersetzt werden (Einzelweisung). Weisungen, die in der Vertragsanlage nicht vorgesehen sind, werden als Antrag auf Leistungsänderung behandelt. Mündliche Weisungen sind unverzüglich schriftlich oder in Textform zu bestätigen.
+
+
+
+
+
4. PFLICHTEN DES AUFTRAGNEHMERS
+
+
4.1. Der Auftragnehmer darf Daten von betroffenen Personen nur im Rahmen des Auftrages und der Weisungen des Auftraggebers verarbeiten, außer es liegt ein Ausnahmefall iSd Art 28 Abs. 3 a) DS-GVO vor. Der Auftragnehmer informiert den Auftraggeber unverzüglich, wenn er der Auffassung ist, dass eine Weisung gegen anwendbare Gesetze verstößt. Der Auftragnehmer darf die Umsetzung der Weisung solange aussetzen, bis sie vom Auftraggeber bestätigt oder abgeändert wurde.
+
4.2. Der Auftragnehmer wird in seinem Verantwortungsbereich die innerbetriebliche Organisation so gestalten, dass sie den besonderen Anforderungen des Datenschutzes gerecht wird. Er wird technische und organisatorische Maßnahmen zum angemessenen Schutz der Daten des Auftraggebers treffen, die den Anforderungen der Datenschutz- Grundverordnung (Art. 32 DS-GVO) genügen. Der Auftragnehmer hat technische und organisatorische Maßnahmen zu treffen, die die Vertraulichkeit, Integrität, Verfügbarkeit und Belastbarkeit der Systeme und Dienste im Zusammenhang mit der Verarbeitung auf Dauer sicherstellen. Der Auftraggeber ist berechtigt, diese technischen und organisatorischen Maßnahmen dahingehend zu überprüfen, ob sie für die Risiken der zu verarbeitenden Daten ein angemessenes Schutzniveau bieten. Eine Änderung der getroffenen Sicherheitsmaßnahmen bleibt dem Auftragnehmer vorbehalten, wobei jedoch sichergestellt sein muss, dass das vertraglich vereinbarte Schutzniveau nicht unterschritten wird.
+
4.3. Der Auftragnehmer gewährleistet, seinen Pflichten nach Art. 32 Abs. 1 lit. d) DS-GVO nachzukommen, ein Verfahren zur regelmäßigen Überprüfung der Wirksamkeit der technischen und organisatorischen Maßnahmen zur Gewährleistung der Sicherheit der Verarbeitung einzusetzen.
+
4.4. Der Auftragnehmer unterstützt den Auftraggeber im Rahmen seiner Möglichkeiten bei der Erfüllung der Anfragen und Ansprüche betroffener Personen gem. Kapitel III der DS-GVO sowie bei der Einhaltung der in Art. 33 bis 36 DS-GVO genannten Pflichten.
+
4.5. Der Auftragnehmer gewährleistet, dass es den mit der Verarbeitung der Daten des Auftraggebers befassten Mitarbeiter und andere für den Auftragnehmer tätigen Personen untersagt ist, die Daten außerhalb der Weisung zu verarbeiten. Ferner gewährleistet der Auftragnehmer, dass sich die zur Verarbeitung der personenbezogenen Daten befugten Personen zur Vertraulichkeit verpflichtet haben oder einer angemessenen gesetzlichen Verschwiegenheitspflicht unterliegen. Die Vertraulichkeits-/ Verschwiegenheitspflicht besteht auch nach Beendigung des Auftrages fort.
+
+
+
+
+
+
+
4.6. Der Auftragnehmer unterrichtet den Auftraggeber unverzüglich, wenn ihm Verletzungen des Schutzes personenbezogener Daten des Auftraggebers bekannt werden. Der Auftragnehmer trifft die erforderlichen Maßnahmen zur Sicherung der Daten und zur Minderung möglicher nachteiliger Folgen der betroffenen Personen und spricht sich hierzu unverzüglich mit dem Auftraggeber ab.
+
4.7. Der Auftragnehmer nennt dem Auftraggeber den Ansprechpartner für im Rahmen des Vertrages anfallende Datenschutzfragen.
+
4.8. Der Auftragnehmer berichtigt oder löscht die vertragsgegenständlichen Daten, wenn der Auftraggeber dies anweist und dies vom Weisungsrahmen umfasst ist. Ist eine datenschutzkonforme Löschung oder eine entsprechende Einschränkung der Datenverarbeitung nicht möglich, übernimmt der Auftragnehmer die datenschutzkonforme Vernichtung von Datenträgern und sonstigen Materialien auf Grund einer Einzelbeauftragung durch den Auftraggeber oder gibt diese Datenträger an den Auftraggeber zurück, sofern nicht im Vertrag bereits vereinbart.
+
4.9. Daten, Datenträger sowie sämtliche sonstige Materialien sind nach Auftragsende auf Verlangen des Auftraggebers entweder herauszugeben oder zu löschen.
+
4.10. Im Falle einer Inanspruchnahme des Auftraggebers oder des Dritten durch eine betroffene Person hinsichtlich etwaiger Ansprüche nach Art. 82 DS-GVO, verpflichtet sich der Auftragnehmer den Auftraggeber bei der Abwehr des Anspruches im Rahmen seiner Möglichkeiten zu unterstützen.
+
4.11. Im Falle einer Inanspruchnahme des Auftraggebers durch den Dritten, verpflichtet sich der Auftragnehmer den Auftraggeber bei der Abwehr des Anspruches im Rahmen seiner Möglichkeiten zu unterstützen.
+
+
+
+
+
5. PFLICHTEN DES AUFTRAGGEBERS
+
+
5.1. Der Auftraggeber hat den Auftragnehmer unverzüglich und vollständig zu informieren, wenn er in den Auftragsergebnissen Fehler oder Unregelmäßigkeiten bzgl. datenschutzrechtlicher Bestimmungen feststellt.
+
5.2. Im Falle einer Inanspruchnahme des Auftraggebers oder des Dritten durch eine betroffene Person hinsichtlich etwaiger Ansprüche nach Art. 82 DS-GVO, gilt §3 Abs. 10 entsprechend.
+
5.3. Der Auftraggeber nennt dem Auftragnehmer den Ansprechpartner für im Rahmen des Vertrages anfallende Datenschutzfragen.
+
+
+
+
+
6. ANFRAGEN BETROFFENER PERSONEN
+
+
6.1. Wendet sich eine betroffene Person mit Forderungen zur Berichtigung, Löschung oder Auskunft an den Auftragnehmer, wird der Auftragnehmer die betroffene Person an den Auftraggeber verweisen und ggf. den Antrag der betroffenen Person unverzüglich an den Auftraggeber weiterleiten. Der Auftragnehmer unterstützt den Auftraggeber im Rahmen seiner Möglichkeiten bei der Erfüllung der jeweiligen Forderung.
+
6.2. Der Auftragnehmer haftet nicht, wenn das Ersuchen der betroffenen Person vom Auftraggeber nicht, nicht richtig oder nicht fristgerecht beantwortet wird.
+
6.3. Der Auftraggeber haftet nicht für Forderungen betroffener Personen, die dadurch entstehen, dass der Auftragnehmer das entsprechende Anliegen nicht zeitgerecht an den Auftraggeber übermittelt hat.
+
+
+
+
+
7. NACHWEISMÖGLICHKEITEN
+
+
7.1. Der Auftragnehmer weist dem Auftraggeber die Einhaltung der in diesem Vertrag niedergelegten Pflichten mit geeigneten Mitteln nach.
+
7.2. Sollten im Einzelfall Inspektionen durch den Auftraggeber oder einen von diesem beauftragten Prüfer erforderlich sein, werden diese zu den üblichen Geschäftszeiten ohne Störung des Betriebsablaufs nach Anmeldung unter Berücksichtigung einer angemessenen Vorlaufzeit durchgeführt. Der Auftragnehmer darf diese von der Unterzeichnung einer Verschwiegenheitserklärung hinsichtlich der Daten anderer Kunden und der eingerichteten technischen und organisatorischen Maßnahmen abhängig machen. Sollte der durch den Auftraggeber beauftragte Prüfer in einem Wettbewerbsverhältnis zu dem Auftragnehmer stehen, hat der Auftragnehmer gegen diesen ein Einspruchsrecht
+
+
+
+
+
+
8. SUBUNTERNEHMER (WEITERE AUFTRAGSVERARBEITER)
+
+
8.1. Der Einsatz von Subunternehmern als weitere Auftragsverarbeiter ist nur zulässig, wenn der Auftraggeber vorher zugestimmt hat.
+
8.2. Ein zustimmungspflichtiges Subunternehmerverhältnis liegt vor, wenn der Auftragnehmer weitere Auftragnehmer mit der ganzen oder einer Teilleistung der im Vertrag vereinbarten Leistung beauftragt. Der Auftragnehmer wird mit diesen Dritten im erforderlichen Umfang Vereinbarungen treffen, um angemessene Datenschutz- und Informationssicherheitsmaßnahmen zu gewährleisten.
+
8.3. Erteilt der Auftragnehmer Aufträge an Subunternehmer, so obliegt es dem Auftragnehmer, seine datenschutzrechtlichen Pflichten aus diesem Vertrag dem Subunternehmer zu überbinden.
+
+
+
+
+
9. INFORMATIONSPFLICHTEN, SCHRIFTFORMKLAUSEL, RECHTSWAHL
+
+
9.1. Sollten die Daten des Auftraggebers beim Auftragnehmer durch Pfändung oder Beschlagnahme, durch ein Insolvenz- oder Vergleichsverfahren oder durch sonstige Ereignisse oder Maßnahmen Dritter gefährdet werden, so hat der Auftragnehmer den Auftraggeber unverzüglich darüber zu informieren. Der Auftragnehmer wird alle in diesem Zusammenhang Verantwortlichen unverzüglich darüber informieren, dass die Hoheit und das Eigentum an den Daten ausschließlich beim Dritten als verantwortliche Person im Sinne der Datenschutz-Grundverordnung liegen.
+
9.2. Änderungen und Ergänzungen dieser Anlage und aller ihrer Bestandteile – einschließlich etwaiger Zusicherungen des Auftragnehmers – bedürfen einer schriftlichen Vereinbarung, die auch in einem elektronischen Format (Textform) erfolgen kann, und des ausdrücklichen Hinweises darauf, dass es sich um eine Änderung bzw. Ergänzung dieser Bedingungen handelt. Dies gilt auch für den Verzicht auf dieses Formerfordernis.
+
9.3. Bei etwaigen Widersprüchen gehen Regelungen dieser Anlage zum Datenschutz den Regelungen des Vertrages vor. Sollten einzelne Teile dieser Anlage unwirksam sein, so berührt dies die Wirksamkeit der Anlage im Übrigen nicht.
+
9.4. Es gilt das auf dem Hauptvertrag anwendbare Recht sowie Gerichtsstand.
+
+
+
+
+
+
Für PROFIT PLANET (Auftraggeber)
+
+
+
{{profitplanetSignature}}
+
{{currentDate}}
+
+
Datum, Unterschrift
+
+
+
Für den VP (Auftragnehmer)
+
+
Name, Datum, Unterschrift
+
+
+
+
+
+
\ No newline at end of file
diff --git a/debug-pdf/template_3_html_full.html b/debug-pdf/template_3_html_full.html
new file mode 100644
index 0000000..ebcd475
--- /dev/null
+++ b/debug-pdf/template_3_html_full.html
@@ -0,0 +1,209 @@
+
+
+
+
+
+ VERTRIEBSPARTNER / BUSINESSPARTNER / AFFILIATE - VERTRAG
+
+
+
+
+
+
VERTRIEBSPARTNER / BUSINESSPARTNER / AFFILIATE - VERTRAG
+
idF 21.05.2025
+
abgeschlossen zwischen
+
Profit Planet GmbH (kurz PROFIT PLANET)
FN 649474i
Liebenauer Hauptstraße 82c
A-8041 Graz
+
und
+
Vertriebspartner / Businesspartner / Affiliate (kurz VP)
+
+
1. Präambel und Vertragsgegenstand
+
1.1. Dieser Vertrag regelt die Zusammenarbeit zwischen PROFIT PLANET und VP als Grundlage einer fairen, langfristigen und erfolgreichen Kooperation. Die VP unterstützen einander im Sinne der Ziele der Zusammenarbeit und unterrichten sich gegenseitig über alle Vorgänge, die für ihre Leistungen im Rahmen der Kooperation von Interesse sind.
+
1.2. PROFIT PLANET bietet über ein Vertriebspartner / Businesspartner / Affiliate-Netzwerk den Vertrieb verschiedener Dienstleistungen und Produkte, vornehmlich aus den Bereichen Nachhaltigkeit, Energie, Handel sowie Consulting und Coaching an.
+
1.3. Der VP vermittelt die jeweiligen Dienstleistungen, Produkte oder qualifizierten Leads, die zu einem Abschluss führen, und erhält dafür eine Provision. Für die Tätigkeit als VP ist es nicht erforderlich, weitere VP zu werben.
+
1.4. Der VP ist berechtigt, weitere Vertriebspartner / Businesspartner / Affiliate für den Vertrieb der Dienstleistungen und Produkte zu gewinnen. Für die Vermittlung und Betreuung der von ihm akquirierten Vertriebspartner / Businesspartner / Affiliate erhält der werbende VP eine Provision, die sich aus den erwirtschafteten Umsätzen der geworbenen VP ermittelt. Die Höhe der Provision ergibt sich aus der Provisionsübersicht.
+
1.5. Die Vertragsabschlüsse kommen nur zwischen dem Endkunden und dem jeweiligen Dienstleister und/oder Produktgeber (Energieversorgungs-, Handels-, Dienstleistungs- oder Coachingunternehmen) zustande, ohne dass dadurch eine Vertragsbeziehung zwischen dem VP und dem Endkunden entsteht. Ein Anspruch auf Abschluss des jeweiligen Vertrags seitens des Endkunden gegenüber PROFIT PLANET oder dem VP entsteht nicht; der Vertragsabschluss ist von der Annahme des entsprechenden Antrags durch den Dienstleister bzw. Produktgeber abhängig. PROFIT PLANET hat darauf keinen Einfluss.
+
1.6. PROFIT PLANET behält sich vor, die angebotenen Produkte zurückzuziehen, zu ändern, neue hinzuzufügen oder sonstige Anpassungen des Produktangebots vorzunehmen. PROFIT PLANET wird den VP über Änderungen von Produkten oder Tarifen nach Maßgabe der Möglichkeiten rechtzeitig vor Wirksamkeit der Änderungen informieren.
+
1.7. Die genauen Produktbestandteile und Konditionen ergeben sich aus dem jeweiligen Produktpartnerinformationsblatt, welches auf der Online-Plattform hinterlegt wird.
+
1.8. PROFIT PLANET ist berechtigt, nach eigenem Ermessen andere Personen und Unternehmen mit der Vermittlung von Produkten und Dienstleistungen von PROFIT PLANET bzw. Produktpartnern von PROFIT PLANET zu beauftragen. Es bestehen grundsätzlich keine Alleinvermittlungsaufträge und keine Exklusivität.
+
+
2. Vertriebspartner / Businesspartner / Affiliate werden
+
2.1. Kapitalgesellschaften, Personengesellschaften und volljährige natürliche Personen können Vertriebspartner / Businesspartner / Affiliate des PROFIT PLANET werden; pro Entität ist die Registrierung nur eines VP-Vertrags vorgesehen. Natürliche Personen, die bloß als Verbraucher handeln (wollen), können nicht Vertriebspartner / Businesspartner / Affiliate von PROFIT PLANET werden.
+
2.2. Kapitalgesellschaften müssen ihrem VP-Antrag die Firmenbuchnummer und gegebenenfalls die Umsatzsteuer-Identifikationsnummer (UID) beilegen. Der Antrag muss von allen Zeichnungsbereichten der Gesellschaft derart gezeichnet werden, dass eine rechtwirksame Vertretung sichergestellt ist. Die Gesellschafter haften gegenüber PROFIT PLANET jeweils persönlich für das Verhalten der Gesellschaft.
+
2.3. Absatz 2.2 gilt inhaltsgemäß auch für Personengesellschaften.
+
2.4. Der VP ist verpflichtet, Änderungen seiner unternehmens- oder personenbezogenen Daten unverzüglich an PROFIT PLANET zu melden.
+
2.5. Für die Verwendung des Online-Systems gelten die allgemeinen Geschäftsbedingungen.
+
2.6. PROFIT PLANET kann Vertriebspartner / Businesspartner / Affiliate ohne Angabe von Gründen ablehnen.
+
+
3. Leistungen / Pflichten des VP
+
3.1. Der VP handelt unabhängig als selbständiger Unternehmer, er ist weder Arbeitnehmer noch Handelsvertreter oder Makler von PROFIT PLANET. Er ist bei der Vermittlung von Produktverträgen eigenverantwortlich tätig, handelt abgesehen von den Pflichten aus diesem Vertrag frei von Weisungen und ist nicht mit der ständigen Vermittlung von Geschäften betraut. Es bestehen seitens PROFIT PLANET keine Umsatzvorgaben und keine Abnahme- oder Vertriebspflichten. Der VP trägt alle mit der Kundenakquisition verbundenen Kosten und Risiken selbst und verwendet eigene Betriebsmittel. Er stellt im geschäftlichen Verkehr klar, dass er nicht im Auftrag oder im Namen von PROFIT PLANET handelt, sondern als unabhängiger Vertriebspartner / Businesspartner / Affiliate.
+
3.2. Der VP betreibt sein Unternehmen mit der Sorgfalt eines ordentlichen Kaufmanns und ist für die Einhaltung aller gesetzlichen sowie der steuer- und sozialrechtlichen Vorgaben selbst verantwortlich.
+
3.3. Der VP hält sich insbesondere auch an das Wettbewerbsrecht und nimmt Abstand von ungenehmigter, irreführender oder sonst unlauterer Werbung. Der VP verpflichtet sich auch, falsche oder irreführende Aussagen über Dienstleistungen, Produkte und Vertriebssystem der PROFIT PLANET zu unterlassen.
+
3.4. Grundsätzlich steht es dem VP frei, Produkte / Dienstleistungen auch für andere Unternehmen zu vertreiben. Falls es allerdings in der Zusammenarbeit mit einem anderen Dienstleister oder Produktgeber in räumlicher oder zeitlicher Nähe zu Überschneidungen im Vertrieb, insbesondere bei Terminisierungen, Promotion-Auftritten (POS) oder anderen dienstleistungs- oder produktspezifischen Werbetätigkeiten kommen, so wäre dies nur nach ausdrücklicher Zustimmung durch PROFIT PLANET zulässig.
+
3.5. Beim Abschluss von Kundenverträgen ist der VP verpflichtet, die von PROFIT PLANET zur Verfügung gestellten Originalunterlagen (zB Antragsformulare, AGB, sonstige Unterlagen der Dienstleister oder Produktgeber) in der jeweils aktuellen Version zu verwenden und dem Kunden bei Vertragsabschluss vorzulegen bzw. auszuhändigen. Die Originalunterlagen sind durch den VP nicht zu verändern, missbräuchliche Verwendung ist zu verhindern.
+
3.6. Kundenverträge in Papierform sind vom VP unverzüglich, spätestens jedoch binnen 1 Woche nach Aufforderung durch PROFIT PLANET oder den Produktgeber an PROFIT PLANET auszuhändigen.
+
3.7. Sämtliche Präsentations-, Werbe- und Schulungsmaterialien sowie label von PROFIT PLANET sind urheberrechtlich geschützt und dürfen ohne ausdrückliches Einverständnis von PROFIT PLANET weder ganz noch teilweise vervielfältigt, verbreitet oder öffentlich zugänglich gemacht werden. Die Herstellung, Verwendung und Verbreitung eigener Werbemittel, Schulungsmaterialien oder Produktbroschüren ist nur nach schriftlicher Genehmigung und Freigabe durch PROFIT PLANET gestattet.
+
3.8. Der VP ist während der Dauer dieser Vereinbarung und für die Dauer von 36 Monaten nach Beendigung dieses Vertrags aus welchem Grund immer, nicht berechtigt, unmittelbar selbst bzw. mittelbar über Dritte Kunden von PROFIT PLANET und ihrer Produktpartner, einschließlich der vom VP vermittelten Endkunden, durch direkte Ansprache abzuwerben. Als Abwerben gilt jede Form des direkten Herantretens an den Kunden mit der Absicht, ihn zum Wechsel zu einem anderen Energieversorgungs-, Dienstleistungs-, Handels-, und/oder Coachingunternehmen zu bewegen (beispielsweise etwa durch Anrufe beim Kunden, Direktmailing mit Absicht der Abwerbung, Haustürgeschäfte etc.).
+
4. Geheimhaltung
+
4.1. Der VP verpflichtet sich, Geschäfts- und Betriebsgeheimnisse und sonstige vertrauliche Informationen von PROFIT PLANET und dessen Struktur, Geschäftspartner, Vertriebspartner / Businesspartner / Affiliate, Produktgeber, Provisionen und Endkunden unter äußerster Geheimhaltung zu behandeln und zu verwahren und diese Daten nur nach erfolgter schriftlicher Zustimmung durch den PROFIT PLANET an Dritte weiterzugeben.
+
4.2. Diese Verpflichtung gilt auch für Mitarbeiter und Unter-Vertriebspartner / Businesspartner / Affiliate des VP. Der VP hat für das Verhalten allfälliger Erfüllungsgehilfen und/oder Subpartner einzustehen.
+
4.3. Zu den Geschäftsgeheimnissen gehören insbesondere auch Informationen zu internen Betriebsabläufen, Provisionen und Provisionsstrukturen, Produkt- und Preiskalkulationen, Vertriebspartner / Businesspartner / Affiliate-strukturen und -aktivitäten.
+
4.4. Dem VP ist es nicht gestattet, auf Presseanfragen zu PROFIT PLANET, dessen Provisionspläne, Produkte oder andere Leistungen zu antworten. Presseanfragen sind immer an PROFIT PLANET weiterzuleiten.
+
5. Datenschutz
+
5.1. Die Vertragspartner sind verpflichtet, die gesetzlichen Datenschutzbestimmungen vollumfänglich einzuhalten. Für Verstöße gegen datenschutzrechtliche Schutzbestimmungen haftet ausschließlich der jeweils die Bestimmung verletzende Vertragspartner, dieser wird den schuldlos handelnden Vertragspartner von allen entsprechenden Ansprüchen freistellen und schad- und klaglos halten.
+
5.2. Im Regelfall ist der VP ist hinsichtlich der Daten der von ihm vermittelten Endkunden und Akquisitionskontakte Subauftragsverarbeiter im Sinne der Datenschutzgesetze (DSG, DSGVO); PROFIT PLANET ist Auftragsverarbeiter im Sinne der DSGVO. Soweit durch die gesetzlichen Bestimmungen vorgesehen, werden zu dieser Vereinbarung entsprechende datenschutzrechtliche Zusatzverträge abgeschlossen.
+
5.3. PROFIT PLANET ist bezüglich der Daten des VP auf Datenschutz verpflichtet. Die Datenschutzerklärung ist Online jederzeit abrufbar.
+
6. VP-Schutz
+
6.1. Ein neu geworbener VP wird in die Struktur desjenigen VP zugewiesen, der ihn geworben hat (VP-Schutz). Wenn mehrere VP denselben VP neu melden, wird seitens PROFIT PLANET nur die zuerst erfolgte Meldung berücksichtigt, wobei das Eingangsdatum des Registrierungsantrags bei PROFIT PLANET für die Zuteilung maßgeblich ist.
+
6.2. Der meldende VP ist verantwortlich dafür, die Daten des geworbenen VP vollständig und ordentlich zu übermitteln. PROFIT PLANET ist berechtigt, die Daten eines geworbenen VP aus ihrem System zu löschen, wenn von diesem innerhalb einer angemessenen Frist keine Umsätze oder Rückmeldungen kommen.
+
6.3. Ein Wechsel von der Struktur eines VP in die eines anderen ist grundsätzlich ausgeschlossen und nur ausnahmsweise möglich, wenn der wechselwillige VP nachweist, dass der in der Struktur über ihm stehende VP versucht hat, ihn zu einem gesetzes- oder vertragswidrigen Verhalten zu veranlassen oder sonst schwerwiegende Vorfälle die weitere Zusammenarbeit in der Struktur dieses VP untragbar machen. Über einen entsprechenden schriftlichen Antrag entscheidet PROFIT PLANET nach freiem Ermessen.
+
6.4. Ein VP, der innerhalb der letzten 12 Monate bereits einen VP-Vertrag mit PROFIT PLANET hatte, kann nicht geworben werden.
+
6.5. Eine Umgehung des VP-Schutzes etwa durch Verwendung der Namen von Strohnamen, -personen oder -firmen ist untersagt.
+
6.6. PROFIT PLANET räumt ihren VP ausdrücklich keinen Gebietsschutz ein. Alle VP können europaweit ohne Einschränkungen tätig sein.
+
7. Provision
+
7.1. Für jedes vom VP erfolgreich vermittelte Vertragsverhältnis zwischen Produktgeber und Endkunden erwirbt der VP Anspruch auf Provision als Bearbeitungs- und Aufwandspauschale
+
7.2. Die Höhe der Provision richtet sich nach der jeweils aktuell gültigen Provisionsübersicht laut Marketingkonzept. Die jeweils gültige Fassung dieser Provisionsübersicht ist jederzeit auf der Website von PROFIT PLANET (www.profit-planet.com) im internen Bereich abrufbar, einsehbar, downloadbar und kann dort auch auf Anfrage zur Verfügung gestellt werden. Änderungen der Provisionsübersicht werden dem VP rechtzeitig bekannt gegeben. Es gelten jeweils die zum Zeitpunkt der Vermittlung gültigen Provisionssätze.
+
7.3. Als erfolgreiche Vermittlung im Sinne dieses Vertrages gilt, wenn das Vertragsverhältnis zwischen Endkunden und Produktpartner tatsächlich zustande gekommen ist. Insbesondere entsteht kein Provisionsanspruch, wenn
+
+ - der Kunde von seinen Widerrufs- oder Rücktrittsrechten Gebrauch macht,
+ - der Vertrag rechtswirksam angefochten wird,
+ - der Kunde vom Dienstleister oder Produktpartner aus welchem Grund auch immer nicht angenommen wird,
+ - fehlerhafte oder unvollständige Kundenanträge eingereicht werden,
+ - der Vertrag widerrechtlich zustande gekommen ist oder
+ - der Dienstleister oder Produktgeber die Auszahlung der Provision an PROFIT PLANET aus Gründen, die nicht von PROFIT PLANET zu verantworten sind, verweigert.
+
+
7.4. Anspruch auf Auszahlung der Provision entsteht gegenüber PROFIT PLANET grundsätzlich erst dann, wenn die Zahlungen seitens des Geschäftspartners / Produktgebers bei PROFIT PLANET eingelangt sind und alle sonstigen Auszahlungsvoraussetzungen vorliegen. Der VP nimmt zur Kenntnis, dass die exakten Zahlungsmodalitäten bei den verschiedenen Dienstleistern oder Produktgebern voneinander abweichen können und PROFIT PLANET diese Unterschiede bei der Auszahlung berücksichtigt. Die unterschiedlichen Zeitspannen divergieren je nach Partnerunternehmen derzeit durchschnittlich zwischen 30 bis 100 Tage. Die genauen Anforderungen und Konditionen ergeben sich aus dem jeweiligen Produktpartnerinformationsblatt und dem Marketingkonzept.
+
7.5. Die Auszahlung durch PROFIT PLANET erfolgt einmal monatlich, ungefähr um den 20. des auf den Zahlungseingang bei PROFIT PLANET folgenden Monats. Die Auszahlung erfolgt bargeldlos per Überweisung auf das vom VP genannte Konto. PROFIT PLANET kann Zahlungen bis zu einer Höhe von EUR 100,00 von der Auszahlung ausschließen (Mindestauszahlungshöhe); die nicht ausbezahlten Provisionsansprüche werden auf dem Provisionskonto des VP rechnerisch fortgeführt und im Folgemonat nach Erreichen der Mindestauszahlungshöhe ausbezahlt. Beträge unterhalb der Mindestauszahlungshöhe werden einmal jährlich zur Auszahlung gebracht.
+
7.6. Der Provisionsanspruch entfällt rückwirkend, wenn PROFIT PLANET, Provisionen an einen Produktgeber zurückzahlen muss, etwa weil ein Kunde den Vertrag widerruft oder andere Ausschlusskriterien seitens des Produktgebers vorliegen (Stornohaftung etc.). PROFIT PLANET ist berechtigt, Forderungen, die dem PROFIT PLANET gegen den VP zustehen, mit dessen Provisionsansprüchen ganz oder teilweise aufzurechnen.
+
7.7. Mit dieser Provision sind sämtliche Tätigkeiten des VP einschließlich aller ihm in Zusammenhang mit dieser Vereinbarung entstandenen Kosten, Auslagen und Aufwendungen, wie beispielsweise Fahrt- und Reisekosten, Bürokosten, Porto und Telefongebühren, abgegolten. Dasselbe gilt für Leistungen des VP in Hinblick auf Pflege und Herstellung eines VP-Bestandes und/oder Kundenstocks, sodass im Fall der Beendigung des Vertrags unbeachtet des Grundes der Auflösung keinesfalls Ansprüche auf Abfindungen oder Ausgleiche jedweder Art gegen PROFIT PLANET bestehen.
+
7.8. Fehlerhafte Provisionszahlungen oder sonstige Zahlungen sind vom VP binnen 60 Tagen schriftlich einzumahnen. Danach gelten die Zahlungen als genehmigt.
+
7.9. Wenn vom VP keine UID-Nummer bekannt gegeben wird, erfolgen alle Auszahlungen netto.
+
8. Vertragsstrafe, Schadenersatz
+
8.1. Bei einem ersten Verstoß gegen die in diesem Vertrag geregelten Pflichten durch den VP erfolgt eine schriftliche Abmahnung durch PROFIT PLANET. Die Pflichtverletzung ist unmittelbar zu beenden bzw. gegebenenfalls zu beheben.
+
8.2. Kommt es erneut zu einem Verstoß gegen diesen Vertrag oder wird der zuerst gemahnte Zustand nicht beseitigt, so verpflichtet sich der VP zur Zahlung einer verschuldensunabhängigen Vertragsstrafe für jeden jeweiligen Verstoß in Höhe von EUR 5.000,00.
+
8.3. Bei Verstößen gegen die Geheimhaltungs- und Datenschutzpflichten, sowie bei besonders schwerwiegenden Verstößen, insbesondere gegen Punkt 10.2 dieses Vertrags, ist PROFIT PLANET auch ohne vorhergehende Abmahnung zur Geltendmachung der jeweiligen Vertragsstrafe berechtigt.
+
8.4. Für jede Zuwiderhandlung gegen Punkt 3.8 verpflichtet sich der VP zur Zahlung einer verschuldens- und schadensunabhängigen Konventionalstrafe an den PROFIT PLANET von EUR 5.000,00 pro Verstoß (z.B. pro an ein anderes Unternehmen oder sonstigen Dritten vermittelten Vertrags oder pro abgeworbenen Kunden). Die Geltendmachung darüber hinausgehender sonstiger Schadenersatzansprüche, der Vertragsstrafe nach 8.2 oder etwa von Erfüllungsansprüchen bleibt dadurch unberührt.
+
8.5. Für jeden Verstoß gegen die in Punkt 4. dieses Vertrags (Geheimhaltungsverpflichtung) normierten Pflichten, verpflichtet sich der VP zur Zahlung einer verschuldensunabhängigen Vertragsstrafe in Höhe von EUR 7.000,00 pro Verstoß. Die Geltendmachung weitergehender zivilrechtlicher Ansprüche – insbesondere auf Unterlassung und Schadenersatz – bleibt davon unberührt.
+
8.6. Bei Handlungen, die dem Katalog außerordentlicher Kündigungsgründe gemäß Punkt 10.2 entsprechen, insbesondere bei treuwidrigem Verhalten im Sinne der dort beschriebenen Fallgruppen (z. B. unautorisierte Kaltakquise, rufschädigendes Verhalten, unbefugtes Auftreten im Namen von PROFIT PLANET), verpflichtet sich der VP zur Zahlung einer verschuldensunabhängigen Vertragsstrafe in Höhe von EUR 10.000,00 pro Verstoß. Auch in diesen Fällen bleiben darüber hinausgehende Ansprüche – insbesondere Schadenersatz oder außerordentliche Kündigung – ausdrücklich vorbehalten.
+
+
9. Haftungsausschluss
+
9.1. Der VP führt seine Tätigkeiten nach bestem Wissen und Gewissen und in eigener Verantwortung, insbesondere auch in Bezug auf die korrekte Beratung der Endkunden aus. Eine Haftungsübernahme von PROFIT PLANET für Falschberatungen oder sonstiges Fehlverhalten des VP ist explizit ausgeschlossen.
+
9.2. Für Schäden haftet PROFIT PLANET nur, soweit diese auf Vorsatz oder grober Fahrlässigkeit oder auf grob schuldhafter Verletzung einer wesentlichen Vertragspflicht durch PROFIT PLANET, ihrer Mitarbeiter oder Erfüllungsgehilfen beruhen.
+
9.3. Eine Haftung von PROFIT PLANET für mittelbare Schäden, Folgeschäden, entgangenen Gewinn oder erwartete Ersparnis ist jedenfalls ausgeschlossen.
+
9.4. PROFIT PLANET übernimmt keine Haftung für Schäden, die durch Datenverlust auf den Servern auftreten, außer der Schaden beruht auf Vorsatz oder grober Fahrlässigkeit seitens PROFIT PLANET, ihrer Mitarbeiter oder Erfüllungsgehilfen.
+
9.5. Der Eintritt eines Schadens ist PROFIT PLANET unverzüglich mitzuteilen.
+
10. Vertragsdauer & Kündigung
+
10.1. Der Vertrag tritt mit Unterzeichnung oder im Fall einer Online-Registrierung, Online mit der Annahme des Vertrags durch PROFIT PLANET in Kraft und wird auf unbestimmte Zeit geschlossen. Er kann von beiden Parteien unter Einhaltung einer Frist von drei Monaten zum Ende jedes Kalendermonats schriftlich gekündigt werden.
+
10.2. Dessen ungeachtet kann der Vertrag seitens PROFIT PLANET aus wichtigem Grund ohne Einhaltung einer Kündigungsfrist gekündigt werden. Das Recht zur außerordentlichen Kündigung besteht ungeachtet weiterer Ansprüche. Folgende Gründe berechtigen insbesondere zur außerordentlichen Kündigung, die Aufzählung ist nicht abschließend:
+
+ - Akte treuwidrigen Verhaltens, die eine weitere Zusammenarbeit zw. den Vertragspartnern unzumutbar machen;
+ - ein solches treuwidriges Verhalten liegt insbesondere etwa dann vor, wenn ein VP ohne ausdrückliche Zustimmung eines vertretungs- und zeichnungsbefugten Organs von PROFIT PLANET Handlungen setzt, welche nach außen den Anschein erwecken, im Namen oder Auftrag von PROFIT PLANET zu erfolgen – insbesondere etwa durch Kaltakquise, Verwendung von Geschäftsdrucksorten oder -signaturen, Auftritt unter Verwendung der Marke PROFIT PLANET oder vergleichbare ruf- bzw. imageschädigende Aktivitäten.
+ - die Anwendung unlauterer Praktiken oder ein grober oder wiederholter Verstoß gegen diesen Vertrag sowie der Verstoß gegen zwingende Rechtsnormen;
+ - wenn über das Vermögen des jeweils anderen Vertragspartners die Einleitung eines Insolvenzverfahrens beantragt oder wenn die Eröffnung eines Insolvenzverfahrens mangels Masse abgelehnt wird;
+ - Verletzung der vereinbarten oder gesetzlichen Datenschutz- oder Geheimhaltungspflichten;
+ - wenn die Kooperation durch das Verhalten eines Vertragspartners oder dessen Ruf in der Öffentlichkeit den anderen Vertragspartnern einen Imageschaden zufügen würde;
+ - wenn die Kooperation aufgrund der Gesetzeslage oder von dritter Seite als unzulässig untersagt wird;
+ - Unzulässige Nebenabsprachen mit am Vertrieb beteiligten Dritten;
+
+
10.3. Abgesehen von 10.2 kann PROFIT PLANET den VP auch außerordentlich kündigen, wenn dieser in den letzten 6 Monaten keine neuen Umsätze erzielt hat oder bei den durch seine Vermittlung zustande gekommenen Verträgen zwischen Endkunden und Produktgebern über einen Zeitraum von 2 Monaten überdurchschnittliche Stornoquoten von mehr als 30% der vermittelten Verträge bestehen. PROFIT PLANET wird den VP vor einer außerordentlichen Kündigung nach diesem Passus einmalig schriftlich verwarnen, so dass der VP die Möglichkeit hat, innerhalb einer Frist von 30 Tagen die erforderlichen neuen Umsätze zu generieren oder seine Stornoquote zu verbessern.
+
10.4. Mit der Beendigung des Vertrags steht dem VP mit Ausnahme der Provision für zu diesem Zeitpunkt bereits erfolgreich vermittelte Verträge, kein Recht auf Provision mehr zu. Ein Anspruch auf Handelsvertreterausgleich ist ausdrücklich ausgeschlossen, da der VP nicht als Handelsvertreter für den PROFIT PLANET tätig wird. Etwaige Ansprüche auf Folgeprovisionen für vermittelte Produkte bestehen für 12 Monate nach Vertragsbeendigung fort; im Falle einer außerordentlichen Kündigung verfallen Ansprüche auf Folgeprovisionen unmittelbar mit der Vertragsbeendigung.
+
10.5. Nach Beendigung des Vertrags sind vom VP sämtliche überlassenen Unterlagen und Werbematerialien unaufgefordert binnen einem Monat an PROFIT PLANET zurückzugeben. Die Verwendung der Marke PROFIT PLANET und entsprechender Logos etwa auf Briefpapier oder in E-Mail-Signaturen ist nach Beendigung des Vertrags untersagt.
+
11. Übertragung
+
11.1. PROFIT PLANET ist jederzeit berechtigt, den Geschäftsbetrieb ganz oder teilweise auf Dritte zu übertragen.
+
11.2. Der VP ist nur mit ausdrücklicher Zustimmung von PROFIT PLANET berechtigt, seine Vertriebsstruktur an einen Dritten zu übertragen.
+
11.3. Wenn eine als VP registrierte Kapital- oder Personengesellschaft einen neuen Gesellschafter aufnimmt, hat dies auf diesen Vertrag keine Auswirkung, sofern der/die Gesellschafter, die den VP-Antrag ursprünglich unterzeichnet haben, als Gesellschafter in der Gesellschaft verbleiben. Wenn ein Gesellschafter aus einer registrierten Gesellschaft ausscheidet oder seine Anteile an einen Dritten überträgt, so ist dies in Bezug auf diesen Vertrag zulässig, sofern er dies PROFIT PLANET schriftlich unter Vorlage der entsprechenden rechtsgültigen Urkunden anzeigt, und der Vorgang keinen anderen Bestimmungen dieses Vertrags widerspricht; anderenfalls behält PROFIT PLANET sich das Recht vor, den VP-Vertrag der betreffenden Kapital- oder Personengesellschaft aufzukündigen.
+
11.4. Bei Auflösung einer als VP registrierten Gemeinschaft (Kapital- oder Personengesellschaft, aber auch z.B. Ehepartnerschaften oder ähnliches, die einen gemeinsamen VP-Vertrag haben), bleibt nur ein VP-Vertrag bestehen. Die Mitglieder der aufzulösenden Gemeinschaft haben sich intern zu einigen, durch welches Mitglied/Gesellschafter die Vertriebspartner / Businesspartner / Affiliateschaft fortgesetzt werden soll, und dies PROFIT PLANET schriftlich anzuzeigen. Falls sich die Mitglieder der Gemeinschaft in Bezug auf die Fortsetzung des VP-vertrags nicht gütlich einigen können, behält sich PROFIT PLANET das Recht einer außerordentlichen Kündigung vor, insbesondere, wenn es durch die Uneinigkeit über die Folgen zur Vernachlässigung der Pflichten des VP, einem Verstoß gegen diesen Vertrag oder geltendes Recht oder zu einer übermäßigen Belastung der Vertriebsstruktur des VP kommt.
+
+
+
+
12. Schlussbestimmungen
+
12.1. Änderungen und Ergänzungen dieser Vereinbarung bedürfen der Schriftform. Dies gilt auch für das Abgehen der Schriftformerfordernis. Mündliche Nebenabreden bestehen nicht.
+
12.2. Sollte eine Bestimmung dieser Vereinbarung unwirksam sein oder werden, gilt anstelle der unwirksamen Bestimmung jene Bestimmung als vereinbart, die dem wirtschaftlichen Zweck der unwirksamen Bestimmung am nächsten kommt.
+
12.3. Vereinbarter Gerichtsstand für alle Streitigkeiten aus oder in Zusammenhang mit dieser Vereinbarung ist das für Graz sachlich zuständige Gericht. Diese Vereinbarung unterliegt österreichischem Recht, nicht jedoch den nichtzwingenden Verweisungsnormen des IPR. Weiter- bzw. Rückverweisungen sind ausgeschlossen. Darüber hinaus steht es PROFIT PLANET frei, den VP auch seinem allgemeinen Gerichtsstand zu klagen.
+
+
+
Für PROFIT PLANET (Auftraggeber)
+
+
+
{{profitplanetSignature}}
+
{{currentDate}}
+
+
Datum, Unterschrift
+
+
+
Für den VP (Auftragnehmer)
+
+
{{signatureImage}}
+
{{fullName}}
+
{{currentDate}}
+
+
Name, Datum, Unterschrift
+
+
+
+
+
+
\ No newline at end of file
diff --git a/debug-pdf/template_3_html_raw.bin b/debug-pdf/template_3_html_raw.bin
new file mode 100644
index 0000000..ebcd475
--- /dev/null
+++ b/debug-pdf/template_3_html_raw.bin
@@ -0,0 +1,209 @@
+
+
+
+
+
+ VERTRIEBSPARTNER / BUSINESSPARTNER / AFFILIATE - VERTRAG
+
+
+
+
+
+
VERTRIEBSPARTNER / BUSINESSPARTNER / AFFILIATE - VERTRAG
+
idF 21.05.2025
+
abgeschlossen zwischen
+
Profit Planet GmbH (kurz PROFIT PLANET)
FN 649474i
Liebenauer Hauptstraße 82c
A-8041 Graz
+
und
+
Vertriebspartner / Businesspartner / Affiliate (kurz VP)
+
+
1. Präambel und Vertragsgegenstand
+
1.1. Dieser Vertrag regelt die Zusammenarbeit zwischen PROFIT PLANET und VP als Grundlage einer fairen, langfristigen und erfolgreichen Kooperation. Die VP unterstützen einander im Sinne der Ziele der Zusammenarbeit und unterrichten sich gegenseitig über alle Vorgänge, die für ihre Leistungen im Rahmen der Kooperation von Interesse sind.
+
1.2. PROFIT PLANET bietet über ein Vertriebspartner / Businesspartner / Affiliate-Netzwerk den Vertrieb verschiedener Dienstleistungen und Produkte, vornehmlich aus den Bereichen Nachhaltigkeit, Energie, Handel sowie Consulting und Coaching an.
+
1.3. Der VP vermittelt die jeweiligen Dienstleistungen, Produkte oder qualifizierten Leads, die zu einem Abschluss führen, und erhält dafür eine Provision. Für die Tätigkeit als VP ist es nicht erforderlich, weitere VP zu werben.
+
1.4. Der VP ist berechtigt, weitere Vertriebspartner / Businesspartner / Affiliate für den Vertrieb der Dienstleistungen und Produkte zu gewinnen. Für die Vermittlung und Betreuung der von ihm akquirierten Vertriebspartner / Businesspartner / Affiliate erhält der werbende VP eine Provision, die sich aus den erwirtschafteten Umsätzen der geworbenen VP ermittelt. Die Höhe der Provision ergibt sich aus der Provisionsübersicht.
+
1.5. Die Vertragsabschlüsse kommen nur zwischen dem Endkunden und dem jeweiligen Dienstleister und/oder Produktgeber (Energieversorgungs-, Handels-, Dienstleistungs- oder Coachingunternehmen) zustande, ohne dass dadurch eine Vertragsbeziehung zwischen dem VP und dem Endkunden entsteht. Ein Anspruch auf Abschluss des jeweiligen Vertrags seitens des Endkunden gegenüber PROFIT PLANET oder dem VP entsteht nicht; der Vertragsabschluss ist von der Annahme des entsprechenden Antrags durch den Dienstleister bzw. Produktgeber abhängig. PROFIT PLANET hat darauf keinen Einfluss.
+
1.6. PROFIT PLANET behält sich vor, die angebotenen Produkte zurückzuziehen, zu ändern, neue hinzuzufügen oder sonstige Anpassungen des Produktangebots vorzunehmen. PROFIT PLANET wird den VP über Änderungen von Produkten oder Tarifen nach Maßgabe der Möglichkeiten rechtzeitig vor Wirksamkeit der Änderungen informieren.
+
1.7. Die genauen Produktbestandteile und Konditionen ergeben sich aus dem jeweiligen Produktpartnerinformationsblatt, welches auf der Online-Plattform hinterlegt wird.
+
1.8. PROFIT PLANET ist berechtigt, nach eigenem Ermessen andere Personen und Unternehmen mit der Vermittlung von Produkten und Dienstleistungen von PROFIT PLANET bzw. Produktpartnern von PROFIT PLANET zu beauftragen. Es bestehen grundsätzlich keine Alleinvermittlungsaufträge und keine Exklusivität.
+
+
2. Vertriebspartner / Businesspartner / Affiliate werden
+
2.1. Kapitalgesellschaften, Personengesellschaften und volljährige natürliche Personen können Vertriebspartner / Businesspartner / Affiliate des PROFIT PLANET werden; pro Entität ist die Registrierung nur eines VP-Vertrags vorgesehen. Natürliche Personen, die bloß als Verbraucher handeln (wollen), können nicht Vertriebspartner / Businesspartner / Affiliate von PROFIT PLANET werden.
+
2.2. Kapitalgesellschaften müssen ihrem VP-Antrag die Firmenbuchnummer und gegebenenfalls die Umsatzsteuer-Identifikationsnummer (UID) beilegen. Der Antrag muss von allen Zeichnungsbereichten der Gesellschaft derart gezeichnet werden, dass eine rechtwirksame Vertretung sichergestellt ist. Die Gesellschafter haften gegenüber PROFIT PLANET jeweils persönlich für das Verhalten der Gesellschaft.
+
2.3. Absatz 2.2 gilt inhaltsgemäß auch für Personengesellschaften.
+
2.4. Der VP ist verpflichtet, Änderungen seiner unternehmens- oder personenbezogenen Daten unverzüglich an PROFIT PLANET zu melden.
+
2.5. Für die Verwendung des Online-Systems gelten die allgemeinen Geschäftsbedingungen.
+
2.6. PROFIT PLANET kann Vertriebspartner / Businesspartner / Affiliate ohne Angabe von Gründen ablehnen.
+
+
3. Leistungen / Pflichten des VP
+
3.1. Der VP handelt unabhängig als selbständiger Unternehmer, er ist weder Arbeitnehmer noch Handelsvertreter oder Makler von PROFIT PLANET. Er ist bei der Vermittlung von Produktverträgen eigenverantwortlich tätig, handelt abgesehen von den Pflichten aus diesem Vertrag frei von Weisungen und ist nicht mit der ständigen Vermittlung von Geschäften betraut. Es bestehen seitens PROFIT PLANET keine Umsatzvorgaben und keine Abnahme- oder Vertriebspflichten. Der VP trägt alle mit der Kundenakquisition verbundenen Kosten und Risiken selbst und verwendet eigene Betriebsmittel. Er stellt im geschäftlichen Verkehr klar, dass er nicht im Auftrag oder im Namen von PROFIT PLANET handelt, sondern als unabhängiger Vertriebspartner / Businesspartner / Affiliate.
+
3.2. Der VP betreibt sein Unternehmen mit der Sorgfalt eines ordentlichen Kaufmanns und ist für die Einhaltung aller gesetzlichen sowie der steuer- und sozialrechtlichen Vorgaben selbst verantwortlich.
+
3.3. Der VP hält sich insbesondere auch an das Wettbewerbsrecht und nimmt Abstand von ungenehmigter, irreführender oder sonst unlauterer Werbung. Der VP verpflichtet sich auch, falsche oder irreführende Aussagen über Dienstleistungen, Produkte und Vertriebssystem der PROFIT PLANET zu unterlassen.
+
3.4. Grundsätzlich steht es dem VP frei, Produkte / Dienstleistungen auch für andere Unternehmen zu vertreiben. Falls es allerdings in der Zusammenarbeit mit einem anderen Dienstleister oder Produktgeber in räumlicher oder zeitlicher Nähe zu Überschneidungen im Vertrieb, insbesondere bei Terminisierungen, Promotion-Auftritten (POS) oder anderen dienstleistungs- oder produktspezifischen Werbetätigkeiten kommen, so wäre dies nur nach ausdrücklicher Zustimmung durch PROFIT PLANET zulässig.
+
3.5. Beim Abschluss von Kundenverträgen ist der VP verpflichtet, die von PROFIT PLANET zur Verfügung gestellten Originalunterlagen (zB Antragsformulare, AGB, sonstige Unterlagen der Dienstleister oder Produktgeber) in der jeweils aktuellen Version zu verwenden und dem Kunden bei Vertragsabschluss vorzulegen bzw. auszuhändigen. Die Originalunterlagen sind durch den VP nicht zu verändern, missbräuchliche Verwendung ist zu verhindern.
+
3.6. Kundenverträge in Papierform sind vom VP unverzüglich, spätestens jedoch binnen 1 Woche nach Aufforderung durch PROFIT PLANET oder den Produktgeber an PROFIT PLANET auszuhändigen.
+
3.7. Sämtliche Präsentations-, Werbe- und Schulungsmaterialien sowie label von PROFIT PLANET sind urheberrechtlich geschützt und dürfen ohne ausdrückliches Einverständnis von PROFIT PLANET weder ganz noch teilweise vervielfältigt, verbreitet oder öffentlich zugänglich gemacht werden. Die Herstellung, Verwendung und Verbreitung eigener Werbemittel, Schulungsmaterialien oder Produktbroschüren ist nur nach schriftlicher Genehmigung und Freigabe durch PROFIT PLANET gestattet.
+
3.8. Der VP ist während der Dauer dieser Vereinbarung und für die Dauer von 36 Monaten nach Beendigung dieses Vertrags aus welchem Grund immer, nicht berechtigt, unmittelbar selbst bzw. mittelbar über Dritte Kunden von PROFIT PLANET und ihrer Produktpartner, einschließlich der vom VP vermittelten Endkunden, durch direkte Ansprache abzuwerben. Als Abwerben gilt jede Form des direkten Herantretens an den Kunden mit der Absicht, ihn zum Wechsel zu einem anderen Energieversorgungs-, Dienstleistungs-, Handels-, und/oder Coachingunternehmen zu bewegen (beispielsweise etwa durch Anrufe beim Kunden, Direktmailing mit Absicht der Abwerbung, Haustürgeschäfte etc.).
+
4. Geheimhaltung
+
4.1. Der VP verpflichtet sich, Geschäfts- und Betriebsgeheimnisse und sonstige vertrauliche Informationen von PROFIT PLANET und dessen Struktur, Geschäftspartner, Vertriebspartner / Businesspartner / Affiliate, Produktgeber, Provisionen und Endkunden unter äußerster Geheimhaltung zu behandeln und zu verwahren und diese Daten nur nach erfolgter schriftlicher Zustimmung durch den PROFIT PLANET an Dritte weiterzugeben.
+
4.2. Diese Verpflichtung gilt auch für Mitarbeiter und Unter-Vertriebspartner / Businesspartner / Affiliate des VP. Der VP hat für das Verhalten allfälliger Erfüllungsgehilfen und/oder Subpartner einzustehen.
+
4.3. Zu den Geschäftsgeheimnissen gehören insbesondere auch Informationen zu internen Betriebsabläufen, Provisionen und Provisionsstrukturen, Produkt- und Preiskalkulationen, Vertriebspartner / Businesspartner / Affiliate-strukturen und -aktivitäten.
+
4.4. Dem VP ist es nicht gestattet, auf Presseanfragen zu PROFIT PLANET, dessen Provisionspläne, Produkte oder andere Leistungen zu antworten. Presseanfragen sind immer an PROFIT PLANET weiterzuleiten.
+
5. Datenschutz
+
5.1. Die Vertragspartner sind verpflichtet, die gesetzlichen Datenschutzbestimmungen vollumfänglich einzuhalten. Für Verstöße gegen datenschutzrechtliche Schutzbestimmungen haftet ausschließlich der jeweils die Bestimmung verletzende Vertragspartner, dieser wird den schuldlos handelnden Vertragspartner von allen entsprechenden Ansprüchen freistellen und schad- und klaglos halten.
+
5.2. Im Regelfall ist der VP ist hinsichtlich der Daten der von ihm vermittelten Endkunden und Akquisitionskontakte Subauftragsverarbeiter im Sinne der Datenschutzgesetze (DSG, DSGVO); PROFIT PLANET ist Auftragsverarbeiter im Sinne der DSGVO. Soweit durch die gesetzlichen Bestimmungen vorgesehen, werden zu dieser Vereinbarung entsprechende datenschutzrechtliche Zusatzverträge abgeschlossen.
+
5.3. PROFIT PLANET ist bezüglich der Daten des VP auf Datenschutz verpflichtet. Die Datenschutzerklärung ist Online jederzeit abrufbar.
+
6. VP-Schutz
+
6.1. Ein neu geworbener VP wird in die Struktur desjenigen VP zugewiesen, der ihn geworben hat (VP-Schutz). Wenn mehrere VP denselben VP neu melden, wird seitens PROFIT PLANET nur die zuerst erfolgte Meldung berücksichtigt, wobei das Eingangsdatum des Registrierungsantrags bei PROFIT PLANET für die Zuteilung maßgeblich ist.
+
6.2. Der meldende VP ist verantwortlich dafür, die Daten des geworbenen VP vollständig und ordentlich zu übermitteln. PROFIT PLANET ist berechtigt, die Daten eines geworbenen VP aus ihrem System zu löschen, wenn von diesem innerhalb einer angemessenen Frist keine Umsätze oder Rückmeldungen kommen.
+
6.3. Ein Wechsel von der Struktur eines VP in die eines anderen ist grundsätzlich ausgeschlossen und nur ausnahmsweise möglich, wenn der wechselwillige VP nachweist, dass der in der Struktur über ihm stehende VP versucht hat, ihn zu einem gesetzes- oder vertragswidrigen Verhalten zu veranlassen oder sonst schwerwiegende Vorfälle die weitere Zusammenarbeit in der Struktur dieses VP untragbar machen. Über einen entsprechenden schriftlichen Antrag entscheidet PROFIT PLANET nach freiem Ermessen.
+
6.4. Ein VP, der innerhalb der letzten 12 Monate bereits einen VP-Vertrag mit PROFIT PLANET hatte, kann nicht geworben werden.
+
6.5. Eine Umgehung des VP-Schutzes etwa durch Verwendung der Namen von Strohnamen, -personen oder -firmen ist untersagt.
+
6.6. PROFIT PLANET räumt ihren VP ausdrücklich keinen Gebietsschutz ein. Alle VP können europaweit ohne Einschränkungen tätig sein.
+
7. Provision
+
7.1. Für jedes vom VP erfolgreich vermittelte Vertragsverhältnis zwischen Produktgeber und Endkunden erwirbt der VP Anspruch auf Provision als Bearbeitungs- und Aufwandspauschale
+
7.2. Die Höhe der Provision richtet sich nach der jeweils aktuell gültigen Provisionsübersicht laut Marketingkonzept. Die jeweils gültige Fassung dieser Provisionsübersicht ist jederzeit auf der Website von PROFIT PLANET (www.profit-planet.com) im internen Bereich abrufbar, einsehbar, downloadbar und kann dort auch auf Anfrage zur Verfügung gestellt werden. Änderungen der Provisionsübersicht werden dem VP rechtzeitig bekannt gegeben. Es gelten jeweils die zum Zeitpunkt der Vermittlung gültigen Provisionssätze.
+
7.3. Als erfolgreiche Vermittlung im Sinne dieses Vertrages gilt, wenn das Vertragsverhältnis zwischen Endkunden und Produktpartner tatsächlich zustande gekommen ist. Insbesondere entsteht kein Provisionsanspruch, wenn
+
+ - der Kunde von seinen Widerrufs- oder Rücktrittsrechten Gebrauch macht,
+ - der Vertrag rechtswirksam angefochten wird,
+ - der Kunde vom Dienstleister oder Produktpartner aus welchem Grund auch immer nicht angenommen wird,
+ - fehlerhafte oder unvollständige Kundenanträge eingereicht werden,
+ - der Vertrag widerrechtlich zustande gekommen ist oder
+ - der Dienstleister oder Produktgeber die Auszahlung der Provision an PROFIT PLANET aus Gründen, die nicht von PROFIT PLANET zu verantworten sind, verweigert.
+
+
7.4. Anspruch auf Auszahlung der Provision entsteht gegenüber PROFIT PLANET grundsätzlich erst dann, wenn die Zahlungen seitens des Geschäftspartners / Produktgebers bei PROFIT PLANET eingelangt sind und alle sonstigen Auszahlungsvoraussetzungen vorliegen. Der VP nimmt zur Kenntnis, dass die exakten Zahlungsmodalitäten bei den verschiedenen Dienstleistern oder Produktgebern voneinander abweichen können und PROFIT PLANET diese Unterschiede bei der Auszahlung berücksichtigt. Die unterschiedlichen Zeitspannen divergieren je nach Partnerunternehmen derzeit durchschnittlich zwischen 30 bis 100 Tage. Die genauen Anforderungen und Konditionen ergeben sich aus dem jeweiligen Produktpartnerinformationsblatt und dem Marketingkonzept.
+
7.5. Die Auszahlung durch PROFIT PLANET erfolgt einmal monatlich, ungefähr um den 20. des auf den Zahlungseingang bei PROFIT PLANET folgenden Monats. Die Auszahlung erfolgt bargeldlos per Überweisung auf das vom VP genannte Konto. PROFIT PLANET kann Zahlungen bis zu einer Höhe von EUR 100,00 von der Auszahlung ausschließen (Mindestauszahlungshöhe); die nicht ausbezahlten Provisionsansprüche werden auf dem Provisionskonto des VP rechnerisch fortgeführt und im Folgemonat nach Erreichen der Mindestauszahlungshöhe ausbezahlt. Beträge unterhalb der Mindestauszahlungshöhe werden einmal jährlich zur Auszahlung gebracht.
+
7.6. Der Provisionsanspruch entfällt rückwirkend, wenn PROFIT PLANET, Provisionen an einen Produktgeber zurückzahlen muss, etwa weil ein Kunde den Vertrag widerruft oder andere Ausschlusskriterien seitens des Produktgebers vorliegen (Stornohaftung etc.). PROFIT PLANET ist berechtigt, Forderungen, die dem PROFIT PLANET gegen den VP zustehen, mit dessen Provisionsansprüchen ganz oder teilweise aufzurechnen.
+
7.7. Mit dieser Provision sind sämtliche Tätigkeiten des VP einschließlich aller ihm in Zusammenhang mit dieser Vereinbarung entstandenen Kosten, Auslagen und Aufwendungen, wie beispielsweise Fahrt- und Reisekosten, Bürokosten, Porto und Telefongebühren, abgegolten. Dasselbe gilt für Leistungen des VP in Hinblick auf Pflege und Herstellung eines VP-Bestandes und/oder Kundenstocks, sodass im Fall der Beendigung des Vertrags unbeachtet des Grundes der Auflösung keinesfalls Ansprüche auf Abfindungen oder Ausgleiche jedweder Art gegen PROFIT PLANET bestehen.
+
7.8. Fehlerhafte Provisionszahlungen oder sonstige Zahlungen sind vom VP binnen 60 Tagen schriftlich einzumahnen. Danach gelten die Zahlungen als genehmigt.
+
7.9. Wenn vom VP keine UID-Nummer bekannt gegeben wird, erfolgen alle Auszahlungen netto.
+
8. Vertragsstrafe, Schadenersatz
+
8.1. Bei einem ersten Verstoß gegen die in diesem Vertrag geregelten Pflichten durch den VP erfolgt eine schriftliche Abmahnung durch PROFIT PLANET. Die Pflichtverletzung ist unmittelbar zu beenden bzw. gegebenenfalls zu beheben.
+
8.2. Kommt es erneut zu einem Verstoß gegen diesen Vertrag oder wird der zuerst gemahnte Zustand nicht beseitigt, so verpflichtet sich der VP zur Zahlung einer verschuldensunabhängigen Vertragsstrafe für jeden jeweiligen Verstoß in Höhe von EUR 5.000,00.
+
8.3. Bei Verstößen gegen die Geheimhaltungs- und Datenschutzpflichten, sowie bei besonders schwerwiegenden Verstößen, insbesondere gegen Punkt 10.2 dieses Vertrags, ist PROFIT PLANET auch ohne vorhergehende Abmahnung zur Geltendmachung der jeweiligen Vertragsstrafe berechtigt.
+
8.4. Für jede Zuwiderhandlung gegen Punkt 3.8 verpflichtet sich der VP zur Zahlung einer verschuldens- und schadensunabhängigen Konventionalstrafe an den PROFIT PLANET von EUR 5.000,00 pro Verstoß (z.B. pro an ein anderes Unternehmen oder sonstigen Dritten vermittelten Vertrags oder pro abgeworbenen Kunden). Die Geltendmachung darüber hinausgehender sonstiger Schadenersatzansprüche, der Vertragsstrafe nach 8.2 oder etwa von Erfüllungsansprüchen bleibt dadurch unberührt.
+
8.5. Für jeden Verstoß gegen die in Punkt 4. dieses Vertrags (Geheimhaltungsverpflichtung) normierten Pflichten, verpflichtet sich der VP zur Zahlung einer verschuldensunabhängigen Vertragsstrafe in Höhe von EUR 7.000,00 pro Verstoß. Die Geltendmachung weitergehender zivilrechtlicher Ansprüche – insbesondere auf Unterlassung und Schadenersatz – bleibt davon unberührt.
+
8.6. Bei Handlungen, die dem Katalog außerordentlicher Kündigungsgründe gemäß Punkt 10.2 entsprechen, insbesondere bei treuwidrigem Verhalten im Sinne der dort beschriebenen Fallgruppen (z. B. unautorisierte Kaltakquise, rufschädigendes Verhalten, unbefugtes Auftreten im Namen von PROFIT PLANET), verpflichtet sich der VP zur Zahlung einer verschuldensunabhängigen Vertragsstrafe in Höhe von EUR 10.000,00 pro Verstoß. Auch in diesen Fällen bleiben darüber hinausgehende Ansprüche – insbesondere Schadenersatz oder außerordentliche Kündigung – ausdrücklich vorbehalten.
+
+
9. Haftungsausschluss
+
9.1. Der VP führt seine Tätigkeiten nach bestem Wissen und Gewissen und in eigener Verantwortung, insbesondere auch in Bezug auf die korrekte Beratung der Endkunden aus. Eine Haftungsübernahme von PROFIT PLANET für Falschberatungen oder sonstiges Fehlverhalten des VP ist explizit ausgeschlossen.
+
9.2. Für Schäden haftet PROFIT PLANET nur, soweit diese auf Vorsatz oder grober Fahrlässigkeit oder auf grob schuldhafter Verletzung einer wesentlichen Vertragspflicht durch PROFIT PLANET, ihrer Mitarbeiter oder Erfüllungsgehilfen beruhen.
+
9.3. Eine Haftung von PROFIT PLANET für mittelbare Schäden, Folgeschäden, entgangenen Gewinn oder erwartete Ersparnis ist jedenfalls ausgeschlossen.
+
9.4. PROFIT PLANET übernimmt keine Haftung für Schäden, die durch Datenverlust auf den Servern auftreten, außer der Schaden beruht auf Vorsatz oder grober Fahrlässigkeit seitens PROFIT PLANET, ihrer Mitarbeiter oder Erfüllungsgehilfen.
+
9.5. Der Eintritt eines Schadens ist PROFIT PLANET unverzüglich mitzuteilen.
+
10. Vertragsdauer & Kündigung
+
10.1. Der Vertrag tritt mit Unterzeichnung oder im Fall einer Online-Registrierung, Online mit der Annahme des Vertrags durch PROFIT PLANET in Kraft und wird auf unbestimmte Zeit geschlossen. Er kann von beiden Parteien unter Einhaltung einer Frist von drei Monaten zum Ende jedes Kalendermonats schriftlich gekündigt werden.
+
10.2. Dessen ungeachtet kann der Vertrag seitens PROFIT PLANET aus wichtigem Grund ohne Einhaltung einer Kündigungsfrist gekündigt werden. Das Recht zur außerordentlichen Kündigung besteht ungeachtet weiterer Ansprüche. Folgende Gründe berechtigen insbesondere zur außerordentlichen Kündigung, die Aufzählung ist nicht abschließend:
+
+ - Akte treuwidrigen Verhaltens, die eine weitere Zusammenarbeit zw. den Vertragspartnern unzumutbar machen;
+ - ein solches treuwidriges Verhalten liegt insbesondere etwa dann vor, wenn ein VP ohne ausdrückliche Zustimmung eines vertretungs- und zeichnungsbefugten Organs von PROFIT PLANET Handlungen setzt, welche nach außen den Anschein erwecken, im Namen oder Auftrag von PROFIT PLANET zu erfolgen – insbesondere etwa durch Kaltakquise, Verwendung von Geschäftsdrucksorten oder -signaturen, Auftritt unter Verwendung der Marke PROFIT PLANET oder vergleichbare ruf- bzw. imageschädigende Aktivitäten.
+ - die Anwendung unlauterer Praktiken oder ein grober oder wiederholter Verstoß gegen diesen Vertrag sowie der Verstoß gegen zwingende Rechtsnormen;
+ - wenn über das Vermögen des jeweils anderen Vertragspartners die Einleitung eines Insolvenzverfahrens beantragt oder wenn die Eröffnung eines Insolvenzverfahrens mangels Masse abgelehnt wird;
+ - Verletzung der vereinbarten oder gesetzlichen Datenschutz- oder Geheimhaltungspflichten;
+ - wenn die Kooperation durch das Verhalten eines Vertragspartners oder dessen Ruf in der Öffentlichkeit den anderen Vertragspartnern einen Imageschaden zufügen würde;
+ - wenn die Kooperation aufgrund der Gesetzeslage oder von dritter Seite als unzulässig untersagt wird;
+ - Unzulässige Nebenabsprachen mit am Vertrieb beteiligten Dritten;
+
+
10.3. Abgesehen von 10.2 kann PROFIT PLANET den VP auch außerordentlich kündigen, wenn dieser in den letzten 6 Monaten keine neuen Umsätze erzielt hat oder bei den durch seine Vermittlung zustande gekommenen Verträgen zwischen Endkunden und Produktgebern über einen Zeitraum von 2 Monaten überdurchschnittliche Stornoquoten von mehr als 30% der vermittelten Verträge bestehen. PROFIT PLANET wird den VP vor einer außerordentlichen Kündigung nach diesem Passus einmalig schriftlich verwarnen, so dass der VP die Möglichkeit hat, innerhalb einer Frist von 30 Tagen die erforderlichen neuen Umsätze zu generieren oder seine Stornoquote zu verbessern.
+
10.4. Mit der Beendigung des Vertrags steht dem VP mit Ausnahme der Provision für zu diesem Zeitpunkt bereits erfolgreich vermittelte Verträge, kein Recht auf Provision mehr zu. Ein Anspruch auf Handelsvertreterausgleich ist ausdrücklich ausgeschlossen, da der VP nicht als Handelsvertreter für den PROFIT PLANET tätig wird. Etwaige Ansprüche auf Folgeprovisionen für vermittelte Produkte bestehen für 12 Monate nach Vertragsbeendigung fort; im Falle einer außerordentlichen Kündigung verfallen Ansprüche auf Folgeprovisionen unmittelbar mit der Vertragsbeendigung.
+
10.5. Nach Beendigung des Vertrags sind vom VP sämtliche überlassenen Unterlagen und Werbematerialien unaufgefordert binnen einem Monat an PROFIT PLANET zurückzugeben. Die Verwendung der Marke PROFIT PLANET und entsprechender Logos etwa auf Briefpapier oder in E-Mail-Signaturen ist nach Beendigung des Vertrags untersagt.
+
11. Übertragung
+
11.1. PROFIT PLANET ist jederzeit berechtigt, den Geschäftsbetrieb ganz oder teilweise auf Dritte zu übertragen.
+
11.2. Der VP ist nur mit ausdrücklicher Zustimmung von PROFIT PLANET berechtigt, seine Vertriebsstruktur an einen Dritten zu übertragen.
+
11.3. Wenn eine als VP registrierte Kapital- oder Personengesellschaft einen neuen Gesellschafter aufnimmt, hat dies auf diesen Vertrag keine Auswirkung, sofern der/die Gesellschafter, die den VP-Antrag ursprünglich unterzeichnet haben, als Gesellschafter in der Gesellschaft verbleiben. Wenn ein Gesellschafter aus einer registrierten Gesellschaft ausscheidet oder seine Anteile an einen Dritten überträgt, so ist dies in Bezug auf diesen Vertrag zulässig, sofern er dies PROFIT PLANET schriftlich unter Vorlage der entsprechenden rechtsgültigen Urkunden anzeigt, und der Vorgang keinen anderen Bestimmungen dieses Vertrags widerspricht; anderenfalls behält PROFIT PLANET sich das Recht vor, den VP-Vertrag der betreffenden Kapital- oder Personengesellschaft aufzukündigen.
+
11.4. Bei Auflösung einer als VP registrierten Gemeinschaft (Kapital- oder Personengesellschaft, aber auch z.B. Ehepartnerschaften oder ähnliches, die einen gemeinsamen VP-Vertrag haben), bleibt nur ein VP-Vertrag bestehen. Die Mitglieder der aufzulösenden Gemeinschaft haben sich intern zu einigen, durch welches Mitglied/Gesellschafter die Vertriebspartner / Businesspartner / Affiliateschaft fortgesetzt werden soll, und dies PROFIT PLANET schriftlich anzuzeigen. Falls sich die Mitglieder der Gemeinschaft in Bezug auf die Fortsetzung des VP-vertrags nicht gütlich einigen können, behält sich PROFIT PLANET das Recht einer außerordentlichen Kündigung vor, insbesondere, wenn es durch die Uneinigkeit über die Folgen zur Vernachlässigung der Pflichten des VP, einem Verstoß gegen diesen Vertrag oder geltendes Recht oder zu einer übermäßigen Belastung der Vertriebsstruktur des VP kommt.
+
+
+
+
12. Schlussbestimmungen
+
12.1. Änderungen und Ergänzungen dieser Vereinbarung bedürfen der Schriftform. Dies gilt auch für das Abgehen der Schriftformerfordernis. Mündliche Nebenabreden bestehen nicht.
+
12.2. Sollte eine Bestimmung dieser Vereinbarung unwirksam sein oder werden, gilt anstelle der unwirksamen Bestimmung jene Bestimmung als vereinbart, die dem wirtschaftlichen Zweck der unwirksamen Bestimmung am nächsten kommt.
+
12.3. Vereinbarter Gerichtsstand für alle Streitigkeiten aus oder in Zusammenhang mit dieser Vereinbarung ist das für Graz sachlich zuständige Gericht. Diese Vereinbarung unterliegt österreichischem Recht, nicht jedoch den nichtzwingenden Verweisungsnormen des IPR. Weiter- bzw. Rückverweisungen sind ausgeschlossen. Darüber hinaus steht es PROFIT PLANET frei, den VP auch seinem allgemeinen Gerichtsstand zu klagen.
+
+
+
Für PROFIT PLANET (Auftraggeber)
+
+
+
{{profitplanetSignature}}
+
{{currentDate}}
+
+
Datum, Unterschrift
+
+
+
Für den VP (Auftragnehmer)
+
+
{{signatureImage}}
+
{{fullName}}
+
{{currentDate}}
+
+
Name, Datum, Unterschrift
+
+
+
+
+
+
\ No newline at end of file
diff --git a/debug-pdf/template_4_html_full.html b/debug-pdf/template_4_html_full.html
new file mode 100644
index 0000000..4df6877
--- /dev/null
+++ b/debug-pdf/template_4_html_full.html
@@ -0,0 +1,229 @@
+
+
+
+
+
+ SUB-AUFTRAGSVERARBEITUNGS-VERTRAG
+
+
+
+
+
+
+
+
+
+
SUB-AUFTRAGSVERARBEITUNGS-VERTRAG
+
i.S.d. Art. 28 Abs. 3 Datenschutz-Grundverordnung (DS-GVO)
+
+
+
abgeschlossen zwischen
+
Profit Planet GmbH (kurz Auftraggeber)
+ FN 649474i
+ Liebenauer Hauptstraße 82c
+ A-8041 Graz
+
und
+
Vertriebspartner (kurz Auftragnehmer)
+
+
+
+
+
1. PRÄAMBEL
+
+
1.1. Diese Anlage konkretisiert die Verpflichtungen der Vertragsparteien zum Datenschutz, die sich aus der im bestehenden Vertriebspartner-Vertrag („Hauptvertrag“) und seinen Anlagen in ihren Einzelheiten beschriebenen Auftragsverarbeitung ergeben. Sie findet Anwendung auf alle Tätigkeiten, die mit dem Vertrag in Zusammenhang stehen, und bei denen Beschäftigte des Auftragnehmers oder durch den Auftragnehmer Beauftragte personenbezogene Daten („Daten“) des Auftraggebers verarbeiten.
+
1.2. Der Auftragnehmer ist sich bewusst, dass der Auftraggeber als Auftragsverarbeiter für Dritte („Verantwortliche“ im Sinne des Art. 4 Nr. 7 DS-GVO) tätig ist. Im Rahmen des vorbezeichneten Hauptvertrags nimmt der Auftraggeber die Dienste des Auftragnehmers als „weiteren Auftragsverarbeiter“ im Sinne von Art. 28 Nr. 4 DS-GVO in Anspruch, um bestimmte Verarbeitungstätigkeiten im Namen des Dritten („Verantwortlicher“ iSd Art. 4 Nr. 7 DS-GVO) auszuführen.
+
1.3. Der Auftragnehmer ist sich bewusst, dass der Auftraggeber gegenüber Dritten für die Einhaltung der Pflichten des Auftragnehmers haftet, falls der Auftragnehmer seinen Datenschutzpflichten nach diesem Vertrag und nach dem Gesetz nicht nachkommt.
+
1.4. Die Laufzeit dieser Anlage richtet sich nach der Laufzeit des Vertriebspartner-Vertrages, sofern sich aus den Bestimmungen dieser Anlage nicht darüber hinausgehende Verpflichtungen ergeben.
+
+
+
+
+
2. DAUER, GEGENSTAND UND SPEZIFIZIERUNG DER AUFTRAGSVERARBEITUNG
+
+
2.1. Alle Daten dürfen nur so lange verarbeitet werden, als das durch die Vertragserfüllung oder den Zweck der Datenverarbeitung erforderlich ist.
+
2.2. Aus dem Vertrag ergeben sich Gegenstand und Dauer des Auftrags sowie Art und Zweck der Verarbeitung.
+
2.3. Im Einzelnen sind insbesondere die folgenden Daten Bestandteil der Datenverarbeitung:
+
+
+
+
+
+
+
+
+
+
+ | Art der Daten |
+ Interessenten- und Kundendaten; Kontaktdaten beim Auftraggeber; Kontaktdaten des jeweiligen Datenverantwortlichen |
+
+
+ | Art und Zweck der Datenverarbeitung |
+ Datenerfassung beim Interessenten (potenziellen Kunden); Datenübermittlung (auch elektronisch via E-Mail bzw. falls vorhanden über elektronische Schnittstellen der Verantwortlichen) an Auftraggeber bzw. Datenverantwortliche zur Legung eines Angebots bzw. zur Verwirklichung der Kundenbestellung; ggf. telefonischer Nachkontakt zur Qualitätskontrolle |
+
+
+ | Kategorien betroffener Daten |
+ Name, Vorname, Adresse, Geburtsdatum, SV-Nr., E-Mail, Kontodaten Ausweiskopie; Daten zur Energieversorgung (z.B. Zählpunkt, Zählernummer, Kilowattprognose, Jahresverbrauch); Aufzeichnung etwaiger Qualitätskontrollen; Aufzeichnung etwaiger Interessensgebiete im Bereich Versicherung, Kreditwirtschaft, Telekommunikation, Energieeffizienz (PV, Speicher, LED, Infrarotheizung, Kalkschutz…). |
+
+
+
+
+
3. ANWENDUNGSBEREICH UND VERANTWORTLICHKEIT
+
+
3.1. Der Auftragnehmer verarbeitet personenbezogene Daten im Auftrag des Auftraggebers. Dies umfasst Tätigkeiten, die im Vertrag und in der Leistungsbeschreibung konkretisiert sind.
+
3.2. Der Auftraggeber ist gegenüber dem/den Dritten als („Verantwortliche Person“ iSd Art. 4 Nr. 7 DS-GVO) für die Einhaltung der gesetzlichen Bestimmungen der Datenschutzgesetze, insbesondere für die Rechtmäßigkeit der Datenweitergabe an den Auftragnehmer sowie für die Rechtmäßigkeit der Datenverarbeitung verantwortlich.
+
3.3. Der Auftragnehmer ist gegenüber dem Auftraggeber im Rahmen dieses Vertrages für die Einhaltung der gesetzlichen Bestimmungen der Datenschutzgesetze, insbesondere für die Rechtmäßigkeit der Datenweitergabe sowie der Datenverarbeitung verantwortlich.
+
3.4. Die Weisungen werden anfänglich durch diese Vertragsanlage festgelegt und können vom Auftraggeber danach in schriftlicher Form oder in einem elektronischen Format (Textform) an die vom Auftragnehmer bezeichnete Stelle durch einzelne Weisungen geändert, ergänzt oder ersetzt werden (Einzelweisung). Weisungen, die in der Vertragsanlage nicht vorgesehen sind, werden als Antrag auf Leistungsänderung behandelt. Mündliche Weisungen sind unverzüglich schriftlich oder in Textform zu bestätigen.
+
+
+
+
+
4. PFLICHTEN DES AUFTRAGNEHMERS
+
+
4.1. Der Auftragnehmer darf Daten von betroffenen Personen nur im Rahmen des Auftrages und der Weisungen des Auftraggebers verarbeiten, außer es liegt ein Ausnahmefall iSd Art 28 Abs. 3 a) DS-GVO vor. Der Auftragnehmer informiert den Auftraggeber unverzüglich, wenn er der Auffassung ist, dass eine Weisung gegen anwendbare Gesetze verstößt. Der Auftragnehmer darf die Umsetzung der Weisung solange aussetzen, bis sie vom Auftraggeber bestätigt oder abgeändert wurde.
+
4.2. Der Auftragnehmer wird in seinem Verantwortungsbereich die innerbetriebliche Organisation so gestalten, dass sie den besonderen Anforderungen des Datenschutzes gerecht wird. Er wird technische und organisatorische Maßnahmen zum angemessenen Schutz der Daten des Auftraggebers treffen, die den Anforderungen der Datenschutz- Grundverordnung (Art. 32 DS-GVO) genügen. Der Auftragnehmer hat technische und organisatorische Maßnahmen zu treffen, die die Vertraulichkeit, Integrität, Verfügbarkeit und Belastbarkeit der Systeme und Dienste im Zusammenhang mit der Verarbeitung auf Dauer sicherstellen. Der Auftraggeber ist berechtigt, diese technischen und organisatorischen Maßnahmen dahingehend zu überprüfen, ob sie für die Risiken der zu verarbeitenden Daten ein angemessenes Schutzniveau bieten. Eine Änderung der getroffenen Sicherheitsmaßnahmen bleibt dem Auftragnehmer vorbehalten, wobei jedoch sichergestellt sein muss, dass das vertraglich vereinbarte Schutzniveau nicht unterschritten wird.
+
4.3. Der Auftragnehmer gewährleistet, seinen Pflichten nach Art. 32 Abs. 1 lit. d) DS-GVO nachzukommen, ein Verfahren zur regelmäßigen Überprüfung der Wirksamkeit der technischen und organisatorischen Maßnahmen zur Gewährleistung der Sicherheit der Verarbeitung einzusetzen.
+
4.4. Der Auftragnehmer unterstützt den Auftraggeber im Rahmen seiner Möglichkeiten bei der Erfüllung der Anfragen und Ansprüche betroffener Personen gem. Kapitel III der DS-GVO sowie bei der Einhaltung der in Art. 33 bis 36 DS-GVO genannten Pflichten.
+
4.5. Der Auftragnehmer gewährleistet, dass es den mit der Verarbeitung der Daten des Auftraggebers befassten Mitarbeiter und andere für den Auftragnehmer tätigen Personen untersagt ist, die Daten außerhalb der Weisung zu verarbeiten. Ferner gewährleistet der Auftragnehmer, dass sich die zur Verarbeitung der personenbezogenen Daten befugten Personen zur Vertraulichkeit verpflichtet haben oder einer angemessenen gesetzlichen Verschwiegenheitspflicht unterliegen. Die Vertraulichkeits-/ Verschwiegenheitspflicht besteht auch nach Beendigung des Auftrages fort.
+
+
+
+
+
+
+
4.6. Der Auftragnehmer unterrichtet den Auftraggeber unverzüglich, wenn ihm Verletzungen des Schutzes personenbezogener Daten des Auftraggebers bekannt werden. Der Auftragnehmer trifft die erforderlichen Maßnahmen zur Sicherung der Daten und zur Minderung möglicher nachteiliger Folgen der betroffenen Personen und spricht sich hierzu unverzüglich mit dem Auftraggeber ab.
+
4.7. Der Auftragnehmer nennt dem Auftraggeber den Ansprechpartner für im Rahmen des Vertrages anfallende Datenschutzfragen.
+
4.8. Der Auftragnehmer berichtigt oder löscht die vertragsgegenständlichen Daten, wenn der Auftraggeber dies anweist und dies vom Weisungsrahmen umfasst ist. Ist eine datenschutzkonforme Löschung oder eine entsprechende Einschränkung der Datenverarbeitung nicht möglich, übernimmt der Auftragnehmer die datenschutzkonforme Vernichtung von Datenträgern und sonstigen Materialien auf Grund einer Einzelbeauftragung durch den Auftraggeber oder gibt diese Datenträger an den Auftraggeber zurück, sofern nicht im Vertrag bereits vereinbart.
+
4.9. Daten, Datenträger sowie sämtliche sonstige Materialien sind nach Auftragsende auf Verlangen des Auftraggebers entweder herauszugeben oder zu löschen.
+
4.10. Im Falle einer Inanspruchnahme des Auftraggebers oder des Dritten durch eine betroffene Person hinsichtlich etwaiger Ansprüche nach Art. 82 DS-GVO, verpflichtet sich der Auftragnehmer den Auftraggeber bei der Abwehr des Anspruches im Rahmen seiner Möglichkeiten zu unterstützen.
+
4.11. Im Falle einer Inanspruchnahme des Auftraggebers durch den Dritten, verpflichtet sich der Auftragnehmer den Auftraggeber bei der Abwehr des Anspruches im Rahmen seiner Möglichkeiten zu unterstützen.
+
+
+
+
+
5. PFLICHTEN DES AUFTRAGGEBERS
+
+
5.1. Der Auftraggeber hat den Auftragnehmer unverzüglich und vollständig zu informieren, wenn er in den Auftragsergebnissen Fehler oder Unregelmäßigkeiten bzgl. datenschutzrechtlicher Bestimmungen feststellt.
+
5.2. Im Falle einer Inanspruchnahme des Auftraggebers oder des Dritten durch eine betroffene Person hinsichtlich etwaiger Ansprüche nach Art. 82 DS-GVO, gilt §3 Abs. 10 entsprechend.
+
5.3. Der Auftraggeber nennt dem Auftragnehmer den Ansprechpartner für im Rahmen des Vertrages anfallende Datenschutzfragen.
+
+
+
+
+
6. ANFRAGEN BETROFFENER PERSONEN
+
+
6.1. Wendet sich eine betroffene Person mit Forderungen zur Berichtigung, Löschung oder Auskunft an den Auftragnehmer, wird der Auftragnehmer die betroffene Person an den Auftraggeber verweisen und ggf. den Antrag der betroffenen Person unverzüglich an den Auftraggeber weiterleiten. Der Auftragnehmer unterstützt den Auftraggeber im Rahmen seiner Möglichkeiten bei der Erfüllung der jeweiligen Forderung.
+
6.2. Der Auftragnehmer haftet nicht, wenn das Ersuchen der betroffenen Person vom Auftraggeber nicht, nicht richtig oder nicht fristgerecht beantwortet wird.
+
6.3. Der Auftraggeber haftet nicht für Forderungen betroffener Personen, die dadurch entstehen, dass der Auftragnehmer das entsprechende Anliegen nicht zeitgerecht an den Auftraggeber übermittelt hat.
+
+
+
+
+
7. NACHWEISMÖGLICHKEITEN
+
+
7.1. Der Auftragnehmer weist dem Auftraggeber die Einhaltung der in diesem Vertrag niedergelegten Pflichten mit geeigneten Mitteln nach.
+
7.2. Sollten im Einzelfall Inspektionen durch den Auftraggeber oder einen von diesem beauftragten Prüfer erforderlich sein, werden diese zu den üblichen Geschäftszeiten ohne Störung des Betriebsablaufs nach Anmeldung unter Berücksichtigung einer angemessenen Vorlaufzeit durchgeführt. Der Auftragnehmer darf diese von der Unterzeichnung einer Verschwiegenheitserklärung hinsichtlich der Daten anderer Kunden und der eingerichteten technischen und organisatorischen Maßnahmen abhängig machen. Sollte der durch den Auftraggeber beauftragte Prüfer in einem Wettbewerbsverhältnis zu dem Auftragnehmer stehen, hat der Auftragnehmer gegen diesen ein Einspruchsrecht
+
+
+
+
+
+
8. SUBUNTERNEHMER (WEITERE AUFTRAGSVERARBEITER)
+
+
8.1. Der Einsatz von Subunternehmern als weitere Auftragsverarbeiter ist nur zulässig, wenn der Auftraggeber vorher zugestimmt hat.
+
8.2. Ein zustimmungspflichtiges Subunternehmerverhältnis liegt vor, wenn der Auftragnehmer weitere Auftragnehmer mit der ganzen oder einer Teilleistung der im Vertrag vereinbarten Leistung beauftragt. Der Auftragnehmer wird mit diesen Dritten im erforderlichen Umfang Vereinbarungen treffen, um angemessene Datenschutz- und Informationssicherheitsmaßnahmen zu gewährleisten.
+
8.3. Erteilt der Auftragnehmer Aufträge an Subunternehmer, so obliegt es dem Auftragnehmer, seine datenschutzrechtlichen Pflichten aus diesem Vertrag dem Subunternehmer zu überbinden.
+
+
+
+
+
9. INFORMATIONSPFLICHTEN, SCHRIFTFORMKLAUSEL, RECHTSWAHL
+
+
9.1. Sollten die Daten des Auftraggebers beim Auftragnehmer durch Pfändung oder Beschlagnahme, durch ein Insolvenz- oder Vergleichsverfahren oder durch sonstige Ereignisse oder Maßnahmen Dritter gefährdet werden, so hat der Auftragnehmer den Auftraggeber unverzüglich darüber zu informieren. Der Auftragnehmer wird alle in diesem Zusammenhang Verantwortlichen unverzüglich darüber informieren, dass die Hoheit und das Eigentum an den Daten ausschließlich beim Dritten als verantwortliche Person im Sinne der Datenschutz-Grundverordnung liegen.
+
9.2. Änderungen und Ergänzungen dieser Anlage und aller ihrer Bestandteile – einschließlich etwaiger Zusicherungen des Auftragnehmers – bedürfen einer schriftlichen Vereinbarung, die auch in einem elektronischen Format (Textform) erfolgen kann, und des ausdrücklichen Hinweises darauf, dass es sich um eine Änderung bzw. Ergänzung dieser Bedingungen handelt. Dies gilt auch für den Verzicht auf dieses Formerfordernis.
+
9.3. Bei etwaigen Widersprüchen gehen Regelungen dieser Anlage zum Datenschutz den Regelungen des Vertrages vor. Sollten einzelne Teile dieser Anlage unwirksam sein, so berührt dies die Wirksamkeit der Anlage im Übrigen nicht.
+
9.4. Es gilt das auf dem Hauptvertrag anwendbare Recht sowie Gerichtsstand.
+
+
+
+
+
+
Für PROFIT PLANET (Auftraggeber)
+
+
+
{{profitplanetSignature}}
+
{{currentDate}}
+
+
Datum, Unterschrift
+
+
+
Für den VP (Auftragnehmer)
+
+
{{signatureImage}}
+
{{fullName}}
+
{{currentDate}}
+
+
Name, Datum, Unterschrift
+
+
+
+
+
+
\ No newline at end of file
diff --git a/debug-pdf/template_4_html_raw.bin b/debug-pdf/template_4_html_raw.bin
new file mode 100644
index 0000000..4df6877
--- /dev/null
+++ b/debug-pdf/template_4_html_raw.bin
@@ -0,0 +1,229 @@
+
+
+
+
+
+ SUB-AUFTRAGSVERARBEITUNGS-VERTRAG
+
+
+
+
+
+
+
+
+
+
SUB-AUFTRAGSVERARBEITUNGS-VERTRAG
+
i.S.d. Art. 28 Abs. 3 Datenschutz-Grundverordnung (DS-GVO)
+
+
+
abgeschlossen zwischen
+
Profit Planet GmbH (kurz Auftraggeber)
+ FN 649474i
+ Liebenauer Hauptstraße 82c
+ A-8041 Graz
+
und
+
Vertriebspartner (kurz Auftragnehmer)
+
+
+
+
+
1. PRÄAMBEL
+
+
1.1. Diese Anlage konkretisiert die Verpflichtungen der Vertragsparteien zum Datenschutz, die sich aus der im bestehenden Vertriebspartner-Vertrag („Hauptvertrag“) und seinen Anlagen in ihren Einzelheiten beschriebenen Auftragsverarbeitung ergeben. Sie findet Anwendung auf alle Tätigkeiten, die mit dem Vertrag in Zusammenhang stehen, und bei denen Beschäftigte des Auftragnehmers oder durch den Auftragnehmer Beauftragte personenbezogene Daten („Daten“) des Auftraggebers verarbeiten.
+
1.2. Der Auftragnehmer ist sich bewusst, dass der Auftraggeber als Auftragsverarbeiter für Dritte („Verantwortliche“ im Sinne des Art. 4 Nr. 7 DS-GVO) tätig ist. Im Rahmen des vorbezeichneten Hauptvertrags nimmt der Auftraggeber die Dienste des Auftragnehmers als „weiteren Auftragsverarbeiter“ im Sinne von Art. 28 Nr. 4 DS-GVO in Anspruch, um bestimmte Verarbeitungstätigkeiten im Namen des Dritten („Verantwortlicher“ iSd Art. 4 Nr. 7 DS-GVO) auszuführen.
+
1.3. Der Auftragnehmer ist sich bewusst, dass der Auftraggeber gegenüber Dritten für die Einhaltung der Pflichten des Auftragnehmers haftet, falls der Auftragnehmer seinen Datenschutzpflichten nach diesem Vertrag und nach dem Gesetz nicht nachkommt.
+
1.4. Die Laufzeit dieser Anlage richtet sich nach der Laufzeit des Vertriebspartner-Vertrages, sofern sich aus den Bestimmungen dieser Anlage nicht darüber hinausgehende Verpflichtungen ergeben.
+
+
+
+
+
2. DAUER, GEGENSTAND UND SPEZIFIZIERUNG DER AUFTRAGSVERARBEITUNG
+
+
2.1. Alle Daten dürfen nur so lange verarbeitet werden, als das durch die Vertragserfüllung oder den Zweck der Datenverarbeitung erforderlich ist.
+
2.2. Aus dem Vertrag ergeben sich Gegenstand und Dauer des Auftrags sowie Art und Zweck der Verarbeitung.
+
2.3. Im Einzelnen sind insbesondere die folgenden Daten Bestandteil der Datenverarbeitung:
+
+
+
+
+
+
+
+
+
+
+ | Art der Daten |
+ Interessenten- und Kundendaten; Kontaktdaten beim Auftraggeber; Kontaktdaten des jeweiligen Datenverantwortlichen |
+
+
+ | Art und Zweck der Datenverarbeitung |
+ Datenerfassung beim Interessenten (potenziellen Kunden); Datenübermittlung (auch elektronisch via E-Mail bzw. falls vorhanden über elektronische Schnittstellen der Verantwortlichen) an Auftraggeber bzw. Datenverantwortliche zur Legung eines Angebots bzw. zur Verwirklichung der Kundenbestellung; ggf. telefonischer Nachkontakt zur Qualitätskontrolle |
+
+
+ | Kategorien betroffener Daten |
+ Name, Vorname, Adresse, Geburtsdatum, SV-Nr., E-Mail, Kontodaten Ausweiskopie; Daten zur Energieversorgung (z.B. Zählpunkt, Zählernummer, Kilowattprognose, Jahresverbrauch); Aufzeichnung etwaiger Qualitätskontrollen; Aufzeichnung etwaiger Interessensgebiete im Bereich Versicherung, Kreditwirtschaft, Telekommunikation, Energieeffizienz (PV, Speicher, LED, Infrarotheizung, Kalkschutz…). |
+
+
+
+
+
3. ANWENDUNGSBEREICH UND VERANTWORTLICHKEIT
+
+
3.1. Der Auftragnehmer verarbeitet personenbezogene Daten im Auftrag des Auftraggebers. Dies umfasst Tätigkeiten, die im Vertrag und in der Leistungsbeschreibung konkretisiert sind.
+
3.2. Der Auftraggeber ist gegenüber dem/den Dritten als („Verantwortliche Person“ iSd Art. 4 Nr. 7 DS-GVO) für die Einhaltung der gesetzlichen Bestimmungen der Datenschutzgesetze, insbesondere für die Rechtmäßigkeit der Datenweitergabe an den Auftragnehmer sowie für die Rechtmäßigkeit der Datenverarbeitung verantwortlich.
+
3.3. Der Auftragnehmer ist gegenüber dem Auftraggeber im Rahmen dieses Vertrages für die Einhaltung der gesetzlichen Bestimmungen der Datenschutzgesetze, insbesondere für die Rechtmäßigkeit der Datenweitergabe sowie der Datenverarbeitung verantwortlich.
+
3.4. Die Weisungen werden anfänglich durch diese Vertragsanlage festgelegt und können vom Auftraggeber danach in schriftlicher Form oder in einem elektronischen Format (Textform) an die vom Auftragnehmer bezeichnete Stelle durch einzelne Weisungen geändert, ergänzt oder ersetzt werden (Einzelweisung). Weisungen, die in der Vertragsanlage nicht vorgesehen sind, werden als Antrag auf Leistungsänderung behandelt. Mündliche Weisungen sind unverzüglich schriftlich oder in Textform zu bestätigen.
+
+
+
+
+
4. PFLICHTEN DES AUFTRAGNEHMERS
+
+
4.1. Der Auftragnehmer darf Daten von betroffenen Personen nur im Rahmen des Auftrages und der Weisungen des Auftraggebers verarbeiten, außer es liegt ein Ausnahmefall iSd Art 28 Abs. 3 a) DS-GVO vor. Der Auftragnehmer informiert den Auftraggeber unverzüglich, wenn er der Auffassung ist, dass eine Weisung gegen anwendbare Gesetze verstößt. Der Auftragnehmer darf die Umsetzung der Weisung solange aussetzen, bis sie vom Auftraggeber bestätigt oder abgeändert wurde.
+
4.2. Der Auftragnehmer wird in seinem Verantwortungsbereich die innerbetriebliche Organisation so gestalten, dass sie den besonderen Anforderungen des Datenschutzes gerecht wird. Er wird technische und organisatorische Maßnahmen zum angemessenen Schutz der Daten des Auftraggebers treffen, die den Anforderungen der Datenschutz- Grundverordnung (Art. 32 DS-GVO) genügen. Der Auftragnehmer hat technische und organisatorische Maßnahmen zu treffen, die die Vertraulichkeit, Integrität, Verfügbarkeit und Belastbarkeit der Systeme und Dienste im Zusammenhang mit der Verarbeitung auf Dauer sicherstellen. Der Auftraggeber ist berechtigt, diese technischen und organisatorischen Maßnahmen dahingehend zu überprüfen, ob sie für die Risiken der zu verarbeitenden Daten ein angemessenes Schutzniveau bieten. Eine Änderung der getroffenen Sicherheitsmaßnahmen bleibt dem Auftragnehmer vorbehalten, wobei jedoch sichergestellt sein muss, dass das vertraglich vereinbarte Schutzniveau nicht unterschritten wird.
+
4.3. Der Auftragnehmer gewährleistet, seinen Pflichten nach Art. 32 Abs. 1 lit. d) DS-GVO nachzukommen, ein Verfahren zur regelmäßigen Überprüfung der Wirksamkeit der technischen und organisatorischen Maßnahmen zur Gewährleistung der Sicherheit der Verarbeitung einzusetzen.
+
4.4. Der Auftragnehmer unterstützt den Auftraggeber im Rahmen seiner Möglichkeiten bei der Erfüllung der Anfragen und Ansprüche betroffener Personen gem. Kapitel III der DS-GVO sowie bei der Einhaltung der in Art. 33 bis 36 DS-GVO genannten Pflichten.
+
4.5. Der Auftragnehmer gewährleistet, dass es den mit der Verarbeitung der Daten des Auftraggebers befassten Mitarbeiter und andere für den Auftragnehmer tätigen Personen untersagt ist, die Daten außerhalb der Weisung zu verarbeiten. Ferner gewährleistet der Auftragnehmer, dass sich die zur Verarbeitung der personenbezogenen Daten befugten Personen zur Vertraulichkeit verpflichtet haben oder einer angemessenen gesetzlichen Verschwiegenheitspflicht unterliegen. Die Vertraulichkeits-/ Verschwiegenheitspflicht besteht auch nach Beendigung des Auftrages fort.
+
+
+
+
+
+
+
4.6. Der Auftragnehmer unterrichtet den Auftraggeber unverzüglich, wenn ihm Verletzungen des Schutzes personenbezogener Daten des Auftraggebers bekannt werden. Der Auftragnehmer trifft die erforderlichen Maßnahmen zur Sicherung der Daten und zur Minderung möglicher nachteiliger Folgen der betroffenen Personen und spricht sich hierzu unverzüglich mit dem Auftraggeber ab.
+
4.7. Der Auftragnehmer nennt dem Auftraggeber den Ansprechpartner für im Rahmen des Vertrages anfallende Datenschutzfragen.
+
4.8. Der Auftragnehmer berichtigt oder löscht die vertragsgegenständlichen Daten, wenn der Auftraggeber dies anweist und dies vom Weisungsrahmen umfasst ist. Ist eine datenschutzkonforme Löschung oder eine entsprechende Einschränkung der Datenverarbeitung nicht möglich, übernimmt der Auftragnehmer die datenschutzkonforme Vernichtung von Datenträgern und sonstigen Materialien auf Grund einer Einzelbeauftragung durch den Auftraggeber oder gibt diese Datenträger an den Auftraggeber zurück, sofern nicht im Vertrag bereits vereinbart.
+
4.9. Daten, Datenträger sowie sämtliche sonstige Materialien sind nach Auftragsende auf Verlangen des Auftraggebers entweder herauszugeben oder zu löschen.
+
4.10. Im Falle einer Inanspruchnahme des Auftraggebers oder des Dritten durch eine betroffene Person hinsichtlich etwaiger Ansprüche nach Art. 82 DS-GVO, verpflichtet sich der Auftragnehmer den Auftraggeber bei der Abwehr des Anspruches im Rahmen seiner Möglichkeiten zu unterstützen.
+
4.11. Im Falle einer Inanspruchnahme des Auftraggebers durch den Dritten, verpflichtet sich der Auftragnehmer den Auftraggeber bei der Abwehr des Anspruches im Rahmen seiner Möglichkeiten zu unterstützen.
+
+
+
+
+
5. PFLICHTEN DES AUFTRAGGEBERS
+
+
5.1. Der Auftraggeber hat den Auftragnehmer unverzüglich und vollständig zu informieren, wenn er in den Auftragsergebnissen Fehler oder Unregelmäßigkeiten bzgl. datenschutzrechtlicher Bestimmungen feststellt.
+
5.2. Im Falle einer Inanspruchnahme des Auftraggebers oder des Dritten durch eine betroffene Person hinsichtlich etwaiger Ansprüche nach Art. 82 DS-GVO, gilt §3 Abs. 10 entsprechend.
+
5.3. Der Auftraggeber nennt dem Auftragnehmer den Ansprechpartner für im Rahmen des Vertrages anfallende Datenschutzfragen.
+
+
+
+
+
6. ANFRAGEN BETROFFENER PERSONEN
+
+
6.1. Wendet sich eine betroffene Person mit Forderungen zur Berichtigung, Löschung oder Auskunft an den Auftragnehmer, wird der Auftragnehmer die betroffene Person an den Auftraggeber verweisen und ggf. den Antrag der betroffenen Person unverzüglich an den Auftraggeber weiterleiten. Der Auftragnehmer unterstützt den Auftraggeber im Rahmen seiner Möglichkeiten bei der Erfüllung der jeweiligen Forderung.
+
6.2. Der Auftragnehmer haftet nicht, wenn das Ersuchen der betroffenen Person vom Auftraggeber nicht, nicht richtig oder nicht fristgerecht beantwortet wird.
+
6.3. Der Auftraggeber haftet nicht für Forderungen betroffener Personen, die dadurch entstehen, dass der Auftragnehmer das entsprechende Anliegen nicht zeitgerecht an den Auftraggeber übermittelt hat.
+
+
+
+
+
7. NACHWEISMÖGLICHKEITEN
+
+
7.1. Der Auftragnehmer weist dem Auftraggeber die Einhaltung der in diesem Vertrag niedergelegten Pflichten mit geeigneten Mitteln nach.
+
7.2. Sollten im Einzelfall Inspektionen durch den Auftraggeber oder einen von diesem beauftragten Prüfer erforderlich sein, werden diese zu den üblichen Geschäftszeiten ohne Störung des Betriebsablaufs nach Anmeldung unter Berücksichtigung einer angemessenen Vorlaufzeit durchgeführt. Der Auftragnehmer darf diese von der Unterzeichnung einer Verschwiegenheitserklärung hinsichtlich der Daten anderer Kunden und der eingerichteten technischen und organisatorischen Maßnahmen abhängig machen. Sollte der durch den Auftraggeber beauftragte Prüfer in einem Wettbewerbsverhältnis zu dem Auftragnehmer stehen, hat der Auftragnehmer gegen diesen ein Einspruchsrecht
+
+
+
+
+
+
8. SUBUNTERNEHMER (WEITERE AUFTRAGSVERARBEITER)
+
+
8.1. Der Einsatz von Subunternehmern als weitere Auftragsverarbeiter ist nur zulässig, wenn der Auftraggeber vorher zugestimmt hat.
+
8.2. Ein zustimmungspflichtiges Subunternehmerverhältnis liegt vor, wenn der Auftragnehmer weitere Auftragnehmer mit der ganzen oder einer Teilleistung der im Vertrag vereinbarten Leistung beauftragt. Der Auftragnehmer wird mit diesen Dritten im erforderlichen Umfang Vereinbarungen treffen, um angemessene Datenschutz- und Informationssicherheitsmaßnahmen zu gewährleisten.
+
8.3. Erteilt der Auftragnehmer Aufträge an Subunternehmer, so obliegt es dem Auftragnehmer, seine datenschutzrechtlichen Pflichten aus diesem Vertrag dem Subunternehmer zu überbinden.
+
+
+
+
+
9. INFORMATIONSPFLICHTEN, SCHRIFTFORMKLAUSEL, RECHTSWAHL
+
+
9.1. Sollten die Daten des Auftraggebers beim Auftragnehmer durch Pfändung oder Beschlagnahme, durch ein Insolvenz- oder Vergleichsverfahren oder durch sonstige Ereignisse oder Maßnahmen Dritter gefährdet werden, so hat der Auftragnehmer den Auftraggeber unverzüglich darüber zu informieren. Der Auftragnehmer wird alle in diesem Zusammenhang Verantwortlichen unverzüglich darüber informieren, dass die Hoheit und das Eigentum an den Daten ausschließlich beim Dritten als verantwortliche Person im Sinne der Datenschutz-Grundverordnung liegen.
+
9.2. Änderungen und Ergänzungen dieser Anlage und aller ihrer Bestandteile – einschließlich etwaiger Zusicherungen des Auftragnehmers – bedürfen einer schriftlichen Vereinbarung, die auch in einem elektronischen Format (Textform) erfolgen kann, und des ausdrücklichen Hinweises darauf, dass es sich um eine Änderung bzw. Ergänzung dieser Bedingungen handelt. Dies gilt auch für den Verzicht auf dieses Formerfordernis.
+
9.3. Bei etwaigen Widersprüchen gehen Regelungen dieser Anlage zum Datenschutz den Regelungen des Vertrages vor. Sollten einzelne Teile dieser Anlage unwirksam sein, so berührt dies die Wirksamkeit der Anlage im Übrigen nicht.
+
9.4. Es gilt das auf dem Hauptvertrag anwendbare Recht sowie Gerichtsstand.
+
+
+
+
+
+
Für PROFIT PLANET (Auftraggeber)
+
+
+
{{profitplanetSignature}}
+
{{currentDate}}
+
+
Datum, Unterschrift
+
+
+
Für den VP (Auftragnehmer)
+
+
{{signatureImage}}
+
{{fullName}}
+
{{currentDate}}
+
+
Name, Datum, Unterschrift
+
+
+
+
+
+
\ No newline at end of file
diff --git a/middleware/authMiddleware.js b/middleware/authMiddleware.js
index 7f4ed0b..3ab00fb 100644
--- a/middleware/authMiddleware.js
+++ b/middleware/authMiddleware.js
@@ -77,6 +77,12 @@ async function authMiddleware(req, res, next) {
return res.status(500).json({ success: false, message: 'Internal server error' });
}
+ // Guest restriction: guest users can only access abo-related routes
+ if (normalizedRole === 'guest') {
+ const guestRestriction = require('./guestRestriction');
+ return guestRestriction(req, res, next);
+ }
+
next();
} catch (error) {
logger.warn('authMiddleware:tokenInvalid', {
diff --git a/middleware/guestRestriction.js b/middleware/guestRestriction.js
new file mode 100644
index 0000000..00873a4
--- /dev/null
+++ b/middleware/guestRestriction.js
@@ -0,0 +1,53 @@
+const { logger } = require('./logger');
+
+/**
+ * Middleware that blocks guest users from accessing non-abonnement routes.
+ * Guest users (role='guest') can ONLY access:
+ * - /abonements/*
+ * - /invoices/mine
+ * - /me
+ * - /user/settings
+ * - /logout
+ * - /refresh
+ *
+ * Place this AFTER authMiddleware in the app-level middleware chain.
+ */
+const GUEST_ALLOWED_PREFIXES = [
+ '/abonements',
+ '/invoices/mine',
+ '/me',
+ '/user/settings',
+ '/user/status',
+ '/logout',
+ '/refresh',
+ '/coffee/active',
+ '/tax/vat-rates',
+];
+
+function guestRestriction(req, res, next) {
+ const user = req.user;
+ if (!user || user.role !== 'guest') {
+ return next();
+ }
+
+ const urlPath = req.originalUrl.split('?')[0];
+
+ const isAllowed = GUEST_ALLOWED_PREFIXES.some((prefix) => urlPath.startsWith(prefix));
+
+ if (isAllowed) {
+ return next();
+ }
+
+ logger.warn('guestRestriction:blocked', {
+ userId: user.userId || user.id,
+ route: urlPath,
+ method: req.method,
+ });
+
+ return res.status(403).json({
+ success: false,
+ message: 'Guest accounts can only access subscription features. Please upgrade your account for full access.',
+ });
+}
+
+module.exports = guestRestriction;
diff --git a/models/Pool.js b/models/Pool.js
index eb3eb89..c024a22 100644
--- a/models/Pool.js
+++ b/models/Pool.js
@@ -1,9 +1,13 @@
class Pool {
- constructor({ id = null, pool_name, description = null, price = 0.00, pool_type = 'other', is_active = true, created_by = null, updated_by = null, created_at = null, updated_at = null, members_count = 0 }) {
+ constructor({ id = null, pool_name, description = null, price = 0.00, subscription_coffee_id = null, subscription_title = null, pool_type = 'other', is_active = true, created_by = null, updated_by = null, created_at = null, updated_at = null, members_count = 0 }) {
this.id = id;
this.pool_name = pool_name;
this.description = description;
this.price = price;
+ this.price_net = Number(price || 0);
+ this.price_per_capsule_net = Number(price || 0);
+ this.subscription_coffee_id = subscription_coffee_id == null ? null : Number(subscription_coffee_id);
+ this.subscription_title = subscription_title || null;
this.pool_type = pool_type;
this.is_active = is_active;
this.created_by = created_by;
diff --git a/package-lock.json b/package-lock.json
index 55c012f..4c47ba3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,29 +9,29 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
- "@aws-sdk/client-s3": "^3.894.0",
- "@aws-sdk/s3-request-presigner": "^3.894.0",
+ "@aws-sdk/client-s3": "^3.992.0",
+ "@aws-sdk/s3-request-presigner": "^3.992.0",
"@getbrevo/brevo": "^3.0.1",
"argon2": "^0.44.0",
"cookie-parser": "^1.4.7",
- "cors": "^2.8.5",
+ "cors": "^2.8.6",
"csv-parse": "^6.1.0",
- "dotenv": "^17.2.2",
- "express": "^5.1.0",
+ "dotenv": "^17.3.1",
+ "express": "^5.2.1",
"get-stream": "^9.0.1",
- "jsonwebtoken": "^9.0.2",
+ "jsonwebtoken": "^9.0.3",
"multer": "^2.0.2",
- "mysql2": "^3.15.0",
- "nodemailer": "^7.0.6",
+ "mysql2": "^3.17.2",
+ "nodemailer": "^8.0.1",
"pdfkit": "^0.17.2",
"pidusage": "^4.0.1",
- "puppeteer": "^24.22.0",
+ "puppeteer": "^24.37.3",
"uuid": "^13.0.0",
- "winston": "^3.17.0",
+ "winston": "^3.19.0",
"winston-daily-rotate-file": "^5.0.0"
},
"devDependencies": {
- "nodemon": "^3.1.10"
+ "nodemon": "^3.1.11"
},
"engines": {
"node": ">=16.0.0"
@@ -240,702 +240,750 @@
}
},
"node_modules/@aws-sdk/client-s3": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.966.0.tgz",
- "integrity": "sha512-IckVv+A6irQyXTiJrNpfi63ZtPuk6/Iu70TnMq2DTRFK/4bD2bOvqL1IHZ2WGmZMoeWd5LI8Fn6pIwdK6g4QJQ==",
+ "version": "3.994.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.994.0.tgz",
+ "integrity": "sha512-zIVQt/XfE2zTFrcPEf8R+KRaRD1++XHMPRhxXM2kVA6NA6Aq/cFCUyYOYYwSbWLF/XeToaX1auYGn3IoZKruPQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha1-browser": "5.2.0",
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
- "@aws-sdk/core": "3.966.0",
- "@aws-sdk/credential-provider-node": "3.966.0",
- "@aws-sdk/middleware-bucket-endpoint": "3.966.0",
- "@aws-sdk/middleware-expect-continue": "3.965.0",
- "@aws-sdk/middleware-flexible-checksums": "3.966.0",
- "@aws-sdk/middleware-host-header": "3.965.0",
- "@aws-sdk/middleware-location-constraint": "3.965.0",
- "@aws-sdk/middleware-logger": "3.965.0",
- "@aws-sdk/middleware-recursion-detection": "3.965.0",
- "@aws-sdk/middleware-sdk-s3": "3.966.0",
- "@aws-sdk/middleware-ssec": "3.965.0",
- "@aws-sdk/middleware-user-agent": "3.966.0",
- "@aws-sdk/region-config-resolver": "3.965.0",
- "@aws-sdk/signature-v4-multi-region": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@aws-sdk/util-endpoints": "3.965.0",
- "@aws-sdk/util-user-agent-browser": "3.965.0",
- "@aws-sdk/util-user-agent-node": "3.966.0",
- "@smithy/config-resolver": "^4.4.5",
- "@smithy/core": "^3.20.1",
- "@smithy/eventstream-serde-browser": "^4.2.7",
- "@smithy/eventstream-serde-config-resolver": "^4.3.7",
- "@smithy/eventstream-serde-node": "^4.2.7",
- "@smithy/fetch-http-handler": "^5.3.8",
- "@smithy/hash-blob-browser": "^4.2.8",
- "@smithy/hash-node": "^4.2.7",
- "@smithy/hash-stream-node": "^4.2.7",
- "@smithy/invalid-dependency": "^4.2.7",
- "@smithy/md5-js": "^4.2.7",
- "@smithy/middleware-content-length": "^4.2.7",
- "@smithy/middleware-endpoint": "^4.4.2",
- "@smithy/middleware-retry": "^4.4.18",
- "@smithy/middleware-serde": "^4.2.8",
- "@smithy/middleware-stack": "^4.2.7",
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/node-http-handler": "^4.4.7",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/smithy-client": "^4.10.3",
- "@smithy/types": "^4.11.0",
- "@smithy/url-parser": "^4.2.7",
+ "@aws-sdk/core": "^3.973.11",
+ "@aws-sdk/credential-provider-node": "^3.972.10",
+ "@aws-sdk/middleware-bucket-endpoint": "^3.972.3",
+ "@aws-sdk/middleware-expect-continue": "^3.972.3",
+ "@aws-sdk/middleware-flexible-checksums": "^3.972.9",
+ "@aws-sdk/middleware-host-header": "^3.972.3",
+ "@aws-sdk/middleware-location-constraint": "^3.972.3",
+ "@aws-sdk/middleware-logger": "^3.972.3",
+ "@aws-sdk/middleware-recursion-detection": "^3.972.3",
+ "@aws-sdk/middleware-sdk-s3": "^3.972.11",
+ "@aws-sdk/middleware-ssec": "^3.972.3",
+ "@aws-sdk/middleware-user-agent": "^3.972.11",
+ "@aws-sdk/region-config-resolver": "^3.972.3",
+ "@aws-sdk/signature-v4-multi-region": "3.994.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@aws-sdk/util-endpoints": "3.994.0",
+ "@aws-sdk/util-user-agent-browser": "^3.972.3",
+ "@aws-sdk/util-user-agent-node": "^3.972.9",
+ "@smithy/config-resolver": "^4.4.6",
+ "@smithy/core": "^3.23.2",
+ "@smithy/eventstream-serde-browser": "^4.2.8",
+ "@smithy/eventstream-serde-config-resolver": "^4.3.8",
+ "@smithy/eventstream-serde-node": "^4.2.8",
+ "@smithy/fetch-http-handler": "^5.3.9",
+ "@smithy/hash-blob-browser": "^4.2.9",
+ "@smithy/hash-node": "^4.2.8",
+ "@smithy/hash-stream-node": "^4.2.8",
+ "@smithy/invalid-dependency": "^4.2.8",
+ "@smithy/md5-js": "^4.2.8",
+ "@smithy/middleware-content-length": "^4.2.8",
+ "@smithy/middleware-endpoint": "^4.4.16",
+ "@smithy/middleware-retry": "^4.4.33",
+ "@smithy/middleware-serde": "^4.2.9",
+ "@smithy/middleware-stack": "^4.2.8",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/node-http-handler": "^4.4.10",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/smithy-client": "^4.11.5",
+ "@smithy/types": "^4.12.0",
+ "@smithy/url-parser": "^4.2.8",
"@smithy/util-base64": "^4.3.0",
"@smithy/util-body-length-browser": "^4.2.0",
"@smithy/util-body-length-node": "^4.2.1",
- "@smithy/util-defaults-mode-browser": "^4.3.17",
- "@smithy/util-defaults-mode-node": "^4.2.20",
- "@smithy/util-endpoints": "^3.2.7",
- "@smithy/util-middleware": "^4.2.7",
- "@smithy/util-retry": "^4.2.7",
- "@smithy/util-stream": "^4.5.8",
+ "@smithy/util-defaults-mode-browser": "^4.3.32",
+ "@smithy/util-defaults-mode-node": "^4.2.35",
+ "@smithy/util-endpoints": "^3.2.8",
+ "@smithy/util-middleware": "^4.2.8",
+ "@smithy/util-retry": "^4.2.8",
+ "@smithy/util-stream": "^4.5.12",
"@smithy/util-utf8": "^4.2.0",
- "@smithy/util-waiter": "^4.2.7",
+ "@smithy/util-waiter": "^4.2.8",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/client-sso": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.966.0.tgz",
- "integrity": "sha512-hQZDQgqRJclALDo9wK+bb5O+VpO8JcjImp52w9KPSz9XveNRgE9AYfklRJd8qT2Bwhxe6IbnqYEino2wqUMA1w==",
+ "version": "3.993.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.993.0.tgz",
+ "integrity": "sha512-VLUN+wIeNX24fg12SCbzTUBnBENlL014yMKZvRhPkcn4wHR6LKgNrjsG3fZ03Xs0XoKaGtNFi1VVrq666sGBoQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
- "@aws-sdk/core": "3.966.0",
- "@aws-sdk/middleware-host-header": "3.965.0",
- "@aws-sdk/middleware-logger": "3.965.0",
- "@aws-sdk/middleware-recursion-detection": "3.965.0",
- "@aws-sdk/middleware-user-agent": "3.966.0",
- "@aws-sdk/region-config-resolver": "3.965.0",
- "@aws-sdk/types": "3.965.0",
- "@aws-sdk/util-endpoints": "3.965.0",
- "@aws-sdk/util-user-agent-browser": "3.965.0",
- "@aws-sdk/util-user-agent-node": "3.966.0",
- "@smithy/config-resolver": "^4.4.5",
- "@smithy/core": "^3.20.1",
- "@smithy/fetch-http-handler": "^5.3.8",
- "@smithy/hash-node": "^4.2.7",
- "@smithy/invalid-dependency": "^4.2.7",
- "@smithy/middleware-content-length": "^4.2.7",
- "@smithy/middleware-endpoint": "^4.4.2",
- "@smithy/middleware-retry": "^4.4.18",
- "@smithy/middleware-serde": "^4.2.8",
- "@smithy/middleware-stack": "^4.2.7",
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/node-http-handler": "^4.4.7",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/smithy-client": "^4.10.3",
- "@smithy/types": "^4.11.0",
- "@smithy/url-parser": "^4.2.7",
+ "@aws-sdk/core": "^3.973.11",
+ "@aws-sdk/middleware-host-header": "^3.972.3",
+ "@aws-sdk/middleware-logger": "^3.972.3",
+ "@aws-sdk/middleware-recursion-detection": "^3.972.3",
+ "@aws-sdk/middleware-user-agent": "^3.972.11",
+ "@aws-sdk/region-config-resolver": "^3.972.3",
+ "@aws-sdk/types": "^3.973.1",
+ "@aws-sdk/util-endpoints": "3.993.0",
+ "@aws-sdk/util-user-agent-browser": "^3.972.3",
+ "@aws-sdk/util-user-agent-node": "^3.972.9",
+ "@smithy/config-resolver": "^4.4.6",
+ "@smithy/core": "^3.23.2",
+ "@smithy/fetch-http-handler": "^5.3.9",
+ "@smithy/hash-node": "^4.2.8",
+ "@smithy/invalid-dependency": "^4.2.8",
+ "@smithy/middleware-content-length": "^4.2.8",
+ "@smithy/middleware-endpoint": "^4.4.16",
+ "@smithy/middleware-retry": "^4.4.33",
+ "@smithy/middleware-serde": "^4.2.9",
+ "@smithy/middleware-stack": "^4.2.8",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/node-http-handler": "^4.4.10",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/smithy-client": "^4.11.5",
+ "@smithy/types": "^4.12.0",
+ "@smithy/url-parser": "^4.2.8",
"@smithy/util-base64": "^4.3.0",
"@smithy/util-body-length-browser": "^4.2.0",
"@smithy/util-body-length-node": "^4.2.1",
- "@smithy/util-defaults-mode-browser": "^4.3.17",
- "@smithy/util-defaults-mode-node": "^4.2.20",
- "@smithy/util-endpoints": "^3.2.7",
- "@smithy/util-middleware": "^4.2.7",
- "@smithy/util-retry": "^4.2.7",
+ "@smithy/util-defaults-mode-browser": "^4.3.32",
+ "@smithy/util-defaults-mode-node": "^4.2.35",
+ "@smithy/util-endpoints": "^3.2.8",
+ "@smithy/util-middleware": "^4.2.8",
+ "@smithy/util-retry": "^4.2.8",
"@smithy/util-utf8": "^4.2.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/client-sso/node_modules/@aws-sdk/util-endpoints": {
+ "version": "3.993.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.993.0.tgz",
+ "integrity": "sha512-j6vioBeRZ4eHX4SWGvGPpwGg/xSOcK7f1GL0VM+rdf3ZFTIsUEhCFmD78B+5r2PgztcECSzEfvHQX01k8dPQPw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/types": "^4.12.0",
+ "@smithy/url-parser": "^4.2.8",
+ "@smithy/util-endpoints": "^3.2.8",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/core": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.966.0.tgz",
- "integrity": "sha512-QaRVBHD1prdrFXIeFAY/1w4b4S0EFyo/ytzU+rCklEjMRT7DKGXGoHXTWLGz+HD7ovlS5u+9cf8a/LeSOEMzww==",
+ "version": "3.973.11",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.973.11.tgz",
+ "integrity": "sha512-wdQ8vrvHkKIV7yNUKXyjPWKCdYEUrZTHJ8Ojd5uJxXp9vqPCkUR1dpi1NtOLcrDgueJH7MUH5lQZxshjFPSbDA==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.965.0",
- "@aws-sdk/xml-builder": "3.965.0",
- "@smithy/core": "^3.20.1",
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/property-provider": "^4.2.7",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/signature-v4": "^5.3.7",
- "@smithy/smithy-client": "^4.10.3",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@aws-sdk/xml-builder": "^3.972.5",
+ "@smithy/core": "^3.23.2",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/property-provider": "^4.2.8",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/signature-v4": "^5.3.8",
+ "@smithy/smithy-client": "^4.11.5",
+ "@smithy/types": "^4.12.0",
"@smithy/util-base64": "^4.3.0",
- "@smithy/util-middleware": "^4.2.7",
+ "@smithy/util-middleware": "^4.2.8",
"@smithy/util-utf8": "^4.2.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/crc64-nvme": {
- "version": "3.965.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/crc64-nvme/-/crc64-nvme-3.965.0.tgz",
- "integrity": "sha512-9FbIyJ/Zz1AdEIrb0+Pn7wRi+F/0Y566ooepg0hDyHUzRV3ZXKjOlu3wJH3YwTz2UkdwQmldfUos2yDJps7RyA==",
+ "version": "3.972.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/crc64-nvme/-/crc64-nvme-3.972.0.tgz",
+ "integrity": "sha512-ThlLhTqX68jvoIVv+pryOdb5coP1cX1/MaTbB9xkGDCbWbsqQcLqzPxuSoW1DCnAAIacmXCWpzUNOB9pv+xXQw==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-env": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.966.0.tgz",
- "integrity": "sha512-sxVKc9PY0SH7jgN/8WxhbKQ7MWDIgaJv1AoAKJkhJ+GM5r09G5Vb2Vl8ALYpsy+r8b+iYpq5dGJj8k2VqxoQMg==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.9.tgz",
+ "integrity": "sha512-ZptrOwQynfupubvcngLkbdIq/aXvl/czdpEG8XJ8mN8Nb19BR0jaK0bR+tfuMU36Ez9q4xv7GGkHFqEEP2hUUQ==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@smithy/property-provider": "^4.2.7",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/core": "^3.973.11",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/property-provider": "^4.2.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-http": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.966.0.tgz",
- "integrity": "sha512-VTJDP1jOibVtc5pn5TNE12rhqOO/n10IjkoJi8fFp9BMfmh3iqo70Ppvphz/Pe/R9LcK5Z3h0Z4EB9IXDR6kag==",
+ "version": "3.972.11",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.11.tgz",
+ "integrity": "sha512-hECWoOoH386bGr89NQc9vA/abkGf5TJrMREt+lhNcnSNmoBS04fK7vc3LrJBSQAUGGVj0Tz3f4dHB3w5veovig==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@smithy/fetch-http-handler": "^5.3.8",
- "@smithy/node-http-handler": "^4.4.7",
- "@smithy/property-provider": "^4.2.7",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/smithy-client": "^4.10.3",
- "@smithy/types": "^4.11.0",
- "@smithy/util-stream": "^4.5.8",
+ "@aws-sdk/core": "^3.973.11",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/fetch-http-handler": "^5.3.9",
+ "@smithy/node-http-handler": "^4.4.10",
+ "@smithy/property-provider": "^4.2.8",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/smithy-client": "^4.11.5",
+ "@smithy/types": "^4.12.0",
+ "@smithy/util-stream": "^4.5.12",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-ini": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.966.0.tgz",
- "integrity": "sha512-4oQKkYMCUx0mffKuH8LQag1M4Fo5daKVmsLAnjrIqKh91xmCrcWlAFNMgeEYvI1Yy125XeNSaFMfir6oNc2ODA==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.9.tgz",
+ "integrity": "sha512-zr1csEu9n4eDiHMTYJabX1mDGuGLgjgUnNckIivvk43DocJC9/f6DefFrnUPZXE+GHtbW50YuXb+JIxKykU74A==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.966.0",
- "@aws-sdk/credential-provider-env": "3.966.0",
- "@aws-sdk/credential-provider-http": "3.966.0",
- "@aws-sdk/credential-provider-login": "3.966.0",
- "@aws-sdk/credential-provider-process": "3.966.0",
- "@aws-sdk/credential-provider-sso": "3.966.0",
- "@aws-sdk/credential-provider-web-identity": "3.966.0",
- "@aws-sdk/nested-clients": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@smithy/credential-provider-imds": "^4.2.7",
- "@smithy/property-provider": "^4.2.7",
- "@smithy/shared-ini-file-loader": "^4.4.2",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/core": "^3.973.11",
+ "@aws-sdk/credential-provider-env": "^3.972.9",
+ "@aws-sdk/credential-provider-http": "^3.972.11",
+ "@aws-sdk/credential-provider-login": "^3.972.9",
+ "@aws-sdk/credential-provider-process": "^3.972.9",
+ "@aws-sdk/credential-provider-sso": "^3.972.9",
+ "@aws-sdk/credential-provider-web-identity": "^3.972.9",
+ "@aws-sdk/nested-clients": "3.993.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/credential-provider-imds": "^4.2.8",
+ "@smithy/property-provider": "^4.2.8",
+ "@smithy/shared-ini-file-loader": "^4.4.3",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-login": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.966.0.tgz",
- "integrity": "sha512-wD1KlqLyh23Xfns/ZAPxebwXixoJJCuDbeJHFrLDpP4D4h3vA2S8nSFgBSFR15q9FhgRfHleClycf6g5K4Ww6w==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.9.tgz",
+ "integrity": "sha512-m4RIpVgZChv0vWS/HKChg1xLgZPpx8Z+ly9Fv7FwA8SOfuC6I3htcSaBz2Ch4bneRIiBUhwP4ziUo0UZgtJStQ==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.966.0",
- "@aws-sdk/nested-clients": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@smithy/property-provider": "^4.2.7",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/shared-ini-file-loader": "^4.4.2",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/core": "^3.973.11",
+ "@aws-sdk/nested-clients": "3.993.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/property-provider": "^4.2.8",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/shared-ini-file-loader": "^4.4.3",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-node": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.966.0.tgz",
- "integrity": "sha512-7QCOERGddMw7QbjE+LSAFgwOBpPv4px2ty0GCK7ZiPJGsni2EYmM4TtYnQb9u1WNHmHqIPWMbZR0pKDbyRyHlQ==",
+ "version": "3.972.10",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.10.tgz",
+ "integrity": "sha512-70nCESlvnzjo4LjJ8By8MYIiBogkYPSXl3WmMZfH9RZcB/Nt9qVWbFpYj6Fk1vLa4Vk8qagFVeXgxdieMxG1QA==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/credential-provider-env": "3.966.0",
- "@aws-sdk/credential-provider-http": "3.966.0",
- "@aws-sdk/credential-provider-ini": "3.966.0",
- "@aws-sdk/credential-provider-process": "3.966.0",
- "@aws-sdk/credential-provider-sso": "3.966.0",
- "@aws-sdk/credential-provider-web-identity": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@smithy/credential-provider-imds": "^4.2.7",
- "@smithy/property-provider": "^4.2.7",
- "@smithy/shared-ini-file-loader": "^4.4.2",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/credential-provider-env": "^3.972.9",
+ "@aws-sdk/credential-provider-http": "^3.972.11",
+ "@aws-sdk/credential-provider-ini": "^3.972.9",
+ "@aws-sdk/credential-provider-process": "^3.972.9",
+ "@aws-sdk/credential-provider-sso": "^3.972.9",
+ "@aws-sdk/credential-provider-web-identity": "^3.972.9",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/credential-provider-imds": "^4.2.8",
+ "@smithy/property-provider": "^4.2.8",
+ "@smithy/shared-ini-file-loader": "^4.4.3",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-process": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.966.0.tgz",
- "integrity": "sha512-q5kCo+xHXisNbbPAh/DiCd+LZX4wdby77t7GLk0b2U0/mrel4lgy6o79CApe+0emakpOS1nPZS7voXA7vGPz4w==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.9.tgz",
+ "integrity": "sha512-gOWl0Fe2gETj5Bk151+LYKpeGi2lBDLNu+NMNpHRlIrKHdBmVun8/AalwMK8ci4uRfG5a3/+zvZBMpuen1SZ0A==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@smithy/property-provider": "^4.2.7",
- "@smithy/shared-ini-file-loader": "^4.4.2",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/core": "^3.973.11",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/property-provider": "^4.2.8",
+ "@smithy/shared-ini-file-loader": "^4.4.3",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-sso": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.966.0.tgz",
- "integrity": "sha512-Rv5aEfbpqsQZzxpX2x+FbSyVFOE3Dngome+exNA8jGzc00rrMZEUnm3J3yAsLp/I2l7wnTfI0r2zMe+T9/nZAQ==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.9.tgz",
+ "integrity": "sha512-ey7S686foGTArvFhi3ifQXmgptKYvLSGE2250BAQceMSXZddz7sUSNERGJT2S7u5KIe/kgugxrt01hntXVln6w==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/client-sso": "3.966.0",
- "@aws-sdk/core": "3.966.0",
- "@aws-sdk/token-providers": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@smithy/property-provider": "^4.2.7",
- "@smithy/shared-ini-file-loader": "^4.4.2",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/client-sso": "3.993.0",
+ "@aws-sdk/core": "^3.973.11",
+ "@aws-sdk/token-providers": "3.993.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/property-provider": "^4.2.8",
+ "@smithy/shared-ini-file-loader": "^4.4.3",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-web-identity": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.966.0.tgz",
- "integrity": "sha512-Yv1lc9iic9xg3ywMmIAeXN1YwuvfcClLVdiF2y71LqUgIOupW8B8my84XJr6pmOQuKzZa++c2znNhC9lGsbKyw==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.9.tgz",
+ "integrity": "sha512-8LnfS76nHXoEc9aRRiMMpxZxJeDG0yusdyo3NvPhCgESmBUgpMa4luhGbClW5NoX/qRcGxxM6Z/esqANSNMTow==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.966.0",
- "@aws-sdk/nested-clients": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@smithy/property-provider": "^4.2.7",
- "@smithy/shared-ini-file-loader": "^4.4.2",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/core": "^3.973.11",
+ "@aws-sdk/nested-clients": "3.993.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/property-provider": "^4.2.8",
+ "@smithy/shared-ini-file-loader": "^4.4.3",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/middleware-bucket-endpoint": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.966.0.tgz",
- "integrity": "sha512-KMPZ7gtFXErd9pMpXJMBwFlxxlGIaIQrUBfj3ea7rlrNtoVHnSI4qsoldLq5l9/Ho64KoCiICH4+qXjze8JTDQ==",
+ "version": "3.972.3",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.3.tgz",
+ "integrity": "sha512-fmbgWYirF67YF1GfD7cg5N6HHQ96EyRNx/rDIrTF277/zTWVuPI2qS/ZHgofwR1NZPe/NWvoppflQY01LrbVLg==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.965.0",
- "@aws-sdk/util-arn-parser": "3.966.0",
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@aws-sdk/util-arn-parser": "^3.972.2",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/types": "^4.12.0",
"@smithy/util-config-provider": "^4.2.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/middleware-expect-continue": {
- "version": "3.965.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.965.0.tgz",
- "integrity": "sha512-UBxVytsmhEmFwkBnt+aV0eAJ7uc+ouNokCqMBrQ7Oc5A77qhlcHfOgXIKz2SxqsiYTsDq+a0lWFM/XpyRWraqA==",
+ "version": "3.972.3",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.3.tgz",
+ "integrity": "sha512-4msC33RZsXQpUKR5QR4HnvBSNCPLGHmB55oDiROqqgyOc+TOfVu2xgi5goA7ms6MdZLeEh2905UfWMnMMF4mRg==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.965.0",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/middleware-flexible-checksums": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.966.0.tgz",
- "integrity": "sha512-0/ofXeceTH/flKhg4EGGYr4cDtaLVkR/2RI05J/hxrHIls+iM6j8++GO0TocxmZYK+8B+7XKSaV9LU26nboTUQ==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.972.9.tgz",
+ "integrity": "sha512-E663+r/UQpvF3aJkD40p5ZANVQFsUcbE39jifMtN7wc0t1M0+2gJJp3i75R49aY9OiSX5lfVyPUNjN/BNRCCZA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/crc32": "5.2.0",
"@aws-crypto/crc32c": "5.2.0",
"@aws-crypto/util": "5.2.0",
- "@aws-sdk/core": "3.966.0",
- "@aws-sdk/crc64-nvme": "3.965.0",
- "@aws-sdk/types": "3.965.0",
+ "@aws-sdk/core": "^3.973.11",
+ "@aws-sdk/crc64-nvme": "3.972.0",
+ "@aws-sdk/types": "^3.973.1",
"@smithy/is-array-buffer": "^4.2.0",
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/types": "^4.11.0",
- "@smithy/util-middleware": "^4.2.7",
- "@smithy/util-stream": "^4.5.8",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/types": "^4.12.0",
+ "@smithy/util-middleware": "^4.2.8",
+ "@smithy/util-stream": "^4.5.12",
"@smithy/util-utf8": "^4.2.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/middleware-host-header": {
- "version": "3.965.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.965.0.tgz",
- "integrity": "sha512-SfpSYqoPOAmdb3DBsnNsZ0vix+1VAtkUkzXM79JL3R5IfacpyKE2zytOgVAQx/FjhhlpSTwuXd+LRhUEVb3MaA==",
+ "version": "3.972.3",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.3.tgz",
+ "integrity": "sha512-aknPTb2M+G3s+0qLCx4Li/qGZH8IIYjugHMv15JTYMe6mgZO8VBpYgeGYsNMGCqCZOcWzuf900jFBG5bopfzmA==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.965.0",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/middleware-location-constraint": {
- "version": "3.965.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.965.0.tgz",
- "integrity": "sha512-07T1rwAarQs33mVg5U28AsSdLB5JUXu9yBTBmspFGajKVsEahIyntf53j9mAXF1N2KR0bNdP0J4A0kst4t43UQ==",
+ "version": "3.972.3",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.3.tgz",
+ "integrity": "sha512-nIg64CVrsXp67vbK0U1/Is8rik3huS3QkRHn2DRDx4NldrEFMgdkZGI/+cZMKD9k4YOS110Dfu21KZLHrFA/1g==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.965.0",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/middleware-logger": {
- "version": "3.965.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.965.0.tgz",
- "integrity": "sha512-gjUvJRZT1bUABKewnvkj51LAynFrfz2h5DYAg5/2F4Utx6UOGByTSr9Rq8JCLbURvvzAbCtcMkkIJRxw+8Zuzw==",
+ "version": "3.972.3",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.3.tgz",
+ "integrity": "sha512-Ftg09xNNRqaz9QNzlfdQWfpqMCJbsQdnZVJP55jfhbKi1+FTWxGuvfPoBhDHIovqWKjqbuiew3HuhxbJ0+OjgA==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.965.0",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/middleware-recursion-detection": {
- "version": "3.965.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.965.0.tgz",
- "integrity": "sha512-6dvD+18Ni14KCRu+tfEoNxq1sIGVp9tvoZDZ7aMvpnA7mDXuRLrOjRQ/TAZqXwr9ENKVGyxcPl0cRK8jk1YWjA==",
+ "version": "3.972.3",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.3.tgz",
+ "integrity": "sha512-PY57QhzNuXHnwbJgbWYTrqIDHYSeOlhfYERTAuc16LKZpTZRJUjzBFokp9hF7u1fuGeE3D70ERXzdbMBOqQz7Q==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.965.0",
+ "@aws-sdk/types": "^3.973.1",
"@aws/lambda-invoke-store": "^0.2.2",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/middleware-sdk-s3": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.966.0.tgz",
- "integrity": "sha512-9N9zncsY5ydDCRatKdrPZcdCwNWt7TdHmqgwQM52PuA5gs1HXWwLLNDy/51H+9RTHi7v6oly+x9utJ/qypCh2g==",
+ "version": "3.972.11",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.11.tgz",
+ "integrity": "sha512-Qr0T7ZQTRMOuR6ahxEoJR1thPVovfWrKB2a6KBGR+a8/ELrFodrgHwhq50n+5VMaGuLtGhHiISU3XGsZmtmVXQ==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@aws-sdk/util-arn-parser": "3.966.0",
- "@smithy/core": "^3.20.1",
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/signature-v4": "^5.3.7",
- "@smithy/smithy-client": "^4.10.3",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/core": "^3.973.11",
+ "@aws-sdk/types": "^3.973.1",
+ "@aws-sdk/util-arn-parser": "^3.972.2",
+ "@smithy/core": "^3.23.2",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/signature-v4": "^5.3.8",
+ "@smithy/smithy-client": "^4.11.5",
+ "@smithy/types": "^4.12.0",
"@smithy/util-config-provider": "^4.2.0",
- "@smithy/util-middleware": "^4.2.7",
- "@smithy/util-stream": "^4.5.8",
+ "@smithy/util-middleware": "^4.2.8",
+ "@smithy/util-stream": "^4.5.12",
"@smithy/util-utf8": "^4.2.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/middleware-ssec": {
- "version": "3.965.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.965.0.tgz",
- "integrity": "sha512-dke++CTw26y+a2D1DdVuZ4+2TkgItdx6TeuE0zOl4lsqXGvTBUG4eaIZalt7ZOAW5ys2pbDOk1bPuh4opoD3pQ==",
+ "version": "3.972.3",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.3.tgz",
+ "integrity": "sha512-dU6kDuULN3o3jEHcjm0c4zWJlY1zWVkjG9NPe9qxYLLpcbdj5kRYBS2DdWYD+1B9f910DezRuws7xDEqKkHQIg==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.965.0",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/middleware-user-agent": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.966.0.tgz",
- "integrity": "sha512-MvGoy0vhMluVpSB5GaGJbYLqwbZfZjwEZhneDHdPhgCgQqmCtugnYIIjpUw7kKqWGsmaMQmNEgSFf1zYYmwOyg==",
+ "version": "3.972.11",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.11.tgz",
+ "integrity": "sha512-R8CvPsPHXwzIHCAza+bllY6PrctEk4lYq/SkHJz9NLoBHCcKQrbOcsfXxO6xmipSbUNIbNIUhH0lBsJGgsRdiw==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@aws-sdk/util-endpoints": "3.965.0",
- "@smithy/core": "^3.20.1",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/core": "^3.973.11",
+ "@aws-sdk/types": "^3.973.1",
+ "@aws-sdk/util-endpoints": "3.993.0",
+ "@smithy/core": "^3.23.2",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/middleware-user-agent/node_modules/@aws-sdk/util-endpoints": {
+ "version": "3.993.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.993.0.tgz",
+ "integrity": "sha512-j6vioBeRZ4eHX4SWGvGPpwGg/xSOcK7f1GL0VM+rdf3ZFTIsUEhCFmD78B+5r2PgztcECSzEfvHQX01k8dPQPw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/types": "^4.12.0",
+ "@smithy/url-parser": "^4.2.8",
+ "@smithy/util-endpoints": "^3.2.8",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/nested-clients": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.966.0.tgz",
- "integrity": "sha512-FRzAWwLNoKiaEWbYhnpnfartIdOgiaBLnPcd3uG1Io+vvxQUeRPhQIy4EfKnT3AuA+g7gzSCjMG2JKoJOplDtQ==",
+ "version": "3.993.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.993.0.tgz",
+ "integrity": "sha512-iOq86f2H67924kQUIPOAvlmMaOAvOLoDOIb66I2YqSUpMYB6ufiuJW3RlREgskxv86S5qKzMnfy/X6CqMjK6XQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
- "@aws-sdk/core": "3.966.0",
- "@aws-sdk/middleware-host-header": "3.965.0",
- "@aws-sdk/middleware-logger": "3.965.0",
- "@aws-sdk/middleware-recursion-detection": "3.965.0",
- "@aws-sdk/middleware-user-agent": "3.966.0",
- "@aws-sdk/region-config-resolver": "3.965.0",
- "@aws-sdk/types": "3.965.0",
- "@aws-sdk/util-endpoints": "3.965.0",
- "@aws-sdk/util-user-agent-browser": "3.965.0",
- "@aws-sdk/util-user-agent-node": "3.966.0",
- "@smithy/config-resolver": "^4.4.5",
- "@smithy/core": "^3.20.1",
- "@smithy/fetch-http-handler": "^5.3.8",
- "@smithy/hash-node": "^4.2.7",
- "@smithy/invalid-dependency": "^4.2.7",
- "@smithy/middleware-content-length": "^4.2.7",
- "@smithy/middleware-endpoint": "^4.4.2",
- "@smithy/middleware-retry": "^4.4.18",
- "@smithy/middleware-serde": "^4.2.8",
- "@smithy/middleware-stack": "^4.2.7",
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/node-http-handler": "^4.4.7",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/smithy-client": "^4.10.3",
- "@smithy/types": "^4.11.0",
- "@smithy/url-parser": "^4.2.7",
+ "@aws-sdk/core": "^3.973.11",
+ "@aws-sdk/middleware-host-header": "^3.972.3",
+ "@aws-sdk/middleware-logger": "^3.972.3",
+ "@aws-sdk/middleware-recursion-detection": "^3.972.3",
+ "@aws-sdk/middleware-user-agent": "^3.972.11",
+ "@aws-sdk/region-config-resolver": "^3.972.3",
+ "@aws-sdk/types": "^3.973.1",
+ "@aws-sdk/util-endpoints": "3.993.0",
+ "@aws-sdk/util-user-agent-browser": "^3.972.3",
+ "@aws-sdk/util-user-agent-node": "^3.972.9",
+ "@smithy/config-resolver": "^4.4.6",
+ "@smithy/core": "^3.23.2",
+ "@smithy/fetch-http-handler": "^5.3.9",
+ "@smithy/hash-node": "^4.2.8",
+ "@smithy/invalid-dependency": "^4.2.8",
+ "@smithy/middleware-content-length": "^4.2.8",
+ "@smithy/middleware-endpoint": "^4.4.16",
+ "@smithy/middleware-retry": "^4.4.33",
+ "@smithy/middleware-serde": "^4.2.9",
+ "@smithy/middleware-stack": "^4.2.8",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/node-http-handler": "^4.4.10",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/smithy-client": "^4.11.5",
+ "@smithy/types": "^4.12.0",
+ "@smithy/url-parser": "^4.2.8",
"@smithy/util-base64": "^4.3.0",
"@smithy/util-body-length-browser": "^4.2.0",
"@smithy/util-body-length-node": "^4.2.1",
- "@smithy/util-defaults-mode-browser": "^4.3.17",
- "@smithy/util-defaults-mode-node": "^4.2.20",
- "@smithy/util-endpoints": "^3.2.7",
- "@smithy/util-middleware": "^4.2.7",
- "@smithy/util-retry": "^4.2.7",
+ "@smithy/util-defaults-mode-browser": "^4.3.32",
+ "@smithy/util-defaults-mode-node": "^4.2.35",
+ "@smithy/util-endpoints": "^3.2.8",
+ "@smithy/util-middleware": "^4.2.8",
+ "@smithy/util-retry": "^4.2.8",
"@smithy/util-utf8": "^4.2.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@aws-sdk/nested-clients/node_modules/@aws-sdk/util-endpoints": {
+ "version": "3.993.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.993.0.tgz",
+ "integrity": "sha512-j6vioBeRZ4eHX4SWGvGPpwGg/xSOcK7f1GL0VM+rdf3ZFTIsUEhCFmD78B+5r2PgztcECSzEfvHQX01k8dPQPw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/types": "^4.12.0",
+ "@smithy/url-parser": "^4.2.8",
+ "@smithy/util-endpoints": "^3.2.8",
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/region-config-resolver": {
- "version": "3.965.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.965.0.tgz",
- "integrity": "sha512-RoMhu9ly2B0coxn8ctXosPP2WmDD0MkQlZGLjoYHQUOCBmty5qmCxOqBmBDa6wbWbB8xKtMQ/4VXloQOgzjHXg==",
+ "version": "3.972.3",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.3.tgz",
+ "integrity": "sha512-v4J8qYAWfOMcZ4MJUyatntOicTzEMaU7j3OpkRCGGFSL2NgXQ5VbxauIyORA+pxdKZ0qQG2tCQjQjZDlXEC3Ow==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.965.0",
- "@smithy/config-resolver": "^4.4.5",
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/config-resolver": "^4.4.6",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/s3-request-presigner": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.966.0.tgz",
- "integrity": "sha512-RUxg33fhT7qOJuqcxuLMs6vS8Fy84KF6lL+G6JHO769AnJkHqGW5iVaiq+/fhkU38tGHviljyx8uIl6dBUM9KA==",
+ "version": "3.994.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.994.0.tgz",
+ "integrity": "sha512-g/jYc++IunLJZpeyLJrbC39XAf57BYjWjKkxRQlwj5fC90Scg4t/2FS0BV2u/U9UZX5HqpQQahI60tPEN84JqQ==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/signature-v4-multi-region": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@aws-sdk/util-format-url": "3.965.0",
- "@smithy/middleware-endpoint": "^4.4.2",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/smithy-client": "^4.10.3",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/signature-v4-multi-region": "3.994.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@aws-sdk/util-format-url": "^3.972.3",
+ "@smithy/middleware-endpoint": "^4.4.16",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/smithy-client": "^4.11.5",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/signature-v4-multi-region": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.966.0.tgz",
- "integrity": "sha512-VNSpyfKtDiBg/nPwSXDvnjISaDE9mI8zhOK3C4/obqh8lK1V6j04xDlwyIWbbIM0f6VgV1FVixlghtJB79eBqA==",
+ "version": "3.994.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.994.0.tgz",
+ "integrity": "sha512-8y04Lv497KKd7f2TVlm2RaKQaNfnY17ZH8d3m+7sW/3R3BhZvHgWQZyqTb/vcN2ERz1YAnWx6woJyB3ZNFvakw==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/middleware-sdk-s3": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/signature-v4": "^5.3.7",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/middleware-sdk-s3": "^3.972.11",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/signature-v4": "^5.3.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/token-providers": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.966.0.tgz",
- "integrity": "sha512-8k5cBTicTGYJHhKaweO4gL4fud1KDnLS5fByT6/Xbiu59AxYM4E/h3ds+3jxDMnniCE3gIWpEnyfM9khtmw2lA==",
+ "version": "3.993.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.993.0.tgz",
+ "integrity": "sha512-+35g4c+8r7sB9Sjp1KPdM8qxGn6B/shBjJtEUN4e+Edw9UEQlZKIzioOGu3UAbyE0a/s450LdLZr4wbJChtmww==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/core": "3.966.0",
- "@aws-sdk/nested-clients": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@smithy/property-provider": "^4.2.7",
- "@smithy/shared-ini-file-loader": "^4.4.2",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/core": "^3.973.11",
+ "@aws-sdk/nested-clients": "3.993.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/property-provider": "^4.2.8",
+ "@smithy/shared-ini-file-loader": "^4.4.3",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/types": {
- "version": "3.965.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.965.0.tgz",
- "integrity": "sha512-jvodoJdMavvg8faN7co58vVJRO5MVep4JFPRzUNCzpJ98BDqWDk/ad045aMJcmxkLzYLS2UAnUmqjJ/tUPNlzQ==",
+ "version": "3.973.1",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.1.tgz",
+ "integrity": "sha512-DwHBiMNOB468JiX6+i34c+THsKHErYUdNQ3HexeXZvVn4zouLjgaS4FejiGSi2HyBuzuyHg7SuOPmjSvoU9NRg==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/util-arn-parser": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.966.0.tgz",
- "integrity": "sha512-WcCLdKBK2nHhtOPE8du5XjOXaOToxGF3Ge8rgK2jaRpjkzjS0/mO+Jp2H4+25hOne3sP2twBu5BrvD9KoXQ5LQ==",
+ "version": "3.972.2",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.972.2.tgz",
+ "integrity": "sha512-VkykWbqMjlSgBFDyrY3nOSqupMc6ivXuGmvci6Q3NnLq5kC+mKQe2QBZ4nrWRE/jqOxeFP2uYzLtwncYYcvQDg==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/util-endpoints": {
- "version": "3.965.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.965.0.tgz",
- "integrity": "sha512-WqSCB0XIsGUwZWvrYkuoofi2vzoVHqyeJ2kN+WyoOsxPLTiQSBIoqm/01R/qJvoxwK/gOOF7su9i84Vw2NQQpQ==",
+ "version": "3.994.0",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.994.0.tgz",
+ "integrity": "sha512-L2obUBw4ACMMd1F/SG5LdfPyZ0xJNs9Maifwr3w0uWO+4YvHmk9FfRskfSfE/SLZ9S387oSZ+1xiP7BfVCP/Og==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.965.0",
- "@smithy/types": "^4.11.0",
- "@smithy/url-parser": "^4.2.7",
- "@smithy/util-endpoints": "^3.2.7",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/types": "^4.12.0",
+ "@smithy/url-parser": "^4.2.8",
+ "@smithy/util-endpoints": "^3.2.8",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/util-format-url": {
- "version": "3.965.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.965.0.tgz",
- "integrity": "sha512-KiplV4xYGXdNCcz5eRP8WfAejT5EkE2gQxC4IY6WsuxYprzQKsnGaAzEQ+giR5GgQLIRBkPaWT0xHEYkMiCQ1Q==",
+ "version": "3.972.3",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.972.3.tgz",
+ "integrity": "sha512-n7F2ycckcKFXa01vAsT/SJdjFHfKH9s96QHcs5gn8AaaigASICeME8WdUL9uBp8XV/OVwEt8+6gzn6KFUgQa8g==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.965.0",
- "@smithy/querystring-builder": "^4.2.7",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/querystring-builder": "^4.2.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/util-locate-window": {
- "version": "3.965.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.0.tgz",
- "integrity": "sha512-9LJFand4bIoOjOF4x3wx0UZYiFZRo4oUauxQSiEX2dVg+5qeBOJSjp2SeWykIE6+6frCZ5wvWm2fGLK8D32aJw==",
+ "version": "3.965.4",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.4.tgz",
+ "integrity": "sha512-H1onv5SkgPBK2P6JR2MjGgbOnttoNzSPIRoeZTNPZYyaplwGg50zS3amXvXqF0/qfXpWEC9rLWU564QTB9bSog==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/util-user-agent-browser": {
- "version": "3.965.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.965.0.tgz",
- "integrity": "sha512-Xiza/zMntQGpkd2dETQeAK8So1pg5+STTzpcdGWxj5q0jGO5ayjqT/q1Q7BrsX5KIr6PvRkl9/V7lLCv04wGjQ==",
+ "version": "3.972.3",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.3.tgz",
+ "integrity": "sha512-JurOwkRUcXD/5MTDBcqdyQ9eVedtAsZgw5rBwktsPTN7QtPiS2Ld1jkJepNgYoCufz1Wcut9iup7GJDoIHp8Fw==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/types": "3.965.0",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/types": "^4.12.0",
"bowser": "^2.11.0",
"tslib": "^2.6.2"
}
},
"node_modules/@aws-sdk/util-user-agent-node": {
- "version": "3.966.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.966.0.tgz",
- "integrity": "sha512-vPPe8V0GLj+jVS5EqFz2NUBgWH35favqxliUOvhp8xBdNRkEjiZm5TqitVtFlxS4RrLY3HOndrWbrP5ejbwl1Q==",
+ "version": "3.972.9",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.972.9.tgz",
+ "integrity": "sha512-JNswdsLdQemxqaSIBL2HRhsHPUBBziAgoi5RQv6/9avmE5g5RSdt1hWr3mHJ7OxqRYf+KeB11ExWbiqfrnoeaA==",
"license": "Apache-2.0",
"dependencies": {
- "@aws-sdk/middleware-user-agent": "3.966.0",
- "@aws-sdk/types": "3.965.0",
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/types": "^4.11.0",
+ "@aws-sdk/middleware-user-agent": "^3.972.11",
+ "@aws-sdk/types": "^3.973.1",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
},
"peerDependencies": {
"aws-crt": ">=1.0.0"
@@ -947,17 +995,17 @@
}
},
"node_modules/@aws-sdk/xml-builder": {
- "version": "3.965.0",
- "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.965.0.tgz",
- "integrity": "sha512-Tcod25/BTupraQwtb+Q+GX8bmEZfxIFjjJ/AvkhUZsZlkPeVluzq1uu3Oeqf145DCdMjzLIN6vab5MrykbDP+g==",
+ "version": "3.972.5",
+ "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.5.tgz",
+ "integrity": "sha512-mCae5Ys6Qm1LDu0qdGwx2UQ63ONUe+FHw908fJzLDqFKTDBK4LDZUqKWm4OkTCNFq19bftjsBSESIGLD/s3/rA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
- "fast-xml-parser": "5.2.5",
+ "@smithy/types": "^4.12.0",
+ "fast-xml-parser": "5.3.6",
"tslib": "^2.6.2"
},
"engines": {
- "node": ">=18.0.0"
+ "node": ">=20.0.0"
}
},
"node_modules/@aws/lambda-invoke-store": {
@@ -970,12 +1018,12 @@
}
},
"node_modules/@babel/code-frame": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
- "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
+ "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
"license": "MIT",
"dependencies": {
- "@babel/helper-validator-identifier": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.28.5",
"js-tokens": "^4.0.0",
"picocolors": "^1.1.1"
},
@@ -1018,144 +1066,12 @@
"integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==",
"license": "MIT"
},
- "node_modules/@eslint-community/eslint-utils": {
- "version": "4.9.1",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
- "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
- "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/regexpp": {
- "version": "4.12.2",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
- "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
- "license": "MIT",
- "engines": {
- "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
- }
- },
- "node_modules/@eslint/eslintrc": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
- "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
- "license": "MIT",
- "dependencies": {
- "ajv": "^6.12.4",
- "debug": "^4.3.2",
- "espree": "^9.6.0",
- "globals": "^13.19.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": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@eslint/js": {
- "version": "8.57.1",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
- "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
- "license": "MIT",
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
"node_modules/@getbrevo/brevo": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@getbrevo/brevo/-/brevo-3.0.1.tgz",
- "integrity": "sha512-BS5hlgb9qPHhXqjV+VbEOciygnsEVZV8BgoX+JYpD+I+R9u3U05y/euqdmk8nATfcEUCUlQq+aWdWOWTF4cEjQ==",
- "license": "MIT",
- "dependencies": {
- "axios": "^1.6.8",
- "bluebird": "^3.5.0",
- "rewire": "^7.0.0"
- }
- },
- "node_modules/@humanwhocodes/config-array": {
- "version": "0.13.0",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
- "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
- "deprecated": "Use @eslint/config-array instead",
- "license": "Apache-2.0",
- "dependencies": {
- "@humanwhocodes/object-schema": "^2.0.3",
- "debug": "^4.3.1",
- "minimatch": "^3.0.5"
- },
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@getbrevo/brevo/-/brevo-3.0.2.tgz",
+ "integrity": "sha512-+vD1ijUbxVI1G6CDLbo7nmtHG6WJczYRYRQa9BQPVBrvDuU36oJUmjsrcfzrjGXQaWRS86y2LMMzOOeN8s9oLw==",
"engines": {
- "node": ">=10.10.0"
- }
- },
- "node_modules/@humanwhocodes/module-importer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
- "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
- "license": "Apache-2.0",
- "engines": {
- "node": ">=12.22"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
- }
- },
- "node_modules/@humanwhocodes/object-schema": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
- "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
- "deprecated": "Use @eslint/object-schema instead",
- "license": "BSD-3-Clause"
- },
- "node_modules/@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "license": "MIT",
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- },
- "engines": {
- "node": ">= 8"
+ "node": ">=18.0.0"
}
},
"node_modules/@phc/format": {
@@ -1168,16 +1084,16 @@
}
},
"node_modules/@puppeteer/browsers": {
- "version": "2.11.0",
- "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.11.0.tgz",
- "integrity": "sha512-n6oQX6mYkG8TRPuPXmbPidkUbsSRalhmaaVAQxvH1IkQy63cwsH+kOjB3e4cpCDHg0aSvsiX9bQ4s2VB6mGWUQ==",
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.0.tgz",
+ "integrity": "sha512-46BZJYJjc/WwmKjsvDFykHtXrtomsCIrwYQPOP7VfMJoZY2bsDF9oROBABR3paDjDcmkUye1Pb1BqdcdiipaWA==",
"license": "Apache-2.0",
"dependencies": {
"debug": "^4.4.3",
"extract-zip": "^2.0.1",
"progress": "^2.0.3",
"proxy-agent": "^6.5.0",
- "semver": "^7.7.3",
+ "semver": "^7.7.4",
"tar-fs": "^3.1.1",
"yargs": "^17.7.2"
},
@@ -1195,12 +1111,12 @@
"license": "MIT"
},
"node_modules/@smithy/abort-controller": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.7.tgz",
- "integrity": "sha512-rzMY6CaKx2qxrbYbqjXWS0plqEy7LOdKHS0bg4ixJ6aoGDPNUcLWk/FRNuCILh7GKLG9TFUXYYeQQldMBBwuyw==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.8.tgz",
+ "integrity": "sha512-peuVfkYHAmS5ybKxWcfraK7WBBP0J+rkfUcbHJJKQ4ir3UAUNQI+Y4Vt/PqSzGqgloJ5O1dk7+WzNL8wcCSXbw==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1233,16 +1149,16 @@
}
},
"node_modules/@smithy/config-resolver": {
- "version": "4.4.5",
- "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.5.tgz",
- "integrity": "sha512-HAGoUAFYsUkoSckuKbCPayECeMim8pOu+yLy1zOxt1sifzEbrsRpYa+mKcMdiHKMeiqOibyPG0sFJnmaV/OGEg==",
+ "version": "4.4.6",
+ "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.6.tgz",
+ "integrity": "sha512-qJpzYC64kaj3S0fueiu3kXm8xPrR3PcXDPEgnaNMRn0EjNSZFoFjvbUp0YUDsRhN1CB90EnHJtbxWKevnH99UQ==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/types": "^4.12.0",
"@smithy/util-config-provider": "^4.2.0",
- "@smithy/util-endpoints": "^3.2.7",
- "@smithy/util-middleware": "^4.2.7",
+ "@smithy/util-endpoints": "^3.2.8",
+ "@smithy/util-middleware": "^4.2.8",
"tslib": "^2.6.2"
},
"engines": {
@@ -1250,18 +1166,18 @@
}
},
"node_modules/@smithy/core": {
- "version": "3.20.2",
- "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.20.2.tgz",
- "integrity": "sha512-nc99TseyTwL1bg+T21cyEA5oItNy1XN4aUeyOlXJnvyRW5VSK1oRKRoSM/Iq0KFPuqZMxjBemSZHZCOZbSyBMw==",
+ "version": "3.23.2",
+ "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.2.tgz",
+ "integrity": "sha512-HaaH4VbGie4t0+9nY3tNBRSxVTr96wzIqexUa6C2qx3MPePAuz7lIxPxYtt1Wc//SPfJLNoZJzfdt0B6ksj2jA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/middleware-serde": "^4.2.8",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/middleware-serde": "^4.2.9",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/types": "^4.12.0",
"@smithy/util-base64": "^4.3.0",
"@smithy/util-body-length-browser": "^4.2.0",
- "@smithy/util-middleware": "^4.2.7",
- "@smithy/util-stream": "^4.5.8",
+ "@smithy/util-middleware": "^4.2.8",
+ "@smithy/util-stream": "^4.5.12",
"@smithy/util-utf8": "^4.2.0",
"@smithy/uuid": "^1.1.0",
"tslib": "^2.6.2"
@@ -1271,15 +1187,15 @@
}
},
"node_modules/@smithy/credential-provider-imds": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.7.tgz",
- "integrity": "sha512-CmduWdCiILCRNbQWFR0OcZlUPVtyE49Sr8yYL0rZQ4D/wKxiNzBNS/YHemvnbkIWj623fplgkexUd/c9CAKdoA==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.8.tgz",
+ "integrity": "sha512-FNT0xHS1c/CPN8upqbMFP83+ul5YgdisfCfkZ86Jh2NSmnqw/AJ6x5pEogVCTVvSm7j9MopRU89bmDelxuDMYw==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/property-provider": "^4.2.7",
- "@smithy/types": "^4.11.0",
- "@smithy/url-parser": "^4.2.7",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/property-provider": "^4.2.8",
+ "@smithy/types": "^4.12.0",
+ "@smithy/url-parser": "^4.2.8",
"tslib": "^2.6.2"
},
"engines": {
@@ -1287,13 +1203,13 @@
}
},
"node_modules/@smithy/eventstream-codec": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.7.tgz",
- "integrity": "sha512-DrpkEoM3j9cBBWhufqBwnbbn+3nf1N9FP6xuVJ+e220jbactKuQgaZwjwP5CP1t+O94brm2JgVMD2atMGX3xIQ==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.8.tgz",
+ "integrity": "sha512-jS/O5Q14UsufqoGhov7dHLOPCzkYJl9QDzusI2Psh4wyYx/izhzvX9P4D69aTxcdfVhEPhjK+wYyn/PzLjKbbw==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/crc32": "5.2.0",
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"@smithy/util-hex-encoding": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -1302,13 +1218,13 @@
}
},
"node_modules/@smithy/eventstream-serde-browser": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.7.tgz",
- "integrity": "sha512-ujzPk8seYoDBmABDE5YqlhQZAXLOrtxtJLrbhHMKjBoG5b4dK4i6/mEU+6/7yXIAkqOO8sJ6YxZl+h0QQ1IJ7g==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.8.tgz",
+ "integrity": "sha512-MTfQT/CRQz5g24ayXdjg53V0mhucZth4PESoA5IhvaWVDTOQLfo8qI9vzqHcPsdd2v6sqfTYqF5L/l+pea5Uyw==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/eventstream-serde-universal": "^4.2.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/eventstream-serde-universal": "^4.2.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1316,12 +1232,12 @@
}
},
"node_modules/@smithy/eventstream-serde-config-resolver": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.7.tgz",
- "integrity": "sha512-x7BtAiIPSaNaWuzm24Q/mtSkv+BrISO/fmheiJ39PKRNH3RmH2Hph/bUKSOBOBC9unqfIYDhKTHwpyZycLGPVQ==",
+ "version": "4.3.8",
+ "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.8.tgz",
+ "integrity": "sha512-ah12+luBiDGzBruhu3efNy1IlbwSEdNiw8fOZksoKoWW1ZHvO/04MQsdnws/9Aj+5b0YXSSN2JXKy/ClIsW8MQ==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1329,13 +1245,13 @@
}
},
"node_modules/@smithy/eventstream-serde-node": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.7.tgz",
- "integrity": "sha512-roySCtHC5+pQq5lK4be1fZ/WR6s/AxnPaLfCODIPArtN2du8s5Ot4mKVK3pPtijL/L654ws592JHJ1PbZFF6+A==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.8.tgz",
+ "integrity": "sha512-cYpCpp29z6EJHa5T9WL0KAlq3SOKUQkcgSoeRfRVwjGgSFl7Uh32eYGt7IDYCX20skiEdRffyDpvF2efEZPC0A==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/eventstream-serde-universal": "^4.2.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/eventstream-serde-universal": "^4.2.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1343,13 +1259,13 @@
}
},
"node_modules/@smithy/eventstream-serde-universal": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.7.tgz",
- "integrity": "sha512-QVD+g3+icFkThoy4r8wVFZMsIP08taHVKjE6Jpmz8h5CgX/kk6pTODq5cht0OMtcapUx+xrPzUTQdA+TmO0m1g==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.8.tgz",
+ "integrity": "sha512-iJ6YNJd0bntJYnX6s52NC4WFYcZeKrPUr1Kmmr5AwZcwCSzVpS7oavAmxMR7pMq7V+D1G4s9F5NJK0xwOsKAlQ==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/eventstream-codec": "^4.2.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/eventstream-codec": "^4.2.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1357,14 +1273,14 @@
}
},
"node_modules/@smithy/fetch-http-handler": {
- "version": "5.3.8",
- "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.8.tgz",
- "integrity": "sha512-h/Fi+o7mti4n8wx1SR6UHWLaakwHRx29sizvp8OOm7iqwKGFneT06GCSFhml6Bha5BT6ot5pj3CYZnCHhGC2Rg==",
+ "version": "5.3.9",
+ "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.9.tgz",
+ "integrity": "sha512-I4UhmcTYXBrct03rwzQX1Y/iqQlzVQaPxWjCjula++5EmWq9YGBrx6bbGqluGc1f0XEfhSkiY4jhLgbsJUMKRA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/querystring-builder": "^4.2.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/querystring-builder": "^4.2.8",
+ "@smithy/types": "^4.12.0",
"@smithy/util-base64": "^4.3.0",
"tslib": "^2.6.2"
},
@@ -1373,14 +1289,14 @@
}
},
"node_modules/@smithy/hash-blob-browser": {
- "version": "4.2.8",
- "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.8.tgz",
- "integrity": "sha512-07InZontqsM1ggTCPSRgI7d8DirqRrnpL7nIACT4PW0AWrgDiHhjGZzbAE5UtRSiU0NISGUYe7/rri9ZeWyDpw==",
+ "version": "4.2.9",
+ "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.9.tgz",
+ "integrity": "sha512-m80d/iicI7DlBDxyQP6Th7BW/ejDGiF0bgI754+tiwK0lgMkcaIBgvwwVc7OFbY4eUzpGtnig52MhPAEJ7iNYg==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/chunked-blob-reader": "^5.2.0",
"@smithy/chunked-blob-reader-native": "^4.2.1",
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1388,12 +1304,12 @@
}
},
"node_modules/@smithy/hash-node": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.7.tgz",
- "integrity": "sha512-PU/JWLTBCV1c8FtB8tEFnY4eV1tSfBc7bDBADHfn1K+uRbPgSJ9jnJp0hyjiFN2PMdPzxsf1Fdu0eo9fJ760Xw==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.8.tgz",
+ "integrity": "sha512-7ZIlPbmaDGxVoxErDZnuFG18WekhbA/g2/i97wGj+wUBeS6pcUeAym8u4BXh/75RXWhgIJhyC11hBzig6MljwA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"@smithy/util-buffer-from": "^4.2.0",
"@smithy/util-utf8": "^4.2.0",
"tslib": "^2.6.2"
@@ -1403,12 +1319,12 @@
}
},
"node_modules/@smithy/hash-stream-node": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.7.tgz",
- "integrity": "sha512-ZQVoAwNYnFMIbd4DUc517HuwNelJUY6YOzwqrbcAgCnVn+79/OK7UjwA93SPpdTOpKDVkLIzavWm/Ck7SmnDPQ==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.8.tgz",
+ "integrity": "sha512-v0FLTXgHrTeheYZFGhR+ehX5qUm4IQsjAiL9qehad2cyjMWcN2QG6/4mSwbSgEQzI7jwfoXj7z4fxZUx/Mhj2w==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"@smithy/util-utf8": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -1417,12 +1333,12 @@
}
},
"node_modules/@smithy/invalid-dependency": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.7.tgz",
- "integrity": "sha512-ncvgCr9a15nPlkhIUx3CU4d7E7WEuVJOV7fS7nnK2hLtPK9tYRBkMHQbhXU1VvvKeBm/O0x26OEoBq+ngFpOEQ==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.8.tgz",
+ "integrity": "sha512-N9iozRybwAQ2dn9Fot9kI6/w9vos2oTXLhtK7ovGqwZjlOcxu6XhPlpLpC+INsxktqHinn5gS2DXDjDF2kG5sQ==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1442,12 +1358,12 @@
}
},
"node_modules/@smithy/md5-js": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.7.tgz",
- "integrity": "sha512-Wv6JcUxtOLTnxvNjDnAiATUsk8gvA6EeS8zzHig07dotpByYsLot+m0AaQEniUBjx97AC41MQR4hW0baraD1Xw==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.8.tgz",
+ "integrity": "sha512-oGMaLj4tVZzLi3itBa9TCswgMBr7k9b+qKYowQ6x1rTyTuO1IU2YHdHUa+891OsOH+wCsH7aTPRsTJO3RMQmjQ==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"@smithy/util-utf8": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -1456,13 +1372,13 @@
}
},
"node_modules/@smithy/middleware-content-length": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.7.tgz",
- "integrity": "sha512-GszfBfCcvt7kIbJ41LuNa5f0wvQCHhnGx/aDaZJCCT05Ld6x6U2s0xsc/0mBFONBZjQJp2U/0uSJ178OXOwbhg==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.8.tgz",
+ "integrity": "sha512-RO0jeoaYAB1qBRhfVyq0pMgBoUK34YEJxVxyjOWYZiOKOq2yMZ4MnVXMZCUDenpozHue207+9P5ilTV1zeda0A==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1470,18 +1386,18 @@
}
},
"node_modules/@smithy/middleware-endpoint": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.3.tgz",
- "integrity": "sha512-Zb8R35hjBhp1oFhiaAZ9QhClpPHdEDmNDC2UrrB2fqV0oNDUUPH12ovZHB5xi/Rd+pg/BJHOR1q+SfsieSKPQg==",
+ "version": "4.4.16",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.16.tgz",
+ "integrity": "sha512-L5GICFCSsNhbJ5JSKeWFGFy16Q2OhoBizb3X2DrxaJwXSEujVvjG9Jt386dpQn2t7jINglQl0b4K/Su69BdbMA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/core": "^3.20.2",
- "@smithy/middleware-serde": "^4.2.8",
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/shared-ini-file-loader": "^4.4.2",
- "@smithy/types": "^4.11.0",
- "@smithy/url-parser": "^4.2.7",
- "@smithy/util-middleware": "^4.2.7",
+ "@smithy/core": "^3.23.2",
+ "@smithy/middleware-serde": "^4.2.9",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/shared-ini-file-loader": "^4.4.3",
+ "@smithy/types": "^4.12.0",
+ "@smithy/url-parser": "^4.2.8",
+ "@smithy/util-middleware": "^4.2.8",
"tslib": "^2.6.2"
},
"engines": {
@@ -1489,18 +1405,18 @@
}
},
"node_modules/@smithy/middleware-retry": {
- "version": "4.4.19",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.19.tgz",
- "integrity": "sha512-QtisFIjIw2tjMm/ESatjWFVIQb5Xd093z8xhxq/SijLg7Mgo2C2wod47Ib/AHpBLFhwYXPzd7Hp2+JVXfeZyMQ==",
+ "version": "4.4.33",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.33.tgz",
+ "integrity": "sha512-jLqZOdJhtIL4lnA9hXnAG6GgnJlo1sD3FqsTxm9wSfjviqgWesY/TMBVnT84yr4O0Vfe0jWoXlfFbzsBVph3WA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/service-error-classification": "^4.2.7",
- "@smithy/smithy-client": "^4.10.4",
- "@smithy/types": "^4.11.0",
- "@smithy/util-middleware": "^4.2.7",
- "@smithy/util-retry": "^4.2.7",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/service-error-classification": "^4.2.8",
+ "@smithy/smithy-client": "^4.11.5",
+ "@smithy/types": "^4.12.0",
+ "@smithy/util-middleware": "^4.2.8",
+ "@smithy/util-retry": "^4.2.8",
"@smithy/uuid": "^1.1.0",
"tslib": "^2.6.2"
},
@@ -1509,13 +1425,13 @@
}
},
"node_modules/@smithy/middleware-serde": {
- "version": "4.2.8",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.8.tgz",
- "integrity": "sha512-8rDGYen5m5+NV9eHv9ry0sqm2gI6W7mc1VSFMtn6Igo25S507/HaOX9LTHAS2/J32VXD0xSzrY0H5FJtOMS4/w==",
+ "version": "4.2.9",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.9.tgz",
+ "integrity": "sha512-eMNiej0u/snzDvlqRGSN3Vl0ESn3838+nKyVfF2FKNXFbi4SERYT6PR392D39iczngbqqGG0Jl1DlCnp7tBbXQ==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1523,12 +1439,12 @@
}
},
"node_modules/@smithy/middleware-stack": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.7.tgz",
- "integrity": "sha512-bsOT0rJ+HHlZd9crHoS37mt8qRRN/h9jRve1SXUhVbkRzu0QaNYZp1i1jha4n098tsvROjcwfLlfvcFuJSXEsw==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.8.tgz",
+ "integrity": "sha512-w6LCfOviTYQjBctOKSwy6A8FIkQy7ICvglrZFl6Bw4FmcQ1Z420fUtIhxaUZZshRe0VCq4kvDiPiXrPZAe8oRA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1536,14 +1452,14 @@
}
},
"node_modules/@smithy/node-config-provider": {
- "version": "4.3.7",
- "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.7.tgz",
- "integrity": "sha512-7r58wq8sdOcrwWe+klL9y3bc4GW1gnlfnFOuL7CXa7UzfhzhxKuzNdtqgzmTV+53lEp9NXh5hY/S4UgjLOzPfw==",
+ "version": "4.3.8",
+ "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.8.tgz",
+ "integrity": "sha512-aFP1ai4lrbVlWjfpAfRSL8KFcnJQYfTl5QxLJXY32vghJrDuFyPZ6LtUL+JEGYiFRG1PfPLHLoxj107ulncLIg==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/property-provider": "^4.2.7",
- "@smithy/shared-ini-file-loader": "^4.4.2",
- "@smithy/types": "^4.11.0",
+ "@smithy/property-provider": "^4.2.8",
+ "@smithy/shared-ini-file-loader": "^4.4.3",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1551,15 +1467,15 @@
}
},
"node_modules/@smithy/node-http-handler": {
- "version": "4.4.7",
- "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.7.tgz",
- "integrity": "sha512-NELpdmBOO6EpZtWgQiHjoShs1kmweaiNuETUpuup+cmm/xJYjT4eUjfhrXRP4jCOaAsS3c3yPsP3B+K+/fyPCQ==",
+ "version": "4.4.10",
+ "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.10.tgz",
+ "integrity": "sha512-u4YeUwOWRZaHbWaebvrs3UhwQwj+2VNmcVCwXcYTvPIuVyM7Ex1ftAj+fdbG/P4AkBwLq/+SKn+ydOI4ZJE9PA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/abort-controller": "^4.2.7",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/querystring-builder": "^4.2.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/abort-controller": "^4.2.8",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/querystring-builder": "^4.2.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1567,12 +1483,12 @@
}
},
"node_modules/@smithy/property-provider": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.7.tgz",
- "integrity": "sha512-jmNYKe9MGGPoSl/D7JDDs1C8b3dC8f/w78LbaVfoTtWy4xAd5dfjaFG9c9PWPihY4ggMQNQSMtzU77CNgAJwmA==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.8.tgz",
+ "integrity": "sha512-EtCTbyIveCKeOXDSWSdze3k612yCPq1YbXsbqX3UHhkOSW8zKsM9NOJG5gTIya0vbY2DIaieG8pKo1rITHYL0w==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1580,12 +1496,12 @@
}
},
"node_modules/@smithy/protocol-http": {
- "version": "5.3.7",
- "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.7.tgz",
- "integrity": "sha512-1r07pb994I20dD/c2seaZhoCuNYm0rWrvBxhCQ70brNh11M5Ml2ew6qJVo0lclB3jMIXirD4s2XRXRe7QEi0xA==",
+ "version": "5.3.8",
+ "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.8.tgz",
+ "integrity": "sha512-QNINVDhxpZ5QnP3aviNHQFlRogQZDfYlCkQT+7tJnErPQbDhysondEjhikuANxgMsZrkGeiAxXy4jguEGsDrWQ==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1593,12 +1509,12 @@
}
},
"node_modules/@smithy/querystring-builder": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.7.tgz",
- "integrity": "sha512-eKONSywHZxK4tBxe2lXEysh8wbBdvDWiA+RIuaxZSgCMmA0zMgoDpGLJhnyj+c0leOQprVnXOmcB4m+W9Rw7sg==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.8.tgz",
+ "integrity": "sha512-Xr83r31+DrE8CP3MqPgMJl+pQlLLmOfiEUnoyAlGzzJIrEsbKsPy1hqH0qySaQm4oWrCBlUqRt+idEgunKB+iw==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"@smithy/util-uri-escape": "^4.2.0",
"tslib": "^2.6.2"
},
@@ -1607,12 +1523,12 @@
}
},
"node_modules/@smithy/querystring-parser": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.7.tgz",
- "integrity": "sha512-3X5ZvzUHmlSTHAXFlswrS6EGt8fMSIxX/c3Rm1Pni3+wYWB6cjGocmRIoqcQF9nU5OgGmL0u7l9m44tSUpfj9w==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.8.tgz",
+ "integrity": "sha512-vUurovluVy50CUlazOiXkPq40KGvGWSdmusa3130MwrR1UNnNgKAlj58wlOe61XSHRpUfIIh6cE0zZ8mzKaDPA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1620,24 +1536,24 @@
}
},
"node_modules/@smithy/service-error-classification": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.7.tgz",
- "integrity": "sha512-YB7oCbukqEb2Dlh3340/8g8vNGbs/QsNNRms+gv3N2AtZz9/1vSBx6/6tpwQpZMEJFs7Uq8h4mmOn48ZZ72MkA==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.8.tgz",
+ "integrity": "sha512-mZ5xddodpJhEt3RkCjbmUQuXUOaPNTkbMGR0bcS8FE0bJDLMZlhmpgrvPNCYglVw5rsYTpSnv19womw9WWXKQQ==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0"
+ "@smithy/types": "^4.12.0"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/shared-ini-file-loader": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.2.tgz",
- "integrity": "sha512-M7iUUff/KwfNunmrgtqBfvZSzh3bmFgv/j/t1Y1dQ+8dNo34br1cqVEqy6v0mYEgi0DkGO7Xig0AnuOaEGVlcg==",
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.3.tgz",
+ "integrity": "sha512-DfQjxXQnzC5UbCUPeC3Ie8u+rIWZTvuDPAGU/BxzrOGhRvgUanaP68kDZA+jaT3ZI+djOf+4dERGlm9mWfFDrg==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1645,16 +1561,16 @@
}
},
"node_modules/@smithy/signature-v4": {
- "version": "5.3.7",
- "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.7.tgz",
- "integrity": "sha512-9oNUlqBlFZFOSdxgImA6X5GFuzE7V2H7VG/7E70cdLhidFbdtvxxt81EHgykGK5vq5D3FafH//X+Oy31j3CKOg==",
+ "version": "5.3.8",
+ "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.8.tgz",
+ "integrity": "sha512-6A4vdGj7qKNRF16UIcO8HhHjKW27thsxYci+5r/uVRkdcBEkOEiY8OMPuydLX4QHSrJqGHPJzPRwwVTqbLZJhg==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/is-array-buffer": "^4.2.0",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/types": "^4.12.0",
"@smithy/util-hex-encoding": "^4.2.0",
- "@smithy/util-middleware": "^4.2.7",
+ "@smithy/util-middleware": "^4.2.8",
"@smithy/util-uri-escape": "^4.2.0",
"@smithy/util-utf8": "^4.2.0",
"tslib": "^2.6.2"
@@ -1664,17 +1580,17 @@
}
},
"node_modules/@smithy/smithy-client": {
- "version": "4.10.4",
- "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.10.4.tgz",
- "integrity": "sha512-rHig+BWjhjlHlah67ryaW9DECYixiJo5pQCTEwsJyarRBAwHMMC3iYz5MXXAHXe64ZAMn1NhTUSTFIu1T6n6jg==",
+ "version": "4.11.5",
+ "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.11.5.tgz",
+ "integrity": "sha512-xixwBRqoeP2IUgcAl3U9dvJXc+qJum4lzo3maaJxifsZxKUYLfVfCXvhT4/jD01sRrHg5zjd1cw2Zmjr4/SuKQ==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/core": "^3.20.2",
- "@smithy/middleware-endpoint": "^4.4.3",
- "@smithy/middleware-stack": "^4.2.7",
- "@smithy/protocol-http": "^5.3.7",
- "@smithy/types": "^4.11.0",
- "@smithy/util-stream": "^4.5.8",
+ "@smithy/core": "^3.23.2",
+ "@smithy/middleware-endpoint": "^4.4.16",
+ "@smithy/middleware-stack": "^4.2.8",
+ "@smithy/protocol-http": "^5.3.8",
+ "@smithy/types": "^4.12.0",
+ "@smithy/util-stream": "^4.5.12",
"tslib": "^2.6.2"
},
"engines": {
@@ -1682,9 +1598,9 @@
}
},
"node_modules/@smithy/types": {
- "version": "4.11.0",
- "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.11.0.tgz",
- "integrity": "sha512-mlrmL0DRDVe3mNrjTcVcZEgkFmufITfUAPBEA+AHYiIeYyJebso/He1qLbP3PssRe22KUzLRpQSdBPbXdgZ2VA==",
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.12.0.tgz",
+ "integrity": "sha512-9YcuJVTOBDjg9LWo23Qp0lTQ3D7fQsQtwle0jVfpbUHy9qBwCEgKuVH4FqFB3VYu0nwdHKiEMA+oXz7oV8X1kw==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.6.2"
@@ -1694,13 +1610,13 @@
}
},
"node_modules/@smithy/url-parser": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.7.tgz",
- "integrity": "sha512-/RLtVsRV4uY3qPWhBDsjwahAtt3x2IsMGnP5W1b2VZIe+qgCqkLxI1UOHDZp1Q1QSOrdOR32MF3Ph2JfWT1VHg==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.8.tgz",
+ "integrity": "sha512-NQho9U68TGMEU639YkXnVMV3GEFFULmmaWdlu1E9qzyIePOHsoSnagTGSDv1Zi8DCNN6btxOSdgmy5E/hsZwhA==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/querystring-parser": "^4.2.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/querystring-parser": "^4.2.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1771,14 +1687,14 @@
}
},
"node_modules/@smithy/util-defaults-mode-browser": {
- "version": "4.3.18",
- "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.18.tgz",
- "integrity": "sha512-Ao1oLH37YmLyHnKdteMp6l4KMCGBeZEAN68YYe00KAaKFijFELDbRQRm3CNplz7bez1HifuBV0l5uR6eVJLhIg==",
+ "version": "4.3.32",
+ "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.32.tgz",
+ "integrity": "sha512-092sjYfFMQ/iaPH798LY/OJFBcYu0sSK34Oy9vdixhsU36zlZu8OcYjF3TD4e2ARupyK7xaxPXl+T0VIJTEkkg==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/property-provider": "^4.2.7",
- "@smithy/smithy-client": "^4.10.4",
- "@smithy/types": "^4.11.0",
+ "@smithy/property-provider": "^4.2.8",
+ "@smithy/smithy-client": "^4.11.5",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1786,17 +1702,17 @@
}
},
"node_modules/@smithy/util-defaults-mode-node": {
- "version": "4.2.21",
- "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.21.tgz",
- "integrity": "sha512-e21ASJDirE96kKXZLcYcnn4Zt0WGOvMYc1P8EK0gQeQ3I8PbJWqBKx9AUr/YeFpDkpYwEu1RsPe4UXk2+QL7IA==",
+ "version": "4.2.35",
+ "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.35.tgz",
+ "integrity": "sha512-miz/ggz87M8VuM29y7jJZMYkn7+IErM5p5UgKIf8OtqVs/h2bXr1Bt3uTsREsI/4nK8a0PQERbAPsVPVNIsG7Q==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/config-resolver": "^4.4.5",
- "@smithy/credential-provider-imds": "^4.2.7",
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/property-provider": "^4.2.7",
- "@smithy/smithy-client": "^4.10.4",
- "@smithy/types": "^4.11.0",
+ "@smithy/config-resolver": "^4.4.6",
+ "@smithy/credential-provider-imds": "^4.2.8",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/property-provider": "^4.2.8",
+ "@smithy/smithy-client": "^4.11.5",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1804,13 +1720,13 @@
}
},
"node_modules/@smithy/util-endpoints": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.7.tgz",
- "integrity": "sha512-s4ILhyAvVqhMDYREeTS68R43B1V5aenV5q/V1QpRQJkCXib5BPRo4s7uNdzGtIKxaPHCfU/8YkvPAEvTpxgspg==",
+ "version": "3.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.8.tgz",
+ "integrity": "sha512-8JaVTn3pBDkhZgHQ8R0epwWt+BqPSLCjdjXXusK1onwJlRuN69fbvSK66aIKKO7SwVFM6x2J2ox5X8pOaWcUEw==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/node-config-provider": "^4.3.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/node-config-provider": "^4.3.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1830,12 +1746,12 @@
}
},
"node_modules/@smithy/util-middleware": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.7.tgz",
- "integrity": "sha512-i1IkpbOae6NvIKsEeLLM9/2q4X+M90KV3oCFgWQI4q0Qz+yUZvsr+gZPdAEAtFhWQhAHpTsJO8DRJPuwVyln+w==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.8.tgz",
+ "integrity": "sha512-PMqfeJxLcNPMDgvPbbLl/2Vpin+luxqTGPpW3NAQVLbRrFRzTa4rNAASYeIGjRV9Ytuhzny39SpyU04EQreF+A==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/types": "^4.11.0",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1843,13 +1759,13 @@
}
},
"node_modules/@smithy/util-retry": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.7.tgz",
- "integrity": "sha512-SvDdsQyF5CIASa4EYVT02LukPHVzAgUA4kMAuZ97QJc2BpAqZfA4PINB8/KOoCXEw9tsuv/jQjMeaHFvxdLNGg==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.8.tgz",
+ "integrity": "sha512-CfJqwvoRY0kTGe5AkQokpURNCT1u/MkRzMTASWMPPo2hNSnKtF1D45dQl3DE2LKLr4m+PW9mCeBMJr5mCAVThg==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/service-error-classification": "^4.2.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/service-error-classification": "^4.2.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1857,14 +1773,14 @@
}
},
"node_modules/@smithy/util-stream": {
- "version": "4.5.8",
- "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.8.tgz",
- "integrity": "sha512-ZnnBhTapjM0YPGUSmOs0Mcg/Gg87k503qG4zU2v/+Js2Gu+daKOJMeqcQns8ajepY8tgzzfYxl6kQyZKml6O2w==",
+ "version": "4.5.12",
+ "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.12.tgz",
+ "integrity": "sha512-D8tgkrmhAX/UNeCZbqbEO3uqyghUnEmmoO9YEvRuwxjlkKKUE7FOgCJnqpTlQPe9MApdWPky58mNQQHbnCzoNg==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/fetch-http-handler": "^5.3.8",
- "@smithy/node-http-handler": "^4.4.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/fetch-http-handler": "^5.3.9",
+ "@smithy/node-http-handler": "^4.4.10",
+ "@smithy/types": "^4.12.0",
"@smithy/util-base64": "^4.3.0",
"@smithy/util-buffer-from": "^4.2.0",
"@smithy/util-hex-encoding": "^4.2.0",
@@ -1901,13 +1817,13 @@
}
},
"node_modules/@smithy/util-waiter": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.2.7.tgz",
- "integrity": "sha512-vHJFXi9b7kUEpHWUCY3Twl+9NPOZvQ0SAi+Ewtn48mbiJk4JY9MZmKQjGB4SCvVb9WPiSphZJYY6RIbs+grrzw==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.2.8.tgz",
+ "integrity": "sha512-n+lahlMWk+aejGuax7DPWtqav8HYnWxQwR+LCG2BgCUmaGcTe9qZCFsmw8TMg9iG75HOwhrJCX9TCJRLH+Yzqg==",
"license": "Apache-2.0",
"dependencies": {
- "@smithy/abort-controller": "^4.2.7",
- "@smithy/types": "^4.11.0",
+ "@smithy/abort-controller": "^4.2.8",
+ "@smithy/types": "^4.12.0",
"tslib": "^2.6.2"
},
"engines": {
@@ -1952,13 +1868,13 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "25.0.6",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.6.tgz",
- "integrity": "sha512-NNu0sjyNxpoiW3YuVFfNz7mxSQ+S4X2G28uqg2s+CzoqoQjLPsWSbsFFyztIAqt2vb8kfEAsJNepMGPTxFDx3Q==",
+ "version": "25.3.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz",
+ "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==",
"license": "MIT",
"optional": true,
"dependencies": {
- "undici-types": "~7.16.0"
+ "undici-types": "~7.18.0"
}
},
"node_modules/@types/triple-beam": {
@@ -1977,12 +1893,6 @@
"@types/node": "*"
}
},
- "node_modules/@ungap/structured-clone": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
- "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
- "license": "ISC"
- },
"node_modules/accepts": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
@@ -1996,28 +1906,6 @@
"node": ">= 0.6"
}
},
- "node_modules/acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
- "license": "MIT",
- "peer": true,
- "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==",
- "license": "MIT",
- "peerDependencies": {
- "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
"node_modules/agent-base": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
@@ -2027,22 +1915,6 @@
"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==",
- "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-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
@@ -2067,6 +1939,24 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/ansi-styles/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==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/ansi-styles/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==",
+ "license": "MIT"
+ },
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
@@ -2127,12 +2017,6 @@
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
"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/aws-ssl-profiles": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
@@ -2142,21 +2026,10 @@
"node": ">= 6.0.0"
}
},
- "node_modules/axios": {
- "version": "1.13.2",
- "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
- "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
- "license": "MIT",
- "dependencies": {
- "follow-redirects": "^1.15.6",
- "form-data": "^4.0.4",
- "proxy-from-env": "^1.1.0"
- }
- },
"node_modules/b4a": {
- "version": "1.7.3",
- "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz",
- "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==",
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz",
+ "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==",
"license": "Apache-2.0",
"peerDependencies": {
"react-native-b4a": "*"
@@ -2168,10 +2041,14 @@
}
},
"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"
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.3.tgz",
+ "integrity": "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "20 || >=22"
+ }
},
"node_modules/bare-events": {
"version": "2.8.2",
@@ -2188,9 +2065,9 @@
}
},
"node_modules/bare-fs": {
- "version": "4.5.2",
- "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.2.tgz",
- "integrity": "sha512-veTnRzkb6aPHOvSKIOy60KzURfBdUflr5VReI+NSaPL6xf+XLdONQgZgpYvUuZLVQ8dCqxpBAudaOM1+KpAUxw==",
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.4.tgz",
+ "integrity": "sha512-POK4oplfA7P7gqvetNmCs4CNtm9fNsx+IAh7jH7GgU0OJdge2rso0R20TNWVq6VoWcCvsTdlNDaleLHGaKx8CA==",
"license": "Apache-2.0",
"optional": true,
"dependencies": {
@@ -2233,13 +2110,14 @@
}
},
"node_modules/bare-stream": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.7.0.tgz",
- "integrity": "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==",
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.8.0.tgz",
+ "integrity": "sha512-reUN0M2sHRqCdG4lUK3Fw8w98eeUIZHL5c3H7Mbhk2yVBL+oofgaIp0ieLfD5QXwPCypBpmEEKU2WZKzbAk8GA==",
"license": "Apache-2.0",
"optional": true,
"dependencies": {
- "streamx": "^2.21.0"
+ "streamx": "^2.21.0",
+ "teex": "^1.0.1"
},
"peerDependencies": {
"bare-buffer": "*",
@@ -2306,12 +2184,6 @@
"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==",
- "license": "MIT"
- },
"node_modules/body-parser": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz",
@@ -2337,19 +2209,22 @@
}
},
"node_modules/bowser": {
- "version": "2.13.1",
- "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.13.1.tgz",
- "integrity": "sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw==",
+ "version": "2.14.1",
+ "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz",
+ "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==",
"license": "MIT"
},
"node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz",
+ "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "20 || >=22"
}
},
"node_modules/braces": {
@@ -2453,43 +2328,6 @@
"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==",
- "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/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "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==",
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@@ -2516,9 +2354,9 @@
}
},
"node_modules/chromium-bidi": {
- "version": "12.0.1",
- "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-12.0.1.tgz",
- "integrity": "sha512-fGg+6jr0xjQhzpy5N4ErZxQ4wF7KLEvhGZXD6EgvZKDhu7iOhZXnZhcDxPJDcwTcrD48NPzOCo84RP2lv3Z+Cg==",
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-14.0.0.tgz",
+ "integrity": "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw==",
"license": "Apache-2.0",
"dependencies": {
"mitt": "^3.0.1",
@@ -2565,22 +2403,25 @@
}
},
"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==",
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz",
+ "integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==",
"license": "MIT",
"dependencies": {
- "color-name": "~1.1.4"
+ "color-name": "^2.0.0"
},
"engines": {
- "node": ">=7.0.0"
+ "node": ">=14.6"
}
},
"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==",
- "license": "MIT"
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz",
+ "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20"
+ }
},
"node_modules/color-string": {
"version": "2.1.4",
@@ -2594,54 +2435,6 @@
"node": ">=18"
}
},
- "node_modules/color-string/node_modules/color-name": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz",
- "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==",
- "license": "MIT",
- "engines": {
- "node": ">=12.20"
- }
- },
- "node_modules/color/node_modules/color-convert": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.3.tgz",
- "integrity": "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==",
- "license": "MIT",
- "dependencies": {
- "color-name": "^2.0.0"
- },
- "engines": {
- "node": ">=14.6"
- }
- },
- "node_modules/color/node_modules/color-name": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.1.0.tgz",
- "integrity": "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==",
- "license": "MIT",
- "engines": {
- "node": ">=12.20"
- }
- },
- "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==",
- "license": "MIT"
- },
"node_modules/concat-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
@@ -2708,9 +2501,9 @@
"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==",
+ "version": "2.8.6",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
+ "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
@@ -2718,6 +2511,10 @@
},
"engines": {
"node": ">= 0.10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
}
},
"node_modules/cosmiconfig": {
@@ -2815,12 +2612,6 @@
}
}
},
- "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==",
- "license": "MIT"
- },
"node_modules/degenerator": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
@@ -2835,15 +2626,6 @@
"node": ">= 14"
}
},
- "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/denque": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
@@ -2863,11 +2645,10 @@
}
},
"node_modules/devtools-protocol": {
- "version": "0.0.1534754",
- "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1534754.tgz",
- "integrity": "sha512-26T91cV5dbOYnXdJi5qQHoTtUoNEqwkHcAyu/IKtjIAxiEqPMrDiRkDOPWVsGfNZGmlQVHQbZRSjD8sxagWVsQ==",
- "license": "BSD-3-Clause",
- "peer": true
+ "version": "0.0.1566079",
+ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1566079.tgz",
+ "integrity": "sha512-MJfAEA1UfVhSs7fbSQOG4czavUp1ajfg6prlAN0+cmfa2zNjaIbvq8VneP7do1WAQQIvgNJWSMeP6UyI90gIlQ==",
+ "license": "BSD-3-Clause"
},
"node_modules/dfa": {
"version": "1.2.0",
@@ -2875,22 +2656,10 @@
"integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==",
"license": "MIT"
},
- "node_modules/doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "license": "Apache-2.0",
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
"node_modules/dotenv": {
- "version": "17.2.3",
- "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
- "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
+ "version": "17.3.1",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz",
+ "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
@@ -3006,21 +2775,6 @@
"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/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@@ -3036,18 +2790,6 @@
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
"license": "MIT"
},
- "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==",
- "license": "MIT",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/escodegen": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
@@ -3069,120 +2811,6 @@
"source-map": "~0.6.1"
}
},
- "node_modules/eslint": {
- "version": "8.57.1",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
- "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
- "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.4",
- "@eslint/js": "8.57.1",
- "@humanwhocodes/config-array": "^0.13.0",
- "@humanwhocodes/module-importer": "^1.0.1",
- "@nodelib/fs.walk": "^1.2.8",
- "@ungap/structured-clone": "^1.2.0",
- "ajv": "^6.12.4",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "debug": "^4.3.2",
- "doctrine": "^3.0.0",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.3",
- "espree": "^9.6.1",
- "esquery": "^1.4.2",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
- "find-up": "^5.0.0",
- "glob-parent": "^6.0.2",
- "globals": "^13.19.0",
- "graphemer": "^1.4.0",
- "ignore": "^5.2.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "is-path-inside": "^3.0.3",
- "js-yaml": "^4.1.0",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.1.2",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.3",
- "strip-ansi": "^6.0.1",
- "text-table": "^0.2.0"
- },
- "bin": {
- "eslint": "bin/eslint.js"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint-scope": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
- "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
- "license": "BSD-2-Clause",
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "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==",
- "license": "Apache-2.0",
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint/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==",
- "license": "ISC",
- "dependencies": {
- "is-glob": "^4.0.3"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/espree": {
- "version": "9.6.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
- "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
- "license": "BSD-2-Clause",
- "dependencies": {
- "acorn": "^8.9.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.4.1"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
"node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
@@ -3196,30 +2824,6 @@
"node": ">=4"
}
},
- "node_modules/esquery": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
- "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
- "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==",
- "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",
@@ -3355,22 +2959,10 @@
"integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
"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==",
- "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==",
- "license": "MIT"
- },
"node_modules/fast-xml-parser": {
- "version": "5.2.5",
- "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz",
- "integrity": "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ==",
+ "version": "5.3.7",
+ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.7.tgz",
+ "integrity": "sha512-JzVLro9NQv92pOM/jTCR6mHlJh2FGwtomH8ZQjhFj/R29P2Fnj38OgPJVtcvYw6SuKClhgYuwUZf5b3rd8u2mA==",
"funding": [
{
"type": "github",
@@ -3379,21 +2971,12 @@
],
"license": "MIT",
"dependencies": {
- "strnum": "^2.1.0"
+ "strnum": "^2.1.2"
},
"bin": {
"fxparser": "src/cli/cli.js"
}
},
- "node_modules/fastq": {
- "version": "1.20.1",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
- "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
- "license": "ISC",
- "dependencies": {
- "reusify": "^1.0.4"
- }
- },
"node_modules/fd-slicer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
@@ -3409,18 +2992,6 @@
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
"license": "MIT"
},
- "node_modules/file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "license": "MIT",
- "dependencies": {
- "flat-cache": "^3.0.4"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
"node_modules/file-stream-rotator": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz",
@@ -3464,68 +3035,12 @@
"url": "https://opencollective.com/express"
}
},
- "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==",
- "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": "3.2.0",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
- "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
- "license": "MIT",
- "dependencies": {
- "flatted": "^3.2.9",
- "keyv": "^4.5.3",
- "rimraf": "^3.0.2"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "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==",
- "license": "ISC"
- },
"node_modules/fn.name": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==",
"license": "MIT"
},
- "node_modules/follow-redirects": {
- "version": "1.15.11",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
- "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
- "funding": [
- {
- "type": "individual",
- "url": "https://github.com/sponsors/RubenVerborgh"
- }
- ],
- "license": "MIT",
- "engines": {
- "node": ">=4.0"
- },
- "peerDependenciesMeta": {
- "debug": {
- "optional": true
- }
- }
- },
"node_modules/fontkit": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz",
@@ -3543,43 +3058,6 @@
"unicode-trie": "^2.0.0"
}
},
- "node_modules/form-data": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
- "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
- "license": "MIT",
- "dependencies": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "es-set-tostringtag": "^2.1.0",
- "hasown": "^2.0.2",
- "mime-types": "^2.1.12"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/form-data/node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "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/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -3598,12 +3076,6 @@
"node": ">= 0.8"
}
},
- "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==",
- "license": "ISC"
- },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -3713,27 +3185,6 @@
"node": ">= 14"
}
},
- "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",
- "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/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
@@ -3747,21 +3198,6 @@
"node": ">= 6"
}
},
- "node_modules/globals": {
- "version": "13.24.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
- "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
- "license": "MIT",
- "dependencies": {
- "type-fest": "^0.20.2"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
@@ -3774,12 +3210,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/graphemer": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
- "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
- "license": "MIT"
- },
"node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@@ -3802,21 +3232,6 @@
"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",
@@ -3891,15 +3306,6 @@
"url": "https://opencollective.com/express"
}
},
- "node_modules/ignore": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
- "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
- "license": "MIT",
- "engines": {
- "node": ">= 4"
- }
- },
"node_modules/ignore-by-default": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
@@ -3923,26 +3329,6 @@
"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==",
- "license": "MIT",
- "engines": {
- "node": ">=0.8.19"
- }
- },
- "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.",
- "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",
@@ -3990,6 +3376,7 @@
"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"
@@ -4008,6 +3395,7 @@
"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"
@@ -4026,15 +3414,6 @@
"node": ">=0.12.0"
}
},
- "node_modules/is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/is-promise": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
@@ -4090,30 +3469,12 @@
"js-yaml": "bin/js-yaml.js"
}
},
- "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==",
- "license": "MIT"
- },
"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==",
"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==",
- "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==",
- "license": "MIT"
- },
"node_modules/jsonwebtoken": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz",
@@ -4157,34 +3518,12 @@
"safe-buffer": "^5.0.1"
}
},
- "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==",
- "license": "MIT",
- "dependencies": {
- "json-buffer": "3.0.1"
- }
- },
"node_modules/kuler": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==",
"license": "MIT"
},
- "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==",
- "license": "MIT",
- "dependencies": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
"node_modules/linebreak": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz",
@@ -4210,21 +3549,6 @@
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
"license": "MIT"
},
- "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==",
- "license": "MIT",
- "dependencies": {
- "p-locate": "^5.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
@@ -4261,12 +3585,6 @@
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
"license": "MIT"
},
- "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==",
- "license": "MIT"
- },
"node_modules/lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
@@ -4306,9 +3624,9 @@
}
},
"node_modules/lru.min": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.3.tgz",
- "integrity": "sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q==",
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz",
+ "integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==",
"license": "MIT",
"engines": {
"bun": ">=1.0.0",
@@ -4376,15 +3694,19 @@
}
},
"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",
+ "version": "10.2.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz",
+ "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
"dependencies": {
- "brace-expansion": "^1.1.7"
+ "brace-expansion": "^5.0.2"
},
"engines": {
- "node": "*"
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/minimist": {
@@ -4491,20 +3813,19 @@
}
},
"node_modules/mysql2": {
- "version": "3.16.0",
- "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.16.0.tgz",
- "integrity": "sha512-AEGW7QLLSuSnjCS4pk3EIqOmogegmze9h8EyrndavUQnIUcfkVal/sK7QznE+a3bc6rzPbAiui9Jcb+96tPwYA==",
+ "version": "3.17.4",
+ "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.17.4.tgz",
+ "integrity": "sha512-RnfuK5tyIuaiPMWOCTTl4vQX/mQXqSA8eoIbwvWccadvPGvh+BYWWVecInMS5s7wcLUkze8LqJzwB/+A4uwuAA==",
"license": "MIT",
"dependencies": {
- "aws-ssl-profiles": "^1.1.1",
+ "aws-ssl-profiles": "^1.1.2",
"denque": "^2.1.0",
"generate-function": "^2.3.1",
- "iconv-lite": "^0.7.0",
- "long": "^5.2.1",
- "lru.min": "^1.0.0",
- "named-placeholders": "^1.1.3",
- "seq-queue": "^0.0.5",
- "sqlstring": "^2.3.2"
+ "iconv-lite": "^0.7.2",
+ "long": "^5.3.2",
+ "lru.min": "^1.1.4",
+ "named-placeholders": "^1.1.6",
+ "sql-escaper": "^1.3.3"
},
"engines": {
"node": ">= 8.0"
@@ -4522,12 +3843,6 @@
"node": ">=8.0.0"
}
},
- "node_modules/natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "license": "MIT"
- },
"node_modules/negotiator": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
@@ -4567,25 +3882,25 @@
}
},
"node_modules/nodemailer": {
- "version": "7.0.12",
- "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.12.tgz",
- "integrity": "sha512-H+rnK5bX2Pi/6ms3sN4/jRQvYSMltV6vqup/0SFOrxYYY/qoNvhXPlYq3e+Pm9RFJRwrMGbMIwi81M4dxpomhA==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.1.tgz",
+ "integrity": "sha512-5kcldIXmaEjZcHR6F28IKGSgpmZHaF1IXLWFTG+Xh3S+Cce4MiakLtWY+PlBU69fLbRa8HlaGIrC/QolUpHkhg==",
"license": "MIT-0",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/nodemon": {
- "version": "3.1.11",
- "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz",
- "integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==",
+ "version": "3.1.13",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.13.tgz",
+ "integrity": "sha512-nPN6L7A9cTA3BnJ3zZIibH5FiDh3GbmibeS17bl5YEU1IRO2mcfvR0ZJXH3ndoeKItjUcaX81FSKc/Kq/IiG6g==",
"dev": true,
"license": "MIT",
"dependencies": {
"chokidar": "^3.5.2",
"debug": "^4",
"ignore-by-default": "^1.0.1",
- "minimatch": "^3.1.2",
+ "minimatch": "^10.2.1",
"pstree.remy": "^1.1.8",
"semver": "^7.5.3",
"simple-update-notifier": "^2.0.0",
@@ -4674,53 +3989,6 @@
"fn.name": "1.x.x"
}
},
- "node_modules/optionator": {
- "version": "0.9.4",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
- "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
- "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==",
- "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==",
- "license": "MIT",
- "dependencies": {
- "p-limit": "^3.0.2"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/pac-proxy-agent": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz",
@@ -4798,24 +4066,6 @@
"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==",
- "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==",
- "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",
@@ -4890,15 +4140,6 @@
"resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz",
"integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g=="
},
- "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==",
- "license": "MIT",
- "engines": {
- "node": ">= 0.8.0"
- }
- },
"node_modules/progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
@@ -4963,27 +4204,18 @@
"once": "^1.3.1"
}
},
- "node_modules/punycode": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
- "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/puppeteer": {
- "version": "24.34.0",
- "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.34.0.tgz",
- "integrity": "sha512-Sdpl/zsYOsagZ4ICoZJPGZw8d9gZmK5DcxVal11dXi/1/t2eIXHjCf5NfmhDg5XnG9Nye+yo/LqMzIxie2rHTw==",
+ "version": "24.37.5",
+ "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.37.5.tgz",
+ "integrity": "sha512-3PAOIQLceyEmn1Fi76GkGO2EVxztv5OtdlB1m8hMUZL3f8KDHnlvXbvCXv+Ls7KzF1R0KdKBqLuT/Hhrok12hQ==",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
- "@puppeteer/browsers": "2.11.0",
- "chromium-bidi": "12.0.1",
+ "@puppeteer/browsers": "2.13.0",
+ "chromium-bidi": "14.0.0",
"cosmiconfig": "^9.0.0",
- "devtools-protocol": "0.0.1534754",
- "puppeteer-core": "24.34.0",
+ "devtools-protocol": "0.0.1566079",
+ "puppeteer-core": "24.37.5",
"typed-query-selector": "^2.12.0"
},
"bin": {
@@ -4994,27 +4226,27 @@
}
},
"node_modules/puppeteer-core": {
- "version": "24.34.0",
- "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.34.0.tgz",
- "integrity": "sha512-24evawO+mUGW4mvS2a2ivwLdX3gk8zRLZr9HP+7+VT2vBQnm0oh9jJEZmUE3ePJhRkYlZ93i7OMpdcoi2qNCLg==",
+ "version": "24.37.5",
+ "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.37.5.tgz",
+ "integrity": "sha512-ybL7iE78YPN4T6J+sPLO7r0lSByp/0NN6PvfBEql219cOnttoTFzCWKiBOjstXSqi/OKpwae623DWAsL7cn2MQ==",
"license": "Apache-2.0",
"dependencies": {
- "@puppeteer/browsers": "2.11.0",
- "chromium-bidi": "12.0.1",
+ "@puppeteer/browsers": "2.13.0",
+ "chromium-bidi": "14.0.0",
"debug": "^4.4.3",
- "devtools-protocol": "0.0.1534754",
+ "devtools-protocol": "0.0.1566079",
"typed-query-selector": "^2.12.0",
- "webdriver-bidi-protocol": "0.3.10",
- "ws": "^8.18.3"
+ "webdriver-bidi-protocol": "0.4.1",
+ "ws": "^8.19.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/qs": {
- "version": "6.14.1",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
- "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz",
+ "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==",
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
@@ -5026,26 +4258,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "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/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -5121,41 +4333,6 @@
"integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==",
"license": "MIT"
},
- "node_modules/reusify": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
- "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
- "license": "MIT",
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
- "node_modules/rewire": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/rewire/-/rewire-7.0.0.tgz",
- "integrity": "sha512-DyyNyzwMtGYgu0Zl/ya0PR/oaunM+VuCuBxCuhYJHHaV0V+YvYa3bBGxb5OZ71vndgmp1pYY8F4YOwQo1siRGw==",
- "license": "MIT",
- "dependencies": {
- "eslint": "^8.47.0"
- }
- },
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "deprecated": "Rimraf versions prior to v4 are no longer supported",
- "license": "ISC",
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/router": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
@@ -5172,29 +4349,6 @@
"node": ">= 18"
}
},
- "node_modules/run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "queue-microtask": "^1.2.2"
- }
- },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -5231,9 +4385,9 @@
"license": "MIT"
},
"node_modules/semver": {
- "version": "7.7.3",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
- "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -5268,11 +4422,6 @@
"url": "https://opencollective.com/express"
}
},
- "node_modules/seq-queue": {
- "version": "0.0.5",
- "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
- "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
- },
"node_modules/serve-static": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz",
@@ -5452,13 +4601,19 @@
"node": ">=0.10.0"
}
},
- "node_modules/sqlstring": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
- "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
+ "node_modules/sql-escaper": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/sql-escaper/-/sql-escaper-1.3.3.tgz",
+ "integrity": "sha512-BsTCV265VpTp8tm1wyIm1xqQCS+Q9NHx2Sr+WcnUrgLrQ6yiDIvHYJV5gHxsj1lMBy2zm5twLaZao8Jd+S8JJw==",
"license": "MIT",
"engines": {
- "node": ">= 0.6"
+ "bun": ">=1.0.0",
+ "deno": ">=2.0.0",
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/mysqljs/sql-escaper?sponsor=1"
}
},
"node_modules/stack-trace": {
@@ -5533,18 +4688,6 @@
"node": ">=8"
}
},
- "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==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/strnum": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz",
@@ -5595,10 +4738,20 @@
"streamx": "^2.15.0"
}
},
+ "node_modules/teex": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz",
+ "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "streamx": "^2.12.5"
+ }
+ },
"node_modules/text-decoder": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz",
- "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==",
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz",
+ "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==",
"license": "Apache-2.0",
"dependencies": {
"b4a": "^1.6.4"
@@ -5610,12 +4763,6 @@
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
"license": "MIT"
},
- "node_modules/text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "license": "MIT"
- },
"node_modules/tiny-inflate": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
@@ -5669,30 +4816,6 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
- "node_modules/type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "license": "MIT",
- "dependencies": {
- "prelude-ls": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "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",
@@ -5727,9 +4850,9 @@
"license": "MIT"
},
"node_modules/undici-types": {
- "version": "7.16.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
- "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
+ "version": "7.18.2",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
+ "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
"license": "MIT",
"optional": true
},
@@ -5762,15 +4885,6 @@
"node": ">= 0.8"
}
},
- "node_modules/uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "license": "BSD-2-Clause",
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -5800,9 +4914,9 @@
}
},
"node_modules/webdriver-bidi-protocol": {
- "version": "0.3.10",
- "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.3.10.tgz",
- "integrity": "sha512-5LAE43jAVLOhB/QqX4bwSiv0Hg1HBfMmOuwBSXHdvg4GMGu9Y0lIq7p4R/yySu6w74WmaR4GM4H9t2IwLW7hgw==",
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.1.tgz",
+ "integrity": "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==",
"license": "Apache-2.0"
},
"node_modules/which": {
@@ -5886,15 +5000,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/word-wrap": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
- "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
@@ -5994,18 +5099,6 @@
"fd-slicer": "~1.1.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==",
- "license": "MIT",
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/zod": {
"version": "3.25.76",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
diff --git a/package.json b/package.json
index 8bd91f7..8559098 100644
--- a/package.json
+++ b/package.json
@@ -17,30 +17,36 @@
"dev": "nodemon server.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
+ "overrides": {
+ "@aws-sdk/xml-builder": {
+ "fast-xml-parser": "^5.3.4",
+ "ajv": "8.18.0"
+ }
+ },
"dependencies": {
- "@aws-sdk/client-s3": "^3.894.0",
- "@aws-sdk/s3-request-presigner": "^3.894.0",
+ "@aws-sdk/client-s3": "^3.992.0",
+ "@aws-sdk/s3-request-presigner": "^3.992.0",
"@getbrevo/brevo": "^3.0.1",
"argon2": "^0.44.0",
"cookie-parser": "^1.4.7",
- "cors": "^2.8.5",
+ "cors": "^2.8.6",
"csv-parse": "^6.1.0",
- "dotenv": "^17.2.2",
- "express": "^5.1.0",
+ "dotenv": "^17.3.1",
+ "express": "^5.2.1",
"get-stream": "^9.0.1",
- "jsonwebtoken": "^9.0.2",
+ "jsonwebtoken": "^9.0.3",
"multer": "^2.0.2",
- "mysql2": "^3.15.0",
- "nodemailer": "^7.0.6",
+ "mysql2": "^3.17.2",
+ "nodemailer": "^8.0.1",
"pdfkit": "^0.17.2",
"pidusage": "^4.0.1",
- "puppeteer": "^24.22.0",
+ "puppeteer": "^24.37.3",
"uuid": "^13.0.0",
- "winston": "^3.17.0",
+ "winston": "^3.19.0",
"winston-daily-rotate-file": "^5.0.0"
},
"devDependencies": {
- "nodemon": "^3.1.10"
+ "nodemon": "^3.1.11"
},
"engines": {
"node": ">=16.0.0"
diff --git a/repositories/abonemments/AbonemmentRepository.js b/repositories/abonemments/AbonemmentRepository.js
index 673d189..e643a1d 100644
--- a/repositories/abonemments/AbonemmentRepository.js
+++ b/repositories/abonemments/AbonemmentRepository.js
@@ -129,14 +129,39 @@ class AbonemmentRepository {
}
async listByUser(userId, { status, limit = 50, offset = 0 } = {}) {
- const params = [userId];
- let sql = `SELECT * FROM coffee_abonements WHERE user_id = ?`;
+ const safeLimit = Number(limit);
+ const safeOffset = Number(offset);
+ const hasUserId = await this.hasColumn('user_id');
+ const hasPurchaserUserId = await this.hasColumn('purchaser_user_id');
+ const hasReferredBy = await this.hasColumn('referred_by');
+
+ let sql = `SELECT * FROM coffee_abonements WHERE `;
+ const params = [];
+
+ if (hasUserId && hasPurchaserUserId) {
+ sql += `(user_id = ? OR purchaser_user_id = ?)`;
+ params.push(userId, userId);
+ } else if (hasUserId) {
+ sql += `user_id = ?`;
+ params.push(userId);
+ } else if (hasPurchaserUserId) {
+ sql += `purchaser_user_id = ?`;
+ params.push(userId);
+ } else if (hasReferredBy) {
+ // Legacy fallback for older schema where ownership was not persisted in user_id.
+ sql += `referred_by = ?`;
+ params.push(userId);
+ } else {
+ // Legacy schema fallback: no owner columns available
+ return [];
+ }
+
if (status) {
sql += ` AND status = ?`;
params.push(status);
}
sql += ` ORDER BY created_at DESC LIMIT ? OFFSET ?`;
- params.push(Number(limit), Number(offset));
+ params.push(safeLimit, safeOffset);
const [rows] = await pool.query(sql, params);
return rows.map((r) => new Abonemment(r));
}
@@ -231,6 +256,44 @@ class AbonemmentRepository {
return this.getAbonementById(id);
}
+ async transitionContent(id, contentPayload = {}) {
+ const conn = await pool.getConnection();
+ try {
+ await conn.beginTransaction();
+ await conn.query(
+ `UPDATE coffee_abonements
+ SET pack_breakdown = ?, price = ?, currency = ?, updated_at = ?
+ WHERE id = ?`,
+ [
+ JSON.stringify(contentPayload.pack_breakdown || []),
+ contentPayload.price ?? null,
+ contentPayload.currency ?? 'EUR',
+ contentPayload.updated_at || new Date(),
+ id,
+ ],
+ );
+ await conn.query(
+ `INSERT INTO coffee_abonement_history
+ (abonement_id, event_type, event_at, actor_user_id, details, created_at)
+ VALUES (?, ?, ?, ?, ?, NOW())`,
+ [
+ id,
+ contentPayload.event_type || 'content_updated',
+ contentPayload.event_at || new Date(),
+ contentPayload.actor_user_id || null,
+ JSON.stringify(contentPayload.details || {}),
+ ],
+ );
+ await conn.commit();
+ } catch (err) {
+ await conn.rollback();
+ throw err;
+ } finally {
+ conn.release();
+ }
+ return this.getAbonementById(id);
+ }
+
async listDueForBilling(now) {
const [rows] = await pool.query(
`SELECT * FROM coffee_abonements
diff --git a/repositories/invoice/InvoiceRepository.js b/repositories/invoice/InvoiceRepository.js
index 202110f..580814b 100644
--- a/repositories/invoice/InvoiceRepository.js
+++ b/repositories/invoice/InvoiceRepository.js
@@ -146,6 +146,22 @@ class InvoiceRepository {
return rows[0] ? new Invoice(rows[0]) : null;
}
+ async getItemsByInvoiceId(invoiceId) {
+ const [rows] = await pool.query(
+ `SELECT * FROM invoice_items WHERE invoice_id = ? ORDER BY id ASC`,
+ [invoiceId],
+ );
+ return rows || [];
+ }
+
+ async updateStorageKey(invoiceId, storageKey) {
+ await pool.query(
+ `UPDATE invoices SET pdf_storage_key = ?, updated_at = NOW() WHERE id = ?`,
+ [storageKey, invoiceId],
+ );
+ return this.getById(invoiceId);
+ }
+
async listByUser(userId, { status, limit = 50, offset = 0 } = {}) {
const params = [userId];
let sql = `SELECT * FROM invoices WHERE user_id = ?`;
@@ -179,6 +195,26 @@ class InvoiceRepository {
);
return rows.map((r) => new Invoice(r));
}
+
+ async updateStatus(invoiceId, newStatus) {
+ const allowed = ['draft', 'issued', 'paid', 'overdue', 'canceled'];
+ if (!allowed.includes(newStatus)) {
+ throw new Error(`Invalid status '${newStatus}'. Allowed: ${allowed.join(', ')}`);
+ }
+ await pool.query(
+ `UPDATE invoices SET status = ?, updated_at = NOW() WHERE id = ?`,
+ [newStatus, invoiceId],
+ );
+ return this.getById(invoiceId);
+ }
+
+ async getPaymentsByInvoiceId(invoiceId) {
+ const [rows] = await pool.query(
+ `SELECT * FROM invoice_payments WHERE invoice_id = ? ORDER BY created_at DESC`,
+ [invoiceId],
+ );
+ return rows || [];
+ }
}
module.exports = InvoiceRepository;
diff --git a/repositories/pool/poolMemberRepository.js b/repositories/pool/poolMemberRepository.js
index de9cbbd..083c4e1 100644
--- a/repositories/pool/poolMemberRepository.js
+++ b/repositories/pool/poolMemberRepository.js
@@ -9,6 +9,25 @@ class PoolMemberRepository {
const conn = this.uow.connection;
try {
logger.info('PoolMemberRepository.listMembers:start', { poolId });
+
+ // 1) Get the pool info (is_core flag, member count, total inflows)
+ const [poolMeta] = await conn.execute(
+ `SELECT
+ p.pool_name,
+ (SELECT COUNT(*) FROM pool_members WHERE pool_id = p.id) AS member_count,
+ COALESCE((SELECT SUM(pi.amount_net) FROM pool_inflows pi WHERE pi.pool_id = p.id), 0) AS total_pool_amount
+ FROM pools p
+ WHERE p.id = ?`,
+ [poolId]
+ );
+ const meta = poolMeta[0] || { pool_name: '', member_count: 0, total_pool_amount: 0 };
+ const isCore = meta.pool_name === 'Core';
+ const memberCount = Number(meta.member_count) || 1;
+ const totalPoolAmount = Number(meta.total_pool_amount) || 0;
+ // For Core: every member gets the full total. Others: equal share.
+ const perMemberShare = isCore ? totalPoolAmount : totalPoolAmount / memberCount;
+
+ // 2) Fetch member rows
const [rows] = await conn.execute(
`SELECT
u.id,
@@ -27,8 +46,12 @@ class PoolMemberRepository {
ORDER BY pm.joined_at DESC`,
[poolId]
);
+
+ // 3) Attach per-member share
+ const enriched = rows.map(r => ({ ...r, share: Number(perMemberShare.toFixed(2)) }));
+
logger.info('PoolMemberRepository.listMembers:success', { poolId, count: rows.length });
- return rows;
+ return enriched;
} catch (error) {
logger.error('PoolMemberRepository.listMembers:error', { poolId, error: error.message });
throw error;
diff --git a/repositories/pool/poolRepository.js b/repositories/pool/poolRepository.js
index d96b7b5..b0340d8 100644
--- a/repositories/pool/poolRepository.js
+++ b/repositories/pool/poolRepository.js
@@ -5,16 +5,16 @@ class PoolRepository {
this.uow = uow;
}
- async create({ pool_name, description = null, price = 0.00, pool_type = 'other', is_active = true, created_by = null }) {
+ async create({ pool_name, description = null, price = 0.00, subscription_coffee_id = null, pool_type = 'other', is_active = true, created_by = null }) {
const conn = this.uow.connection;
try {
- console.info('PoolRepository.create:start', { pool_name, pool_type, is_active, price, created_by });
- const sql = `INSERT INTO pools (pool_name, description, price, pool_type, is_active, created_by)
- VALUES (?, ?, ?, ?, ?, ?)`;
- const params = [pool_name, description, price, pool_type, is_active, created_by];
+ console.info('PoolRepository.create:start', { pool_name, pool_type, is_active, price, subscription_coffee_id, created_by });
+ const sql = `INSERT INTO pools (pool_name, description, price, subscription_coffee_id, pool_type, is_active, created_by)
+ VALUES (?, ?, ?, ?, ?, ?, ?)`;
+ const params = [pool_name, description, price, subscription_coffee_id, pool_type, is_active, created_by];
const [res] = await conn.execute(sql, params);
console.info('PoolRepository.create:success', { insertId: res?.insertId });
- return new Pool({ id: res.insertId, pool_name, description, price, pool_type, is_active, created_by });
+ return new Pool({ id: res.insertId, pool_name, description, price, subscription_coffee_id, pool_type, is_active, created_by });
} catch (err) {
console.error('PoolRepository.create:error', { code: err?.code, errno: err?.errno, sqlMessage: err?.sqlMessage, message: err?.message });
const e = new Error('Failed to create pool');
@@ -29,13 +29,15 @@ class PoolRepository {
try {
console.info('PoolRepository.findAll:start');
const sql = `SELECT
- p.id, p.pool_name, p.description, p.price, p.pool_type, p.is_active,
+ p.id, p.pool_name, p.description, p.price, p.subscription_coffee_id, c.title AS subscription_title, p.pool_type, p.is_active,
p.created_by, p.updated_by, p.created_at, p.updated_at,
COUNT(pm.user_id) AS members_count
FROM pools p
+ LEFT JOIN coffee_table c ON c.id = p.subscription_coffee_id
LEFT JOIN pool_members pm ON pm.pool_id = p.id
+ WHERE p.pool_name IN ('ABO 60', 'ABO 120', 'Business', 'Gigantea', 'Core')
GROUP BY p.id
- ORDER BY p.created_at DESC`;
+ ORDER BY FIELD(p.pool_name, 'ABO 60', 'ABO 120', 'Business', 'Gigantea', 'Core')`;
const [rows] = await conn.execute(sql);
console.info('PoolRepository.findAll:success', { count: rows.length });
return rows.map(r => new Pool(r));
@@ -66,7 +68,10 @@ class PoolRepository {
[is_active, updated_by, id]
);
const [updated] = await conn.execute(
- `SELECT id, pool_name, description, price, pool_type, is_active, created_by, updated_by, created_at, updated_at FROM pools WHERE id = ?`,
+ `SELECT p.id, p.pool_name, p.description, p.price, p.subscription_coffee_id, c.title AS subscription_title, p.pool_type, p.is_active, p.created_by, p.updated_by, p.created_at, p.updated_at
+ FROM pools p
+ LEFT JOIN coffee_table c ON c.id = p.subscription_coffee_id
+ WHERE p.id = ?`,
[id]
);
console.info('PoolRepository.updateActive:success', { id, is_active });
@@ -82,6 +87,43 @@ class PoolRepository {
throw err;
}
}
+
+ async updateSubscriptionLink(id, subscription_coffee_id = null, updated_by = null) {
+ const conn = this.uow.connection;
+ try {
+ console.info('PoolRepository.updateSubscriptionLink:start', { id, subscription_coffee_id, updated_by });
+ const [rows] = await conn.execute(`SELECT id FROM pools WHERE id = ?`, [id]);
+ if (!rows || rows.length === 0) {
+ const err = new Error('Pool not found');
+ err.status = 404;
+ throw err;
+ }
+
+ await conn.execute(
+ `UPDATE pools SET subscription_coffee_id = ?, updated_by = ?, updated_at = NOW() WHERE id = ?`,
+ [subscription_coffee_id, updated_by, id]
+ );
+
+ const [updated] = await conn.execute(
+ `SELECT p.id, p.pool_name, p.description, p.price, p.subscription_coffee_id, c.title AS subscription_title, p.pool_type, p.is_active, p.created_by, p.updated_by, p.created_at, p.updated_at
+ FROM pools p
+ LEFT JOIN coffee_table c ON c.id = p.subscription_coffee_id
+ WHERE p.id = ?`,
+ [id]
+ );
+
+ return new Pool(updated[0]);
+ } catch (err) {
+ console.error('PoolRepository.updateSubscriptionLink:error', { id, subscription_coffee_id, code: err?.code, message: err?.message });
+ if (!err.status) {
+ const e = new Error('Failed to update pool subscription link');
+ e.status = 500;
+ e.cause = err;
+ throw e;
+ }
+ throw err;
+ }
+ }
}
module.exports = PoolRepository;
\ No newline at end of file
diff --git a/repositories/referral/ReferralTokenRepository.js b/repositories/referral/ReferralTokenRepository.js
index 21ebf51..8bdfdf1 100644
--- a/repositories/referral/ReferralTokenRepository.js
+++ b/repositories/referral/ReferralTokenRepository.js
@@ -197,7 +197,7 @@ class ReferralTokenRepository {
u.email AS referrer_email,
u.user_type AS referrer_user_type
FROM referral_tokens rt
- JOIN users u ON rt.created_by_user_id = u.id
+ LEFT JOIN users u ON rt.created_by_user_id = u.id
WHERE rt.token = ?
LIMIT 1
`;
@@ -209,7 +209,8 @@ class ReferralTokenRepository {
token: r.token,
max_uses: r.max_uses,
uses_remaining: r.uses_remaining,
- used_count: r.used_count
+ used_count: r.used_count,
+ referrer_id: r.referrer_id
});
logger.info('ReferralTokenRepository.getReferrerInfoByToken:success', { token });
} else {
diff --git a/repositories/settings/CompanySettingsRepository.js b/repositories/settings/CompanySettingsRepository.js
new file mode 100644
index 0000000..a0f9f13
--- /dev/null
+++ b/repositories/settings/CompanySettingsRepository.js
@@ -0,0 +1,24 @@
+const pool = require('../../database/database');
+
+class CompanySettingsRepository {
+ async get() {
+ const [rows] = await pool.query('SELECT * FROM company_settings WHERE id = 1');
+ return rows[0] || null;
+ }
+
+ async update({ company_name, company_street, company_postal_city, company_country }) {
+ await pool.query(
+ `INSERT INTO company_settings (id, company_name, company_street, company_postal_city, company_country)
+ VALUES (1, ?, ?, ?, ?)
+ ON DUPLICATE KEY UPDATE
+ company_name = VALUES(company_name),
+ company_street = VALUES(company_street),
+ company_postal_city = VALUES(company_postal_city),
+ company_country = VALUES(company_country)`,
+ [company_name || '', company_street || '', company_postal_city || '', company_country || '']
+ );
+ return this.get();
+ }
+}
+
+module.exports = CompanySettingsRepository;
diff --git a/repositories/template/DocumentTemplateRepository.js b/repositories/template/DocumentTemplateRepository.js
index 5dd113e..c3355d7 100644
--- a/repositories/template/DocumentTemplateRepository.js
+++ b/repositories/template/DocumentTemplateRepository.js
@@ -193,6 +193,36 @@ class DocumentTemplateRepository {
}
}
+ // Deactivate other active invoice templates for the same language.
+ // Invoices always use user_type='both', so only lang matters.
+ async deactivateOtherActiveInvoices({ excludeId, lang }, conn) {
+ logger.info('DocumentTemplateRepository.deactivateOtherActiveInvoices:start', { excludeId, lang });
+ const safeLang = (lang === 'en' || lang === 'de') ? lang : 'en';
+
+ const query = `
+ UPDATE document_templates
+ SET state = 'inactive', updatedAt = NOW()
+ WHERE id <> ?
+ AND type = 'invoice'
+ AND lang = ?
+ AND state = 'active'
+ `;
+ const params = [excludeId, safeLang];
+ try {
+ if (conn) {
+ const [res] = await conn.execute(query, params);
+ logger.info('DocumentTemplateRepository.deactivateOtherActiveInvoices:success', { affected: res?.affectedRows });
+ return res?.affectedRows || 0;
+ }
+ const res = await db.execute(query, params);
+ logger.info('DocumentTemplateRepository.deactivateOtherActiveInvoices:success', { affected: res?.affectedRows });
+ return res?.affectedRows || 0;
+ } catch (error) {
+ logger.error('DocumentTemplateRepository.deactivateOtherActiveInvoices:error', { error: error.message });
+ throw error;
+ }
+ }
+
async delete(id, conn) {
logger.info('DocumentTemplateRepository.delete:start', { id });
const query = `DELETE FROM document_templates WHERE id = ?`;
@@ -209,9 +239,11 @@ class DocumentTemplateRepository {
async findActiveByUserType(userType, templateType = null, contractType = null, conn) {
logger.info('DocumentTemplateRepository.findActiveByUserType:start', { userType, templateType, contractType });
- const safeType = (userType === 'personal' || userType === 'company') ? userType : 'personal';
- let query = `SELECT * FROM document_templates WHERE state = 'active' AND (user_type = ? OR user_type = 'both')`;
- const params = [safeType];
+ const safeType = (userType === 'both') ? 'both' : (userType === 'personal' || userType === 'company') ? userType : 'personal';
+ let query = safeType === 'both'
+ ? `SELECT * FROM document_templates WHERE state = 'active' AND user_type = 'both'`
+ : `SELECT * FROM document_templates WHERE state = 'active' AND (user_type = ? OR user_type = 'both')`;
+ const params = safeType === 'both' ? [] : [safeType];
if (templateType) {
query += ` AND type = ?`;
params.push(templateType);
diff --git a/routes/getRoutes.js b/routes/getRoutes.js
index 6f7b7be..dc60a58 100644
--- a/routes/getRoutes.js
+++ b/routes/getRoutes.js
@@ -27,6 +27,7 @@ const AbonemmentController = require('../controller/abonemments/AbonemmentContro
const NewsController = require('../controller/news/NewsController');
const InvoiceController = require('../controller/invoice/InvoiceController'); // NEW
const DevManagementController = require('../controller/dev/DevManagementController');
+const CompanySettingsController = require('../controller/admin/CompanySettingsController');
// small helpers copied from original files
@@ -49,6 +50,7 @@ router.get('/user/settings', authMiddleware, UserSettingsController.getSettings)
router.get('/users/:id/permissions', authMiddleware, PermissionController.getUserPermissions);
router.get('/admin/users/:id/full', authMiddleware, adminOnly, AdminUserController.getFullUserAccountDetails);
router.get('/admin/users/:id/detailed', authMiddleware, adminOnly, AdminUserController.getDetailedUserInfo);
+router.get('/admin/company-settings', authMiddleware, adminOnly, CompanySettingsController.get);
router.get('/users/:id/documents', authMiddleware, UserController.getUserDocumentsAndContracts);
router.get('/verify-password-reset', (req, res) => { /* Note: was moved from PasswordResetController.verifyPasswordResetToken */ res.status(204).end(); }); // keep placeholder if controller already registered via other verb
@@ -116,6 +118,7 @@ router.get('/company-stamps/all', authMiddleware, adminOnly, forceCompanyForAdmi
// Admin: coffee products
router.get('/admin/coffee', authMiddleware, adminOnly, CoffeeController.list);
router.get('/admin/coffee/active', authMiddleware, adminOnly, CoffeeController.listActive);
+router.get('/coffee/active', authMiddleware, CoffeeController.listActive);
// Matrix GETs
@@ -134,6 +137,10 @@ router.post('/admin/matrix/add-user', authMiddleware, adminOnly, MatrixControlle
router.get('/admin/pools', authMiddleware, adminOnly, PoolController.list);
// NEW: Admin list pool members
router.get('/admin/pools/:id/members', authMiddleware, adminOnly, PoolController.listMembers);
+// NEW: Admin diagnose pool inflow for invoice
+router.get('/admin/pools/inflow-diagnostics', authMiddleware, adminOnly, PoolController.inflowDiagnostics);
+// NEW: Admin pool inflow stats
+router.get('/admin/pools/:id/stats', authMiddleware, adminOnly, PoolController.poolStats);
// NEW: User matrices list and per-instance overview
router.get('/matrix/me/list', authMiddleware, MatrixController.listMyMatrices);
@@ -156,6 +163,8 @@ router.get('/affiliates/active', AffiliateController.listActive);
// Abonement GETs
router.get('/abonements/mine', authMiddleware, AbonemmentController.getMine);
+router.get('/abonements/mine/status', authMiddleware, AbonemmentController.getMineStatus);
+router.get('/abonements/:id/invoices', authMiddleware, AbonemmentController.getInvoices);
router.get('/abonements/:id/history', authMiddleware, AbonemmentController.getHistory);
router.get('/admin/abonements', authMiddleware, adminOnly, AbonemmentController.adminList);
@@ -167,6 +176,7 @@ router.get('/news/:slug', NewsController.getPublic);
// NEW: Invoice GETs
router.get('/invoices/mine', authMiddleware, InvoiceController.listMine);
router.get('/admin/invoices', authMiddleware, adminOnly, InvoiceController.adminList);
+router.get('/admin/invoices/:id/detail', authMiddleware, adminOnly, InvoiceController.getDetail);
// NOTE: Contract signing uses UnitOfWork; any DB cleanup must happen before commit() closes the connection.
diff --git a/routes/patchRoutes.js b/routes/patchRoutes.js
index 32f7bf1..43fd94e 100644
--- a/routes/patchRoutes.js
+++ b/routes/patchRoutes.js
@@ -12,6 +12,8 @@ const PoolController = require('../controller/pool/PoolController'); // <-- new
const MatrixController = require('../controller/matrix/MatrixController'); // <-- new
const AffiliateController = require('../controller/affiliate/AffiliateController'); // <-- new
const NewsController = require('../controller/news/NewsController');
+const AbonemmentController = require('../controller/abonemments/AbonemmentController');
+const InvoiceController = require('../controller/invoice/InvoiceController');
const multer = require('multer');
const upload = multer({ storage: multer.memoryStorage() });
@@ -40,6 +42,8 @@ router.patch('/admin/update-user-status/:id', authMiddleware, adminOnly, AdminUs
router.patch('/admin/coffee/:id/state', authMiddleware, adminOnly, CoffeeController.setState);
// NEW: Admin pool active status update
router.patch('/admin/pools/:id/active', authMiddleware, adminOnly, PoolController.updateActive);
+// NEW: Admin update pool linked subscription
+router.patch('/admin/pools/:id/subscription', authMiddleware, adminOnly, PoolController.updateSubscription);
// NEW: deactivate a matrix instance (admin-only)
router.patch('/admin/matrix/:id/deactivate', authMiddleware, adminOnly, MatrixController.deactivate);
// NEW: activate a matrix instance (admin-only)
@@ -53,9 +57,13 @@ router.patch('/admin/affiliates/:id/status', authMiddleware, adminOnly, Affiliat
router.patch('/admin/news/:id', authMiddleware, adminOnly, upload.single('image'), NewsController.update);
router.patch('/admin/news/:id/status', authMiddleware, adminOnly, NewsController.updateStatus);
+// Admin: update invoice status
+router.patch('/admin/invoices/:id/status', authMiddleware, adminOnly, InvoiceController.updateStatus);
+
// Personal profile (self-service) - no admin guard
router.patch('/profile/personal/basic', authMiddleware, PersonalProfileController.updateBasic);
router.patch('/profile/personal/bank', authMiddleware, PersonalProfileController.updateBank);
+router.patch('/abonements/:id/content', authMiddleware, AbonemmentController.updateContent);
// Add other PATCH routes here as needed
diff --git a/routes/postRoutes.js b/routes/postRoutes.js
index 4f9b9d6..52c640b 100644
--- a/routes/postRoutes.js
+++ b/routes/postRoutes.js
@@ -14,6 +14,7 @@ const PermissionController = require('../controller/permissions/PermissionContro
const DocumentTemplateController = require('../controller/documentTemplate/DocumentTemplateController');
const PersonalRegisterController = require('../controller/register/PersonalRegisterController');
const CompanyRegisterController = require('../controller/register/CompanyRegisterController');
+const GuestRegisterController = require('../controller/register/GuestRegisterController');
const PersonalDocumentController = require('../controller/documents/PersonalDocumentController');
const CompanyDocumentController = require('../controller/documents/CompanyDocumentController');
const ContractUploadController = require('../controller/documents/ContractUploadController');
@@ -192,6 +193,10 @@ router.post('/register/company', (req, res) => {
console.log('🔗 POST /register/company route accessed');
CompanyRegisterController.register(req, res);
});
+router.post('/register/guest', (req, res) => {
+ console.log('🔗 POST /register/guest route accessed');
+ GuestRegisterController.register(req, res);
+});
console.log('✅ POST routes configured successfully');
diff --git a/routes/putRoutes.js b/routes/putRoutes.js
index d219cc1..b0f4af3 100644
--- a/routes/putRoutes.js
+++ b/routes/putRoutes.js
@@ -6,6 +6,7 @@ const adminOnly = require('../middleware/adminOnly');
const AdminUserController = require('../controller/admin/AdminUserController');
const DocumentTemplateController = require('../controller/documentTemplate/DocumentTemplateController');
const CoffeeController = require('../controller/admin/CoffeeController');
+const CompanySettingsController = require('../controller/admin/CompanySettingsController');
const multer = require('multer');
const upload = multer({ storage: multer.memoryStorage() });
@@ -17,4 +18,7 @@ router.put('/document-templates/:id', authMiddleware, upload.single('file'), Doc
// Admin: update coffee product (supports picture file replacement)
router.put('/admin/coffee/:id', authMiddleware, adminOnly, upload.single('picture'), CoffeeController.update);
+// Admin: update company settings (invoice address etc.)
+router.put('/admin/company-settings', authMiddleware, adminOnly, CompanySettingsController.update);
+
module.exports = router;
diff --git a/scripts/createAdminUser.js b/scripts/createAdminUser.js
index 0cdcf4c..1f25dc8 100644
--- a/scripts/createAdminUser.js
+++ b/scripts/createAdminUser.js
@@ -4,8 +4,8 @@ const argon2 = require('argon2');
async function createAdminUser() {
// const adminEmail = process.env.ADMIN_EMAIL || 'office@profit-planet.com';
- // const adminEmail = process.env.ADMIN_EMAIL || 'alexander.ibrahim.ai@gmail.com';
- const adminEmail = process.env.ADMIN_EMAIL || 'loki.aahi@gmail.com';
+ const adminEmail = process.env.ADMIN_EMAIL || 'alexander.ibrahim.ai@gmail.com';
+ // const adminEmail = process.env.ADMIN_EMAIL || 'loki.aahi@gmail.com';
const adminPassword = process.env.ADMIN_PASSWORD || 'Chalanger75$%';
// const adminPassword = process.env.ADMIN_PASSWORD || 'W.profit-planet.com.2025';
const firstName = process.env.ADMIN_FIRST_NAME || 'Admin';
diff --git a/scripts/initPermissions.js b/scripts/initPermissions.js
index 0d9b9a0..169a4d5 100644
--- a/scripts/initPermissions.js
+++ b/scripts/initPermissions.js
@@ -39,8 +39,12 @@ const REQUIRED_PERMISSIONS = [
name: 'can_create_referrals',
description: 'User can create referral links',
is_active: true
+ },
+ {
+ name: 'can_subscribe',
+ description: 'User can complete a subscription',
+ is_active: true
}
- // Add more permissions here as needed
];
async function ensurePermissions() {
diff --git a/services/abonemments/AbonemmentService.js b/services/abonemments/AbonemmentService.js
index 4c4793e..3b90fe1 100644
--- a/services/abonemments/AbonemmentService.js
+++ b/services/abonemments/AbonemmentService.js
@@ -1,6 +1,10 @@
const pool = require('../../database/database');
const AbonemmentRepository = require('../../repositories/abonemments/AbonemmentRepository');
const InvoiceService = require('../invoice/InvoiceService'); // NEW
+const UnitOfWork = require('../../database/UnitOfWork');
+const ReferralService = require('../referral/ReferralService');
+const ReferralTokenRepository = require('../../repositories/referral/ReferralTokenRepository');
+const MailService = require('../email/MailService');
class AbonemmentService {
constructor() {
@@ -23,7 +27,7 @@ class AbonemmentService {
async getCoffeeProduct(id) {
const [rows] = await pool.query(
- `SELECT id, price, currency, billing_interval, interval_count, state AS is_active, pack_group FROM coffee_table WHERE id = ?`,
+ `SELECT id, title, price, currency, billing_interval, interval_count, state AS is_active, pack_group FROM coffee_table WHERE id = ?`,
[id],
);
return rows[0] || null;
@@ -40,6 +44,10 @@ class AbonemmentService {
billingInterval,
intervalCount,
isAutoRenew,
+ isForSelf,
+ recipientName,
+ recipientEmail,
+ recipientNotes,
firstName,
lastName,
email,
@@ -67,6 +75,12 @@ class AbonemmentService {
});
const normalizedEmail = this.normalizeEmail(email);
+ const normalizedRecipientEmail = this.normalizeEmail(recipientEmail);
+ const forSelf = isForSelf !== false && !normalizedRecipientEmail;
+
+ if (!forSelf && !normalizedRecipientEmail) {
+ throw new Error('recipient_email is required when subscription is for another person');
+ }
if (!Array.isArray(items) || items.length === 0) throw new Error('items must be a non-empty array');
@@ -83,13 +97,17 @@ class AbonemmentService {
const product = await this.getCoffeeProduct(coffeeId);
if (!product || !product.is_active) throw new Error(`Product ${coffeeId} not available`);
+ const capsulePrice = Number(product.price);
+ const packPrice = capsulePrice * 10; // 10 capsules per pack
+
totalPacks += packs;
- totalPrice += packs * Number(product.price);
+ totalPrice += packs * packPrice;
breakdown.push({
coffee_table_id: coffeeId,
+ coffee_title: product.title || null,
packs,
- price_per_pack: Number(product.price),
+ price_per_pack: packPrice,
currency: product.currency,
});
}
@@ -98,6 +116,9 @@ class AbonemmentService {
const startDateObj = startDate ? new Date(startDate) : now;
const nextBilling = this.addInterval(startDateObj, billingInterval || 'month', intervalCount || 1);
+ const effectiveRecipientName = recipientName || `${firstName || ''} ${lastName || ''}`.trim() || null;
+ const effectiveEmail = forSelf ? normalizedEmail : normalizedRecipientEmail;
+
const snapshot = {
status: 'active',
started_at: startDateObj,
@@ -108,18 +129,24 @@ class AbonemmentService {
currency: breakdown[0]?.currency || 'EUR',
is_auto_renew: isAutoRenew !== false,
actor_user_id: actorUser?.id,
- details: { origin: 'subscribe_order', total_packs: totalPacks },
+ details: {
+ origin: 'subscribe_order',
+ total_packs: totalPacks,
+ is_for_self: forSelf,
+ recipient_name: forSelf ? null : effectiveRecipientName,
+ recipient_notes: forSelf ? null : (recipientNotes || null)
+ },
pack_breakdown: breakdown,
- first_name: firstName,
- last_name: lastName,
- email: normalizedEmail,
+ first_name: forSelf ? firstName : (effectiveRecipientName || firstName),
+ last_name: forSelf ? lastName : null,
+ email: effectiveEmail,
street,
postal_code: postalCode,
city,
country,
frequency,
- referred_by: referredBy || null, // Pass referred_by to snapshot
- user_id: actorUser?.id ?? null, // NEW: set owner (purchaser acts as owner here)
+ referred_by: referredBy || (forSelf ? (actorUser?.id ?? null) : null),
+ user_id: forSelf ? (actorUser?.id ?? null) : null,
purchaser_user_id: actorUser?.id ?? null, // NEW: also store purchaser
};
@@ -145,7 +172,10 @@ class AbonemmentService {
abonement,
snapshot.started_at,
snapshot.next_billing_at,
- { actorUserId: actorUser?.id || null }
+ {
+ actorUserId: actorUser?.id || null,
+ lang: actorUser?.lang || actorUser?.language || 'en'
+ }
);
console.log('[SUBSCRIBE ORDER] Issued invoice:', {
id: invoice?.id,
@@ -165,9 +195,68 @@ class AbonemmentService {
// intentionally not throwing to avoid blocking subscription; adjust if you want transactional consistency
}
+ if (!forSelf && effectiveEmail) {
+ const existingUser = await this.findUserByEmail(effectiveEmail);
+ console.log('[SUBSCRIBE ORDER] Gift flow:', { forSelf, effectiveEmail, existingUser: existingUser?.id || null });
+ if (!existingUser) {
+ await this.repo.upsertNoUserAboMail(effectiveEmail, abonement.id, actorUser?.id || null);
+ const referralLink = await this.getOrCreateReferralLink(actorUser?.id || null);
+ console.log('[SUBSCRIBE ORDER] Referral link generated:', referralLink);
+ if (referralLink) {
+ try {
+ await MailService.sendSubscriptionInvitationEmail({
+ email: effectiveEmail,
+ inviterName: actorUser?.email || 'ProfitPlanet user',
+ referralLink,
+ lang: actorUser?.lang || actorUser?.language || 'en'
+ });
+ } catch (mailError) {
+ console.error('[SUBSCRIBE ORDER] Invitation email failed:', mailError);
+ }
+ }
+ }
+ }
+
return abonement;
}
+ async findUserByEmail(email) {
+ const normalized = this.normalizeEmail(email);
+ if (!normalized) return null;
+ const [rows] = await pool.query(
+ `SELECT id, email FROM users WHERE email = ? LIMIT 1`,
+ [normalized]
+ );
+ return rows && rows[0] ? rows[0] : null;
+ }
+
+ async getOrCreateReferralLink(userId) {
+ if (!userId) return null;
+ const unitOfWork = new UnitOfWork();
+ await unitOfWork.start();
+ try {
+ // Always create a fresh single-use token for each gift invitation
+ const created = await ReferralService.createReferralToken({
+ userId,
+ expiresInDays: 7,
+ maxUses: 1,
+ unitOfWork,
+ });
+ const tokenValue = created?.token;
+ console.log('[REFERRAL LINK] Created new gift token:', tokenValue);
+
+ await unitOfWork.commit();
+ if (!tokenValue) return null;
+
+ const base = (process.env.FRONTEND_URL || 'https://profit-planet.partners').replace(/\/$/, '');
+ return `${base}/register?ref=${tokenValue}&guest=true`;
+ } catch (error) {
+ await unitOfWork.rollback(error);
+ console.error('[ABONEMENT] getOrCreateReferralLink failed:', error);
+ return null;
+ }
+ }
+
async subscribe({
userId,
coffeeId,
@@ -235,6 +324,13 @@ class AbonemmentService {
recipient_email: normalizedRecipientEmail || null, // CHANGED
details,
recipient: recipientMeta || undefined,
+ pack_breakdown: [{
+ coffee_table_id: product.id,
+ coffee_title: product.title || null,
+ packs: 1,
+ price_per_pack: Number(product.price) * 10, // 10 capsules per pack
+ currency: product.currency,
+ }],
purchaser_user_id, // NEW
user_id: ownerUserId ?? null, // NEW: persist owner
referred_by: referredBy || null, // Pass referred_by to snapshot
@@ -267,7 +363,10 @@ class AbonemmentService {
abonement,
snapshot.started_at,
snapshot.next_billing_at,
- { actorUserId: actorUser?.id || null }
+ {
+ actorUserId: actorUser?.id || null,
+ lang: actorUser?.lang || actorUser?.language || 'en'
+ }
);
console.log('[SUBSCRIBE] Issued invoice:', {
id: invoice?.id,
@@ -337,6 +436,70 @@ class AbonemmentService {
});
}
+ async updateContent({ abonementId, actorUser, items }) {
+ const abon = await this.repo.getAbonementById(abonementId);
+ if (!abon) throw new Error('Not found');
+ if (!this.canManageAbonement(abon, actorUser)) throw new Error('Forbidden');
+ if (!['active', 'paused'].includes(abon.status)) {
+ throw new Error('Only active or paused abonements can be updated');
+ }
+
+ if (!Array.isArray(items) || items.length === 0) {
+ throw new Error('items must be a non-empty array');
+ }
+
+ let totalPacks = 0;
+ let totalPrice = 0;
+ const breakdown = [];
+
+ for (const item of items) {
+ const coffeeId = item?.coffeeId;
+ const packs = Number(item?.quantity ?? 0);
+ if (!coffeeId) throw new Error('coffeeId is required for each item');
+ if (!Number.isFinite(packs) || packs <= 0) {
+ throw new Error('quantity must be a positive integer per item');
+ }
+
+ const product = await this.getCoffeeProduct(coffeeId);
+ if (!product || !product.is_active) throw new Error(`Product ${coffeeId} not available`);
+
+ const capsulePrice = Number(product.price);
+ const packPrice = capsulePrice * 10; // 10 capsules per pack
+
+ totalPacks += packs;
+ totalPrice += packs * packPrice;
+ breakdown.push({
+ coffee_table_id: coffeeId,
+ coffee_title: product.title || null,
+ packs,
+ price_per_pack: packPrice,
+ currency: product.currency,
+ });
+ }
+
+ if (totalPacks !== 6 && totalPacks !== 12) {
+ throw new Error('Order must contain exactly 6 packs (60 capsules) or 12 packs (120 capsules).');
+ }
+
+ const previousPacks = Array.isArray(abon.pack_breakdown)
+ ? abon.pack_breakdown.reduce((sum, item) => sum + Number(item?.packs || item?.quantity || 0), 0)
+ : null;
+
+ return this.repo.transitionContent(abonementId, {
+ pack_breakdown: breakdown,
+ price: Number(totalPrice.toFixed(2)),
+ currency: breakdown[0]?.currency || abon.currency || 'EUR',
+ actor_user_id: actorUser?.id || null,
+ event_type: 'content_updated',
+ details: {
+ pack_group: abon.pack_group,
+ previous_total_packs: previousPacks,
+ total_packs: totalPacks,
+ effective_from: 'next_billing_cycle',
+ },
+ });
+ }
+
async renew({ abonementId, actorUser, invoiceId }) {
const abon = await this.repo.getAbonementById(abonementId);
if (!abon) throw new Error('Not found');
@@ -354,7 +517,10 @@ class AbonemmentService {
renewed,
new Date(abon.next_billing_at || new Date()),
next,
- { actorUserId: actorUser?.id || null }
+ {
+ actorUserId: actorUser?.id || null,
+ lang: actorUser?.lang || actorUser?.language || 'en'
+ }
);
await this.repo.appendHistory(
abonementId,
@@ -374,6 +540,26 @@ class AbonemmentService {
return this.repo.listByUser(userId);
}
+ async getMyAbonementStatus({ userId }) {
+ const list = await this.repo.listByUser(userId);
+ const current = list.find((a) => ['active', 'paused'].includes(a.status)) || list[0] || null;
+ return {
+ hasAbo: Boolean(current),
+ abonement: current,
+ };
+ }
+
+ async getInvoicesForAbonement({ abonementId, actorUser }) {
+ const abon = await this.repo.getAbonementById(abonementId);
+ if (!abon) {
+ throw new Error('Not found');
+ }
+ if (!this.canManageAbonement(abon, actorUser)) {
+ throw new Error('Forbidden');
+ }
+ return this.invoiceService.listByAbonement(abonementId);
+ }
+
async getHistory({ abonementId }) {
return this.repo.listHistory(abonementId);
}
diff --git a/services/email/MailService.js b/services/email/MailService.js
index 4a9c681..6f23e8a 100644
--- a/services/email/MailService.js
+++ b/services/email/MailService.js
@@ -1,19 +1,14 @@
-const brevo = require('@getbrevo/brevo');
+const { BrevoClient } = require('@getbrevo/brevo');
const fs = require('fs');
const path = require('path');
const { logger } = require('../../middleware/logger');
class MailService {
constructor() {
- this.brevo = new brevo.TransactionalEmailsApi();
-
const rawApiKey = process.env.BREVO_API_KEY;
const apiKey = (rawApiKey || '').trim(); // helps catch whitespace/newline issues
- this.brevo.setApiKey(
- brevo.TransactionalEmailsApiApiKeys.apiKey,
- apiKey
- );
+ this.brevo = new BrevoClient({ apiKey });
logger.info('MailService:brevo_api_key_loaded', {
present: Boolean(apiKey),
@@ -59,8 +54,8 @@ class MailService {
}
_extractBrevoErrorDetails(error) {
- const status = error?.response?.status;
- const data = error?.response?.data;
+ const status = error?.statusCode ?? error?.response?.status;
+ const data = error?.body ?? error?.response?.data;
let dataSafe;
try {
dataSafe = typeof data === 'string' ? data.slice(0, 2000) : JSON.parse(JSON.stringify(data));
@@ -101,24 +96,25 @@ class MailService {
}
try {
- const payload = new brevo.SendSmtpEmail();
- payload.sender = this.sender;
- payload.to = [{ email }];
- payload.subject = subject;
- payload.textContent = text;
+ const payload = {
+ sender: this.sender,
+ to: [{ email }],
+ subject,
+ textContent: text
+ };
- const data = await this.brevo.sendTransacEmail(payload);
+ const data = await this.brevo.transactionalEmails.sendTransacEmail(payload);
logger.info('MailService.sendRegistrationEmail:email_sent', { email, userType, lang: chosenLang });
return data;
} catch (error) {
- const brevo = this._extractBrevoErrorDetails(error);
+ const brevoError = this._extractBrevoErrorDetails(error);
logger.error('MailService.sendRegistrationEmail:error', {
email,
userType,
lang: chosenLang,
message: error?.message,
- brevoStatus: brevo.status,
- brevoData: brevo.data
+ brevoStatus: brevoError.status,
+ brevoData: brevoError.data
});
throw error;
}
@@ -136,23 +132,24 @@ class MailService {
}, chosenLang);
try {
- const payload = new brevo.SendSmtpEmail();
- payload.sender = this.sender;
- payload.to = [{ email }];
- payload.subject = subject;
- payload.textContent = text;
+ const payload = {
+ sender: this.sender,
+ to: [{ email }],
+ subject,
+ textContent: text
+ };
- const data = await this.brevo.sendTransacEmail(payload);
+ const data = await this.brevo.transactionalEmails.sendTransacEmail(payload);
logger.info('MailService.sendVerificationCodeEmail:email_sent', { email, lang: chosenLang }); // don't log code
return data;
} catch (error) {
- const brevo = this._extractBrevoErrorDetails(error);
+ const brevoError = this._extractBrevoErrorDetails(error);
logger.error('MailService.sendVerificationCodeEmail:error', {
email,
lang: chosenLang,
message: error?.message,
- brevoStatus: brevo.status,
- brevoData: brevo.data
+ brevoStatus: brevoError.status,
+ brevoData: brevoError.data
});
throw error;
}
@@ -172,24 +169,25 @@ class MailService {
}, chosenLang);
try {
- const payload = new brevo.SendSmtpEmail();
- payload.sender = this.sender;
- payload.to = [{ email }];
- payload.subject = subject;
- payload.textContent = text;
+ const payload = {
+ sender: this.sender,
+ to: [{ email }],
+ subject,
+ textContent: text
+ };
- const data = await this.brevo.sendTransacEmail(payload);
+ const data = await this.brevo.transactionalEmails.sendTransacEmail(payload);
logger.info('MailService.sendLoginNotificationEmail:email_sent', { email, ip, lang: chosenLang });
return data;
} catch (error) {
- const brevo = this._extractBrevoErrorDetails(error);
+ const brevoError = this._extractBrevoErrorDetails(error);
logger.error('MailService.sendLoginNotificationEmail:error', {
email,
ip,
lang: chosenLang,
message: error?.message,
- brevoStatus: brevo.status,
- brevoData: brevo.data
+ brevoStatus: brevoError.status,
+ brevoData: brevoError.data
});
throw error;
}
@@ -209,28 +207,149 @@ class MailService {
}, chosenLang);
try {
- const payload = new brevo.SendSmtpEmail();
- payload.sender = this.sender;
- payload.to = [{ email }];
- payload.subject = subject;
- payload.textContent = text;
+ const payload = {
+ sender: this.sender,
+ to: [{ email }],
+ subject,
+ textContent: text
+ };
- const data = await this.brevo.sendTransacEmail(payload);
+ const data = await this.brevo.transactionalEmails.sendTransacEmail(payload);
logger.info('MailService.sendPasswordResetEmail:email_sent', { email, token, lang: chosenLang });
return data;
} catch (error) {
- const brevo = this._extractBrevoErrorDetails(error);
+ const brevoError = this._extractBrevoErrorDetails(error);
logger.error('MailService.sendPasswordResetEmail:error', {
email,
token,
lang: chosenLang,
message: error?.message,
- brevoStatus: brevo.status,
- brevoData: brevo.data
+ brevoStatus: brevoError.status,
+ brevoData: brevoError.data
});
throw error;
}
}
+
+ async sendInvoiceEmail({ email, subject, text, html, lang, attachments = [] }) {
+ logger.info('MailService.sendInvoiceEmail:start', { email, lang, hasHtml: Boolean(html), attachments: attachments.length });
+ try {
+ const payload = {
+ sender: this.sender,
+ to: [{ email }],
+ subject,
+ textContent: text
+ };
+
+ if (html) {
+ payload.htmlContent = html;
+ }
+
+ if (Array.isArray(attachments) && attachments.length) {
+ payload.attachment = attachments;
+ }
+
+ const data = await this.brevo.transactionalEmails.sendTransacEmail(payload);
+ logger.info('MailService.sendInvoiceEmail:email_sent', { email, lang, hasHtml: Boolean(html), attachments: attachments.length });
+ return data;
+ } catch (error) {
+ const brevoError = this._extractBrevoErrorDetails(error);
+ logger.error('MailService.sendInvoiceEmail:error', {
+ email,
+ lang,
+ message: error?.message,
+ brevoStatus: brevoError.status,
+ brevoData: brevoError.data
+ });
+ throw error;
+ }
+ }
+
+ async sendSubscriptionInvitationEmail({ email, inviterName, referralLink, lang = 'en' }) {
+ logger.info('MailService.sendSubscriptionInvitationEmail:start', { email, lang });
+ const isDe = lang === 'de';
+ const subject = isDe
+ ? 'ProfitPlanet: Einladung zum Kaffee-Abonnement'
+ : 'ProfitPlanet: Invite for Coffee Abonnement';
+
+ const text = isDe
+ ? `Hallo,\n\n${inviterName || 'Ein Benutzer'} hat ein Kaffee-Abonnement für Sie erstellt.\nBitte registrieren Sie sich als Gastkunde hier: ${referralLink}\n\nSobald Sie sich registriert haben, können Sie Ihr Abonnement einsehen und verwalten.\n\nViele Grüße\nProfitPlanet Team`
+ : `Hi,\n\n${inviterName || 'A user'} created a coffee abonnement for you.\nPlease register as a guest customer here: ${referralLink}\n\nOnce registered, you can view and manage your subscription.\n\nBest regards\nProfitPlanet Team`;
+
+ const html = `
+
+
+
+
+
+
+
+
+
+ ${isDe ? 'Einladung zum Kaffee-Abonnement' : 'Invite for Coffee Abonnement'}
+ |
+
+
+ |
+ ${isDe
+ ? `${this._escapeForHtml(inviterName || 'Ein Benutzer')} hat ein Kaffee-Abonnement für Sie erstellt.`
+ : `${this._escapeForHtml(inviterName || 'A user')} created a coffee abonnement for you.`}
+ ${isDe
+ ? 'Als Gastkunde können Sie Ihr Abonnement einsehen und verwalten.'
+ : 'As a guest customer, you can view and manage your subscription.'}
+ ${isDe ? 'Bitte registrieren Sie sich über den folgenden Link:' : 'Please register using the link below:'}
+
+ ${isDe ? 'Jetzt als Gastkunde registrieren' : 'Register as Guest Customer'}
+
+ |
+
+
+ |
+ ${isDe
+ ? 'Sie erhalten als Gastkunde Zugang zu Ihrem Abonnement. Weitere Funktionen der Plattform stehen Ihnen nach einem Upgrade zur Verfügung.'
+ : 'As a guest customer you will have access to your subscription. Other platform features are available after upgrading your account.'}
+ |
+
+
+ |
+
+
+
+`;
+
+ try {
+ const payload = {
+ sender: this.sender,
+ to: [{ email }],
+ subject,
+ textContent: text,
+ htmlContent: html,
+ };
+
+ const data = await this.brevo.transactionalEmails.sendTransacEmail(payload);
+ logger.info('MailService.sendSubscriptionInvitationEmail:email_sent', { email, lang });
+ return data;
+ } catch (error) {
+ const brevoError = this._extractBrevoErrorDetails(error);
+ logger.error('MailService.sendSubscriptionInvitationEmail:error', {
+ email,
+ lang,
+ message: error?.message,
+ brevoStatus: brevoError.status,
+ brevoData: brevoError.data
+ });
+ throw error;
+ }
+ }
+
+ _escapeForHtml(value) {
+ return String(value ?? '')
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
+ }
}
module.exports = new MailService();
\ No newline at end of file
diff --git a/services/invoice/InvoiceService.js b/services/invoice/InvoiceService.js
index 527ef4e..04485fc 100644
--- a/services/invoice/InvoiceService.js
+++ b/services/invoice/InvoiceService.js
@@ -1,12 +1,399 @@
const InvoiceRepository = require('../../repositories/invoice/InvoiceRepository');
const UnitOfWork = require('../../database/UnitOfWork'); // NEW
const TaxRepository = require('../../repositories/tax/taxRepository'); // NEW
+const PoolInflowService = require('../pool/PoolInflowService');
+const DocumentTemplateService = require('../template/DocumentTemplateService');
+const MailService = require('../email/MailService');
+const { GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
+const { s3: sharedExoscaleClient } = require('../../utils/exoscaleUploader');
+const { logger } = require('../../middleware/logger');
+const puppeteer = require('puppeteer');
+
+const CompanySettingsRepository = require('../../repositories/settings/CompanySettingsRepository');
class InvoiceService {
constructor() {
this.repo = new InvoiceRepository();
}
+ _escapeHtml(value) {
+ return String(value ?? '')
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
+ }
+
+ _formatAmount(amount, currency = 'EUR') {
+ const numeric = Number(amount || 0);
+ return `${numeric.toFixed(2)} ${currency}`;
+ }
+
+ async _s3BodyToString(body) {
+ if (!body) return '';
+ if (typeof body.transformToString === 'function') {
+ return body.transformToString();
+ }
+ const chunks = [];
+ for await (const chunk of body) {
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
+ }
+ return Buffer.concat(chunks).toString('utf8');
+ }
+
+ _getEmailSubject(lang, invoiceNumber) {
+ return lang === 'de'
+ ? `ProfitPlanet Rechnung ${invoiceNumber}`
+ : `ProfitPlanet Invoice ${invoiceNumber}`;
+ }
+
+ _buildItemsText(items, currency) {
+ if (!Array.isArray(items) || !items.length) return '- Subscription item';
+ return items.map((item, index) => {
+ const qty = Number(item.quantity || 0);
+ const lineGross = Number(item.line_gross || 0);
+ return `${index + 1}. ${item.description || 'Coffee'} | qty: ${qty} | total: ${this._formatAmount(lineGross, currency)}`;
+ }).join('\n');
+ }
+
+ _buildItemsHtml(items, currency) {
+ if (!Array.isArray(items) || !items.length) {
+ return 'Subscription item';
+ }
+ return items.map((item) => {
+ const desc = this._escapeHtml(item.description || 'Coffee');
+ const qty = Number(item.quantity || 0);
+ const unit = this._formatAmount(item.unit_price || 0, currency);
+ const total = this._formatAmount(item.line_gross || 0, currency);
+ return `${desc} — ${qty} x ${this._escapeHtml(unit)} = ${this._escapeHtml(total)}`;
+ }).join('');
+ }
+
+ _buildInvoiceText({ invoice, items, abonement, lang }) {
+ const isDe = lang === 'de';
+ const customerName = [abonement?.first_name, abonement?.last_name].filter(Boolean).join(' ') || invoice.buyer_name || '-';
+ const issuedAt = invoice.issued_at ? new Date(invoice.issued_at).toISOString().slice(0, 10) : new Date().toISOString().slice(0, 10);
+
+ return [
+ isDe ? 'Ihre Rechnung wurde erstellt.' : 'Your invoice has been created.',
+ `${isDe ? 'Rechnungsnummer' : 'Invoice number'}: ${invoice.invoice_number}`,
+ `${isDe ? 'Kunde' : 'Customer'}: ${customerName}`,
+ `${isDe ? 'Datum' : 'Date'}: ${issuedAt}`,
+ `${isDe ? 'Positionen' : 'Items'}:`,
+ this._buildItemsText(items, invoice.currency),
+ `${isDe ? 'Gesamtbetrag' : 'Total'}: ${this._formatAmount(invoice.total_gross, invoice.currency)}`,
+ ].join('\n');
+ }
+
+ _buildInvoiceMailText({ invoice, items, abonement, lang }) {
+ const isDe = lang === 'de';
+ const customerName = [abonement?.first_name, abonement?.last_name].filter(Boolean).join(' ') || invoice.buyer_name || '-';
+ return [
+ isDe ? `Vielen Dank für Ihr Abonnement, ${customerName}.` : `Thank you for your subscription, ${customerName}.`,
+ isDe ? 'Ihre Rechnung ist als PDF im Anhang enthalten.' : 'Your invoice is attached as a PDF.',
+ `${isDe ? 'Rechnungsnummer' : 'Invoice number'}: ${invoice.invoice_number}`,
+ `${isDe ? 'Gesamtbetrag' : 'Total'}: ${this._formatAmount(invoice.total_gross, invoice.currency)}`,
+ '',
+ `${isDe ? 'Positionen' : 'Items'}:`,
+ this._buildItemsText(items, invoice.currency),
+ ].join('\n');
+ }
+
+ _buildInvoiceMailHtml({ invoice, abonement, lang }) {
+ const isDe = lang === 'de';
+ const customerName = [abonement?.first_name, abonement?.last_name].filter(Boolean).join(' ') || invoice.buyer_name || 'Customer';
+ const logoUrl = process.env.MAIL_LOGO_URL || process.env.BREVO_LOGO_URL || process.env.APP_LOGO_URL || '';
+
+ return `
+
+
+
+
+ ${this._escapeHtml(invoice.invoice_number)}
+
+
+
+
+
+
+
+
+ ${logoUrl ? ` ` : ''}
+ ${isDe ? 'Danke für Ihr Abonnement!' : 'Thank you for your subscription!'}
+ |
+
+
+ |
+ ${isDe ? 'Hallo' : 'Hi'} ${this._escapeHtml(customerName)},
+ ${isDe ? 'vielen Dank für Ihr Abonnement. Ihre Rechnung haben wir als PDF angehängt.' : 'thank you for your subscription. We attached your invoice as a PDF.'}
+
+
+
+ | ${isDe ? 'Rechnungsnummer' : 'Invoice number'} |
+ ${this._escapeHtml(invoice.invoice_number || '')} |
+
+
+ | ${isDe ? 'Gesamtbetrag' : 'Total'} |
+ ${this._escapeHtml(this._formatAmount(invoice.total_gross, invoice.currency))} |
+
+
+
+ ${isDe ? 'Falls diese E-Mail nicht korrekt angezeigt wird, nutzen Sie bitte den Textinhalt oder kontaktieren Sie unseren Support.' : 'If this email is not displayed correctly, please use the text version or contact support.'}
+ |
+
+
+ |
+
+
+
+`;
+ }
+
+ _buildItemsTableRows(items, currency) {
+ if (!Array.isArray(items) || !items.length) {
+ return `| 1 | Subscription item | 1 | - | - |
`;
+ }
+ return items.map((item, i) => {
+ const desc = this._escapeHtml(item.description || 'Coffee');
+ const qty = Number(item.quantity || 0);
+ const unit = this._formatAmount(item.unit_price || 0, currency);
+ const total = this._formatAmount(item.line_gross || 0, currency);
+ return `| ${i + 1} | ${desc} | ${qty} | ${unit} | ${total} |
`;
+ }).join('');
+ }
+
+ async _loadInvoiceHtmlTemplate() {
+ // Load the latest active invoice template from the contract manager (S3)
+ try {
+ const templates = await DocumentTemplateService.getActiveTemplatesForUserType('both', 'invoice');
+ if (!Array.isArray(templates) || !templates.length) return null;
+ const selected = templates[0]; // latest active version
+ if (!selected?.storageKey) return null;
+ const command = new GetObjectCommand({
+ Bucket: process.env.EXOSCALE_BUCKET,
+ Key: selected.storageKey,
+ });
+ const obj = await sharedExoscaleClient.send(command);
+ return await this._s3BodyToString(obj.Body) || null;
+ } catch (e) {
+ logger.warn('InvoiceService._loadInvoiceHtmlTemplate:error', { message: e?.message });
+ return null;
+ }
+ }
+
+ async _buildInvoiceTemplateVariables({ invoice, items, abonement, lang }) {
+ const isDe = lang === 'de';
+ const isGift = abonement?.details?.is_for_self === false;
+ const issuedAt = invoice.issued_at ? new Date(invoice.issued_at).toISOString().slice(0, 10) : new Date().toISOString().slice(0, 10);
+ const dueAt = invoice.due_at ? new Date(invoice.due_at).toISOString().slice(0, 10) : '-';
+ const vatRate = invoice.vat_rate != null ? Number(invoice.vat_rate) : 0;
+
+ // Load company info from DB
+ let companyInfo = { company_name: 'ProfitPlanet GmbH', company_street: '', company_postal_city: '', company_country: 'Germany' };
+ try {
+ const repo = new CompanySettingsRepository();
+ const row = await repo.get();
+ if (row) companyInfo = row;
+ } catch (e) {
+ logger.warn('InvoiceService._buildInvoiceTemplateVariables:company_settings_error', { message: e?.message });
+ }
+
+ // For gift subscriptions: "Bill To" = recipient, "Ordered by" = purchaser
+ // For self subscriptions: "Bill To" = the subscriber
+ let customerName;
+ let customerEmail = '';
+ let orderedByBlock = '';
+
+ if (isGift) {
+ // Recipient info for "Bill To"
+ const recipientName = abonement?.details?.recipient_name || '';
+ const recipientEmail = abonement?.email || invoice.buyer_email || '';
+ customerName = recipientName || recipientEmail || '-';
+ customerEmail = recipientName ? recipientEmail : '';
+
+ // Purchaser info for "Ordered by"
+ const purchaserName = invoice.buyer_name || [abonement?.first_name, abonement?.last_name].filter(Boolean).join(' ') || '';
+ if (purchaserName) {
+ const orderedByLabel = isDe ? 'Bestellt von' : 'Ordered By';
+ orderedByBlock = ``;
+ }
+ } else {
+ customerName = [abonement?.first_name, abonement?.last_name].filter(Boolean).join(' ') || invoice.buyer_name || '-';
+ customerEmail = abonement?.email || invoice.buyer_email || '';
+ }
+
+ return {
+ lang: isDe ? 'de' : 'en',
+ documentTitle: isDe ? 'Rechnung' : 'Invoice',
+ invoiceNumber: this._escapeHtml(invoice.invoice_number || ''),
+ invoiceNumberLabel: isDe ? 'Rechnungsnummer' : 'Invoice Number',
+ fromLabel: isDe ? 'Von' : 'From',
+ toLabel: isDe ? 'An' : 'Bill To',
+ detailsLabel: isDe ? 'Details' : 'Details',
+ dateLabel: isDe ? 'Datum' : 'Date',
+ dueDateLabel: isDe ? 'Fällig am' : 'Due Date',
+ statusLabel: 'Status',
+ invoiceStatus: this._escapeHtml((invoice.status || 'issued').toUpperCase()),
+ companyName: this._escapeHtml(companyInfo.company_name || 'ProfitPlanet GmbH'),
+ companyStreet: this._escapeHtml(companyInfo.company_street || ''),
+ companyPostalCity: this._escapeHtml(companyInfo.company_postal_city || ''),
+ companyCountry: this._escapeHtml(companyInfo.company_country || 'Germany'),
+ customerName: this._escapeHtml(customerName),
+ customerEmail: this._escapeHtml(customerEmail),
+ customerStreet: this._escapeHtml(invoice.buyer_street || ''),
+ customerPostalCity: this._escapeHtml([invoice.buyer_postal_code, invoice.buyer_city].filter(Boolean).join(' ')),
+ customerCountry: this._escapeHtml(invoice.buyer_country || ''),
+ orderedByBlock,
+ issuedAt: this._escapeHtml(issuedAt),
+ dueAt: this._escapeHtml(dueAt),
+ descriptionHeader: isDe ? 'Beschreibung' : 'Description',
+ qtyHeader: isDe ? 'Menge' : 'Qty',
+ unitPriceHeader: isDe ? 'Stückpreis' : 'Unit Price',
+ totalHeader: isDe ? 'Gesamt' : 'Total',
+ itemsRows: this._buildItemsTableRows(items, invoice.currency),
+ subtotalLabel: isDe ? 'Nettobetrag' : 'Subtotal (net)',
+ taxLabel: isDe ? 'MwSt.' : 'Tax',
+ vatRateDisplay: vatRate ? `${vatRate}%` : '0%',
+ totalNet: this._escapeHtml(this._formatAmount(invoice.total_net, invoice.currency)),
+ totalTax: this._escapeHtml(this._formatAmount(invoice.total_tax, invoice.currency)),
+ totalLabel: isDe ? 'Gesamtbetrag (brutto)' : 'Total (gross)',
+ totalGross: this._escapeHtml(this._formatAmount(invoice.total_gross, invoice.currency)),
+ paymentInfoTitle: isDe ? 'Zahlungsinformationen' : 'Payment Information',
+ paymentInfoText: isDe
+ ? 'Bitte überweisen Sie den Gesamtbetrag unter Angabe der Rechnungsnummer.'
+ : 'Please transfer the total amount stating the invoice number as reference.',
+ footerText: isDe
+ ? 'Vielen Dank für Ihr Vertrauen.'
+ : 'Thank you for your business.',
+ // Legacy key used by S3-stored templates
+ itemsHtml: this._buildItemsHtml(items, invoice.currency),
+ };
+ }
+
+ async _buildFallbackInvoiceHtml({ invoice, items, abonement, lang }) {
+ const variables = await this._buildInvoiceTemplateVariables({ invoice, items, abonement, lang });
+
+ const template = await this._loadInvoiceHtmlTemplate();
+ if (template) {
+ return this._renderTemplate(template, variables);
+ }
+
+ // Absolute fallback if template file is missing
+ const isDe = lang === 'de';
+ return `
+
+ ${this._escapeHtml(invoice.invoice_number)}
+
+ ${isDe ? 'Rechnung' : 'Invoice'} ${this._escapeHtml(invoice.invoice_number)}
+ ${isDe ? 'Kunde' : 'Customer'}: ${variables.customerName}
+ ${isDe ? 'Datum' : 'Date'}: ${variables.issuedAt}
+ ${isDe ? 'Positionen' : 'Items'}
+
+ ${isDe ? 'Gesamtbetrag' : 'Total'}: ${variables.totalGross}
+
+`;
+ }
+
+ async _loadInvoiceTemplateHtml({ lang = 'en' } = {}) {
+ try {
+ const templates = await DocumentTemplateService.getActiveTemplatesForUserType('both', 'invoice');
+ if (!Array.isArray(templates) || !templates.length) return null;
+
+ const selected = templates.find((t) => t.lang === lang) || templates.find((t) => t.lang === 'en') || templates[0];
+ if (!selected?.storageKey) return null;
+
+ const command = new GetObjectCommand({
+ Bucket: process.env.EXOSCALE_BUCKET,
+ Key: selected.storageKey,
+ });
+ const obj = await sharedExoscaleClient.send(command);
+ const html = await this._s3BodyToString(obj.Body);
+ return html || null;
+ } catch (error) {
+ logger.warn('InvoiceService._loadInvoiceTemplateHtml:error', { message: error?.message });
+ return null;
+ }
+ }
+
+ _renderTemplate(template, variables) {
+ if (!template) return null;
+ return template.replace(/{{\s*([\w]+)\s*}}/g, (_, key) => variables[key] ?? '');
+ }
+
+ async _renderPdfFromHtml(html) {
+ const browser = await puppeteer.launch({
+ headless: 'new',
+ args: ['--no-sandbox', '--disable-setuid-sandbox']
+ });
+ try {
+ const page = await browser.newPage();
+ await page.setContent(html, { waitUntil: 'networkidle0' });
+ const pdfBuffer = await page.pdf({
+ format: 'A4',
+ printBackground: true,
+ margin: { top: '16mm', right: '14mm', bottom: '16mm', left: '14mm' }
+ });
+ return Buffer.isBuffer(pdfBuffer) ? pdfBuffer : Buffer.from(pdfBuffer);
+ } finally {
+ await browser.close();
+ }
+ }
+
+ async _storeInvoicePdf(invoice, pdfBuffer) {
+ if (!pdfBuffer) return null;
+ const safeUser = invoice.user_id || 'unknown';
+ const key = `invoices/${safeUser}/${invoice.invoice_number || `invoice-${invoice.id}`}.pdf`;
+ await sharedExoscaleClient.send(new PutObjectCommand({
+ Bucket: process.env.EXOSCALE_BUCKET,
+ Key: key,
+ Body: pdfBuffer,
+ ContentType: 'application/pdf',
+ }));
+ await this.repo.updateStorageKey(invoice.id, key);
+ return key;
+ }
+
+ async _sendInvoiceEmail({ invoice, abonement, lang = 'en' }) {
+ const recipientEmail = invoice.buyer_email || abonement?.email;
+ if (!recipientEmail) {
+ logger.warn('InvoiceService._sendInvoiceEmail:missing_recipient', { invoiceId: invoice.id });
+ return;
+ }
+
+ const items = await this.repo.getItemsByInvoiceId(invoice.id);
+ const text = this._buildInvoiceMailText({ invoice, items, abonement, lang });
+ const subject = this._getEmailSubject(lang, invoice.invoice_number);
+
+ // Build the full set of template variables once – used by both S3 and local paths
+ const variables = await this._buildInvoiceTemplateVariables({ invoice, items, abonement, lang });
+
+ const templateHtml = await this._loadInvoiceTemplateHtml({ lang });
+ let html = null;
+
+ if (templateHtml) {
+ html = this._renderTemplate(templateHtml, variables);
+ }
+
+ const htmlForPdf = html || await this._buildFallbackInvoiceHtml({ invoice, items, abonement, lang });
+ const pdfBuffer = await this._renderPdfFromHtml(htmlForPdf);
+ await this._storeInvoicePdf(invoice, pdfBuffer);
+
+ const mailHtml = this._buildInvoiceMailHtml({ invoice, abonement, lang });
+
+ await MailService.sendInvoiceEmail({
+ email: recipientEmail,
+ subject,
+ text,
+ html: mailHtml,
+ attachments: [{
+ name: `${invoice.invoice_number || `invoice-${invoice.id}`}.pdf`,
+ content: pdfBuffer.toString('base64')
+ }],
+ lang,
+ });
+ }
+
// NEW: resolve current standard VAT rate for a buyer country code
async resolveVatRateForCountry(countryCode) {
if (!countryCode) return null;
@@ -34,7 +421,7 @@ class InvoiceService {
}
// Issue invoice for a subscription period, with items from pack_breakdown
- async issueForAbonement(abonement, periodStart, periodEnd, { actorUserId } = {}) {
+ async issueForAbonement(abonement, periodStart, periodEnd, { actorUserId, lang = 'en' } = {}) {
console.log('[INVOICE ISSUE] Inputs:', {
abonement_id: abonement?.id,
abonement_user_id: abonement?.user_id,
@@ -62,7 +449,7 @@ class InvoiceService {
? breakdown.map((b) => ({
product_id: Number(b.coffee_table_id) || null,
sku: `COFFEE-${b.coffee_table_id || 'N/A'}`,
- description: `Coffee subscription: ${b.coffee_table_id}`,
+ description: b.coffee_title || `Coffee subscription: ${b.coffee_table_id}`,
quantity: Number(b.packs || 1),
unit_price: Number(b.price_per_pack || 0),
tax_rate: b.tax_rate != null ? Number(b.tax_rate) : vat_rate, // CHANGED: default to invoice vat_rate
@@ -121,20 +508,89 @@ class InvoiceService {
total_gross: invoice?.total_gross,
});
+ try {
+ await this._sendInvoiceEmail({
+ invoice,
+ abonement,
+ lang,
+ });
+ logger.info('InvoiceService.issueForAbonement:invoice_email_sent', {
+ invoiceId: invoice?.id,
+ userId: invoice?.user_id,
+ hasEmail: Boolean(invoice?.buyer_email || abonement?.email),
+ });
+ } catch (mailError) {
+ logger.error('InvoiceService.issueForAbonement:invoice_email_error', {
+ invoiceId: invoice?.id,
+ message: mailError?.message,
+ });
+ }
+
return invoice;
}
async markPaid(invoiceId, { payment_method, transaction_id, amount, paid_at = new Date(), details } = {}) {
- return this.repo.markPaid(invoiceId, { payment_method, transaction_id, amount, paid_at, details });
+ const paidInvoice = await this.repo.markPaid(invoiceId, { payment_method, transaction_id, amount, paid_at, details });
+
+ let poolResult = null;
+ try {
+ const inflowResult = await PoolInflowService.bookForPaidInvoice({
+ invoiceId: paidInvoice?.id,
+ paidAt: paid_at,
+ actorUserId: null,
+ });
+ poolResult = inflowResult;
+ console.log('[INVOICE PAID] Pool inflow booking result:', {
+ invoiceId: paidInvoice?.id,
+ ...inflowResult,
+ });
+ } catch (e) {
+ poolResult = { error: e?.message || 'Pool inflow booking failed' };
+ console.error('[INVOICE PAID] Pool inflow booking failed:', e);
+ }
+
+ // Attach pool result to returned data so the frontend can display it
+ if (paidInvoice) {
+ paidInvoice._poolResult = poolResult;
+ }
+ return paidInvoice;
}
async listMine(userId, { status, limit = 50, offset = 0 } = {}) {
return this.repo.listByUser(userId, { status, limit, offset });
}
+ async listByAbonement(abonementId) {
+ return this.repo.findByAbonement(abonementId);
+ }
+
async adminList({ status, limit = 200, offset = 0 } = {}) {
return this.repo.listAll({ status, limit, offset });
}
+
+ async updateStatus(invoiceId, newStatus) {
+ const invoice = await this.repo.getById(invoiceId);
+ if (!invoice) throw new Error(`Invoice ${invoiceId} not found.`);
+
+ // If transitioning to 'paid', use the full markPaid flow for pool inflow booking
+ if (newStatus === 'paid' && invoice.status !== 'paid') {
+ return this.markPaid(invoiceId, {
+ payment_method: 'admin_manual',
+ amount: invoice.total_gross ?? 0,
+ paid_at: new Date(),
+ });
+ }
+
+ return this.repo.updateStatus(invoiceId, newStatus);
+ }
+
+ async getInvoiceDetail(invoiceId) {
+ const invoice = await this.repo.getById(invoiceId);
+ if (!invoice) throw new Error(`Invoice ${invoiceId} not found.`);
+ const items = await this.repo.getItemsByInvoiceId(invoiceId);
+ const payments = await this.repo.getPaymentsByInvoiceId(invoiceId);
+ return { invoice, items, payments };
+ }
}
module.exports = InvoiceService;
diff --git a/services/permissions/PermissionService.js b/services/permissions/PermissionService.js
index 4adabbc..40be6e6 100644
--- a/services/permissions/PermissionService.js
+++ b/services/permissions/PermissionService.js
@@ -1,7 +1,25 @@
const PermissionRepository = require('../../repositories/permissions/PermissionRepository');
+const db = require('../../database/database');
const { logger } = require('../../middleware/logger');
class PermissionService {
+ static async userHasPermission(userId, permissionName) {
+ if (!userId || !permissionName) return false;
+ try {
+ const [rows] = await db.query(
+ `SELECT 1 FROM user_permissions up
+ JOIN permissions p ON up.permission_id = p.id
+ WHERE up.user_id = ? AND p.name = ? AND p.is_active = TRUE
+ LIMIT 1`,
+ [userId, permissionName]
+ );
+ return rows.length > 0;
+ } catch (error) {
+ logger.error('PermissionService.userHasPermission:error', { userId, permissionName, error: error.message });
+ return false;
+ }
+ }
+
static async getAllPermissions(unitOfWork) {
logger.info('PermissionService.getAllPermissions:start');
try {
diff --git a/services/pool/PoolInflowService.js b/services/pool/PoolInflowService.js
new file mode 100644
index 0000000..7813a43
--- /dev/null
+++ b/services/pool/PoolInflowService.js
@@ -0,0 +1,336 @@
+const db = require('../../database/database');
+
+const SYSTEM_POOL_NAMES = ['ABO 60', 'ABO 120', 'Business', 'Gigantea', 'Core'];
+
+function toTwo(value) {
+ return Number(Number(value || 0).toFixed(2));
+}
+
+function toFour(value) {
+ return Number(Number(value || 0).toFixed(4));
+}
+
+class PoolInflowService {
+ async upsertCapsuleSalesForInvoice({ conn, invoiceId, abonementId, paidAtDate, currency, byCoffee }) {
+ const entries = Array.from(byCoffee.entries());
+ for (const [coffeeId, capsulesCountRaw] of entries) {
+ const capsulesCount = Number(capsulesCountRaw || 0);
+ if (!Number.isFinite(capsulesCount) || capsulesCount <= 0) continue;
+
+ const details = {
+ source: 'invoice_paid',
+ formula: 'packs * 10',
+ };
+
+ await conn.query(
+ `INSERT INTO capsule_sales
+ (invoice_id, abonement_id, coffee_table_id, capsules_count, sold_at, currency, details, created_at, updated_at)
+ VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())
+ ON DUPLICATE KEY UPDATE
+ abonement_id = VALUES(abonement_id),
+ capsules_count = VALUES(capsules_count),
+ sold_at = VALUES(sold_at),
+ currency = VALUES(currency),
+ details = VALUES(details),
+ updated_at = NOW()`,
+ [
+ Number(invoiceId),
+ Number(abonementId),
+ Number(coffeeId),
+ capsulesCount,
+ paidAtDate,
+ currency || 'EUR',
+ JSON.stringify(details),
+ ]
+ );
+ }
+ }
+
+ async getCapsuleSalesMap({ conn, invoiceId }) {
+ const [rows] = await conn.query(
+ `SELECT coffee_table_id, capsules_count
+ FROM capsule_sales
+ WHERE invoice_id = ?`,
+ [Number(invoiceId)]
+ );
+
+ const byCoffee = new Map();
+ for (const row of rows || []) {
+ const coffeeId = Number(row.coffee_table_id);
+ const capsulesCount = Number(row.capsules_count || 0);
+ if (!Number.isFinite(coffeeId) || coffeeId <= 0) continue;
+ if (!Number.isFinite(capsulesCount) || capsulesCount <= 0) continue;
+ byCoffee.set(coffeeId, (byCoffee.get(coffeeId) || 0) + capsulesCount);
+ }
+ return byCoffee;
+ }
+
+ async analyzePaidInvoice({ invoiceId, paidAt }) {
+ const normalizedInvoiceId = Number(invoiceId);
+ if (!Number.isFinite(normalizedInvoiceId) || normalizedInvoiceId <= 0) {
+ return { ok: false, reason: 'invalid_invoice_id' };
+ }
+
+ const [invoiceRows] = await db.query(
+ `SELECT id, source_type, source_id, currency, status, context
+ FROM invoices
+ WHERE id = ?
+ LIMIT 1`,
+ [normalizedInvoiceId]
+ );
+ const invoice = invoiceRows?.[0];
+ if (!invoice) return { ok: false, reason: 'invoice_not_found' };
+ if (String(invoice.status) !== 'paid') return { ok: false, reason: 'invoice_not_paid', invoice };
+ if (String(invoice.source_type) !== 'subscription') return { ok: false, reason: 'unsupported_source_type', invoice };
+
+ const abonementId = Number(invoice.source_id);
+ if (!Number.isFinite(abonementId) || abonementId <= 0) {
+ return { ok: false, reason: 'missing_abonement_relation', invoice };
+ }
+
+ const paidAtCandidate = paidAt ? new Date(paidAt) : new Date();
+ const paidAtDate = Number.isFinite(paidAtCandidate.getTime()) ? paidAtCandidate : new Date();
+
+ let context = {};
+ try {
+ context = invoice.context && typeof invoice.context === 'string' ? JSON.parse(invoice.context) : (invoice.context || {});
+ } catch (_) {
+ context = {};
+ }
+ const periodStart = context?.period_start ? new Date(context.period_start) : null;
+ if (periodStart && Number.isFinite(periodStart.getTime()) && paidAtDate < periodStart) {
+ return { ok: false, reason: 'paid_before_period_start', invoice, abonementId, paidAtDate, periodStart };
+ }
+
+ const [abonRows] = await db.query(
+ `SELECT id, pack_breakdown, currency
+ FROM coffee_abonements
+ WHERE id = ?
+ LIMIT 1`,
+ [abonementId]
+ );
+ const abonement = abonRows?.[0];
+ if (!abonement) return { ok: false, reason: 'abonement_not_found', invoice, abonementId };
+
+ const breakdownRaw = abonement.pack_breakdown;
+ let breakdown = [];
+ try {
+ breakdown = breakdownRaw
+ ? (typeof breakdownRaw === 'string' ? JSON.parse(breakdownRaw) : breakdownRaw)
+ : [];
+ } catch (_) {
+ breakdown = [];
+ }
+
+ const normalizedLines = Array.isArray(breakdown)
+ ? breakdown
+ .map((line) => ({
+ coffeeId: Number(line?.coffee_table_id),
+ capsulesCount: Number(line?.packs || 0) * 10,
+ }))
+ .filter((line) => Number.isFinite(line.coffeeId) && line.coffeeId > 0 && Number.isFinite(line.capsulesCount) && line.capsulesCount > 0)
+ : [];
+
+ if (!normalizedLines.length) return { ok: false, reason: 'no_breakdown_lines', invoice, abonementId };
+
+ const byCoffee = new Map();
+ for (const line of normalizedLines) {
+ byCoffee.set(line.coffeeId, (byCoffee.get(line.coffeeId) || 0) + line.capsulesCount);
+ }
+
+ const placeholders = SYSTEM_POOL_NAMES.map(() => '?').join(',');
+ const [pools] = await db.query(
+ `SELECT p.id,
+ p.pool_name,
+ MAX(COALESCE(r.price_per_capsule_gross, p.price, 0)) AS price_per_capsule_gross,
+ COUNT(DISTINCT pm.user_id) AS members_count
+ FROM pools p
+ LEFT JOIN pool_capsule_rules r ON r.pool_id = p.id AND r.is_active = 1
+ LEFT JOIN pool_members pm ON pm.pool_id = p.id
+ WHERE p.is_active = 1
+ AND p.pool_name IN (${placeholders})
+ GROUP BY p.id, p.pool_name`,
+ SYSTEM_POOL_NAMES
+ );
+
+ if (!Array.isArray(pools) || pools.length === 0) {
+ return { ok: false, reason: 'no_active_system_pools', invoice, abonementId, normalizedLines };
+ }
+
+ return {
+ ok: true,
+ reason: 'ok',
+ invoice,
+ abonementId,
+ paidAtDate,
+ byCoffee,
+ pools,
+ normalizedLines,
+ currency: invoice.currency || abonement.currency || 'EUR',
+ };
+ }
+
+ async bookForPaidInvoice({ invoiceId, paidAt, actorUserId = null }) {
+ const analysis = await this.analyzePaidInvoice({ invoiceId, paidAt });
+ if (!analysis.ok) {
+ return { inserted: 0, skipped: 0, reason: analysis.reason };
+ }
+
+ const normalizedInvoiceId = Number(analysis.invoice.id);
+ const abonementId = Number(analysis.abonementId);
+ const paidAtDate = analysis.paidAtDate;
+ const byCoffee = analysis.byCoffee;
+ const pools = analysis.pools;
+ const currency = analysis.currency;
+ const conn = await db.getConnection();
+ let inserted = 0;
+ try {
+ let alreadyExists = 0;
+ await conn.beginTransaction();
+
+ await this.upsertCapsuleSalesForInvoice({
+ conn,
+ invoiceId: normalizedInvoiceId,
+ abonementId,
+ paidAtDate,
+ currency,
+ byCoffee,
+ });
+
+ const capsuleSalesByCoffee = await this.getCapsuleSalesMap({ conn, invoiceId: normalizedInvoiceId });
+ const coffeeEntries = Array.from(capsuleSalesByCoffee.entries());
+ const totalCandidates = pools.reduce((acc, pool) => {
+ const memberMultiplier = pool.pool_name === 'Core' ? Number(pool.members_count || 0) : 1;
+ if (memberMultiplier <= 0) return acc;
+ return acc + coffeeEntries.length;
+ }, 0);
+
+ for (const pool of pools) {
+ const pricePerCapsuleGross = toFour(pool.price_per_capsule_gross);
+ const memberMultiplier = pool.pool_name === 'Core' ? Number(pool.members_count || 0) : 1;
+ if (memberMultiplier <= 0) continue;
+
+ for (const [coffeeId, capsulesCountRaw] of coffeeEntries) {
+ const capsulesCount = Number(capsulesCountRaw || 0);
+ if (!capsulesCount) continue;
+
+ const amountGross = toTwo(capsulesCount * pricePerCapsuleGross * memberMultiplier);
+ const details = {
+ source: 'invoice_paid',
+ formula: 'capsules_count * price_per_capsule_gross * member_multiplier',
+ paid_at: paidAtDate,
+ booking_basis: 'gross',
+ compatibility_note: 'gross values stored in existing net columns',
+ member_multiplier: memberMultiplier,
+ core_members_count: pool.pool_name === 'Core' ? memberMultiplier : null,
+ };
+
+ const [res] = await conn.query(
+ `INSERT INTO pool_inflows
+ (pool_id, invoice_id, abonement_id, coffee_table_id, event_type, capsules_count, price_per_capsule_net, amount_net, currency, details, created_by_user_id, created_at)
+ VALUES (?, ?, ?, ?, 'invoice_paid', ?, ?, ?, ?, ?, ?, NOW())
+ ON DUPLICATE KEY UPDATE id = id`,
+ [
+ Number(pool.id),
+ normalizedInvoiceId,
+ abonementId,
+ Number(coffeeId),
+ capsulesCount,
+ pricePerCapsuleGross,
+ amountGross,
+ currency,
+ JSON.stringify(details),
+ actorUserId || null,
+ ]
+ );
+
+ if (res && Number(res.affectedRows) === 1) inserted += 1;
+ else alreadyExists += 1;
+ }
+ }
+
+ await conn.commit();
+ return { inserted, alreadyExists, skipped: Math.max(0, totalCandidates - inserted - alreadyExists), reason: 'ok' };
+ } catch (err) {
+ await conn.rollback();
+ throw err;
+ } finally {
+ conn.release();
+ }
+ }
+
+ async getInvoiceInflowDiagnostics({ invoiceId, paidAt }) {
+ const analysis = await this.analyzePaidInvoice({ invoiceId, paidAt });
+ if (!analysis.ok) {
+ return {
+ ok: false,
+ reason: analysis.reason,
+ invoiceId: Number(invoiceId),
+ };
+ }
+
+ const invoiceIdNum = Number(analysis.invoice.id);
+ const poolEntries = [];
+ let coffeeEntries = [];
+
+ const [salesRows] = await db.query(
+ `SELECT coffee_table_id, capsules_count
+ FROM capsule_sales
+ WHERE invoice_id = ?`,
+ [invoiceIdNum]
+ );
+
+ if (Array.isArray(salesRows) && salesRows.length) {
+ coffeeEntries = salesRows
+ .map((row) => [Number(row.coffee_table_id), Number(row.capsules_count || 0)])
+ .filter(([coffeeId, capsulesCount]) => Number.isFinite(coffeeId) && coffeeId > 0 && Number.isFinite(capsulesCount) && capsulesCount > 0);
+ } else {
+ coffeeEntries = Array.from(analysis.byCoffee.entries());
+ }
+
+ for (const pool of analysis.pools) {
+ const pricePerCapsuleGross = toFour(pool.price_per_capsule_gross);
+ const memberMultiplier = pool.pool_name === 'Core' ? Number(pool.members_count || 0) : 1;
+ if (memberMultiplier <= 0) continue;
+
+ for (const [coffeeId, capsulesCountRaw] of coffeeEntries) {
+ const capsulesCount = Number(capsulesCountRaw || 0);
+ const amountGross = toTwo(capsulesCount * pricePerCapsuleGross * memberMultiplier);
+ const [existingRows] = await db.query(
+ `SELECT id, created_at
+ FROM pool_inflows
+ WHERE pool_id = ? AND invoice_id = ? AND coffee_table_id = ? AND event_type = 'invoice_paid'
+ LIMIT 1`,
+ [Number(pool.id), invoiceIdNum, Number(coffeeId)]
+ );
+
+ poolEntries.push({
+ pool_id: Number(pool.id),
+ pool_name: pool.pool_name,
+ coffee_table_id: Number(coffeeId),
+ capsules_count: capsulesCount,
+ price_per_capsule_gross: pricePerCapsuleGross,
+ member_multiplier: memberMultiplier,
+ core_members_count: pool.pool_name === 'Core' ? memberMultiplier : null,
+ amount_gross: amountGross,
+ already_booked: !!existingRows?.length,
+ existing_inflow_id: existingRows?.[0]?.id || null,
+ });
+ }
+ }
+
+ return {
+ ok: true,
+ reason: 'ok',
+ invoice_id: invoiceIdNum,
+ abonement_id: Number(analysis.abonementId),
+ paid_at: analysis.paidAtDate,
+ currency: analysis.currency,
+ candidates: poolEntries,
+ will_book_count: poolEntries.filter((x) => !x.already_booked).length,
+ already_booked_count: poolEntries.filter((x) => x.already_booked).length,
+ };
+ }
+}
+
+module.exports = new PoolInflowService();
diff --git a/services/pool/PoolService.js b/services/pool/PoolService.js
index 2dc35e4..6154fb0 100644
--- a/services/pool/PoolService.js
+++ b/services/pool/PoolService.js
@@ -1,30 +1,11 @@
const UnitOfWork = require('../../database/UnitOfWork');
const PoolRepository = require('../../repositories/pool/poolRepository');
+const db = require('../../database/database');
-function isValidPoolType(pool_type) {
- return pool_type === 'coffee' || pool_type === 'other';
-}
-
-async function createPool({ pool_name, description = null, price = 0.00, pool_type = 'other', is_active = true, created_by = null }) {
- if (!isValidPoolType(pool_type)) {
- const err = new Error('Invalid pool_type. Allowed: coffee, other');
- err.status = 400;
- throw err;
- }
- const uow = new UnitOfWork();
- try {
- console.debug('[PoolService.createPool] start', { pool_name, pool_type });
- await uow.start();
- const repo = new PoolRepository(uow);
- const pool = await repo.create({ pool_name, description, price, pool_type, is_active, created_by });
- await uow.commit();
- console.debug('[PoolService.createPool] success', { id: pool.id });
- return pool;
- } catch (err) {
- console.error('[PoolService.createPool] error', err);
- try { await uow.rollback(); } catch (_) { console.warn('[PoolService.createPool] rollback failed'); }
- throw err;
- }
+async function createPool({ pool_name, description = null, price = 0.00, subscription_coffee_id = null, pool_type = 'other', is_active = true, created_by = null }) {
+ const err = new Error('Manual pool creation is disabled. System supports only: ABO 60, ABO 120, Business, Gigantea, Core.');
+ err.status = 400;
+ throw err;
}
async function listPools() {
@@ -67,4 +48,35 @@ async function updatePoolState(id, is_active, actorUserId) {
}
}
-module.exports = { createPool, listPools, updatePoolState };
\ No newline at end of file
+async function updatePoolSubscription({ id, subscription_coffee_id = null, actorUserId = null }) {
+ let normalizedSubscriptionCoffeeId = null;
+ if (subscription_coffee_id !== null && subscription_coffee_id !== undefined && String(subscription_coffee_id).trim() !== '') {
+ const sid = Number(subscription_coffee_id);
+ if (!Number.isFinite(sid) || sid <= 0) {
+ const err = new Error('Invalid subscription_coffee_id');
+ err.status = 400;
+ throw err;
+ }
+ const [rows] = await db.query('SELECT id FROM coffee_table WHERE id = ? LIMIT 1', [sid]);
+ if (!rows.length) {
+ const err = new Error('Selected subscription not found');
+ err.status = 400;
+ throw err;
+ }
+ normalizedSubscriptionCoffeeId = sid;
+ }
+
+ const uow = new UnitOfWork();
+ try {
+ await uow.start();
+ const repo = new PoolRepository(uow);
+ const updated = await repo.updateSubscriptionLink(id, normalizedSubscriptionCoffeeId, actorUserId);
+ await uow.commit();
+ return updated;
+ } catch (err) {
+ try { await uow.rollback(); } catch (_) { console.warn('[PoolService.updatePoolSubscription] rollback failed'); }
+ throw err;
+ }
+}
+
+module.exports = { createPool, listPools, updatePoolState, updatePoolSubscription };
\ No newline at end of file
diff --git a/services/referral/ReferralService.js b/services/referral/ReferralService.js
index efa979d..8731fdc 100644
--- a/services/referral/ReferralService.js
+++ b/services/referral/ReferralService.js
@@ -382,7 +382,24 @@ class ReferralService {
const repo = new ReferralTokenRepository(unitOfWork);
const raw = await repo.getReferrerInfoByToken(token);
if (!raw) {
- logger.warn('ReferralService:getReferrerInfo:not_found', { token });
+ // Diagnostic: check if token exists at all (without JOIN)
+ try {
+ const conn = unitOfWork.connection;
+ const [diag] = await conn.query(
+ 'SELECT id, token, status, created_by_user_id, expires_at, max_uses, uses_remaining FROM referral_tokens WHERE token = ? LIMIT 1',
+ [token]
+ );
+ if (diag.length) {
+ logger.warn('ReferralService:getReferrerInfo:token_exists_but_join_failed', {
+ token, tokenId: diag[0].id, created_by_user_id: diag[0].created_by_user_id,
+ status: diag[0].status, expires_at: diag[0].expires_at
+ });
+ } else {
+ logger.warn('ReferralService:getReferrerInfo:token_truly_not_in_db', { token });
+ }
+ } catch (diagErr) {
+ logger.warn('ReferralService:getReferrerInfo:diagnostic_query_failed', { error: diagErr.message });
+ }
return { valid: false, reason: 'not_found' };
}
const evalResult = this.evaluateTokenRecord(raw);
diff --git a/services/status/UserStatusService.js b/services/status/UserStatusService.js
index c51ce49..539bd01 100644
--- a/services/status/UserStatusService.js
+++ b/services/status/UserStatusService.js
@@ -58,6 +58,27 @@ class UserStatusService {
const status = await repo.getStatusByUserId(userId);
if (!status) return null;
+ // Guest users are always fully onboarded — skip quickaction flow
+ if (status.status === 'active') {
+ // Check if this is a guest user
+ const conn = unitOfWork.connection;
+ const [userRows] = await conn.query('SELECT role FROM users WHERE id = ? LIMIT 1', [userId]);
+ if (userRows?.[0]?.role === 'guest') {
+ const allCompleteSteps = [
+ { key: 'email_verified', label: 'Email Verified', completed: true },
+ { key: 'profile_completed', label: 'Profile Completed', completed: true },
+ { key: 'documents_uploaded', label: 'Documents Uploaded', completed: true },
+ { key: 'contract_signed', label: 'Contract Signed', completed: true },
+ ];
+ return {
+ status: 'active',
+ steps: allCompleteSteps,
+ completedSteps: allCompleteSteps.map(s => s.label),
+ progressPercent: 100,
+ };
+ }
+ }
+
// Calculate progress steps
const steps = [
{ key: 'email_verified', label: 'Email Verified' },
diff --git a/services/template/DocumentTemplateService.js b/services/template/DocumentTemplateService.js
index 351066b..ff94aa5 100644
--- a/services/template/DocumentTemplateService.js
+++ b/services/template/DocumentTemplateService.js
@@ -135,6 +135,14 @@ class DocumentTemplateService {
}, uow.connection);
}
+ // Enforce singleton active invoice template per lang
+ if (state === 'active' && current.type === 'invoice') {
+ await DocumentTemplateRepository.deactivateOtherActiveInvoices({
+ excludeId: id,
+ lang: current.lang,
+ }, uow.connection);
+ }
+
const updated = await DocumentTemplateRepository.findById(id, uow.connection);
await uow.commit();
logger.info('DocumentTemplateService.updateTemplateState:success', { id, state });
@@ -186,6 +194,15 @@ class DocumentTemplateService {
}, uow.connection);
}
+ // If new template is active and is an invoice template, deactivate other active invoices for same lang
+ const effectiveType = data.type || previous.type;
+ if (nextState === 'active' && effectiveType === 'invoice') {
+ await DocumentTemplateRepository.deactivateOtherActiveInvoices({
+ excludeId: created.id,
+ lang: (data.lang || previous.lang),
+ }, uow.connection);
+ }
+
// Deactivate previous (requirement: deactive the previous one)
await DocumentTemplateRepository.updateState(previousId, 'inactive', uow.connection);
diff --git a/services/user/guest/GuestUserService.js b/services/user/guest/GuestUserService.js
new file mode 100644
index 0000000..37f7a73
--- /dev/null
+++ b/services/user/guest/GuestUserService.js
@@ -0,0 +1,112 @@
+const PersonalUserRepository = require('../../../repositories/user/personal/PersonalUserRepository');
+const UserStatusService = require('../../status/UserStatusService');
+const UnitOfWork = require('../../../database/UnitOfWork');
+const MailService = require('../../email/MailService');
+const AbonemmentService = require('../../abonemments/AbonemmentService');
+const User = require('../../../models/User');
+const { logger } = require('../../../middleware/logger');
+
+const abonemmentService = new AbonemmentService();
+
+class GuestUserService {
+ /**
+ * Create a guest user account with role='guest'.
+ * Guest users only have access to subscriptions, nothing else.
+ */
+ static async createGuestUser({ email, password, firstName, lastName, referralEmail, lang }) {
+ logger.info('GuestUserService.createGuestUser:start', { email, firstName, lastName });
+
+ const unitOfWork = new UnitOfWork();
+ await unitOfWork.start();
+ unitOfWork.registerRepository('personalUser', new PersonalUserRepository(unitOfWork));
+
+ try {
+ const personalRepo = unitOfWork.getRepository('personalUser');
+
+ // Check if user already exists
+ const existing = await personalRepo.findByEmail(email);
+ if (existing) {
+ await unitOfWork.rollback();
+ throw new Error('User already exists');
+ }
+
+ // Create user in DB with role='guest'
+ const conn = unitOfWork.connection;
+ const hashedPassword = await User.hashPassword(password);
+
+ const [userResult] = await conn.query(
+ `INSERT INTO users (email, password, user_type, role) VALUES (?, ?, 'personal', 'guest')`,
+ [email, hashedPassword]
+ );
+ const userId = userResult.insertId;
+
+ await conn.query(
+ `INSERT INTO personal_profiles (user_id, first_name, last_name) VALUES (?, ?, ?)`,
+ [userId, firstName, lastName]
+ );
+
+ // Initialize user status as active (skip full registration flow for guests)
+ await UserStatusService.initializeUserStatus(userId, 'personal', unitOfWork, 'active');
+
+ // Mark ALL status flags as completed for guests — they skip the entire quickaction flow
+ await conn.query(
+ `UPDATE user_status SET email_verified = TRUE, profile_completed = TRUE, documents_uploaded = TRUE, contract_signed = TRUE, registration_completed = TRUE, is_admin_verified = TRUE WHERE user_id = ?`,
+ [userId]
+ );
+
+ // Handle referral if provided
+ if (referralEmail) {
+ try {
+ const ReferralService = require('../../referral/ReferralService');
+ await ReferralService.processReferral(userId, referralEmail, unitOfWork);
+ } catch (refErr) {
+ logger.warn('GuestUserService.createGuestUser:referral_failed', { userId, error: refErr?.message });
+ }
+ }
+
+ // Link any pending gift subscriptions to this user
+ await abonemmentService.linkGiftFlagsToUser(email, userId);
+
+ // Send a welcome email
+ const chosenLang = lang || 'en';
+ await MailService.sendRegistrationEmail({
+ email,
+ firstName,
+ lastName,
+ userType: 'personal',
+ lang: chosenLang,
+ });
+
+ await unitOfWork.commit();
+
+ logger.info('GuestUserService.createGuestUser:success', { userId, email });
+ return { id: userId, email, firstName, lastName, role: 'guest' };
+ } catch (error) {
+ logger.error('GuestUserService.createGuestUser:error', { email, error: error.message });
+ await unitOfWork.rollback(error);
+ throw error;
+ }
+ }
+
+ static async findGuestByEmail(email) {
+ const unitOfWork = new UnitOfWork();
+ await unitOfWork.start();
+ try {
+ const conn = unitOfWork.connection;
+ const [rows] = await conn.query(
+ `SELECT u.id, u.email, u.role, pp.first_name, pp.last_name
+ FROM users u
+ LEFT JOIN personal_profiles pp ON u.id = pp.user_id
+ WHERE u.email = ? AND u.role = 'guest' LIMIT 1`,
+ [email]
+ );
+ await unitOfWork.commit();
+ return rows[0] || null;
+ } catch (error) {
+ await unitOfWork.rollback(error);
+ throw error;
+ }
+ }
+}
+
+module.exports = GuestUserService;
diff --git a/templates/invoice/invoiceTemplate.html b/templates/invoice/invoiceTemplate.html
new file mode 100644
index 0000000..f4d9e5b
--- /dev/null
+++ b/templates/invoice/invoiceTemplate.html
@@ -0,0 +1,287 @@
+
+
+
+
+
+ {{documentTitle}} {{invoiceNumber}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | # |
+ {{descriptionHeader}} |
+ {{qtyHeader}} |
+ {{unitPriceHeader}} |
+ {{totalHeader}} |
+
+
+
+ {{itemsRows}}
+
+
+
+
+
+
+
+ {{subtotalLabel}}
+ {{totalNet}}
+
+
+ {{taxLabel}} ({{vatRateDisplay}})
+ {{totalTax}}
+
+
+ {{totalLabel}}
+ {{totalGross}}
+
+
+
+
+
+
+
{{paymentInfoTitle}}
+
{{paymentInfoText}}
+
+
+
+
+
+
+