ShieldX commited on
Commit
e14bacb
·
verified ·
1 Parent(s): 0c942f3

Upload 24 files

Browse files
Dockerfile ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:18-slim
2
+
3
+ WORKDIR /app
4
+
5
+ COPY package*.json ./
6
+ RUN npm install --production
7
+
8
+ COPY . .
9
+
10
+ ENV NODE_ENV=production
11
+ ENV PORT=7860
12
+
13
+ EXPOSE 7860
14
+
15
+ CMD ["node", "index.js"]
index.js ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ global.isStrikeRunning = false;
2
+
3
+ require('dotenv').config();
4
+ const express = require('express');
5
+ const mongoose = require('mongoose');
6
+ const cors = require('cors');
7
+ const { generateKUS } = require('./utils/kusGenerator');
8
+
9
+ const authRoute = require('./routes/auth');
10
+ const marketRoute = require('./routes/market');
11
+ const adminRoute = require('./routes/admin');
12
+
13
+ // Import Models
14
+ const User = require('./models/User');
15
+ const Transaction = require('./models/Transaction');
16
+ const Asset = require('./models/Asset');
17
+ const notificationRoute = require('./routes/notification');
18
+
19
+ const startStrike = require('./jobs/strike');
20
+
21
+ const logTransaction = require('./utils/ledgerLogger');
22
+ const { sendToUser } = require('./utils/sendPush');
23
+
24
+ startStrike(); // Starts the internal clock
25
+
26
+ const app = express();
27
+
28
+ // Middleware
29
+ app.use(cors());
30
+ app.use(express.json()); // Allows us to read JSON from the iPhone
31
+
32
+ // Route Middlewares
33
+ app.use('/api/auth', authRoute);
34
+ app.use('/api/market', marketRoute);
35
+ app.use('/api/admin', adminRoute);
36
+ app.use('/api/notifications', notificationRoute);
37
+ app.use("/api/strike", require("./routes/strike"));
38
+ app.use('/api/fairness', require('./routes/fairness'));
39
+
40
+ // ------------------------------------------------------------------
41
+ // ROUTE 1: Health Check (To see if server is alive)
42
+ // ------------------------------------------------------------------
43
+ app.get('/', (req, res) => {
44
+ res.send('KoshX System: Securely Running....');
45
+ });
46
+
47
+ // ------------------------------------------------------------------
48
+ // ROUTE 2: The Payment Webhook (Where the iPhone talks to us)
49
+ // ------------------------------------------------------------------
50
+ app.post('/api/webhook/sms-capture', async (req, res) => {
51
+ try {
52
+ // 1. Security Gate
53
+ const secret = req.headers['x-admin-secret'];
54
+ if (secret !== process.env.ADMIN_SECRET) {
55
+ console.log('Unauthorized Webhook Attempt');
56
+ return res.status(403).json({ error: "Access Denied" });
57
+ }
58
+
59
+ // 2. Extract Data
60
+ const { utr, amount } = req.body;
61
+ console.log(`[Webhook] Received UTR: ${utr}`);
62
+
63
+ // 3. Find the Pending Transaction
64
+ // NOTE: In a real flow, the user creates a "Pending" transaction via the App first.
65
+ // If you are just testing the Webhook without the App, we might not find a transaction yet.
66
+ // For now, let's assume the App created it.
67
+
68
+ const transaction = await Transaction.findOne({ utr: utr, status: 'Pending' });
69
+
70
+ if (!transaction) {
71
+ return res.status(404).json({ message: "Transaction not found or already verified." });
72
+ }
73
+
74
+ // 4. Generate the Asset
75
+ const newKUS = await generateKUS(transaction.tier);
76
+
77
+ // 5. Assign to User
78
+ const newAsset = new Asset({
79
+ owner_id: transaction.user_id,
80
+ kus_id: newKUS,
81
+ tier: transaction.tier
82
+ });
83
+ await newAsset.save();
84
+
85
+ // 6. Update Transaction Status
86
+ transaction.status = 'Verified';
87
+ await transaction.save();
88
+
89
+ // 7. Referral Logic (Check if First Purchase)
90
+ const assetCount = await Asset.countDocuments({ owner_id: tx.user_id });
91
+ if (assetCount === 1) {
92
+ const user = await User.findById(tx.user_id);
93
+ if (user.referred_by) {
94
+ const referrer = await User.findOne({ referral_code: user.referred_by });
95
+ if (referrer) {
96
+ let reward = 0;
97
+ if (tx.tier === 'Silver') reward = 100;
98
+ if (tx.tier === 'Gold') reward = 150;
99
+ if (tx.tier === 'Platinum') reward = 250;
100
+
101
+ let userReward = 0;
102
+ if (tx.tier === 'Silver') reward = 50;
103
+ if (tx.tier === 'Gold') reward = 75;
104
+ if (tx.tier === 'Platinum') reward = 125;
105
+
106
+ referrer.points += reward;
107
+ await referrer.save();
108
+
109
+ user.points += userReward;
110
+ await user.save();
111
+
112
+ await logTransaction(referrer._id, 'REFERRAL_BONUS', reward, 'INR', `Referral Bonus Tier: ${tx.tier}`);
113
+ await sendToUser(referrer._id, "Referral Bonus Credited", `${reward} points credited to your account.`, "/profile");
114
+
115
+ await logTransaction(user._id, 'REFERRAL_BONUS', userReward, 'INR', `Referral Bonus Tier: ${tx.tier}`);
116
+ await sendToUser(user._id, "Referral Bonus Credited", `${userReward} points credited to your account.`, "/profile");
117
+
118
+ console.log(`[Referral] ${reward} points added to ${referrer.name}`);
119
+ }
120
+ }
121
+ }
122
+
123
+ console.log(`[Success] Asset ${newKUS} generated for UTR ${utr}`);
124
+ res.status(200).json({ success: true, kus: newKUS });
125
+
126
+ } catch (error) {
127
+ console.error("Webhook Error:", error);
128
+ res.status(500).json({ error: "Server Internal Error" });
129
+ }
130
+ });
131
+
132
+ // Database Connection & Server Start
133
+ mongoose.connect(process.env.MONGO_URI)
134
+ .then(() => {
135
+ console.log('✅ Connected to MongoDB Atlas');
136
+ app.listen(process.env.PORT, '0.0.0.0', () => {
137
+ console.log(`🚀 Server running on port ${process.env.PORT}`);
138
+ });
139
+ })
140
+ .catch((err) => console.error('❌ DB Connection Error:', err));
jobs/strike.js ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const cron = require("node-cron");
2
+ const { runStrike } = require("../services/strikeEngine");
3
+
4
+ const startStrike = () => {
5
+ cron.schedule("00 20 * * *", async () => {
6
+ console.log("⚡ CRON STRIKE START ⚡");
7
+ try {
8
+ await runStrike({ triggeredBy: "CRON" });
9
+ } catch (err) {
10
+ console.error("Strike Error:", err.message);
11
+ }
12
+ }, { timezone: "Asia/Kolkata" });
13
+ };
14
+
15
+ module.exports = startStrike;
models/AllTransaction.js ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const mongoose = require('mongoose');
2
+
3
+ const allTransactionSchema = new mongoose.Schema({
4
+ user_id: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
5
+
6
+ // The specific type of action
7
+ type: {
8
+ type: String,
9
+ enum: [
10
+ 'DEPOSIT', // Cash Added
11
+ 'WITHDRAWAL', // Cash Removed
12
+ 'ASSET_PURCHASE', // Bought with Cash
13
+ 'POINT_REDEMPTION', // Bought with Points
14
+ 'LIQUIDATION', // Sold for Points
15
+ 'REFERRAL_BONUS', // Points earned
16
+ 'STRIKE_WIN', // Won 8 PM game
17
+ 'REFUND', // 8 PM game cancelled
18
+ 'ADMIN_ADJUSTMENT' // Manual fix
19
+ ],
20
+ required: true
21
+ },
22
+
23
+ amount: { type: Number, required: true }, // The value
24
+ currency: { type: String, enum: ['INR', 'POINTS'], required: true }, // What was exchanged
25
+ description: { type: String }, // e.g. "Silver Tier Purchase" or "UTR 12345"
26
+
27
+ timestamp: { type: Date, default: Date.now }
28
+ });
29
+
30
+ module.exports = mongoose.model('AllTransaction', allTransactionSchema);
models/Asset.js ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const mongoose = require('mongoose');
2
+
3
+ const assetSchema = new mongoose.Schema({
4
+ owner_id: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
5
+ kus_id: { type: String, unique: true }, // The KoshX Unique Serial (e.g., AG171225W0000001)
6
+ tier: { type: String, enum: ['Silver', 'Gold', 'Platinum'], required: true },
7
+ purchase_date: { type: Date, default: Date.now },
8
+ status: { type: String, enum: ['Pending', 'Held', 'Liquidated', 'Burned'], default: 'Pending' },
9
+ hash: { type: String } // Cryptographic signature for premium feel
10
+ });
11
+
12
+ module.exports = mongoose.model('Asset', assetSchema);
models/Counter.js ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ const mongoose = require('mongoose');
2
+
3
+ const counterSchema = new mongoose.Schema({
4
+ _id: { type: String, required: true }, // This stores the key like "Silver_181225"
5
+ seq: { type: Number, default: 0 } // This stores the running count
6
+ });
7
+
8
+ // Important: We export the Model directly
9
+ module.exports = mongoose.model('Counter', counterSchema);
models/Notification.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const mongoose = require('mongoose');
2
+
3
+ const notificationSchema = new mongoose.Schema({
4
+ title: { type: String, required: true },
5
+ message: { type: String, required: true },
6
+ type: { type: String, enum: ['INFO', 'ALERT', 'WIN', 'UPDATE'], default: 'INFO' },
7
+ target_user_id: { type: mongoose.Schema.Types.ObjectId, ref: 'User', default: null },
8
+ created_at: { type: Date, default: Date.now, expires: '3d' }
9
+ });
10
+
11
+ module.exports = mongoose.model('Notification', notificationSchema);
models/StrikeHistory.js ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const mongoose = require('mongoose');
2
+
3
+ const strikeHistorySchema = new mongoose.Schema({
4
+ date: { type: Date, default: Date.now },
5
+
6
+ target_price: Number,
7
+ winning_digits: Number,
8
+ total_pool: Number,
9
+
10
+ // NEW (provable fairness)
11
+ audit_hash: { type: String, required: true },
12
+ audit_payload: { type: Object, required: true },
13
+
14
+ winners: [{
15
+ tier: String,
16
+ user_id: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
17
+ amount: Number,
18
+ rank: Number,
19
+ kus_id: String
20
+ }]
21
+ });
22
+
23
+ module.exports = mongoose.model('StrikeHistory', strikeHistorySchema);
models/Transaction.js ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const mongoose = require('mongoose');
2
+
3
+ const transactionSchema = new mongoose.Schema({
4
+ user_id: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
5
+ utr: { type: String, unique: true },
6
+ amount: { type: Number, required: true },
7
+ tier: { type: String }, // Optional for withdrawals
8
+
9
+ asset_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Asset' },
10
+
11
+ // Status Enum Expanded
12
+ status: {
13
+ type: String,
14
+ enum: ['Pending', 'Verified', 'Failed', 'Pending_Withdrawal', 'Withdrawn', 'Rejected_Withdrawal'],
15
+ default: 'Pending'
16
+ },
17
+
18
+ // NEW FIELD
19
+ rejection_reason: { type: String, default: null },
20
+
21
+ timestamp: { type: Date, default: Date.now }
22
+ });
23
+
24
+ module.exports = mongoose.model('Transaction', transactionSchema);
models/User.js ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const mongoose = require('mongoose');
2
+
3
+ const userSchema = new mongoose.Schema({
4
+ name: { type: String, required: true },
5
+ email: { type: String, required: true, unique: true },
6
+ password: { type: String, required: true },
7
+ referral_code: { type: String, unique: true },
8
+ referred_by: { type: String, default: null },
9
+ points: { type: Number, default: 0 },
10
+
11
+ // NEW: Wallet & Withdrawal Info
12
+ wallet_balance: { type: Number, default: 0 }, // Winnings sit here
13
+ upi_id: { type: String, default: null }, // e.g., user@okhdfc
14
+
15
+ role: { type: String, enum: ['user', 'admin'], default: 'user' },
16
+ kyc_status: { type: Boolean, default: false },
17
+ ban_strikes: { type: Number, default: 0 },
18
+
19
+ pushSubscription: { type: Object, default: null },
20
+
21
+ createdAt: { type: Date, default: Date.now }
22
+ });
23
+
24
+ module.exports = mongoose.model('User', userSchema);
package-lock.json ADDED
@@ -0,0 +1,2174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "koshx",
3
+ "version": "1.0.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "koshx",
9
+ "version": "1.0.0",
10
+ "license": "ISC",
11
+ "dependencies": {
12
+ "axios": "^1.13.2",
13
+ "bcryptjs": "^3.0.3",
14
+ "cors": "^2.8.5",
15
+ "dotenv": "^17.2.3",
16
+ "express": "^5.2.1",
17
+ "google-auth-library": "^10.5.0",
18
+ "jsonwebtoken": "^9.0.3",
19
+ "mongoose": "^9.0.1",
20
+ "node-cron": "^4.2.1",
21
+ "use-sound": "^5.0.0",
22
+ "web-push": "^3.6.7"
23
+ }
24
+ },
25
+ "node_modules/@isaacs/cliui": {
26
+ "version": "8.0.2",
27
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
28
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
29
+ "license": "ISC",
30
+ "dependencies": {
31
+ "string-width": "^5.1.2",
32
+ "string-width-cjs": "npm:string-width@^4.2.0",
33
+ "strip-ansi": "^7.0.1",
34
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
35
+ "wrap-ansi": "^8.1.0",
36
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
37
+ },
38
+ "engines": {
39
+ "node": ">=12"
40
+ }
41
+ },
42
+ "node_modules/@mongodb-js/saslprep": {
43
+ "version": "1.4.4",
44
+ "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.4.4.tgz",
45
+ "integrity": "sha512-p7X/ytJDIdwUfFL/CLOhKgdfJe1Fa8uw9seJYvdOmnP9JBWGWHW69HkOixXS6Wy9yvGf1MbhcS6lVmrhy4jm2g==",
46
+ "license": "MIT",
47
+ "dependencies": {
48
+ "sparse-bitfield": "^3.0.3"
49
+ }
50
+ },
51
+ "node_modules/@pkgjs/parseargs": {
52
+ "version": "0.11.0",
53
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
54
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
55
+ "license": "MIT",
56
+ "optional": true,
57
+ "engines": {
58
+ "node": ">=14"
59
+ }
60
+ },
61
+ "node_modules/@types/webidl-conversions": {
62
+ "version": "7.0.3",
63
+ "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
64
+ "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==",
65
+ "license": "MIT"
66
+ },
67
+ "node_modules/@types/whatwg-url": {
68
+ "version": "13.0.0",
69
+ "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-13.0.0.tgz",
70
+ "integrity": "sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==",
71
+ "license": "MIT",
72
+ "dependencies": {
73
+ "@types/webidl-conversions": "*"
74
+ }
75
+ },
76
+ "node_modules/accepts": {
77
+ "version": "2.0.0",
78
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
79
+ "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
80
+ "license": "MIT",
81
+ "dependencies": {
82
+ "mime-types": "^3.0.0",
83
+ "negotiator": "^1.0.0"
84
+ },
85
+ "engines": {
86
+ "node": ">= 0.6"
87
+ }
88
+ },
89
+ "node_modules/agent-base": {
90
+ "version": "7.1.4",
91
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
92
+ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
93
+ "license": "MIT",
94
+ "engines": {
95
+ "node": ">= 14"
96
+ }
97
+ },
98
+ "node_modules/ansi-regex": {
99
+ "version": "6.2.2",
100
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
101
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
102
+ "license": "MIT",
103
+ "engines": {
104
+ "node": ">=12"
105
+ },
106
+ "funding": {
107
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
108
+ }
109
+ },
110
+ "node_modules/ansi-styles": {
111
+ "version": "6.2.3",
112
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
113
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
114
+ "license": "MIT",
115
+ "engines": {
116
+ "node": ">=12"
117
+ },
118
+ "funding": {
119
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
120
+ }
121
+ },
122
+ "node_modules/asn1.js": {
123
+ "version": "5.4.1",
124
+ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
125
+ "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
126
+ "license": "MIT",
127
+ "dependencies": {
128
+ "bn.js": "^4.0.0",
129
+ "inherits": "^2.0.1",
130
+ "minimalistic-assert": "^1.0.0",
131
+ "safer-buffer": "^2.1.0"
132
+ }
133
+ },
134
+ "node_modules/asynckit": {
135
+ "version": "0.4.0",
136
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
137
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
138
+ "license": "MIT"
139
+ },
140
+ "node_modules/axios": {
141
+ "version": "1.13.2",
142
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
143
+ "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
144
+ "license": "MIT",
145
+ "dependencies": {
146
+ "follow-redirects": "^1.15.6",
147
+ "form-data": "^4.0.4",
148
+ "proxy-from-env": "^1.1.0"
149
+ }
150
+ },
151
+ "node_modules/balanced-match": {
152
+ "version": "1.0.2",
153
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
154
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
155
+ "license": "MIT"
156
+ },
157
+ "node_modules/base64-js": {
158
+ "version": "1.5.1",
159
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
160
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
161
+ "funding": [
162
+ {
163
+ "type": "github",
164
+ "url": "https://github.com/sponsors/feross"
165
+ },
166
+ {
167
+ "type": "patreon",
168
+ "url": "https://www.patreon.com/feross"
169
+ },
170
+ {
171
+ "type": "consulting",
172
+ "url": "https://feross.org/support"
173
+ }
174
+ ],
175
+ "license": "MIT"
176
+ },
177
+ "node_modules/bcryptjs": {
178
+ "version": "3.0.3",
179
+ "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz",
180
+ "integrity": "sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==",
181
+ "license": "BSD-3-Clause",
182
+ "bin": {
183
+ "bcrypt": "bin/bcrypt"
184
+ }
185
+ },
186
+ "node_modules/bignumber.js": {
187
+ "version": "9.3.1",
188
+ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
189
+ "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
190
+ "license": "MIT",
191
+ "engines": {
192
+ "node": "*"
193
+ }
194
+ },
195
+ "node_modules/bn.js": {
196
+ "version": "4.12.2",
197
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz",
198
+ "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==",
199
+ "license": "MIT"
200
+ },
201
+ "node_modules/body-parser": {
202
+ "version": "2.2.1",
203
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz",
204
+ "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==",
205
+ "license": "MIT",
206
+ "dependencies": {
207
+ "bytes": "^3.1.2",
208
+ "content-type": "^1.0.5",
209
+ "debug": "^4.4.3",
210
+ "http-errors": "^2.0.0",
211
+ "iconv-lite": "^0.7.0",
212
+ "on-finished": "^2.4.1",
213
+ "qs": "^6.14.0",
214
+ "raw-body": "^3.0.1",
215
+ "type-is": "^2.0.1"
216
+ },
217
+ "engines": {
218
+ "node": ">=18"
219
+ },
220
+ "funding": {
221
+ "type": "opencollective",
222
+ "url": "https://opencollective.com/express"
223
+ }
224
+ },
225
+ "node_modules/brace-expansion": {
226
+ "version": "2.0.2",
227
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
228
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
229
+ "license": "MIT",
230
+ "dependencies": {
231
+ "balanced-match": "^1.0.0"
232
+ }
233
+ },
234
+ "node_modules/bson": {
235
+ "version": "7.0.0",
236
+ "resolved": "https://registry.npmjs.org/bson/-/bson-7.0.0.tgz",
237
+ "integrity": "sha512-Kwc6Wh4lQ5OmkqqKhYGKIuELXl+EPYSCObVE6bWsp1T/cGkOCBN0I8wF/T44BiuhHyNi1mmKVPXk60d41xZ7kw==",
238
+ "license": "Apache-2.0",
239
+ "engines": {
240
+ "node": ">=20.19.0"
241
+ }
242
+ },
243
+ "node_modules/buffer-equal-constant-time": {
244
+ "version": "1.0.1",
245
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
246
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
247
+ "license": "BSD-3-Clause"
248
+ },
249
+ "node_modules/bytes": {
250
+ "version": "3.1.2",
251
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
252
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
253
+ "license": "MIT",
254
+ "engines": {
255
+ "node": ">= 0.8"
256
+ }
257
+ },
258
+ "node_modules/call-bind-apply-helpers": {
259
+ "version": "1.0.2",
260
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
261
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
262
+ "license": "MIT",
263
+ "dependencies": {
264
+ "es-errors": "^1.3.0",
265
+ "function-bind": "^1.1.2"
266
+ },
267
+ "engines": {
268
+ "node": ">= 0.4"
269
+ }
270
+ },
271
+ "node_modules/call-bound": {
272
+ "version": "1.0.4",
273
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
274
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
275
+ "license": "MIT",
276
+ "dependencies": {
277
+ "call-bind-apply-helpers": "^1.0.2",
278
+ "get-intrinsic": "^1.3.0"
279
+ },
280
+ "engines": {
281
+ "node": ">= 0.4"
282
+ },
283
+ "funding": {
284
+ "url": "https://github.com/sponsors/ljharb"
285
+ }
286
+ },
287
+ "node_modules/color-convert": {
288
+ "version": "2.0.1",
289
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
290
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
291
+ "license": "MIT",
292
+ "dependencies": {
293
+ "color-name": "~1.1.4"
294
+ },
295
+ "engines": {
296
+ "node": ">=7.0.0"
297
+ }
298
+ },
299
+ "node_modules/color-name": {
300
+ "version": "1.1.4",
301
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
302
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
303
+ "license": "MIT"
304
+ },
305
+ "node_modules/combined-stream": {
306
+ "version": "1.0.8",
307
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
308
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
309
+ "license": "MIT",
310
+ "dependencies": {
311
+ "delayed-stream": "~1.0.0"
312
+ },
313
+ "engines": {
314
+ "node": ">= 0.8"
315
+ }
316
+ },
317
+ "node_modules/content-disposition": {
318
+ "version": "1.0.1",
319
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
320
+ "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==",
321
+ "license": "MIT",
322
+ "engines": {
323
+ "node": ">=18"
324
+ },
325
+ "funding": {
326
+ "type": "opencollective",
327
+ "url": "https://opencollective.com/express"
328
+ }
329
+ },
330
+ "node_modules/content-type": {
331
+ "version": "1.0.5",
332
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
333
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
334
+ "license": "MIT",
335
+ "engines": {
336
+ "node": ">= 0.6"
337
+ }
338
+ },
339
+ "node_modules/cookie": {
340
+ "version": "0.7.2",
341
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
342
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
343
+ "license": "MIT",
344
+ "engines": {
345
+ "node": ">= 0.6"
346
+ }
347
+ },
348
+ "node_modules/cookie-signature": {
349
+ "version": "1.2.2",
350
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
351
+ "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
352
+ "license": "MIT",
353
+ "engines": {
354
+ "node": ">=6.6.0"
355
+ }
356
+ },
357
+ "node_modules/cors": {
358
+ "version": "2.8.5",
359
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
360
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
361
+ "license": "MIT",
362
+ "dependencies": {
363
+ "object-assign": "^4",
364
+ "vary": "^1"
365
+ },
366
+ "engines": {
367
+ "node": ">= 0.10"
368
+ }
369
+ },
370
+ "node_modules/cross-spawn": {
371
+ "version": "7.0.6",
372
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
373
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
374
+ "license": "MIT",
375
+ "dependencies": {
376
+ "path-key": "^3.1.0",
377
+ "shebang-command": "^2.0.0",
378
+ "which": "^2.0.1"
379
+ },
380
+ "engines": {
381
+ "node": ">= 8"
382
+ }
383
+ },
384
+ "node_modules/data-uri-to-buffer": {
385
+ "version": "4.0.1",
386
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
387
+ "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
388
+ "license": "MIT",
389
+ "engines": {
390
+ "node": ">= 12"
391
+ }
392
+ },
393
+ "node_modules/debug": {
394
+ "version": "4.4.3",
395
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
396
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
397
+ "license": "MIT",
398
+ "dependencies": {
399
+ "ms": "^2.1.3"
400
+ },
401
+ "engines": {
402
+ "node": ">=6.0"
403
+ },
404
+ "peerDependenciesMeta": {
405
+ "supports-color": {
406
+ "optional": true
407
+ }
408
+ }
409
+ },
410
+ "node_modules/delayed-stream": {
411
+ "version": "1.0.0",
412
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
413
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
414
+ "license": "MIT",
415
+ "engines": {
416
+ "node": ">=0.4.0"
417
+ }
418
+ },
419
+ "node_modules/depd": {
420
+ "version": "2.0.0",
421
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
422
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
423
+ "license": "MIT",
424
+ "engines": {
425
+ "node": ">= 0.8"
426
+ }
427
+ },
428
+ "node_modules/dotenv": {
429
+ "version": "17.2.3",
430
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
431
+ "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
432
+ "license": "BSD-2-Clause",
433
+ "engines": {
434
+ "node": ">=12"
435
+ },
436
+ "funding": {
437
+ "url": "https://dotenvx.com"
438
+ }
439
+ },
440
+ "node_modules/dunder-proto": {
441
+ "version": "1.0.1",
442
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
443
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
444
+ "license": "MIT",
445
+ "dependencies": {
446
+ "call-bind-apply-helpers": "^1.0.1",
447
+ "es-errors": "^1.3.0",
448
+ "gopd": "^1.2.0"
449
+ },
450
+ "engines": {
451
+ "node": ">= 0.4"
452
+ }
453
+ },
454
+ "node_modules/eastasianwidth": {
455
+ "version": "0.2.0",
456
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
457
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
458
+ "license": "MIT"
459
+ },
460
+ "node_modules/ecdsa-sig-formatter": {
461
+ "version": "1.0.11",
462
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
463
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
464
+ "license": "Apache-2.0",
465
+ "dependencies": {
466
+ "safe-buffer": "^5.0.1"
467
+ }
468
+ },
469
+ "node_modules/ee-first": {
470
+ "version": "1.1.1",
471
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
472
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
473
+ "license": "MIT"
474
+ },
475
+ "node_modules/emoji-regex": {
476
+ "version": "9.2.2",
477
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
478
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
479
+ "license": "MIT"
480
+ },
481
+ "node_modules/encodeurl": {
482
+ "version": "2.0.0",
483
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
484
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
485
+ "license": "MIT",
486
+ "engines": {
487
+ "node": ">= 0.8"
488
+ }
489
+ },
490
+ "node_modules/es-define-property": {
491
+ "version": "1.0.1",
492
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
493
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
494
+ "license": "MIT",
495
+ "engines": {
496
+ "node": ">= 0.4"
497
+ }
498
+ },
499
+ "node_modules/es-errors": {
500
+ "version": "1.3.0",
501
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
502
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
503
+ "license": "MIT",
504
+ "engines": {
505
+ "node": ">= 0.4"
506
+ }
507
+ },
508
+ "node_modules/es-object-atoms": {
509
+ "version": "1.1.1",
510
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
511
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
512
+ "license": "MIT",
513
+ "dependencies": {
514
+ "es-errors": "^1.3.0"
515
+ },
516
+ "engines": {
517
+ "node": ">= 0.4"
518
+ }
519
+ },
520
+ "node_modules/es-set-tostringtag": {
521
+ "version": "2.1.0",
522
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
523
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
524
+ "license": "MIT",
525
+ "dependencies": {
526
+ "es-errors": "^1.3.0",
527
+ "get-intrinsic": "^1.2.6",
528
+ "has-tostringtag": "^1.0.2",
529
+ "hasown": "^2.0.2"
530
+ },
531
+ "engines": {
532
+ "node": ">= 0.4"
533
+ }
534
+ },
535
+ "node_modules/escape-html": {
536
+ "version": "1.0.3",
537
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
538
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
539
+ "license": "MIT"
540
+ },
541
+ "node_modules/etag": {
542
+ "version": "1.8.1",
543
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
544
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
545
+ "license": "MIT",
546
+ "engines": {
547
+ "node": ">= 0.6"
548
+ }
549
+ },
550
+ "node_modules/express": {
551
+ "version": "5.2.1",
552
+ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
553
+ "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
554
+ "license": "MIT",
555
+ "dependencies": {
556
+ "accepts": "^2.0.0",
557
+ "body-parser": "^2.2.1",
558
+ "content-disposition": "^1.0.0",
559
+ "content-type": "^1.0.5",
560
+ "cookie": "^0.7.1",
561
+ "cookie-signature": "^1.2.1",
562
+ "debug": "^4.4.0",
563
+ "depd": "^2.0.0",
564
+ "encodeurl": "^2.0.0",
565
+ "escape-html": "^1.0.3",
566
+ "etag": "^1.8.1",
567
+ "finalhandler": "^2.1.0",
568
+ "fresh": "^2.0.0",
569
+ "http-errors": "^2.0.0",
570
+ "merge-descriptors": "^2.0.0",
571
+ "mime-types": "^3.0.0",
572
+ "on-finished": "^2.4.1",
573
+ "once": "^1.4.0",
574
+ "parseurl": "^1.3.3",
575
+ "proxy-addr": "^2.0.7",
576
+ "qs": "^6.14.0",
577
+ "range-parser": "^1.2.1",
578
+ "router": "^2.2.0",
579
+ "send": "^1.1.0",
580
+ "serve-static": "^2.2.0",
581
+ "statuses": "^2.0.1",
582
+ "type-is": "^2.0.1",
583
+ "vary": "^1.1.2"
584
+ },
585
+ "engines": {
586
+ "node": ">= 18"
587
+ },
588
+ "funding": {
589
+ "type": "opencollective",
590
+ "url": "https://opencollective.com/express"
591
+ }
592
+ },
593
+ "node_modules/extend": {
594
+ "version": "3.0.2",
595
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
596
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
597
+ "license": "MIT"
598
+ },
599
+ "node_modules/fetch-blob": {
600
+ "version": "3.2.0",
601
+ "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
602
+ "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
603
+ "funding": [
604
+ {
605
+ "type": "github",
606
+ "url": "https://github.com/sponsors/jimmywarting"
607
+ },
608
+ {
609
+ "type": "paypal",
610
+ "url": "https://paypal.me/jimmywarting"
611
+ }
612
+ ],
613
+ "license": "MIT",
614
+ "dependencies": {
615
+ "node-domexception": "^1.0.0",
616
+ "web-streams-polyfill": "^3.0.3"
617
+ },
618
+ "engines": {
619
+ "node": "^12.20 || >= 14.13"
620
+ }
621
+ },
622
+ "node_modules/finalhandler": {
623
+ "version": "2.1.1",
624
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
625
+ "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
626
+ "license": "MIT",
627
+ "dependencies": {
628
+ "debug": "^4.4.0",
629
+ "encodeurl": "^2.0.0",
630
+ "escape-html": "^1.0.3",
631
+ "on-finished": "^2.4.1",
632
+ "parseurl": "^1.3.3",
633
+ "statuses": "^2.0.1"
634
+ },
635
+ "engines": {
636
+ "node": ">= 18.0.0"
637
+ },
638
+ "funding": {
639
+ "type": "opencollective",
640
+ "url": "https://opencollective.com/express"
641
+ }
642
+ },
643
+ "node_modules/follow-redirects": {
644
+ "version": "1.15.11",
645
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
646
+ "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
647
+ "funding": [
648
+ {
649
+ "type": "individual",
650
+ "url": "https://github.com/sponsors/RubenVerborgh"
651
+ }
652
+ ],
653
+ "license": "MIT",
654
+ "engines": {
655
+ "node": ">=4.0"
656
+ },
657
+ "peerDependenciesMeta": {
658
+ "debug": {
659
+ "optional": true
660
+ }
661
+ }
662
+ },
663
+ "node_modules/foreground-child": {
664
+ "version": "3.3.1",
665
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
666
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
667
+ "license": "ISC",
668
+ "dependencies": {
669
+ "cross-spawn": "^7.0.6",
670
+ "signal-exit": "^4.0.1"
671
+ },
672
+ "engines": {
673
+ "node": ">=14"
674
+ },
675
+ "funding": {
676
+ "url": "https://github.com/sponsors/isaacs"
677
+ }
678
+ },
679
+ "node_modules/form-data": {
680
+ "version": "4.0.5",
681
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
682
+ "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
683
+ "license": "MIT",
684
+ "dependencies": {
685
+ "asynckit": "^0.4.0",
686
+ "combined-stream": "^1.0.8",
687
+ "es-set-tostringtag": "^2.1.0",
688
+ "hasown": "^2.0.2",
689
+ "mime-types": "^2.1.12"
690
+ },
691
+ "engines": {
692
+ "node": ">= 6"
693
+ }
694
+ },
695
+ "node_modules/form-data/node_modules/mime-db": {
696
+ "version": "1.52.0",
697
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
698
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
699
+ "license": "MIT",
700
+ "engines": {
701
+ "node": ">= 0.6"
702
+ }
703
+ },
704
+ "node_modules/form-data/node_modules/mime-types": {
705
+ "version": "2.1.35",
706
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
707
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
708
+ "license": "MIT",
709
+ "dependencies": {
710
+ "mime-db": "1.52.0"
711
+ },
712
+ "engines": {
713
+ "node": ">= 0.6"
714
+ }
715
+ },
716
+ "node_modules/formdata-polyfill": {
717
+ "version": "4.0.10",
718
+ "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
719
+ "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
720
+ "license": "MIT",
721
+ "dependencies": {
722
+ "fetch-blob": "^3.1.2"
723
+ },
724
+ "engines": {
725
+ "node": ">=12.20.0"
726
+ }
727
+ },
728
+ "node_modules/forwarded": {
729
+ "version": "0.2.0",
730
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
731
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
732
+ "license": "MIT",
733
+ "engines": {
734
+ "node": ">= 0.6"
735
+ }
736
+ },
737
+ "node_modules/fresh": {
738
+ "version": "2.0.0",
739
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
740
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
741
+ "license": "MIT",
742
+ "engines": {
743
+ "node": ">= 0.8"
744
+ }
745
+ },
746
+ "node_modules/function-bind": {
747
+ "version": "1.1.2",
748
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
749
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
750
+ "license": "MIT",
751
+ "funding": {
752
+ "url": "https://github.com/sponsors/ljharb"
753
+ }
754
+ },
755
+ "node_modules/gaxios": {
756
+ "version": "7.1.3",
757
+ "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.3.tgz",
758
+ "integrity": "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==",
759
+ "license": "Apache-2.0",
760
+ "dependencies": {
761
+ "extend": "^3.0.2",
762
+ "https-proxy-agent": "^7.0.1",
763
+ "node-fetch": "^3.3.2",
764
+ "rimraf": "^5.0.1"
765
+ },
766
+ "engines": {
767
+ "node": ">=18"
768
+ }
769
+ },
770
+ "node_modules/gcp-metadata": {
771
+ "version": "7.0.1",
772
+ "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-7.0.1.tgz",
773
+ "integrity": "sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==",
774
+ "license": "Apache-2.0",
775
+ "optional": true,
776
+ "peer": true,
777
+ "dependencies": {
778
+ "gaxios": "^7.0.0",
779
+ "google-logging-utils": "^1.0.0",
780
+ "json-bigint": "^1.0.0"
781
+ },
782
+ "engines": {
783
+ "node": ">=18"
784
+ }
785
+ },
786
+ "node_modules/get-intrinsic": {
787
+ "version": "1.3.0",
788
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
789
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
790
+ "license": "MIT",
791
+ "dependencies": {
792
+ "call-bind-apply-helpers": "^1.0.2",
793
+ "es-define-property": "^1.0.1",
794
+ "es-errors": "^1.3.0",
795
+ "es-object-atoms": "^1.1.1",
796
+ "function-bind": "^1.1.2",
797
+ "get-proto": "^1.0.1",
798
+ "gopd": "^1.2.0",
799
+ "has-symbols": "^1.1.0",
800
+ "hasown": "^2.0.2",
801
+ "math-intrinsics": "^1.1.0"
802
+ },
803
+ "engines": {
804
+ "node": ">= 0.4"
805
+ },
806
+ "funding": {
807
+ "url": "https://github.com/sponsors/ljharb"
808
+ }
809
+ },
810
+ "node_modules/get-proto": {
811
+ "version": "1.0.1",
812
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
813
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
814
+ "license": "MIT",
815
+ "dependencies": {
816
+ "dunder-proto": "^1.0.1",
817
+ "es-object-atoms": "^1.0.0"
818
+ },
819
+ "engines": {
820
+ "node": ">= 0.4"
821
+ }
822
+ },
823
+ "node_modules/glob": {
824
+ "version": "10.5.0",
825
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
826
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
827
+ "license": "ISC",
828
+ "dependencies": {
829
+ "foreground-child": "^3.1.0",
830
+ "jackspeak": "^3.1.2",
831
+ "minimatch": "^9.0.4",
832
+ "minipass": "^7.1.2",
833
+ "package-json-from-dist": "^1.0.0",
834
+ "path-scurry": "^1.11.1"
835
+ },
836
+ "bin": {
837
+ "glob": "dist/esm/bin.mjs"
838
+ },
839
+ "funding": {
840
+ "url": "https://github.com/sponsors/isaacs"
841
+ }
842
+ },
843
+ "node_modules/google-auth-library": {
844
+ "version": "10.5.0",
845
+ "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.5.0.tgz",
846
+ "integrity": "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==",
847
+ "license": "Apache-2.0",
848
+ "dependencies": {
849
+ "base64-js": "^1.3.0",
850
+ "ecdsa-sig-formatter": "^1.0.11",
851
+ "gaxios": "^7.0.0",
852
+ "gcp-metadata": "^8.0.0",
853
+ "google-logging-utils": "^1.0.0",
854
+ "gtoken": "^8.0.0",
855
+ "jws": "^4.0.0"
856
+ },
857
+ "engines": {
858
+ "node": ">=18"
859
+ }
860
+ },
861
+ "node_modules/google-auth-library/node_modules/gcp-metadata": {
862
+ "version": "8.1.2",
863
+ "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz",
864
+ "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==",
865
+ "license": "Apache-2.0",
866
+ "dependencies": {
867
+ "gaxios": "^7.0.0",
868
+ "google-logging-utils": "^1.0.0",
869
+ "json-bigint": "^1.0.0"
870
+ },
871
+ "engines": {
872
+ "node": ">=18"
873
+ }
874
+ },
875
+ "node_modules/google-logging-utils": {
876
+ "version": "1.1.3",
877
+ "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz",
878
+ "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==",
879
+ "license": "Apache-2.0",
880
+ "engines": {
881
+ "node": ">=14"
882
+ }
883
+ },
884
+ "node_modules/gopd": {
885
+ "version": "1.2.0",
886
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
887
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
888
+ "license": "MIT",
889
+ "engines": {
890
+ "node": ">= 0.4"
891
+ },
892
+ "funding": {
893
+ "url": "https://github.com/sponsors/ljharb"
894
+ }
895
+ },
896
+ "node_modules/gtoken": {
897
+ "version": "8.0.0",
898
+ "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz",
899
+ "integrity": "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==",
900
+ "license": "MIT",
901
+ "dependencies": {
902
+ "gaxios": "^7.0.0",
903
+ "jws": "^4.0.0"
904
+ },
905
+ "engines": {
906
+ "node": ">=18"
907
+ }
908
+ },
909
+ "node_modules/has-symbols": {
910
+ "version": "1.1.0",
911
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
912
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
913
+ "license": "MIT",
914
+ "engines": {
915
+ "node": ">= 0.4"
916
+ },
917
+ "funding": {
918
+ "url": "https://github.com/sponsors/ljharb"
919
+ }
920
+ },
921
+ "node_modules/has-tostringtag": {
922
+ "version": "1.0.2",
923
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
924
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
925
+ "license": "MIT",
926
+ "dependencies": {
927
+ "has-symbols": "^1.0.3"
928
+ },
929
+ "engines": {
930
+ "node": ">= 0.4"
931
+ },
932
+ "funding": {
933
+ "url": "https://github.com/sponsors/ljharb"
934
+ }
935
+ },
936
+ "node_modules/hasown": {
937
+ "version": "2.0.2",
938
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
939
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
940
+ "license": "MIT",
941
+ "dependencies": {
942
+ "function-bind": "^1.1.2"
943
+ },
944
+ "engines": {
945
+ "node": ">= 0.4"
946
+ }
947
+ },
948
+ "node_modules/howler": {
949
+ "version": "2.2.4",
950
+ "resolved": "https://registry.npmjs.org/howler/-/howler-2.2.4.tgz",
951
+ "integrity": "sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w==",
952
+ "license": "MIT"
953
+ },
954
+ "node_modules/http_ece": {
955
+ "version": "1.2.0",
956
+ "resolved": "https://registry.npmjs.org/http_ece/-/http_ece-1.2.0.tgz",
957
+ "integrity": "sha512-JrF8SSLVmcvc5NducxgyOrKXe3EsyHMgBFgSaIUGmArKe+rwr0uphRkRXvwiom3I+fpIfoItveHrfudL8/rxuA==",
958
+ "license": "MIT",
959
+ "engines": {
960
+ "node": ">=16"
961
+ }
962
+ },
963
+ "node_modules/http-errors": {
964
+ "version": "2.0.1",
965
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
966
+ "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
967
+ "license": "MIT",
968
+ "dependencies": {
969
+ "depd": "~2.0.0",
970
+ "inherits": "~2.0.4",
971
+ "setprototypeof": "~1.2.0",
972
+ "statuses": "~2.0.2",
973
+ "toidentifier": "~1.0.1"
974
+ },
975
+ "engines": {
976
+ "node": ">= 0.8"
977
+ },
978
+ "funding": {
979
+ "type": "opencollective",
980
+ "url": "https://opencollective.com/express"
981
+ }
982
+ },
983
+ "node_modules/https-proxy-agent": {
984
+ "version": "7.0.6",
985
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
986
+ "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
987
+ "license": "MIT",
988
+ "dependencies": {
989
+ "agent-base": "^7.1.2",
990
+ "debug": "4"
991
+ },
992
+ "engines": {
993
+ "node": ">= 14"
994
+ }
995
+ },
996
+ "node_modules/iconv-lite": {
997
+ "version": "0.7.1",
998
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz",
999
+ "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==",
1000
+ "license": "MIT",
1001
+ "dependencies": {
1002
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
1003
+ },
1004
+ "engines": {
1005
+ "node": ">=0.10.0"
1006
+ },
1007
+ "funding": {
1008
+ "type": "opencollective",
1009
+ "url": "https://opencollective.com/express"
1010
+ }
1011
+ },
1012
+ "node_modules/inherits": {
1013
+ "version": "2.0.4",
1014
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1015
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
1016
+ "license": "ISC"
1017
+ },
1018
+ "node_modules/ipaddr.js": {
1019
+ "version": "1.9.1",
1020
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
1021
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
1022
+ "license": "MIT",
1023
+ "engines": {
1024
+ "node": ">= 0.10"
1025
+ }
1026
+ },
1027
+ "node_modules/is-fullwidth-code-point": {
1028
+ "version": "3.0.0",
1029
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
1030
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
1031
+ "license": "MIT",
1032
+ "engines": {
1033
+ "node": ">=8"
1034
+ }
1035
+ },
1036
+ "node_modules/is-promise": {
1037
+ "version": "4.0.0",
1038
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
1039
+ "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
1040
+ "license": "MIT"
1041
+ },
1042
+ "node_modules/isexe": {
1043
+ "version": "2.0.0",
1044
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
1045
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
1046
+ "license": "ISC"
1047
+ },
1048
+ "node_modules/jackspeak": {
1049
+ "version": "3.4.3",
1050
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
1051
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
1052
+ "license": "BlueOak-1.0.0",
1053
+ "dependencies": {
1054
+ "@isaacs/cliui": "^8.0.2"
1055
+ },
1056
+ "funding": {
1057
+ "url": "https://github.com/sponsors/isaacs"
1058
+ },
1059
+ "optionalDependencies": {
1060
+ "@pkgjs/parseargs": "^0.11.0"
1061
+ }
1062
+ },
1063
+ "node_modules/json-bigint": {
1064
+ "version": "1.0.0",
1065
+ "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
1066
+ "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
1067
+ "license": "MIT",
1068
+ "dependencies": {
1069
+ "bignumber.js": "^9.0.0"
1070
+ }
1071
+ },
1072
+ "node_modules/jsonwebtoken": {
1073
+ "version": "9.0.3",
1074
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz",
1075
+ "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==",
1076
+ "license": "MIT",
1077
+ "dependencies": {
1078
+ "jws": "^4.0.1",
1079
+ "lodash.includes": "^4.3.0",
1080
+ "lodash.isboolean": "^3.0.3",
1081
+ "lodash.isinteger": "^4.0.4",
1082
+ "lodash.isnumber": "^3.0.3",
1083
+ "lodash.isplainobject": "^4.0.6",
1084
+ "lodash.isstring": "^4.0.1",
1085
+ "lodash.once": "^4.0.0",
1086
+ "ms": "^2.1.1",
1087
+ "semver": "^7.5.4"
1088
+ },
1089
+ "engines": {
1090
+ "node": ">=12",
1091
+ "npm": ">=6"
1092
+ }
1093
+ },
1094
+ "node_modules/jwa": {
1095
+ "version": "2.0.1",
1096
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
1097
+ "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
1098
+ "license": "MIT",
1099
+ "dependencies": {
1100
+ "buffer-equal-constant-time": "^1.0.1",
1101
+ "ecdsa-sig-formatter": "1.0.11",
1102
+ "safe-buffer": "^5.0.1"
1103
+ }
1104
+ },
1105
+ "node_modules/jws": {
1106
+ "version": "4.0.1",
1107
+ "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz",
1108
+ "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==",
1109
+ "license": "MIT",
1110
+ "dependencies": {
1111
+ "jwa": "^2.0.1",
1112
+ "safe-buffer": "^5.0.1"
1113
+ }
1114
+ },
1115
+ "node_modules/kareem": {
1116
+ "version": "3.0.0",
1117
+ "resolved": "https://registry.npmjs.org/kareem/-/kareem-3.0.0.tgz",
1118
+ "integrity": "sha512-RKhaOBSPN8L7y4yAgNhDT2602G5FD6QbOIISbjN9D6mjHPeqeg7K+EB5IGSU5o81/X2Gzm3ICnAvQW3x3OP8HA==",
1119
+ "license": "Apache-2.0",
1120
+ "engines": {
1121
+ "node": ">=18.0.0"
1122
+ }
1123
+ },
1124
+ "node_modules/lodash.includes": {
1125
+ "version": "4.3.0",
1126
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
1127
+ "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
1128
+ "license": "MIT"
1129
+ },
1130
+ "node_modules/lodash.isboolean": {
1131
+ "version": "3.0.3",
1132
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
1133
+ "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
1134
+ "license": "MIT"
1135
+ },
1136
+ "node_modules/lodash.isinteger": {
1137
+ "version": "4.0.4",
1138
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
1139
+ "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
1140
+ "license": "MIT"
1141
+ },
1142
+ "node_modules/lodash.isnumber": {
1143
+ "version": "3.0.3",
1144
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
1145
+ "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
1146
+ "license": "MIT"
1147
+ },
1148
+ "node_modules/lodash.isplainobject": {
1149
+ "version": "4.0.6",
1150
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
1151
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
1152
+ "license": "MIT"
1153
+ },
1154
+ "node_modules/lodash.isstring": {
1155
+ "version": "4.0.1",
1156
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
1157
+ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
1158
+ "license": "MIT"
1159
+ },
1160
+ "node_modules/lodash.once": {
1161
+ "version": "4.1.1",
1162
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
1163
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
1164
+ "license": "MIT"
1165
+ },
1166
+ "node_modules/lru-cache": {
1167
+ "version": "10.4.3",
1168
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
1169
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
1170
+ "license": "ISC"
1171
+ },
1172
+ "node_modules/math-intrinsics": {
1173
+ "version": "1.1.0",
1174
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
1175
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
1176
+ "license": "MIT",
1177
+ "engines": {
1178
+ "node": ">= 0.4"
1179
+ }
1180
+ },
1181
+ "node_modules/media-typer": {
1182
+ "version": "1.1.0",
1183
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
1184
+ "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
1185
+ "license": "MIT",
1186
+ "engines": {
1187
+ "node": ">= 0.8"
1188
+ }
1189
+ },
1190
+ "node_modules/memory-pager": {
1191
+ "version": "1.5.0",
1192
+ "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
1193
+ "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
1194
+ "license": "MIT"
1195
+ },
1196
+ "node_modules/merge-descriptors": {
1197
+ "version": "2.0.0",
1198
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
1199
+ "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
1200
+ "license": "MIT",
1201
+ "engines": {
1202
+ "node": ">=18"
1203
+ },
1204
+ "funding": {
1205
+ "url": "https://github.com/sponsors/sindresorhus"
1206
+ }
1207
+ },
1208
+ "node_modules/mime-db": {
1209
+ "version": "1.54.0",
1210
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
1211
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
1212
+ "license": "MIT",
1213
+ "engines": {
1214
+ "node": ">= 0.6"
1215
+ }
1216
+ },
1217
+ "node_modules/mime-types": {
1218
+ "version": "3.0.2",
1219
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
1220
+ "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
1221
+ "license": "MIT",
1222
+ "dependencies": {
1223
+ "mime-db": "^1.54.0"
1224
+ },
1225
+ "engines": {
1226
+ "node": ">=18"
1227
+ },
1228
+ "funding": {
1229
+ "type": "opencollective",
1230
+ "url": "https://opencollective.com/express"
1231
+ }
1232
+ },
1233
+ "node_modules/minimalistic-assert": {
1234
+ "version": "1.0.1",
1235
+ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
1236
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
1237
+ "license": "ISC"
1238
+ },
1239
+ "node_modules/minimatch": {
1240
+ "version": "9.0.5",
1241
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
1242
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
1243
+ "license": "ISC",
1244
+ "dependencies": {
1245
+ "brace-expansion": "^2.0.1"
1246
+ },
1247
+ "engines": {
1248
+ "node": ">=16 || 14 >=14.17"
1249
+ },
1250
+ "funding": {
1251
+ "url": "https://github.com/sponsors/isaacs"
1252
+ }
1253
+ },
1254
+ "node_modules/minimist": {
1255
+ "version": "1.2.8",
1256
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
1257
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
1258
+ "license": "MIT",
1259
+ "funding": {
1260
+ "url": "https://github.com/sponsors/ljharb"
1261
+ }
1262
+ },
1263
+ "node_modules/minipass": {
1264
+ "version": "7.1.2",
1265
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
1266
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
1267
+ "license": "ISC",
1268
+ "engines": {
1269
+ "node": ">=16 || 14 >=14.17"
1270
+ }
1271
+ },
1272
+ "node_modules/mongodb": {
1273
+ "version": "7.0.0",
1274
+ "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-7.0.0.tgz",
1275
+ "integrity": "sha512-vG/A5cQrvGGvZm2mTnCSz1LUcbOPl83hfB6bxULKQ8oFZauyox/2xbZOoGNl+64m8VBrETkdGCDBdOsCr3F3jg==",
1276
+ "license": "Apache-2.0",
1277
+ "dependencies": {
1278
+ "@mongodb-js/saslprep": "^1.3.0",
1279
+ "bson": "^7.0.0",
1280
+ "mongodb-connection-string-url": "^7.0.0"
1281
+ },
1282
+ "engines": {
1283
+ "node": ">=20.19.0"
1284
+ },
1285
+ "peerDependencies": {
1286
+ "@aws-sdk/credential-providers": "^3.806.0",
1287
+ "@mongodb-js/zstd": "^7.0.0",
1288
+ "gcp-metadata": "^7.0.1",
1289
+ "kerberos": "^7.0.0",
1290
+ "mongodb-client-encryption": ">=7.0.0 <7.1.0",
1291
+ "snappy": "^7.3.2",
1292
+ "socks": "^2.8.6"
1293
+ },
1294
+ "peerDependenciesMeta": {
1295
+ "@aws-sdk/credential-providers": {
1296
+ "optional": true
1297
+ },
1298
+ "@mongodb-js/zstd": {
1299
+ "optional": true
1300
+ },
1301
+ "gcp-metadata": {
1302
+ "optional": true
1303
+ },
1304
+ "kerberos": {
1305
+ "optional": true
1306
+ },
1307
+ "mongodb-client-encryption": {
1308
+ "optional": true
1309
+ },
1310
+ "snappy": {
1311
+ "optional": true
1312
+ },
1313
+ "socks": {
1314
+ "optional": true
1315
+ }
1316
+ }
1317
+ },
1318
+ "node_modules/mongodb-connection-string-url": {
1319
+ "version": "7.0.0",
1320
+ "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-7.0.0.tgz",
1321
+ "integrity": "sha512-irhhjRVLE20hbkRl4zpAYLnDMM+zIZnp0IDB9akAFFUZp/3XdOfwwddc7y6cNvF2WCEtfTYRwYbIfYa2kVY0og==",
1322
+ "license": "Apache-2.0",
1323
+ "dependencies": {
1324
+ "@types/whatwg-url": "^13.0.0",
1325
+ "whatwg-url": "^14.1.0"
1326
+ },
1327
+ "engines": {
1328
+ "node": ">=20.19.0"
1329
+ }
1330
+ },
1331
+ "node_modules/mongoose": {
1332
+ "version": "9.0.1",
1333
+ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-9.0.1.tgz",
1334
+ "integrity": "sha512-aHPfQx2YX5UwAmMVud7OD4lIz9AEO4jI+oDnRh3lPZq9lrKTiHmOzszVffDMyQHXvrf4NXsJ34kpmAhyYAZGbw==",
1335
+ "license": "MIT",
1336
+ "dependencies": {
1337
+ "kareem": "3.0.0",
1338
+ "mongodb": "~7.0",
1339
+ "mpath": "0.9.0",
1340
+ "mquery": "6.0.0",
1341
+ "ms": "2.1.3",
1342
+ "sift": "17.1.3"
1343
+ },
1344
+ "engines": {
1345
+ "node": ">=20.19.0"
1346
+ },
1347
+ "funding": {
1348
+ "type": "opencollective",
1349
+ "url": "https://opencollective.com/mongoose"
1350
+ }
1351
+ },
1352
+ "node_modules/mpath": {
1353
+ "version": "0.9.0",
1354
+ "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
1355
+ "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
1356
+ "license": "MIT",
1357
+ "engines": {
1358
+ "node": ">=4.0.0"
1359
+ }
1360
+ },
1361
+ "node_modules/mquery": {
1362
+ "version": "6.0.0",
1363
+ "resolved": "https://registry.npmjs.org/mquery/-/mquery-6.0.0.tgz",
1364
+ "integrity": "sha512-b2KQNsmgtkscfeDgkYMcWGn9vZI9YoXh802VDEwE6qc50zxBFQ0Oo8ROkawbPAsXCY1/Z1yp0MagqsZStPWJjw==",
1365
+ "license": "MIT",
1366
+ "engines": {
1367
+ "node": ">=20.19.0"
1368
+ }
1369
+ },
1370
+ "node_modules/ms": {
1371
+ "version": "2.1.3",
1372
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1373
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1374
+ "license": "MIT"
1375
+ },
1376
+ "node_modules/negotiator": {
1377
+ "version": "1.0.0",
1378
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
1379
+ "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
1380
+ "license": "MIT",
1381
+ "engines": {
1382
+ "node": ">= 0.6"
1383
+ }
1384
+ },
1385
+ "node_modules/node-cron": {
1386
+ "version": "4.2.1",
1387
+ "resolved": "https://registry.npmjs.org/node-cron/-/node-cron-4.2.1.tgz",
1388
+ "integrity": "sha512-lgimEHPE/QDgFlywTd8yTR61ptugX3Qer29efeyWw2rv259HtGBNn1vZVmp8lB9uo9wC0t/AT4iGqXxia+CJFg==",
1389
+ "license": "ISC",
1390
+ "engines": {
1391
+ "node": ">=6.0.0"
1392
+ }
1393
+ },
1394
+ "node_modules/node-domexception": {
1395
+ "version": "1.0.0",
1396
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
1397
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
1398
+ "deprecated": "Use your platform's native DOMException instead",
1399
+ "funding": [
1400
+ {
1401
+ "type": "github",
1402
+ "url": "https://github.com/sponsors/jimmywarting"
1403
+ },
1404
+ {
1405
+ "type": "github",
1406
+ "url": "https://paypal.me/jimmywarting"
1407
+ }
1408
+ ],
1409
+ "license": "MIT",
1410
+ "engines": {
1411
+ "node": ">=10.5.0"
1412
+ }
1413
+ },
1414
+ "node_modules/node-fetch": {
1415
+ "version": "3.3.2",
1416
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
1417
+ "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
1418
+ "license": "MIT",
1419
+ "dependencies": {
1420
+ "data-uri-to-buffer": "^4.0.0",
1421
+ "fetch-blob": "^3.1.4",
1422
+ "formdata-polyfill": "^4.0.10"
1423
+ },
1424
+ "engines": {
1425
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
1426
+ },
1427
+ "funding": {
1428
+ "type": "opencollective",
1429
+ "url": "https://opencollective.com/node-fetch"
1430
+ }
1431
+ },
1432
+ "node_modules/object-assign": {
1433
+ "version": "4.1.1",
1434
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1435
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
1436
+ "license": "MIT",
1437
+ "engines": {
1438
+ "node": ">=0.10.0"
1439
+ }
1440
+ },
1441
+ "node_modules/object-inspect": {
1442
+ "version": "1.13.4",
1443
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
1444
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
1445
+ "license": "MIT",
1446
+ "engines": {
1447
+ "node": ">= 0.4"
1448
+ },
1449
+ "funding": {
1450
+ "url": "https://github.com/sponsors/ljharb"
1451
+ }
1452
+ },
1453
+ "node_modules/on-finished": {
1454
+ "version": "2.4.1",
1455
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
1456
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
1457
+ "license": "MIT",
1458
+ "dependencies": {
1459
+ "ee-first": "1.1.1"
1460
+ },
1461
+ "engines": {
1462
+ "node": ">= 0.8"
1463
+ }
1464
+ },
1465
+ "node_modules/once": {
1466
+ "version": "1.4.0",
1467
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1468
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
1469
+ "license": "ISC",
1470
+ "dependencies": {
1471
+ "wrappy": "1"
1472
+ }
1473
+ },
1474
+ "node_modules/package-json-from-dist": {
1475
+ "version": "1.0.1",
1476
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
1477
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
1478
+ "license": "BlueOak-1.0.0"
1479
+ },
1480
+ "node_modules/parseurl": {
1481
+ "version": "1.3.3",
1482
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
1483
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
1484
+ "license": "MIT",
1485
+ "engines": {
1486
+ "node": ">= 0.8"
1487
+ }
1488
+ },
1489
+ "node_modules/path-key": {
1490
+ "version": "3.1.1",
1491
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
1492
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
1493
+ "license": "MIT",
1494
+ "engines": {
1495
+ "node": ">=8"
1496
+ }
1497
+ },
1498
+ "node_modules/path-scurry": {
1499
+ "version": "1.11.1",
1500
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
1501
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
1502
+ "license": "BlueOak-1.0.0",
1503
+ "dependencies": {
1504
+ "lru-cache": "^10.2.0",
1505
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
1506
+ },
1507
+ "engines": {
1508
+ "node": ">=16 || 14 >=14.18"
1509
+ },
1510
+ "funding": {
1511
+ "url": "https://github.com/sponsors/isaacs"
1512
+ }
1513
+ },
1514
+ "node_modules/path-to-regexp": {
1515
+ "version": "8.3.0",
1516
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
1517
+ "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
1518
+ "license": "MIT",
1519
+ "funding": {
1520
+ "type": "opencollective",
1521
+ "url": "https://opencollective.com/express"
1522
+ }
1523
+ },
1524
+ "node_modules/proxy-addr": {
1525
+ "version": "2.0.7",
1526
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
1527
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
1528
+ "license": "MIT",
1529
+ "dependencies": {
1530
+ "forwarded": "0.2.0",
1531
+ "ipaddr.js": "1.9.1"
1532
+ },
1533
+ "engines": {
1534
+ "node": ">= 0.10"
1535
+ }
1536
+ },
1537
+ "node_modules/proxy-from-env": {
1538
+ "version": "1.1.0",
1539
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
1540
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
1541
+ "license": "MIT"
1542
+ },
1543
+ "node_modules/punycode": {
1544
+ "version": "2.3.1",
1545
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
1546
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
1547
+ "license": "MIT",
1548
+ "engines": {
1549
+ "node": ">=6"
1550
+ }
1551
+ },
1552
+ "node_modules/qs": {
1553
+ "version": "6.14.0",
1554
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
1555
+ "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
1556
+ "license": "BSD-3-Clause",
1557
+ "dependencies": {
1558
+ "side-channel": "^1.1.0"
1559
+ },
1560
+ "engines": {
1561
+ "node": ">=0.6"
1562
+ },
1563
+ "funding": {
1564
+ "url": "https://github.com/sponsors/ljharb"
1565
+ }
1566
+ },
1567
+ "node_modules/range-parser": {
1568
+ "version": "1.2.1",
1569
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1570
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
1571
+ "license": "MIT",
1572
+ "engines": {
1573
+ "node": ">= 0.6"
1574
+ }
1575
+ },
1576
+ "node_modules/raw-body": {
1577
+ "version": "3.0.2",
1578
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
1579
+ "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
1580
+ "license": "MIT",
1581
+ "dependencies": {
1582
+ "bytes": "~3.1.2",
1583
+ "http-errors": "~2.0.1",
1584
+ "iconv-lite": "~0.7.0",
1585
+ "unpipe": "~1.0.0"
1586
+ },
1587
+ "engines": {
1588
+ "node": ">= 0.10"
1589
+ }
1590
+ },
1591
+ "node_modules/react": {
1592
+ "version": "19.2.3",
1593
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
1594
+ "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
1595
+ "license": "MIT",
1596
+ "peer": true,
1597
+ "engines": {
1598
+ "node": ">=0.10.0"
1599
+ }
1600
+ },
1601
+ "node_modules/rimraf": {
1602
+ "version": "5.0.10",
1603
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
1604
+ "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==",
1605
+ "license": "ISC",
1606
+ "dependencies": {
1607
+ "glob": "^10.3.7"
1608
+ },
1609
+ "bin": {
1610
+ "rimraf": "dist/esm/bin.mjs"
1611
+ },
1612
+ "funding": {
1613
+ "url": "https://github.com/sponsors/isaacs"
1614
+ }
1615
+ },
1616
+ "node_modules/router": {
1617
+ "version": "2.2.0",
1618
+ "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
1619
+ "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
1620
+ "license": "MIT",
1621
+ "dependencies": {
1622
+ "debug": "^4.4.0",
1623
+ "depd": "^2.0.0",
1624
+ "is-promise": "^4.0.0",
1625
+ "parseurl": "^1.3.3",
1626
+ "path-to-regexp": "^8.0.0"
1627
+ },
1628
+ "engines": {
1629
+ "node": ">= 18"
1630
+ }
1631
+ },
1632
+ "node_modules/safe-buffer": {
1633
+ "version": "5.2.1",
1634
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1635
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1636
+ "funding": [
1637
+ {
1638
+ "type": "github",
1639
+ "url": "https://github.com/sponsors/feross"
1640
+ },
1641
+ {
1642
+ "type": "patreon",
1643
+ "url": "https://www.patreon.com/feross"
1644
+ },
1645
+ {
1646
+ "type": "consulting",
1647
+ "url": "https://feross.org/support"
1648
+ }
1649
+ ],
1650
+ "license": "MIT"
1651
+ },
1652
+ "node_modules/safer-buffer": {
1653
+ "version": "2.1.2",
1654
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1655
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
1656
+ "license": "MIT"
1657
+ },
1658
+ "node_modules/semver": {
1659
+ "version": "7.7.3",
1660
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
1661
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
1662
+ "license": "ISC",
1663
+ "bin": {
1664
+ "semver": "bin/semver.js"
1665
+ },
1666
+ "engines": {
1667
+ "node": ">=10"
1668
+ }
1669
+ },
1670
+ "node_modules/send": {
1671
+ "version": "1.2.1",
1672
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
1673
+ "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
1674
+ "license": "MIT",
1675
+ "dependencies": {
1676
+ "debug": "^4.4.3",
1677
+ "encodeurl": "^2.0.0",
1678
+ "escape-html": "^1.0.3",
1679
+ "etag": "^1.8.1",
1680
+ "fresh": "^2.0.0",
1681
+ "http-errors": "^2.0.1",
1682
+ "mime-types": "^3.0.2",
1683
+ "ms": "^2.1.3",
1684
+ "on-finished": "^2.4.1",
1685
+ "range-parser": "^1.2.1",
1686
+ "statuses": "^2.0.2"
1687
+ },
1688
+ "engines": {
1689
+ "node": ">= 18"
1690
+ },
1691
+ "funding": {
1692
+ "type": "opencollective",
1693
+ "url": "https://opencollective.com/express"
1694
+ }
1695
+ },
1696
+ "node_modules/serve-static": {
1697
+ "version": "2.2.1",
1698
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz",
1699
+ "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==",
1700
+ "license": "MIT",
1701
+ "dependencies": {
1702
+ "encodeurl": "^2.0.0",
1703
+ "escape-html": "^1.0.3",
1704
+ "parseurl": "^1.3.3",
1705
+ "send": "^1.2.0"
1706
+ },
1707
+ "engines": {
1708
+ "node": ">= 18"
1709
+ },
1710
+ "funding": {
1711
+ "type": "opencollective",
1712
+ "url": "https://opencollective.com/express"
1713
+ }
1714
+ },
1715
+ "node_modules/setprototypeof": {
1716
+ "version": "1.2.0",
1717
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
1718
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
1719
+ "license": "ISC"
1720
+ },
1721
+ "node_modules/shebang-command": {
1722
+ "version": "2.0.0",
1723
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
1724
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
1725
+ "license": "MIT",
1726
+ "dependencies": {
1727
+ "shebang-regex": "^3.0.0"
1728
+ },
1729
+ "engines": {
1730
+ "node": ">=8"
1731
+ }
1732
+ },
1733
+ "node_modules/shebang-regex": {
1734
+ "version": "3.0.0",
1735
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
1736
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
1737
+ "license": "MIT",
1738
+ "engines": {
1739
+ "node": ">=8"
1740
+ }
1741
+ },
1742
+ "node_modules/side-channel": {
1743
+ "version": "1.1.0",
1744
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
1745
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
1746
+ "license": "MIT",
1747
+ "dependencies": {
1748
+ "es-errors": "^1.3.0",
1749
+ "object-inspect": "^1.13.3",
1750
+ "side-channel-list": "^1.0.0",
1751
+ "side-channel-map": "^1.0.1",
1752
+ "side-channel-weakmap": "^1.0.2"
1753
+ },
1754
+ "engines": {
1755
+ "node": ">= 0.4"
1756
+ },
1757
+ "funding": {
1758
+ "url": "https://github.com/sponsors/ljharb"
1759
+ }
1760
+ },
1761
+ "node_modules/side-channel-list": {
1762
+ "version": "1.0.0",
1763
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
1764
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
1765
+ "license": "MIT",
1766
+ "dependencies": {
1767
+ "es-errors": "^1.3.0",
1768
+ "object-inspect": "^1.13.3"
1769
+ },
1770
+ "engines": {
1771
+ "node": ">= 0.4"
1772
+ },
1773
+ "funding": {
1774
+ "url": "https://github.com/sponsors/ljharb"
1775
+ }
1776
+ },
1777
+ "node_modules/side-channel-map": {
1778
+ "version": "1.0.1",
1779
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
1780
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
1781
+ "license": "MIT",
1782
+ "dependencies": {
1783
+ "call-bound": "^1.0.2",
1784
+ "es-errors": "^1.3.0",
1785
+ "get-intrinsic": "^1.2.5",
1786
+ "object-inspect": "^1.13.3"
1787
+ },
1788
+ "engines": {
1789
+ "node": ">= 0.4"
1790
+ },
1791
+ "funding": {
1792
+ "url": "https://github.com/sponsors/ljharb"
1793
+ }
1794
+ },
1795
+ "node_modules/side-channel-weakmap": {
1796
+ "version": "1.0.2",
1797
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
1798
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
1799
+ "license": "MIT",
1800
+ "dependencies": {
1801
+ "call-bound": "^1.0.2",
1802
+ "es-errors": "^1.3.0",
1803
+ "get-intrinsic": "^1.2.5",
1804
+ "object-inspect": "^1.13.3",
1805
+ "side-channel-map": "^1.0.1"
1806
+ },
1807
+ "engines": {
1808
+ "node": ">= 0.4"
1809
+ },
1810
+ "funding": {
1811
+ "url": "https://github.com/sponsors/ljharb"
1812
+ }
1813
+ },
1814
+ "node_modules/sift": {
1815
+ "version": "17.1.3",
1816
+ "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz",
1817
+ "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==",
1818
+ "license": "MIT"
1819
+ },
1820
+ "node_modules/signal-exit": {
1821
+ "version": "4.1.0",
1822
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
1823
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
1824
+ "license": "ISC",
1825
+ "engines": {
1826
+ "node": ">=14"
1827
+ },
1828
+ "funding": {
1829
+ "url": "https://github.com/sponsors/isaacs"
1830
+ }
1831
+ },
1832
+ "node_modules/sparse-bitfield": {
1833
+ "version": "3.0.3",
1834
+ "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
1835
+ "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
1836
+ "license": "MIT",
1837
+ "dependencies": {
1838
+ "memory-pager": "^1.0.2"
1839
+ }
1840
+ },
1841
+ "node_modules/statuses": {
1842
+ "version": "2.0.2",
1843
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
1844
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
1845
+ "license": "MIT",
1846
+ "engines": {
1847
+ "node": ">= 0.8"
1848
+ }
1849
+ },
1850
+ "node_modules/string-width": {
1851
+ "version": "5.1.2",
1852
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
1853
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
1854
+ "license": "MIT",
1855
+ "dependencies": {
1856
+ "eastasianwidth": "^0.2.0",
1857
+ "emoji-regex": "^9.2.2",
1858
+ "strip-ansi": "^7.0.1"
1859
+ },
1860
+ "engines": {
1861
+ "node": ">=12"
1862
+ },
1863
+ "funding": {
1864
+ "url": "https://github.com/sponsors/sindresorhus"
1865
+ }
1866
+ },
1867
+ "node_modules/string-width-cjs": {
1868
+ "name": "string-width",
1869
+ "version": "4.2.3",
1870
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
1871
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
1872
+ "license": "MIT",
1873
+ "dependencies": {
1874
+ "emoji-regex": "^8.0.0",
1875
+ "is-fullwidth-code-point": "^3.0.0",
1876
+ "strip-ansi": "^6.0.1"
1877
+ },
1878
+ "engines": {
1879
+ "node": ">=8"
1880
+ }
1881
+ },
1882
+ "node_modules/string-width-cjs/node_modules/ansi-regex": {
1883
+ "version": "5.0.1",
1884
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
1885
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
1886
+ "license": "MIT",
1887
+ "engines": {
1888
+ "node": ">=8"
1889
+ }
1890
+ },
1891
+ "node_modules/string-width-cjs/node_modules/emoji-regex": {
1892
+ "version": "8.0.0",
1893
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
1894
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
1895
+ "license": "MIT"
1896
+ },
1897
+ "node_modules/string-width-cjs/node_modules/strip-ansi": {
1898
+ "version": "6.0.1",
1899
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
1900
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
1901
+ "license": "MIT",
1902
+ "dependencies": {
1903
+ "ansi-regex": "^5.0.1"
1904
+ },
1905
+ "engines": {
1906
+ "node": ">=8"
1907
+ }
1908
+ },
1909
+ "node_modules/strip-ansi": {
1910
+ "version": "7.1.2",
1911
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
1912
+ "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
1913
+ "license": "MIT",
1914
+ "dependencies": {
1915
+ "ansi-regex": "^6.0.1"
1916
+ },
1917
+ "engines": {
1918
+ "node": ">=12"
1919
+ },
1920
+ "funding": {
1921
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
1922
+ }
1923
+ },
1924
+ "node_modules/strip-ansi-cjs": {
1925
+ "name": "strip-ansi",
1926
+ "version": "6.0.1",
1927
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
1928
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
1929
+ "license": "MIT",
1930
+ "dependencies": {
1931
+ "ansi-regex": "^5.0.1"
1932
+ },
1933
+ "engines": {
1934
+ "node": ">=8"
1935
+ }
1936
+ },
1937
+ "node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
1938
+ "version": "5.0.1",
1939
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
1940
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
1941
+ "license": "MIT",
1942
+ "engines": {
1943
+ "node": ">=8"
1944
+ }
1945
+ },
1946
+ "node_modules/toidentifier": {
1947
+ "version": "1.0.1",
1948
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
1949
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
1950
+ "license": "MIT",
1951
+ "engines": {
1952
+ "node": ">=0.6"
1953
+ }
1954
+ },
1955
+ "node_modules/tr46": {
1956
+ "version": "5.1.1",
1957
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz",
1958
+ "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==",
1959
+ "license": "MIT",
1960
+ "dependencies": {
1961
+ "punycode": "^2.3.1"
1962
+ },
1963
+ "engines": {
1964
+ "node": ">=18"
1965
+ }
1966
+ },
1967
+ "node_modules/type-is": {
1968
+ "version": "2.0.1",
1969
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
1970
+ "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
1971
+ "license": "MIT",
1972
+ "dependencies": {
1973
+ "content-type": "^1.0.5",
1974
+ "media-typer": "^1.1.0",
1975
+ "mime-types": "^3.0.0"
1976
+ },
1977
+ "engines": {
1978
+ "node": ">= 0.6"
1979
+ }
1980
+ },
1981
+ "node_modules/unpipe": {
1982
+ "version": "1.0.0",
1983
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1984
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
1985
+ "license": "MIT",
1986
+ "engines": {
1987
+ "node": ">= 0.8"
1988
+ }
1989
+ },
1990
+ "node_modules/use-sound": {
1991
+ "version": "5.0.0",
1992
+ "resolved": "https://registry.npmjs.org/use-sound/-/use-sound-5.0.0.tgz",
1993
+ "integrity": "sha512-MNHT3FFC5HxNCrgZtrnpIMJI2cw/0D2xismcrtyht8BTuF5FhFhb57xO/jlQr2xJaFrc/0btzRQvGyHQwB7PVA==",
1994
+ "license": "MIT",
1995
+ "dependencies": {
1996
+ "howler": "^2.2.4"
1997
+ },
1998
+ "peerDependencies": {
1999
+ "react": ">=16.8"
2000
+ }
2001
+ },
2002
+ "node_modules/vary": {
2003
+ "version": "1.1.2",
2004
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
2005
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
2006
+ "license": "MIT",
2007
+ "engines": {
2008
+ "node": ">= 0.8"
2009
+ }
2010
+ },
2011
+ "node_modules/web-push": {
2012
+ "version": "3.6.7",
2013
+ "resolved": "https://registry.npmjs.org/web-push/-/web-push-3.6.7.tgz",
2014
+ "integrity": "sha512-OpiIUe8cuGjrj3mMBFWY+e4MMIkW3SVT+7vEIjvD9kejGUypv8GPDf84JdPWskK8zMRIJ6xYGm+Kxr8YkPyA0A==",
2015
+ "license": "MPL-2.0",
2016
+ "dependencies": {
2017
+ "asn1.js": "^5.3.0",
2018
+ "http_ece": "1.2.0",
2019
+ "https-proxy-agent": "^7.0.0",
2020
+ "jws": "^4.0.0",
2021
+ "minimist": "^1.2.5"
2022
+ },
2023
+ "bin": {
2024
+ "web-push": "src/cli.js"
2025
+ },
2026
+ "engines": {
2027
+ "node": ">= 16"
2028
+ }
2029
+ },
2030
+ "node_modules/web-streams-polyfill": {
2031
+ "version": "3.3.3",
2032
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
2033
+ "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
2034
+ "license": "MIT",
2035
+ "engines": {
2036
+ "node": ">= 8"
2037
+ }
2038
+ },
2039
+ "node_modules/webidl-conversions": {
2040
+ "version": "7.0.0",
2041
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
2042
+ "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
2043
+ "license": "BSD-2-Clause",
2044
+ "engines": {
2045
+ "node": ">=12"
2046
+ }
2047
+ },
2048
+ "node_modules/whatwg-url": {
2049
+ "version": "14.2.0",
2050
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
2051
+ "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
2052
+ "license": "MIT",
2053
+ "dependencies": {
2054
+ "tr46": "^5.1.0",
2055
+ "webidl-conversions": "^7.0.0"
2056
+ },
2057
+ "engines": {
2058
+ "node": ">=18"
2059
+ }
2060
+ },
2061
+ "node_modules/which": {
2062
+ "version": "2.0.2",
2063
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
2064
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
2065
+ "license": "ISC",
2066
+ "dependencies": {
2067
+ "isexe": "^2.0.0"
2068
+ },
2069
+ "bin": {
2070
+ "node-which": "bin/node-which"
2071
+ },
2072
+ "engines": {
2073
+ "node": ">= 8"
2074
+ }
2075
+ },
2076
+ "node_modules/wrap-ansi": {
2077
+ "version": "8.1.0",
2078
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
2079
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
2080
+ "license": "MIT",
2081
+ "dependencies": {
2082
+ "ansi-styles": "^6.1.0",
2083
+ "string-width": "^5.0.1",
2084
+ "strip-ansi": "^7.0.1"
2085
+ },
2086
+ "engines": {
2087
+ "node": ">=12"
2088
+ },
2089
+ "funding": {
2090
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
2091
+ }
2092
+ },
2093
+ "node_modules/wrap-ansi-cjs": {
2094
+ "name": "wrap-ansi",
2095
+ "version": "7.0.0",
2096
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
2097
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
2098
+ "license": "MIT",
2099
+ "dependencies": {
2100
+ "ansi-styles": "^4.0.0",
2101
+ "string-width": "^4.1.0",
2102
+ "strip-ansi": "^6.0.0"
2103
+ },
2104
+ "engines": {
2105
+ "node": ">=10"
2106
+ },
2107
+ "funding": {
2108
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
2109
+ }
2110
+ },
2111
+ "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
2112
+ "version": "5.0.1",
2113
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
2114
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
2115
+ "license": "MIT",
2116
+ "engines": {
2117
+ "node": ">=8"
2118
+ }
2119
+ },
2120
+ "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
2121
+ "version": "4.3.0",
2122
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
2123
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
2124
+ "license": "MIT",
2125
+ "dependencies": {
2126
+ "color-convert": "^2.0.1"
2127
+ },
2128
+ "engines": {
2129
+ "node": ">=8"
2130
+ },
2131
+ "funding": {
2132
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
2133
+ }
2134
+ },
2135
+ "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
2136
+ "version": "8.0.0",
2137
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
2138
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
2139
+ "license": "MIT"
2140
+ },
2141
+ "node_modules/wrap-ansi-cjs/node_modules/string-width": {
2142
+ "version": "4.2.3",
2143
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
2144
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
2145
+ "license": "MIT",
2146
+ "dependencies": {
2147
+ "emoji-regex": "^8.0.0",
2148
+ "is-fullwidth-code-point": "^3.0.0",
2149
+ "strip-ansi": "^6.0.1"
2150
+ },
2151
+ "engines": {
2152
+ "node": ">=8"
2153
+ }
2154
+ },
2155
+ "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
2156
+ "version": "6.0.1",
2157
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
2158
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
2159
+ "license": "MIT",
2160
+ "dependencies": {
2161
+ "ansi-regex": "^5.0.1"
2162
+ },
2163
+ "engines": {
2164
+ "node": ">=8"
2165
+ }
2166
+ },
2167
+ "node_modules/wrappy": {
2168
+ "version": "1.0.2",
2169
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
2170
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
2171
+ "license": "ISC"
2172
+ }
2173
+ }
2174
+ }
package.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "koshx",
3
+ "version": "1.0.0",
4
+ "description": "Digital KoshX Unique Number Collectible",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "start": "node index.js",
8
+ "dev": "nodemon"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "koshx"
13
+ },
14
+ "author": "Rohan Shaw",
15
+ "license": "ISC",
16
+ "dependencies": {
17
+ "axios": "^1.13.2",
18
+ "bcryptjs": "^3.0.3",
19
+ "cors": "^2.8.5",
20
+ "dotenv": "^17.2.3",
21
+ "express": "^5.2.1",
22
+ "google-auth-library": "^10.5.0",
23
+ "jsonwebtoken": "^9.0.3",
24
+ "mongoose": "^9.0.1",
25
+ "node-cron": "^4.2.1",
26
+ "use-sound": "^5.0.0",
27
+ "web-push": "^3.6.7"
28
+ }
29
+ }
routes/admin.js ADDED
@@ -0,0 +1,344 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const router = require('express').Router();
2
+ const User = require('../models/User');
3
+ const Transaction = require('../models/Transaction');
4
+ const Asset = require('../models/Asset');
5
+ const verify = require('../utils/verifyToken');
6
+ const { generateKUS } = require('../utils/kusGenerator');
7
+ const StrikeHistory = require('../models/StrikeHistory');
8
+
9
+ const AllTransaction = require('../models/AllTransaction');
10
+ const logTransaction = require('../utils/ledgerLogger');
11
+ const { sendToUser } = require('../utils/sendPush');
12
+ const { runStrike } = require('../services/strikeEngine');
13
+
14
+ // MIDDLEWARE: Check if Admin
15
+ const verifyAdmin = async (req, res, next) => {
16
+ const user = await User.findById(req.user._id);
17
+ if (user.role !== 'admin') return res.status(403).send("ACCESS DENIED");
18
+ next();
19
+ };
20
+
21
+ // 1. DASHBOARD STATS (The Top Grid)
22
+ router.get('/stats', verify, verifyAdmin, async (req, res) => {
23
+ try {
24
+ const today = new Date();
25
+ today.setHours(0,0,0,0);
26
+
27
+ // Calculate Today's Sales
28
+ const dailySales = await Transaction.aggregate([
29
+ { $match: { timestamp: { $gte: today }, status: 'Verified' } },
30
+ { $group: { _id: null, total: { $sum: "$amount" } } }
31
+ ]);
32
+
33
+ const pendingCount = await Transaction.countDocuments({ status: 'Pending' });
34
+ const userCount = await User.countDocuments();
35
+ const bannedCount = await User.countDocuments({ ban_strikes: { $gte: 3 } });
36
+
37
+ res.json({
38
+ sales: dailySales[0]?.total || 0,
39
+ pending: pendingCount,
40
+ users: userCount,
41
+ banned: bannedCount
42
+ });
43
+ } catch (err) {
44
+ res.status(500).send("Stats Error");
45
+ }
46
+ });
47
+
48
+ // 2. GET PENDING TRANSACTIONS (The Worklist)
49
+ router.get('/transactions/pending', verify, verifyAdmin, async (req, res) => {
50
+ try {
51
+ // Populate user name to see who is paying
52
+ const txs = await Transaction.find({ status: 'Pending' })
53
+ .populate('user_id', 'name email ban_strikes')
54
+ .sort({ timestamp: -1 });
55
+ res.json(txs);
56
+ } catch (err) {
57
+ res.status(500).send("Fetch Error");
58
+ }
59
+ });
60
+
61
+ // 3. ACTION: APPROVE PAYMENT (Manual Verification)
62
+ router.post('/approve', verify, verifyAdmin, async (req, res) => {
63
+ try {
64
+ const { transactionId } = req.body;
65
+ const tx = await Transaction.findById(transactionId);
66
+ if (!tx || tx.status !== 'Pending') return res.status(400).send("Invalid Transaction");
67
+
68
+ // 1. Generate Asset
69
+ const newKUS = await generateKUS(tx.tier);
70
+
71
+ // 3. Update Tx
72
+ tx.status = 'Verified';
73
+ await tx.save();
74
+
75
+ await Asset.findByIdAndUpdate(tx.asset_id, { status: 'Held' });
76
+
77
+ await logTransaction(tx.user_id, 'DEPOSIT', tx.amount, 'INR', `Deposit Verified (Tier: ${tx.tier})`);
78
+
79
+ // 4. Referral Logic (Simplified)
80
+ const assetCount = await Asset.countDocuments({ owner_id: tx.user_id });
81
+ if (assetCount === 1) {
82
+ const user = await User.findById(tx.user_id);
83
+ if (user.referred_by) {
84
+ const referrer = await User.findOne({ referral_code: user.referred_by });
85
+ if (referrer) {
86
+ let reward = 0;
87
+ if (tx.tier === 'Silver') reward = 100;
88
+ if (tx.tier === 'Gold') reward = 150;
89
+ if (tx.tier === 'Platinum') reward = 250;
90
+
91
+ let userReward = 0;
92
+ if (tx.tier === 'Silver') reward = 50;
93
+ if (tx.tier === 'Gold') reward = 75;
94
+ if (tx.tier === 'Platinum') reward = 125;
95
+
96
+ referrer.points += reward;
97
+ await referrer.save();
98
+
99
+ user.points += userReward;
100
+ await user.save();
101
+
102
+ await logTransaction(referrer._id, 'REFERRAL_BONUS', reward, 'INR', `Referral Bonus Tier: ${tx.tier}`);
103
+ await sendToUser(referrer._id, "Referral Bonus Credited", `${reward} points credited to your account.`, "/profile");
104
+
105
+ await logTransaction(user._id, 'REFERRAL_BONUS', userReward, 'INR', `Referral Bonus Tier: ${tx.tier}`);
106
+ await sendToUser(user._id, "Referral Bonus Credited", `${userReward} points credited to your account.`, "/profile");
107
+
108
+ console.log(`[Referral] ${reward} points added to ${referrer.name}`);
109
+ }
110
+ }
111
+ }
112
+
113
+ await sendToUser(tx.user_id, "✅ Deposit Verified", `₹${tx.amount} added to your assets.`, "/profile");
114
+
115
+ res.json({ success: true, message: "Payment Verified & Asset Assigned" });
116
+ } catch (err) {
117
+ res.status(500).send("Approval Error");
118
+ }
119
+ });
120
+
121
+ // 4. ACTION: REJECT & STRIKE (The Ban Hammer)
122
+ router.post('/reject', verify, verifyAdmin, async (req, res) => {
123
+ try {
124
+ const { transactionId } = req.body;
125
+ const tx = await Transaction.findById(transactionId);
126
+ if (!tx) return res.status(404).send("Tx not found");
127
+
128
+ // 1. Mark Failed
129
+ tx.status = 'Failed';
130
+ tx.rejection_reason = "Invalid UTR / Payment Not Received"; // Static Reason
131
+ await tx.save();
132
+
133
+ await Asset.findByIdAndDelete(tx.asset_id);
134
+
135
+ // 2. Add Strike to User
136
+ const user = await User.findById(tx.user_id);
137
+ user.ban_strikes += 1;
138
+ await user.save();
139
+
140
+ res.json({
141
+ success: true,
142
+ message: `Transaction Rejected. User Strikes: ${user.ban_strikes}/3`
143
+ });
144
+ await sendToUser(tx.user_id, "❌ Deposit Failed", "Your UTR was rejected. Check Activity Log.", "/profile");
145
+ } catch (err) {
146
+ res.status(500).send("Reject Error");
147
+ }
148
+ });
149
+
150
+ module.exports = router;
151
+
152
+ // ADD STRIKE (Called when Admin rejects a UTR)
153
+ router.post('/strike-user', verify, verifyAdmin, async (req, res) => {
154
+ const { userId } = req.body;
155
+
156
+ const user = await User.findById(userId);
157
+ user.ban_strikes += 1;
158
+ await user.save();
159
+
160
+ if (user.ban_strikes >= 3) {
161
+ // Optional: Send email notification "You are banned"
162
+ console.log(`User ${user.name} is now BANNED.`);
163
+ }
164
+
165
+ res.send({ message: `Strike added. Total: ${user.ban_strikes}/3` });
166
+ });
167
+
168
+ // 5. GET ALL USERS (Manage Users)
169
+ router.get('/users', verify, verifyAdmin, async (req, res) => {
170
+ const users = await User.find().select('-password').sort({ createdAt: -1 });
171
+ res.json(users);
172
+ });
173
+
174
+ // 6. GET ALL ASSETS (Asset Inventory)
175
+ router.get('/assets', verify, verifyAdmin, async (req, res) => {
176
+ const assets = await Asset.find({ status: 'Held' }).populate('owner_id', 'name email');
177
+ res.json(assets);
178
+ });
179
+
180
+ // 7. GET WINNER HISTORY (Last 60 Days)
181
+ router.get('/history', verify, verifyAdmin, async (req, res) => {
182
+ const history = await StrikeHistory.find().sort({ date: -1 }).limit(60).populate('winners.user_id', 'name');
183
+ res.json(history);
184
+ });
185
+
186
+ // 8. LEDGER (All Transactions)
187
+ router.get('/ledger', verify, verifyAdmin, async (req, res) => {
188
+ const txs = await Transaction.find().populate('user_id', 'name').sort({ timestamp: -1 }).limit(100);
189
+ res.json(txs);
190
+ });
191
+
192
+ // 9. MANUAL STRIKE TRIGGER
193
+ router.post('/trigger-strike', verify, verifyAdmin, async (req, res) => {
194
+ // SECURITY: Ensure you export the logic function properly from jobs/strike.js
195
+ // For now, let's assume you moved the logic to a controller function called `executeStrikeLogic`
196
+ // await executeStrikeLogic();
197
+
198
+ startStrike();
199
+ res.json({ message: "Strike Triggered Manually" });
200
+ });
201
+
202
+ router.post('/manual-strike', verify, verifyAdmin, async (req, res) => {
203
+ try {
204
+ await runStrike({ triggeredBy: "ADMIN" });
205
+ res.json({ success: true });
206
+ } catch (err) {
207
+ if (err.message === "STRIKE_ALREADY_EXECUTED") {
208
+ return res.status(400).json("Strike already executed today");
209
+ }
210
+ res.status(500).json("Strike failed");
211
+ }
212
+ });
213
+
214
+ // 10. UNBAN USER
215
+ router.post('/unban', verify, verifyAdmin, async (req, res) => {
216
+ const { userId } = req.body;
217
+ await User.findByIdAndUpdate(userId, { ban_strikes: 0 });
218
+ res.json({ message: "User Unbanned" });
219
+ });
220
+
221
+ // WITHDRAWAL REQUESTS (Fixes 404)
222
+ router.get('/withdrawals', verify, verifyAdmin, async (req, res) => {
223
+ const requests = await Transaction.find({ status: 'Pending_Withdrawal' })
224
+ .populate('user_id', 'name email upi_id');
225
+ res.json(requests);
226
+ });
227
+
228
+ // CONFIRM WITHDRAWAL PAID
229
+ router.post('/withdraw-confirm', verify, verifyAdmin, async (req, res) => {
230
+ const { transactionId, adminUtr } = req.body;
231
+ await Transaction.findByIdAndUpdate(transactionId, {
232
+ status: 'Withdrawn',
233
+ utr: adminUtr
234
+ });
235
+ await sendToUser(tx.user_id, "💸 Payment Sent", "Your withdrawal has been processed via UPI.", "/profile");
236
+ res.json({ success: true });
237
+ });
238
+
239
+ router.get('/global-ledger', verify, verifyAdmin, async (req, res) => {
240
+ try {
241
+ // Support Filtering via Query Params
242
+ const { type, email } = req.query;
243
+ let query = {};
244
+
245
+ if (type && type !== 'ALL') query.type = type;
246
+
247
+ if (email) {
248
+ const user = await User.findOne({ email });
249
+ if (user) query.user_id = user._id;
250
+ }
251
+
252
+ const history = await AllTransaction.find(query)
253
+ .populate('user_id', 'name email')
254
+ .sort({ timestamp: -1 })
255
+ .limit(200); // Limit to prevent crashing
256
+
257
+ res.json(history);
258
+ } catch (err) {
259
+ res.status(500).send("Error");
260
+ }
261
+ });
262
+
263
+ // REJECT WITHDRAWAL (Admin Action)
264
+ router.post('/withdraw-reject', verify, verifyAdmin, async (req, res) => {
265
+ const { transactionId, reason } = req.body;
266
+
267
+ const tx = await Transaction.findById(transactionId);
268
+ if (!tx) return res.status(404).send("Tx Not Found");
269
+
270
+ // 1. Refund the money to wallet
271
+ const user = await User.findById(tx.user_id);
272
+ user.wallet_balance += tx.amount;
273
+ await user.save();
274
+
275
+ // 2. Update Transaction
276
+ tx.status = 'Rejected_Withdrawal';
277
+ tx.rejection_reason = reason || "Admin Rejected Request";
278
+ await tx.save();
279
+
280
+ // 3. Log to Ledger (Refund)
281
+ await logTransaction(user._id, 'REFUND', tx.amount, 'INR', `Withdrawal Rejected: ${reason}`);
282
+
283
+ res.json({ success: true });
284
+ });
285
+
286
+ // 12. GET SINGLE USER DETAILS (Deep Dive)
287
+ router.get('/user/:id', verify, verifyAdmin, async (req, res) => {
288
+ try {
289
+ const user = await User.findById(req.params.id).select('-password');
290
+ if (!user) return res.status(404).send("User not found");
291
+
292
+ // Fetch their assets
293
+ const assets = await Asset.find({ owner_id: user._id });
294
+
295
+ // Fetch their transactions (Last 50)
296
+ const txs = await Transaction.find({ user_id: user._id }).sort({ timestamp: -1 }).limit(50);
297
+
298
+ res.json({ user, assets, transactions: txs });
299
+ } catch (err) {
300
+ res.status(500).send("Error fetching user details");
301
+ }
302
+ });
303
+
304
+ // 13. UPDATE USER (Edit Details)
305
+ router.put('/user/:id', verify, verifyAdmin, async (req, res) => {
306
+ try {
307
+ const { name, email, wallet_balance, points, ban_strikes } = req.body;
308
+
309
+ await User.findByIdAndUpdate(req.params.id, {
310
+ name,
311
+ email,
312
+ wallet_balance,
313
+ points,
314
+ ban_strikes
315
+ });
316
+
317
+ res.json({ success: true, message: "User Updated" });
318
+ } catch (err) {
319
+ res.status(500).send("Update Failed");
320
+ }
321
+ });
322
+
323
+ // 14. DELETE USER (Hard Delete)
324
+ router.delete('/user/:id', verify, verifyAdmin, async (req, res) => {
325
+ try {
326
+ const userId = req.params.id;
327
+
328
+ // 1. Delete User
329
+ await User.findByIdAndDelete(userId);
330
+
331
+ // 2. Delete Assets? (Optional: Keep them or burn them)
332
+ await Asset.deleteMany({ owner_id: userId });
333
+
334
+ // 3. Transactions are usually kept for ledger integrity,
335
+ // but if you want a clean wipe:
336
+ // await Transaction.deleteMany({ user_id: userId });
337
+
338
+ res.json({ success: true, message: "User Deleted" });
339
+ } catch (err) {
340
+ res.status(500).send("Delete Failed");
341
+ }
342
+ });
343
+
344
+ module.exports = router;
routes/auth.js ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const router = require('express').Router();
2
+ const User = require('../models/User');
3
+ const bcrypt = require('bcryptjs');
4
+ const jwt = require('jsonwebtoken');
5
+ const { OAuth2Client } = require('google-auth-library');
6
+ const verify = require('../utils/verifyToken');
7
+
8
+ const client = new OAuth2Client(process.env.GOOGLE_CLIENT_ID);
9
+
10
+ // In-memory OTP store (Use Redis for production scaling)
11
+ const otpStore = {};
12
+
13
+ // 1. INITIATE SIGNUP (Send OTP)
14
+ router.post('/signup/initiate', async (req, res) => {
15
+ try {
16
+ const { email } = req.body;
17
+
18
+ // Check if user already exists
19
+ const userExists = await User.findOne({ email });
20
+ if (userExists) return res.status(400).send("Email already registered. Please Login.");
21
+
22
+ // Generate OTP (Fixed to 111111 for testing as requested)
23
+ const otp = "111111";
24
+
25
+ // Store OTP with a 10-minute expiry timestamp (optional logic, kept simple here)
26
+ otpStore[email] = otp;
27
+
28
+ // console.log(`[OTP] Sent to ${email}: ${otp}`); // Uncomment for debug
29
+ res.send({ message: "OTP sent to email" });
30
+ } catch (err) {
31
+ res.status(500).send("Server Error");
32
+ }
33
+ });
34
+
35
+ // 2. VERIFY OTP & CREATE ACCOUNT
36
+ router.post('/signup/verify', async (req, res) => {
37
+ try {
38
+ const { name, email, password, referral_code, otp, termsAccepted } = req.body;
39
+
40
+ if (!termsAccepted) return res.status(400).send("You must accept Terms & Conditions");
41
+
42
+ // Validate OTP
43
+ if (!otpStore[email] || otpStore[email] !== otp) {
44
+ return res.status(400).send("Invalid or Expired OTP");
45
+ }
46
+
47
+ // Hash Password
48
+ const salt = await bcrypt.genSalt(10);
49
+ const hashedPassword = await bcrypt.hash(password, salt);
50
+
51
+ // Generate My Referral Code
52
+ const myReferralCode = Math.random().toString(36).substring(2, 8).toUpperCase();
53
+
54
+ const user = new User({
55
+ name,
56
+ email,
57
+ password: hashedPassword,
58
+ referral_code: myReferralCode,
59
+ referred_by: referral_code || null,
60
+ kyc_status: true // Storing consent as initial KYC step
61
+ });
62
+
63
+ await user.save();
64
+
65
+ // Cleanup OTP
66
+ delete otpStore[email];
67
+
68
+ // Auto Login
69
+ const token = jwt.sign({ _id: user._id, role: user.role }, process.env.JWT_SECRET);
70
+ res.send({ token, name: user.name, upi: user.upi_id });
71
+
72
+ } catch (err) {
73
+ res.status(500).send("Signup Failed");
74
+ }
75
+ });
76
+
77
+ // 3. LOGIN (Email + Password only)
78
+ router.post('/login', async (req, res) => {
79
+ try {
80
+ const { email, password } = req.body;
81
+
82
+ // Check User
83
+ const user = await User.findOne({ email });
84
+ if (!user) return res.status(400).send("Email not found");
85
+
86
+ // Check Password
87
+ const validPass = await bcrypt.compare(password, user.password);
88
+ if (!validPass) return res.status(400).send("Invalid Password");
89
+
90
+ // Issue Token
91
+ const token = jwt.sign({ _id: user._id, role: user.role }, process.env.JWT_SECRET);
92
+ res.send({ token, name: user.name, upi: user.upi_id });
93
+
94
+ } catch (err) {
95
+ res.status(500).send("Login Failed");
96
+ }
97
+ });
98
+
99
+ // 4. GOOGLE AUTH (Smart Handling)
100
+ router.post('/google', async (req, res) => {
101
+ try {
102
+ const { token, referral_code, termsAccepted } = req.body;
103
+
104
+ const ticket = await client.verifyIdToken({
105
+ idToken: token,
106
+ audience: process.env.GOOGLE_CLIENT_ID,
107
+ });
108
+ const { name, email, sub } = ticket.getPayload();
109
+
110
+ let user = await User.findOne({ email });
111
+
112
+ // IF NEW USER: Require Consent
113
+ if (!user) {
114
+ if (!termsAccepted) return res.status(400).send("Please tick the Terms & Conditions box to Register.");
115
+
116
+ const randomPassword = Math.random().toString(36).slice(-8);
117
+ const salt = await bcrypt.genSalt(10);
118
+ const hashedPassword = await bcrypt.hash(randomPassword, salt);
119
+ const myReferralCode = Math.random().toString(36).substring(2, 8).toUpperCase();
120
+
121
+ user = new User({
122
+ name, email, password: hashedPassword,
123
+ referral_code: myReferralCode,
124
+ referred_by: referral_code || null,
125
+ kyc_status: true
126
+ });
127
+ await user.save();
128
+ }
129
+
130
+ const jwtToken = jwt.sign({ _id: user._id, role: user.role }, process.env.JWT_SECRET);
131
+ res.send({ token: jwtToken, name: user.name, upi: user.upi_id });
132
+
133
+ } catch (err) {
134
+ res.status(400).send("Google Auth Failed");
135
+ }
136
+ });
137
+
138
+ // 5. LOGOUT
139
+ router.post('/logout', async (req, res) => {
140
+ try {
141
+ res.send({ message: "Logged Out" });
142
+ } catch (err) {
143
+ res.status(500).send("Logout Failed");
144
+ }
145
+ });
146
+
147
+ // GET CURRENT USER DETAILS (Protected)
148
+ router.get('/me', verify, async (req, res) => {
149
+ try {
150
+ // Find user by ID (exclude password for security)
151
+ const user = await User.findById(req.user._id).select('-password');
152
+
153
+ if (!user) return res.status(404).send("User not found");
154
+
155
+ res.json(user);
156
+ } catch (err) {
157
+ res.status(500).send("Server Error");
158
+ }
159
+ });
160
+
161
+ router.post('/update-upi', verify, async (req, res) => {
162
+ const { upi_id } = req.body;
163
+
164
+ if (!upi_id || !upi_id.includes('@')) {
165
+ return res.status(400).send("Invalid UPI ID");
166
+ }
167
+
168
+ await User.findByIdAndUpdate(req.user._id, { upi_id });
169
+ res.send("UPI updated");
170
+ });
171
+
172
+ module.exports = router;
routes/fairness.js ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const router = require('express').Router();
2
+ const StrikeHistory = require('../models/StrikeHistory');
3
+ const crypto = require('crypto');
4
+
5
+ // PUBLIC — no verify middleware
6
+ router.get('/verify/:date', async (req, res) => {
7
+ try {
8
+ const dayStart = new Date(req.params.date);
9
+ dayStart.setHours(0,0,0,0);
10
+
11
+ const dayEnd = new Date(dayStart);
12
+ dayEnd.setHours(23,59,59,999);
13
+
14
+ const strike = await StrikeHistory.findOne({
15
+ date: { $gte: dayStart, $lte: dayEnd }
16
+ }).lean();
17
+
18
+ if (!strike) {
19
+ return res.status(404).json({ error: 'No strike found for this date' });
20
+ }
21
+
22
+ // Recompute hash
23
+ const recomputedHash = crypto
24
+ .createHash('sha256')
25
+ .update(JSON.stringify(strike.audit_payload))
26
+ .digest('hex');
27
+
28
+ res.json({
29
+ date: strike.date,
30
+ target_price: strike.target_price,
31
+ winning_digits: strike.winning_digits,
32
+ audit_hash: strike.audit_hash,
33
+ recomputed_hash: recomputedHash,
34
+ is_valid: recomputedHash === strike.audit_hash,
35
+ audit_payload: strike.audit_payload,
36
+ winners: strike.winners.map(w => ({
37
+ tier: w.tier,
38
+ amount: w.amount,
39
+ rank: w.rank,
40
+ kus_id: w.kus_id
41
+ }))
42
+ });
43
+
44
+ } catch (err) {
45
+ console.log(err);
46
+ res.status(500).json({ error: 'Verification failed' });
47
+ }
48
+ });
49
+
50
+ module.exports = router;
routes/market.js ADDED
@@ -0,0 +1,276 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const router = require('express').Router();
2
+ const Transaction = require('../models/Transaction');
3
+ const User = require('../models/User');
4
+ const Asset = require('../models/Asset');
5
+ const AllTransaction = require('../models/AllTransaction');
6
+ const logTransaction = require('../utils/ledgerLogger');
7
+ const verify = require('../utils/verifyToken');
8
+ const { generateKUS } = require('../utils/kusGenerator');
9
+ const StrikeHistory = require('../models/StrikeHistory');
10
+
11
+ // 1. INITIATE DEPOSIT (User clicks "Pay via UPI")
12
+ // POST /deposit
13
+ router.post('/deposit', verify, async (req, res) => {
14
+ const { amount, tier, utr, selectedNumber } = req.body;
15
+
16
+ let asset = null; // ✅ declare outside
17
+
18
+ try {
19
+ // 0. Prevent duplicate UTR
20
+ const existingUTR = await Transaction.findOne({ utr });
21
+ if (existingUTR) {
22
+ return res.status(400).send("UTR already used.");
23
+ }
24
+
25
+ // 1. Generate / reserve KUS
26
+ const kus = await generateKUS(tier, selectedNumber);
27
+
28
+ // 2. Create Asset (Pending payment)
29
+ asset = new Asset({
30
+ owner_id: req.user._id,
31
+ kus_id: kus,
32
+ tier,
33
+ status: 'Pending' // make sure enum allows this
34
+ });
35
+ await asset.save();
36
+
37
+ // 3. Create Transaction
38
+ const tx = new Transaction({
39
+ user_id: req.user._id,
40
+ utr,
41
+ amount,
42
+ tier,
43
+ asset_id: asset._id,
44
+ status: 'Pending'
45
+ });
46
+ await tx.save();
47
+
48
+ res.send({ message: "Number Reserved. Verifying Payment..." });
49
+
50
+ } catch (err) {
51
+ // 🧹 rollback reserved asset if something failed
52
+ if (kus) {
53
+ console.log("Rolling back reserved asset");
54
+ await Asset.deleteOne({ kus_id: kus });
55
+ }
56
+ res.status(400).send(err.message || "Deposit failed");
57
+ }
58
+ });
59
+
60
+
61
+ // 2. UPDATE BANK DETAILS (User saves UPI ID)
62
+ router.put('/profile/bank', verify, async (req, res) => {
63
+ try {
64
+ const { upi_id } = req.body;
65
+ await User.findByIdAndUpdate(req.user._id, { upi_id: upi_id });
66
+ res.send("UPI ID Updated");
67
+ } catch (err) {
68
+ res.status(400).send(err);
69
+ }
70
+ });
71
+
72
+ // 3. WITHDRAW REQUEST
73
+ router.post('/withdraw', verify, async (req, res) => {
74
+ try {
75
+ const { amount } = req.body;
76
+ const withdrawAmount = parseFloat(amount);
77
+
78
+ if (withdrawAmount < 500) return res.status(400).send("Minimum withdrawal is ₹500");
79
+
80
+ const user = await User.findById(req.user._id);
81
+
82
+ // 1. Check Balance
83
+ if (user.wallet_balance < withdrawAmount) {
84
+ return res.status(400).send("Insufficient Wallet Balance");
85
+ }
86
+
87
+ // 2. Check Banking Info
88
+ if (!user.upi_id) {
89
+ return res.status(400).send("Please add your UPI ID in Profile first");
90
+ }
91
+
92
+ // 3. Deduct Balance (Lock funds)
93
+ user.wallet_balance -= withdrawAmount;
94
+ await user.save();
95
+
96
+ // 4. Create Transaction Record
97
+ const tx = new Transaction({
98
+ user_id: user._id,
99
+ utr: `W-${Date.now()}`, // Temporary ID until you pay
100
+ amount: withdrawAmount,
101
+ tier: 'Silver', // Placeholder, or make field optional
102
+ status: 'Pending_Withdrawal', // Special status
103
+ timestamp: new Date()
104
+ });
105
+ await tx.save();
106
+
107
+ await logTransaction(user._id, 'WITHDRAWAL', -withdrawAmount, 'INR', 'Withdrawal Request');
108
+
109
+ res.send({ message: "Withdrawal Requested. Processing...", new_balance: user.wallet_balance });
110
+ } catch (err) {
111
+ console.log(err);
112
+ res.status(400).send(err);
113
+ }
114
+ });
115
+
116
+ // LIQUIDATE ASSET (Burn for Points)
117
+ router.post('/liquidate/:assetId', verify, async (req, res) => {
118
+ try {
119
+ const asset = await Asset.findOne({ _id: req.params.assetId, owner_id: req.user._id });
120
+
121
+ if (!asset) return res.status(404).send("Asset not found or not owned by you");
122
+ if (asset.status !== 'Held') return res.status(400).send("Asset already used");
123
+
124
+ // Point Values
125
+ let points = 0;
126
+ if (asset.tier === 'Silver') points = 50;
127
+ if (asset.tier === 'Gold') points = 100;
128
+ if (asset.tier === 'Platinum') points = 250;
129
+
130
+ // Update Asset Status
131
+ asset.status = 'Burned'; // Permanently removed from pool
132
+ await asset.save();
133
+
134
+ // Add Points to User
135
+ await User.findByIdAndUpdate(req.user._id, { $inc: { points: points } });
136
+
137
+ await logTransaction(req.user._id, 'LIQUIDATION', points, 'POINTS', `Liquidated ${asset.tier} Asset`);
138
+
139
+ res.send({ success: true, points_added: points });
140
+ } catch (err) {
141
+ res.status(500).send(err.message);
142
+ }
143
+ });
144
+
145
+ // REDEEM POINTS FOR ASSET
146
+ router.post('/redeem', verify, async (req, res) => {
147
+ try {
148
+ const { tier } = req.body; // 'Silver', 'Gold', 'Platinum'
149
+
150
+ // 1. Define Costs
151
+ const pointCosts = {
152
+ 'Silver': 500,
153
+ 'Gold': 1000,
154
+ 'Platinum': 2500
155
+ };
156
+
157
+ const cost = pointCosts[tier];
158
+ if (!cost) return res.status(400).send("Invalid Tier");
159
+
160
+ // 2. Check User Points
161
+ const user = await User.findById(req.user._id);
162
+ if (user.points < cost) {
163
+ return res.status(400).send(`Insufficient Points. You need ${cost} pts.`);
164
+ }
165
+
166
+ // 3. Deduct Points
167
+ user.points -= cost;
168
+ await user.save();
169
+
170
+ // 4. Generate Asset
171
+ const newKUS = await generateKUS(tier);
172
+ const newAsset = new Asset({
173
+ owner_id: user._id,
174
+ kus_id: newKUS,
175
+ tier: tier,
176
+ status: 'Held',
177
+ purchase_date: new Date()
178
+ });
179
+ await newAsset.save();
180
+
181
+ await logTransaction(req.user._id, 'POINT_REDEMPTION', -cost, 'POINTS', `Redeemed ${tier} Asset`);
182
+
183
+ res.send({ success: true, kus: newKUS, remaining_points: user.points });
184
+
185
+ } catch (err) {
186
+ console.log(err);
187
+ res.status(500).send("Redemption Error");
188
+ }
189
+ });
190
+
191
+ // GET USER ASSETS
192
+ router.get('/my-assets', verify, async (req, res) => {
193
+ try {
194
+ const assets = await Asset.find({ owner_id: req.user._id }).sort({ purchase_date: -1 });
195
+ res.json(assets);
196
+ } catch (err) {
197
+ console.log(err);
198
+ res.status(500).send("Server Error");
199
+ }
200
+ });
201
+
202
+ router.get('/my-ledger', verify, async (req, res) => {
203
+ try {
204
+ const history = await AllTransaction.find({ user_id: req.user._id }).sort({ timestamp: -1 });
205
+ res.json(history);
206
+ } catch (err) {
207
+ res.status(500).send("Error");
208
+ }
209
+ });
210
+
211
+ // GET MY TRANSACTIONS (Status View)
212
+ router.get('/my-transactions', verify, async (req, res) => {
213
+ try {
214
+ const txs = await Transaction.find({ user_id: req.user._id }).sort({ timestamp: -1 });
215
+ res.json(txs);
216
+ } catch (err) {
217
+ res.status(500).send("Error");
218
+ }
219
+ });
220
+
221
+ router.get('/home-stats', verify, async (req, res) => {
222
+ try {
223
+ // A. Get the very last Strike Result (Today's or Yesterday's)
224
+ const lastStrike = await StrikeHistory.findOne().sort({ date: -1 }).populate('winners.user_id', 'name');
225
+
226
+ // B. Get Last 7 Days of History for "Recent Captures"
227
+ const recentHistory = await StrikeHistory.find().sort({ date: -1 }).limit(7).populate('winners.user_id', 'name');
228
+
229
+ // Flatten winners into a single list for the ticker
230
+ let recentCaptures = [];
231
+ recentHistory.forEach(day => {
232
+ day.winners.slice(0, 3).forEach(winner => { // Take Top 3 from each day
233
+ recentCaptures.push({
234
+ userName: winner.user_id?.name || "Unknown",
235
+ amount: winner.amount,
236
+ tier: winner.tier,
237
+ date: day.date
238
+ });
239
+ });
240
+ });
241
+
242
+ res.json({
243
+ latestWinners: lastStrike ? lastStrike.winners : [],
244
+ targetPrice: lastStrike ? lastStrike.target_price : 0,
245
+ recentCaptures: recentCaptures
246
+ });
247
+
248
+ } catch (err) {
249
+ res.status(500).send("Stats Error");
250
+ }
251
+ });
252
+
253
+ router.post('/verify-asset', verify, async (req, res) => {
254
+ try {
255
+ const { serial } = req.body; // e.g., AU171225W0000001
256
+
257
+ const asset = await Asset.findOne({ kus_id: serial }).populate('owner_id', 'name');
258
+
259
+ if (!asset) return res.status(404).json({ found: false, message: "Invalid Serial Number" });
260
+
261
+ // Mask the name for privacy (e.g., "Rohan" -> "Ro***")
262
+ const name = asset.owner_id.name;
263
+ const maskedName = name.substring(0, 2) + "***";
264
+
265
+ res.json({
266
+ found: true,
267
+ tier: asset.tier,
268
+ owner: maskedName,
269
+ status: asset.status
270
+ });
271
+ } catch (err) {
272
+ res.status(500).send("Server Error");
273
+ }
274
+ });
275
+
276
+ module.exports = router;
routes/notification.js ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const router = require('express').Router();
2
+ const Notification = require('../models/Notification');
3
+ const User = require('../models/User');
4
+ const verify = require('../utils/verifyToken');
5
+ const webpush = require('web-push');
6
+
7
+ const verifyAdmin = async (req, res, next) => {
8
+ const user = await User.findById(req.user._id);
9
+ if (user.role !== 'admin') return res.status(403).send("ACCESS DENIED");
10
+ next();
11
+ };
12
+
13
+
14
+ // Configure Web Push
15
+ webpush.setVapidDetails(
16
+ process.env.VAPID_EMAIL,
17
+ process.env.VAPID_PUBLIC_KEY,
18
+ process.env.VAPID_PRIVATE_KEY
19
+ );
20
+
21
+ // 1. GET MY NOTIFICATIONS
22
+ router.get('/', verify, async (req, res) => {
23
+ try {
24
+ const notes = await Notification.find({
25
+ $or: [
26
+ { target_user_id: null }, // Global
27
+ { target_user_id: req.user._id } // Personal
28
+ ]
29
+ }).sort({ created_at: -1 }).limit(20);
30
+
31
+ res.json(notes);
32
+ } catch (err) {
33
+ res.status(500).send("Error fetching notifications");
34
+ }
35
+ });
36
+
37
+ // 1. SAVE SUBSCRIPTION
38
+ router.post('/subscribe', verify, async (req, res) => {
39
+ const subscription = req.body;
40
+ // Save this object to the user in DB
41
+ await User.findByIdAndUpdate(req.user._id, { pushSubscription: subscription });
42
+ res.status(201).json({});
43
+ });
44
+
45
+ // 2. SEND NOTIFICATION (Updated Admin Route)
46
+ router.post('/send', verify, verifyAdmin, async (req, res) => {
47
+ const { title, message, url, targetUserId } = req.body;
48
+ const payload = JSON.stringify({ title, body: message, url });
49
+
50
+ try {
51
+ if (targetUserId) {
52
+ // Send to ONE User
53
+ const user = await User.findById(targetUserId);
54
+ if (user?.pushSubscription) {
55
+ await webpush.sendNotification(user.pushSubscription, payload);
56
+ }
57
+ } else {
58
+ // Send to ALL Users (Global)
59
+ // Ideally, do this in batches or a queue for thousands of users
60
+ const users = await User.find({ pushSubscription: { $exists: true } });
61
+
62
+ const promises = users.map(user =>
63
+ webpush.sendNotification(user.pushSubscription, payload).catch(err => {
64
+ if (err.statusCode === 410) {
65
+ // Subscription expired (user cleared data), remove from DB
66
+ User.findByIdAndUpdate(user._id, { $unset: { pushSubscription: "" } });
67
+ }
68
+ })
69
+ );
70
+ await Promise.all(promises);
71
+ }
72
+
73
+ res.json({ success: true });
74
+ } catch (err) {
75
+ res.status(500).json({ error: "Push Failed" });
76
+ }
77
+ });
78
+
79
+ module.exports = router;
routes/strike.js ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const express = require("express");
2
+ const router = require("express").Router();
3
+ const crypto = require("crypto");
4
+ const StrikeHistory = require("../models/StrikeHistory");
5
+
6
+ const sha256 = (payload) =>
7
+ crypto.createHash("sha256").update(JSON.stringify(payload)).digest("hex");
8
+
9
+ router.get("/verify/:strikeId", async (req, res) => {
10
+ try {
11
+ const strike = await StrikeHistory.findById(req.params.strikeId);
12
+ if (!strike) return res.status(404).json({ valid: false });
13
+
14
+ const recomputed = sha256(strike.audit_payload);
15
+
16
+ res.json({
17
+ valid: recomputed === strike.audit_hash,
18
+ audit_hash: strike.audit_hash,
19
+ recomputed_hash: recomputed,
20
+ strike,
21
+ });
22
+ } catch (err) {
23
+ res.status(500).json({ valid: false });
24
+ }
25
+ });
26
+
27
+ // GET /api/strike/status
28
+ router.get("/status", async (req, res) => {
29
+ try {
30
+ const start = new Date();
31
+ start.setHours(0, 0, 0, 0);
32
+
33
+ const end = new Date();
34
+ end.setHours(23, 59, 59, 999);
35
+
36
+ // Fetch today's strike
37
+ const strike = await StrikeHistory.findOne({
38
+ date: { $gte: start, $lte: end },
39
+ }).populate("winners.user_id", "name email");
40
+
41
+ // 1️⃣ STRIKE RUNNING (manual or cron)
42
+ if (global.isStrikeRunning) {
43
+ return res.json({
44
+ status: "RUNNING",
45
+ live: global.liveStrikeData || null,
46
+ });
47
+ }
48
+
49
+ // 2️⃣ NO STRIKE YET
50
+ if (!strike) {
51
+ return res.json({
52
+ status: "IDLE",
53
+ });
54
+ }
55
+
56
+ // 3️⃣ STRIKE COMPLETED
57
+ strike_completed_json = {
58
+ status: "COMPLETED",
59
+ date: strike.date,
60
+ result: {
61
+ target_price: strike.target_price,
62
+ winning_digits: strike.winning_digits,
63
+ total_pool: strike.total_pool,
64
+ audit_hash: strike.audit_hash,
65
+ audit_payload: strike.audit_payload,
66
+ winners: strike.winners
67
+ .sort((a, b) => a.rank - b.rank)
68
+ .slice(0, 3)
69
+ .map((w) => ({
70
+ name: w.user_id?.name || "Anonymous",
71
+ tier: w.tier,
72
+ amount: w.amount,
73
+ rank: w.rank,
74
+ kus_id: w.kus_id,
75
+ })),
76
+ },
77
+ };
78
+
79
+ return res.json(strike_completed_json);
80
+
81
+ console.log("Strike Result:", strike_completed_json);
82
+ } catch (err) {
83
+ console.error("Strike Status Error:", err);
84
+ res.status(500).json({
85
+ status: "ERROR",
86
+ message: "Failed to fetch strike status",
87
+ });
88
+ }
89
+ });
90
+
91
+ module.exports = router;
services/strikeEngine.js ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const axios = require("axios");
2
+ const crypto = require("crypto");
3
+
4
+ const Asset = require("../models/Asset");
5
+ const User = require("../models/User");
6
+ const Transaction = require("../models/Transaction");
7
+ const StrikeHistory = require("../models/StrikeHistory");
8
+ const { sendGlobal, sendToUser } = require('../utils/sendPush');
9
+
10
+ const WIN_PCT = {
11
+ Silver: [0.30, 0.15, 0.08],
12
+ Gold: [0.40, 0.20, 0.10],
13
+ Platinum: [0.50, 0.25, 0.125]
14
+ };
15
+
16
+ const circularDiff = (a, b, mod) => {
17
+ const diff = Math.abs(a - b);
18
+ return Math.min(diff, mod - diff);
19
+ };
20
+
21
+ const secureShuffle = (arr) => {
22
+ for (let i = arr.length - 1; i > 0; i--) {
23
+ const j = crypto.randomInt(0, i + 1);
24
+ [arr[i], arr[j]] = [arr[j], arr[i]];
25
+ }
26
+ };
27
+
28
+ const sha256 = (payload) =>
29
+ crypto.createHash("sha256").update(JSON.stringify(payload)).digest("hex");
30
+
31
+ async function runStrike({ triggeredBy = "CRON" } = {}) {
32
+ if (global.isStrikeRunning) return;
33
+
34
+ global.isStrikeRunning = true;
35
+ global.lastStrikeStatus = "RUNNING";
36
+ global.lastStrikeResult = null;
37
+
38
+ try {
39
+ // ⛔ prevent double strike per day
40
+ const startOfDay = new Date();
41
+ startOfDay.setUTCHours(0, 0, 0, 0);
42
+
43
+ const already = await StrikeHistory.findOne({
44
+ date: { $gte: startOfDay }
45
+ });
46
+
47
+ if (already) {
48
+ global.lastStrikeStatus = "COMPLETED";
49
+ return;
50
+ }
51
+
52
+ // 🔔 START EVENT
53
+ await sendGlobal(
54
+ "⚡ Strike Started!",
55
+ triggeredBy === "ADMIN"
56
+ ? "Admin manually triggered today's strike."
57
+ : "The 8 PM Strike is LIVE.",
58
+ "/"
59
+ );
60
+
61
+ // 1️⃣ BTC PRICE
62
+ const { data } = await axios.get(
63
+ "https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT"
64
+ );
65
+
66
+ const price = parseFloat(data.price).toFixed(2);
67
+
68
+ const btcInt = price.split(".")[0];
69
+ const btcLast3 = parseInt(btcInt.slice(-3));
70
+ const btcLast6 = parseInt(btcInt.slice(-6));
71
+
72
+ global.liveStrikeData = {
73
+ price,
74
+ btcLast3,
75
+ btcLast6
76
+ };
77
+
78
+ // 2️⃣ POOL
79
+ const txs = await Transaction.find({
80
+ timestamp: { $gte: startOfDay },
81
+ status: "Verified"
82
+ });
83
+
84
+ const totalPool = txs.reduce((s, t) => s + t.amount, 0);
85
+
86
+ if (!totalPool) {
87
+ global.lastStrikeStatus = "CANCELLED";
88
+ return;
89
+ }
90
+
91
+ // 3️⃣ ASSETS
92
+ const assets = await Asset.find({
93
+ purchase_date: { $gte: startOfDay },
94
+ status: "Held"
95
+ }).populate("owner_id");
96
+
97
+ // 4️⃣ LOW PARTICIPATION → CANCEL
98
+ if (assets.length <= 3) {
99
+ const prices = { Silver: 500, Gold: 1000, Platinum: 2500 };
100
+
101
+ for (const a of assets) {
102
+ await User.findByIdAndUpdate(a.owner_id._id, {
103
+ $inc: { wallet_balance: prices[a.tier] }
104
+ });
105
+ a.status = "Burned";
106
+ await a.save();
107
+ }
108
+
109
+ global.lastStrikeStatus = "CANCELLED";
110
+ global.lastStrikeResult = { cancelled: true };
111
+
112
+ await sendGlobal(
113
+ "🚫 Strike Cancelled",
114
+ "Low participation. Refunds issued.",
115
+ "/profile"
116
+ );
117
+
118
+ return;
119
+ }
120
+
121
+ // 5️⃣ RANKING
122
+ let ranked = assets.map(asset => {
123
+ const kusLast6 = parseInt(asset.kus_id.slice(-6));
124
+ const kusLast3 = kusLast6 % 1000;
125
+
126
+ return {
127
+ asset,
128
+ diff3: circularDiff(kusLast3, btcLast3, 1000),
129
+ diff6: circularDiff(kusLast6, btcLast6, 1_000_000)
130
+ };
131
+ });
132
+
133
+ ranked.sort((a, b) => {
134
+ if (a.diff3 !== b.diff3) return a.diff3 - b.diff3;
135
+ if (a.diff6 !== b.diff6) return a.diff6 - b.diff6;
136
+ return 0;
137
+ });
138
+
139
+ secureShuffle(ranked.slice(0, 3));
140
+
141
+ // 6️⃣ WINNERS
142
+ const historyWinners = [];
143
+
144
+ for (let i = 0; i < 3; i++) {
145
+ const { asset } = ranked[i];
146
+ const pct = WIN_PCT[asset.tier][i];
147
+ if (!pct) continue;
148
+
149
+ const gross = totalPool * pct;
150
+ const net = gross * (1 - 0.312);
151
+
152
+ await User.findByIdAndUpdate(asset.owner_id._id, {
153
+ $inc: { wallet_balance: net }
154
+ });
155
+
156
+ await Transaction.create({
157
+ user_id: asset.owner_id._id,
158
+ amount: net,
159
+ status: "Verified",
160
+ tier: asset.tier,
161
+ utr: `STRIKE-${Date.now()}`
162
+ });
163
+
164
+ historyWinners.push({
165
+ tier: asset.tier,
166
+ user_id: asset.owner_id._id,
167
+ amount: net,
168
+ rank: i + 1,
169
+ kus_id: asset.kus_id
170
+ });
171
+
172
+ await sendToUser(
173
+ asset.owner_id._id,
174
+ "🏆 YOU WON!",
175
+ `Rank #${i + 1} in today's strike.`,
176
+ "/profile"
177
+ );
178
+ }
179
+
180
+ // 7️⃣ AUDIT
181
+ const auditPayload = {
182
+ price,
183
+ btcLast3,
184
+ btcLast6,
185
+ pool: totalPool,
186
+ participants: assets.map(a => a.kus_id),
187
+ winners: historyWinners,
188
+ triggeredBy
189
+ };
190
+
191
+ const auditHash = sha256(auditPayload);
192
+
193
+ await StrikeHistory.create({
194
+ target_price: price,
195
+ winning_digits: btcLast3,
196
+ total_pool: totalPool,
197
+ audit_hash: auditHash,
198
+ audit_payload: auditPayload,
199
+ winners: historyWinners
200
+ });
201
+
202
+ // ✅ FINAL GLOBAL RESULT (frontend reads this)
203
+ global.lastStrikeStatus = "COMPLETED";
204
+ global.lastStrikeResult = {
205
+ cancelled: false,
206
+ winningDigits: btcLast3,
207
+ winners: historyWinners
208
+ };
209
+
210
+ await sendGlobal(
211
+ "🏁 Results Announced",
212
+ "Strike completed successfully.",
213
+ "/"
214
+ );
215
+
216
+ } catch (err) {
217
+ console.error("❌ Strike failed:", err);
218
+ global.lastStrikeStatus = "FAILED";
219
+ } finally {
220
+ global.isStrikeRunning = false;
221
+ global.liveStrikeData = null;
222
+ console.log("⚡ STRIKE ENDED ⚡");
223
+ }
224
+ }
225
+
226
+
227
+ module.exports = { runStrike };
utils/genKeys.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ const webpush = require('web-push');
2
+ const vapidKeys = webpush.generateVAPIDKeys();
3
+ console.log(vapidKeys);
utils/kusGenerator.js ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const Asset = require('../models/Asset');
2
+
3
+ // Helper to get today's date string (DDMMYY)
4
+ const getTodayDateStr = () => {
5
+ const now = new Date();
6
+ const istOffset = 5.5 * 60 * 60 * 1000;
7
+ const istDate = new Date(now.getTime() + istOffset);
8
+ const dd = String(istDate.getUTCDate()).padStart(2, '0');
9
+ const mm = String(istDate.getUTCMonth() + 1).padStart(2, '0');
10
+ const yy = String(istDate.getUTCFullYear()).slice(-2);
11
+ return `${dd}${mm}${yy}`;
12
+ };
13
+
14
+ // Check if a number is available for today
15
+ const checkAvailability = async (number) => {
16
+ const dateStr = getTodayDateStr();
17
+ // Regex to match any tier prefix but specific date and number
18
+ // Pattern: [XX][DATE][D][NUMBER]
19
+ // We just check if the "number" part (last 6 digits) exists for today
20
+
21
+ // Actually, simpler: Store 'daily_sequence' in Asset or check KUS suffix
22
+ // Let's stick to the requested format: [SYMBOL][DATE][DAY][NUMBER]
23
+
24
+ // We need to query if any asset ends with this number for TODAY
25
+ const startOfDay = new Date();
26
+ startOfDay.setHours(0,0,0,0);
27
+
28
+ const exists = await Asset.findOne({
29
+ purchase_date: { $gte: startOfDay },
30
+ kus_id: { $regex: `${number}$` } // Ends with the number
31
+ });
32
+
33
+ return !exists;
34
+ };
35
+
36
+ // Generate KUS (Random or Specific)
37
+ const generateKUS = async (tier, requestedNumber = null) => {
38
+ const symbols = { Silver: "AG", Gold: "AU", Platinum: "PT" };
39
+ const symbol = symbols[tier];
40
+ const dateStr = getTodayDateStr();
41
+
42
+ const days = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
43
+ const istDate = new Date(new Date().getTime() + (5.5 * 60 * 60 * 1000));
44
+ const dayInitial = days[istDate.getUTCDay()];
45
+
46
+ let finalNumber;
47
+
48
+ if (requestedNumber) {
49
+ // Validate availability
50
+ const isAvailable = await checkAvailability(requestedNumber);
51
+ if (!isAvailable) throw new Error("Number already taken today");
52
+ finalNumber = requestedNumber;
53
+ } else {
54
+ // Random Shuffle Logic (Try until unique)
55
+ let attempts = 0;
56
+ while (attempts < 50) {
57
+ const random = Math.floor(Math.random() * 1000000).toString().padStart(6, '0');
58
+ if (await checkAvailability(random)) {
59
+ finalNumber = random;
60
+ break;
61
+ }
62
+ attempts++;
63
+ }
64
+ if (!finalNumber) throw new Error("High traffic. Try again.");
65
+ }
66
+
67
+ // Format: AU171225W000000
68
+ // Note: Requested 6 digits (0 to 1 million) -> 000000 to 999999
69
+ return `${symbol}${dateStr}${dayInitial}${finalNumber}`;
70
+ };
71
+
72
+ module.exports = { generateKUS, checkAvailability };
utils/ledgerLogger.js ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const AllTransaction = require('../models/AllTransaction');
2
+
3
+ const logTransaction = async (userId, type, amount, currency, description) => {
4
+ try {
5
+ const entry = new AllTransaction({
6
+ user_id: userId,
7
+ type,
8
+ amount,
9
+ currency,
10
+ description
11
+ });
12
+ await entry.save();
13
+ } catch (err) {
14
+ console.error("Ledger Logging Failed:", err);
15
+ }
16
+ };
17
+
18
+ module.exports = logTransaction;
utils/sendPush.js ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const webpush = require('web-push');
2
+ const User = require('../models/User');
3
+
4
+ // Configure Keys (Ensure these are in your .env)
5
+ webpush.setVapidDetails(
6
+ process.env.VAPID_EMAIL,
7
+ process.env.VAPID_PUBLIC_KEY,
8
+ process.env.VAPID_PRIVATE_KEY
9
+ );
10
+
11
+ // SEND TO ONE USER
12
+ const sendToUser = async (userId, title, message, url = '/') => {
13
+ try {
14
+ const user = await User.findById(userId);
15
+ if (user && user.pushSubscription) {
16
+ await webpush.sendNotification(
17
+ user.pushSubscription,
18
+ JSON.stringify({ title, body: message, url })
19
+ );
20
+ }
21
+ } catch (err) {
22
+ // 410 = Gone (User unsubscribed/cleared cache)
23
+ if (err.statusCode === 410) {
24
+ await User.findByIdAndUpdate(userId, { $unset: { pushSubscription: "" } });
25
+ }
26
+ console.error("Push Error (Single):", err.statusCode);
27
+ }
28
+ };
29
+
30
+ // SEND TO EVERYONE (Batching for performance)
31
+ const sendGlobal = async (title, message, url = '/') => {
32
+ try {
33
+ // Fetch users who have a subscription
34
+ const users = await User.find({ pushSubscription: { $exists: true } });
35
+ const payload = JSON.stringify({ title, body: message, url });
36
+
37
+ console.log(`📢 Sending Global Push to ${users.length} devices...`);
38
+
39
+ const promises = users.map(user =>
40
+ webpush.sendNotification(user.pushSubscription, payload).catch(err => {
41
+ if (err.statusCode === 410) {
42
+ User.findByIdAndUpdate(user._id, { $unset: { pushSubscription: "" } });
43
+ }
44
+ })
45
+ );
46
+
47
+ await Promise.all(promises);
48
+ } catch (err) {
49
+ console.error("Push Error (Global):", err);
50
+ }
51
+ };
52
+
53
+ module.exports = { sendToUser, sendGlobal };
utils/verifyToken.js ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const jwt = require('jsonwebtoken');
2
+ const User = require('../models/User'); // Import User model
3
+
4
+ module.exports = async function (req, res, next) {
5
+ const token = req.header('auth-token');
6
+ if (!token) return res.status(401).send('Access Denied');
7
+
8
+ try {
9
+ const verified = jwt.verify(token, process.env.JWT_SECRET);
10
+ req.user = verified;
11
+
12
+ // --- BAN CHECK ---
13
+ // We fetch the user to check their strike count
14
+ const user = await User.findById(req.user._id);
15
+
16
+ if (user && user.ban_strikes >= 3) {
17
+ return res.status(403).json({
18
+ error: "ACCOUNT_BANNED",
19
+ message: "Your account is permanently suspended due to repeated invalid UTR submissions."
20
+ });
21
+ }
22
+ // -----------------
23
+
24
+ next();
25
+ } catch (err) {
26
+ res.status(400).send('Invalid Token');
27
+ }
28
+ };