diff --git a/platforms/eReputation-api/package.json b/platforms/eReputation-api/package.json index a8f32ff02..e249de606 100644 --- a/platforms/eReputation-api/package.json +++ b/platforms/eReputation-api/package.json @@ -14,11 +14,9 @@ }, "dependencies": { "axios": "^1.6.7", - "bullmq": "^5.3.0", "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.18.2", - "ioredis": "^5.3.2", "jsonwebtoken": "^9.0.2", "openai": "^4.20.1", "pg": "^8.11.3", diff --git a/platforms/eReputation-api/src/controllers/WebhookController.ts b/platforms/eReputation-api/src/controllers/WebhookController.ts index f788badd7..39b1e13e9 100644 --- a/platforms/eReputation-api/src/controllers/WebhookController.ts +++ b/platforms/eReputation-api/src/controllers/WebhookController.ts @@ -3,11 +3,13 @@ import { UserService } from "../services/UserService"; import { GroupService } from "../services/GroupService"; import { VoteService } from "../services/VoteService"; import { PollService } from "../services/PollService"; -import { JobQueueService } from "../services/JobQueueService"; +import { VotingReputationService } from "../services/VotingReputationService"; +import { MessageService } from "../services/MessageService"; import { adapter } from "../web3adapter/watchers/subscriber"; import { User } from "../database/entities/User"; import { Group } from "../database/entities/Group"; import { Poll } from "../database/entities/Poll"; +import { VoteReputationResult } from "../database/entities/VoteReputationResult"; import { AppDataSource } from "../database/data-source"; import axios from "axios"; @@ -16,15 +18,17 @@ export class WebhookController { groupService: GroupService; voteService: VoteService; pollService: PollService; - jobQueueService: JobQueueService; + votingReputationService: VotingReputationService; + messageService: MessageService; adapter: typeof adapter; - constructor(jobQueueService: JobQueueService) { + constructor() { this.userService = new UserService(); this.groupService = new GroupService(); this.voteService = new VoteService(); this.pollService = new PollService(); - this.jobQueueService = jobQueueService; + this.votingReputationService = new VotingReputationService(); + this.messageService = new MessageService(); this.adapter = adapter; } @@ -261,17 +265,11 @@ export class WebhookController { await pollRepository.save(poll); finalLocalId = poll.id; - // Enqueue reputation calculation job if needed + // Process eReputation calculation if needed if (this.voteService.isEReputationWeighted(poll) && poll.groupId) { - try { - await this.jobQueueService.enqueuePollReputationJob( - poll.id, - poll.groupId, - globalId // Use globalId as eventId for idempotency - ); - } catch (error) { - console.error(`Failed to enqueue reputation job for poll ${poll.id}:`, error); - } + this.processEReputationWeightedPoll(poll).catch((error) => { + console.error(`Error processing eReputation for poll ${poll.id}:`, error); + }); } } } else { @@ -297,17 +295,11 @@ export class WebhookController { }); finalLocalId = savedPoll.id; - // Enqueue reputation calculation job if needed + // Process eReputation calculation if needed if (this.voteService.isEReputationWeighted(savedPoll) && savedPoll.groupId) { - try { - await this.jobQueueService.enqueuePollReputationJob( - savedPoll.id, - savedPoll.groupId, - globalId // Use globalId as eventId for idempotency - ); - } catch (error) { - console.error(`Failed to enqueue reputation job for poll ${savedPoll.id}:`, error); - } + this.processEReputationWeightedPoll(savedPoll).catch((error) => { + console.error(`Error processing eReputation for poll ${savedPoll.id}:`, error); + }); } } } @@ -319,4 +311,115 @@ export class WebhookController { } }; + private async processEReputationWeightedPoll(poll: Poll): Promise { + if (!poll.groupId) return; + + const group = await this.groupService.getGroupById(poll.groupId); + if (!group || !group.charter) return; + + const reputationResults = await this.votingReputationService.calculateGroupMemberReputations( + poll.groupId, + group.charter + ); + + const voteReputationResult = await this.votingReputationService.saveReputationResults( + poll.id, + poll.groupId, + reputationResults + ); + + await this.transmitReputationResults(voteReputationResult, poll, group); + await this.createReputationMessage(poll, reputationResults); + } + + private async transmitReputationResults( + result: VoteReputationResult, + poll: Poll, + group: Group + ): Promise { + const voteReputationResultRepository = AppDataSource.getRepository(VoteReputationResult); + const pollRepository = AppDataSource.getRepository(Poll); + const groupRepository = AppDataSource.getRepository(Group); + + const reloadedResult = await voteReputationResultRepository.findOne({ + where: { id: result.id }, + relations: ["poll", "group"] + }); + + if (!reloadedResult) throw new Error(`Result not found: ${result.id}`); + + let pollEntity: Poll | null = reloadedResult.poll || null; + let groupEntity: Group | null = reloadedResult.group || null; + + if (!pollEntity && reloadedResult.pollId) { + pollEntity = await pollRepository.findOne({ where: { id: reloadedResult.pollId } }); + } + + if (!groupEntity && reloadedResult.groupId) { + groupEntity = await groupRepository.findOne({ + where: { id: reloadedResult.groupId }, + select: ["id", "ename", "name"] + }); + } + + if (!pollEntity || !groupEntity || !groupEntity.ename) { + throw new Error("Missing required data for transmission"); + } + + const data: any = { + id: reloadedResult.id, + pollId: reloadedResult.pollId, + groupId: reloadedResult.groupId, + results: JSON.stringify(reloadedResult.results), + createdAt: reloadedResult.createdAt, + updatedAt: reloadedResult.updatedAt, + poll: { + id: pollEntity.id, + groupId: pollEntity.groupId, + group: { + id: groupEntity.id, + ename: groupEntity.ename, + name: groupEntity.name + } + } + }; + + if (!data.groupId) { + data.groupId = groupEntity.id; + } + + await this.adapter.handleChange({ + data, + tableName: "vote_reputation_results" + }); + } + + private async createReputationMessage( + poll: Poll, + reputationResults: Array<{ ename: string; score: number; justification: string }> + ): Promise { + if (!poll.groupId) return; + + try { + const messageLines: string[] = []; + messageLines.push(`eReputation scores calculated for poll: "${poll.title}"`); + messageLines.push(``); + + for (const result of reputationResults) { + const user = await this.userService.getUserByEname(result.ename); + const userName = user?.name || "Unknown"; + messageLines.push(`${userName} (@${result.ename}): ${result.score}/5`); + messageLines.push(` ${result.justification}`); + messageLines.push(``); + } + + await this.messageService.createSystemMessage({ + text: messageLines.join('\n'), + groupId: poll.groupId, + voteId: poll.id + }); + } catch (error) { + console.error(`Failed to create system message for poll ${poll.id}:`, error); + } + } } diff --git a/platforms/eReputation-api/src/index.ts b/platforms/eReputation-api/src/index.ts index 359688874..8269f06e6 100644 --- a/platforms/eReputation-api/src/index.ts +++ b/platforms/eReputation-api/src/index.ts @@ -15,8 +15,6 @@ import { GroupController } from "./controllers/GroupController"; import { DashboardController } from "./controllers/DashboardController"; import { authMiddleware, authGuard } from "./middleware/auth"; import { adapter } from "./web3adapter/watchers/subscriber"; -import { JobQueueService } from "./services/JobQueueService"; -import { PollReputationWorker } from "./workers/PollReputationWorker"; config({ path: path.resolve(__dirname, "../../../.env") }); @@ -51,14 +49,10 @@ app.use( app.use(express.json({ limit: "50mb" })); app.use(express.urlencoded({ limit: "50mb", extended: true })); -// Initialize job queue and worker -const jobQueueService = new JobQueueService(); -const pollReputationWorker = new PollReputationWorker(jobQueueService); - // Controllers const userController = new UserController(); const authController = new AuthController(); -const webhookController = new WebhookController(jobQueueService); +const webhookController = new WebhookController(); const referenceController = new ReferenceController(); const calculationController = new CalculationController(); const platformController = new PlatformController(); diff --git a/platforms/eReputation-api/src/services/JobQueueService.ts b/platforms/eReputation-api/src/services/JobQueueService.ts deleted file mode 100644 index 6dba43faf..000000000 --- a/platforms/eReputation-api/src/services/JobQueueService.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { Queue, QueueOptions } from "bullmq"; -import Redis from "ioredis"; - -export interface PollReputationJobData { - pollId: string; - eventId: string; // For idempotency - groupId: string; -} - -export class JobQueueService { - private queue: Queue; - private redis: Redis; - - constructor() { - // Create Redis connection - this.redis = new Redis({ - host: process.env.REDIS_HOST || "localhost", - port: parseInt(process.env.REDIS_PORT || "6379", 10), - maxRetriesPerRequest: null, - }); - - // Create BullMQ queue - const queueOptions: QueueOptions = { - connection: { - host: process.env.REDIS_HOST || "localhost", - port: parseInt(process.env.REDIS_PORT || "6379", 10), - }, - defaultJobOptions: { - attempts: 3, - backoff: { - type: "exponential", - delay: 2000, - }, - removeOnComplete: { - age: 3600, // Keep completed jobs for 1 hour - count: 1000, - }, - removeOnFail: { - age: 86400, // Keep failed jobs for 24 hours - }, - }, - }; - - this.queue = new Queue("poll-reputation-calculation", queueOptions); - } - - /** - * Enqueue a poll reputation calculation job with deduplication - */ - async enqueuePollReputationJob( - pollId: string, - groupId: string, - eventId: string - ): Promise { - try { - // Use pollId as the job ID for deduplication (same poll = same job) - const jobId = `poll-reputation:${pollId}`; - - // Check if job already exists or was recently processed - const existingJob = await this.queue.getJob(jobId); - if (existingJob) { - const state = await existingJob.getState(); - if (state === "active" || state === "waiting" || state === "delayed") { - // Job already queued, skip - return; - } - } - - // Add job with deduplication - await this.queue.add( - "calculate-poll-reputation", - { - pollId, - groupId, - eventId, - }, - { - jobId, // Use pollId as job ID for deduplication - removeOnComplete: true, - removeOnFail: false, - } - ); - } catch (error) { - throw error; - } - } - - /** - * Close the queue connection - */ - async close(): Promise { - await this.queue.close(); - await this.redis.quit(); - } - - getQueue(): Queue { - return this.queue; - } -} - diff --git a/platforms/eReputation-api/src/workers/PollReputationWorker.ts b/platforms/eReputation-api/src/workers/PollReputationWorker.ts deleted file mode 100644 index ba7dc4adb..000000000 --- a/platforms/eReputation-api/src/workers/PollReputationWorker.ts +++ /dev/null @@ -1,219 +0,0 @@ -import { Worker, Job } from "bullmq"; -import { PollReputationJobData, JobQueueService } from "../services/JobQueueService"; -import { VotingReputationService } from "../services/VotingReputationService"; -import { MessageService } from "../services/MessageService"; -import { GroupService } from "../services/GroupService"; -import { PollService } from "../services/PollService"; -import { AppDataSource } from "../database/data-source"; -import { Poll } from "../database/entities/Poll"; -import { VoteReputationResult } from "../database/entities/VoteReputationResult"; -import { Group } from "../database/entities/Group"; -import { UserService } from "../services/UserService"; - -export class PollReputationWorker { - private worker: Worker; - private votingReputationService: VotingReputationService; - private messageService: MessageService; - private groupService: GroupService; - private pollService: PollService; - private userService: UserService; - - constructor(queueService: JobQueueService) { - this.votingReputationService = new VotingReputationService(); - this.messageService = new MessageService(); - this.groupService = new GroupService(); - this.pollService = new PollService(); - this.userService = new UserService(); - - this.worker = new Worker( - "poll-reputation-calculation", - async (job: Job) => { - await this.processJob(job); - }, - { - connection: { - host: process.env.REDIS_HOST || "localhost", - port: parseInt(process.env.REDIS_PORT || "6379", 10), - }, - concurrency: 1, // Process one job at a time to avoid conflicts - limiter: { - max: 5, - duration: 10000, // Max 5 jobs per 10 seconds - }, - } - ); - - this.worker.on("failed", (job, err) => { - console.error(`Job ${job?.id} failed:`, err); - }); - } - - private async processJob(job: Job): Promise { - const { pollId, groupId, eventId } = job.data; - - try { - // Load poll - const poll = await this.pollService.getPollById(pollId); - if (!poll) { - throw new Error(`Poll not found: ${pollId}`); - } - - if (!poll.groupId) { - throw new Error("Poll has no groupId, cannot calculate eReputation"); - } - - // Get group with charter - const group = await this.groupService.getGroupById(poll.groupId); - if (!group) { - throw new Error("Group not found for poll"); - } - - if (!group.charter) { - throw new Error("Group has no charter, cannot calculate eReputation"); - } - - // Calculate reputations for all group members - const reputationResults = await this.votingReputationService.calculateGroupMemberReputations( - poll.groupId, - group.charter - ); - - // Save results - const voteReputationResult = await this.votingReputationService.saveReputationResults( - poll.id, - poll.groupId, - reputationResults - ); - - // Transmit results via web3adapter - await this.transmitReputationResults(voteReputationResult, poll, group); - - // Create system message with eReputation results - await this.createReputationMessage(poll, reputationResults); - } catch (error) { - console.error(`Error processing poll reputation job for poll ${pollId}:`, error); - throw error; // Re-throw to mark job as failed - } - } - - private async transmitReputationResults( - result: VoteReputationResult, - poll: Poll, - group: Group - ): Promise { - const voteReputationResultRepository = AppDataSource.getRepository(VoteReputationResult); - const pollRepository = AppDataSource.getRepository(Poll); - const groupRepository = AppDataSource.getRepository(Group); - - // Reload result with relations - const reloadedResult = await voteReputationResultRepository.findOne({ - where: { id: result.id }, - relations: ["poll", "group"] - }); - - if (!reloadedResult) { - throw new Error(`Result not found: ${result.id}`); - } - - let pollEntity: Poll | null = reloadedResult.poll || null; - let groupEntity: Group | null = reloadedResult.group || null; - - if (!pollEntity && reloadedResult.pollId) { - pollEntity = await pollRepository.findOne({ - where: { id: reloadedResult.pollId } - }); - } - - if (!groupEntity && reloadedResult.groupId) { - groupEntity = await groupRepository.findOne({ - where: { id: reloadedResult.groupId }, - select: ["id", "ename", "name"] - }); - } - - if (!pollEntity) { - throw new Error(`Poll not found: ${reloadedResult.pollId}`); - } - - if (!groupEntity) { - throw new Error(`Group not found: ${reloadedResult.groupId}`); - } - - if (!groupEntity.ename) { - throw new Error(`Group ${groupEntity.id} has no ename! This will cause ownerEnamePath to fail.`); - } - - // Convert entity to plain object for web3adapter - const data: any = { - id: reloadedResult.id, - pollId: reloadedResult.pollId, - groupId: reloadedResult.groupId, - results: JSON.stringify(reloadedResult.results), - createdAt: reloadedResult.createdAt, - updatedAt: reloadedResult.updatedAt - }; - - // Add poll with group for ownerEnamePath resolution - data.poll = { - id: pollEntity.id, - groupId: pollEntity.groupId, - group: { - id: groupEntity.id, - ename: groupEntity.ename, - name: groupEntity.name - } - }; - - if (!data.groupId) { - data.groupId = groupEntity.id; - } - - // Use web3adapter to sync to eVault - const { adapter } = await import("../web3adapter/watchers/subscriber"); - await adapter.handleChange({ - data, - tableName: "vote_reputation_results" - }); - } - - private async createReputationMessage( - poll: Poll, - reputationResults: Array<{ ename: string; score: number; justification: string }> - ): Promise { - if (!poll.groupId) return; - - try { - const messageLines: string[] = []; - messageLines.push(`eReputation scores calculated for poll: "${poll.title}"`); - messageLines.push(``); - - for (const result of reputationResults) { - const user = await this.userService.getUserByEname(result.ename); - const userName = user?.name || "Unknown"; - const userEname = result.ename; - const score = result.score; - const justification = result.justification; - - messageLines.push(`${userName} (@${userEname}): ${score}/5`); - messageLines.push(` ${justification}`); - messageLines.push(``); - } - - const messageText = messageLines.join('\n'); - - await this.messageService.createSystemMessage({ - text: messageText, - groupId: poll.groupId, - voteId: poll.id - }); - } catch (error) { - console.error(`Failed to create system message for poll ${poll.id}:`, error); - // Don't throw - message creation failure shouldn't fail the job - } - } - - async close(): Promise { - await this.worker.close(); - } -} - diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b88459a70..b5c9d6698 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1478,9 +1478,6 @@ importers: axios: specifier: ^1.6.7 version: 1.13.2 - bullmq: - specifier: ^5.3.0 - version: 5.64.0 cors: specifier: ^2.8.5 version: 2.8.5 @@ -1490,9 +1487,6 @@ importers: express: specifier: ^4.18.2 version: 4.21.2 - ioredis: - specifier: ^5.3.2 - version: 5.8.2 jsonwebtoken: specifier: ^9.0.2 version: 9.0.2 @@ -4591,36 +4585,6 @@ packages: '@mixmark-io/domino@2.2.0': resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==} - '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': - resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==} - cpu: [arm64] - os: [darwin] - - '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3': - resolution: {integrity: sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==} - cpu: [x64] - os: [darwin] - - '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3': - resolution: {integrity: sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==} - cpu: [arm64] - os: [linux] - - '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3': - resolution: {integrity: sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==} - cpu: [arm] - os: [linux] - - '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3': - resolution: {integrity: sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==} - cpu: [x64] - os: [linux] - - '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': - resolution: {integrity: sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==} - cpu: [x64] - os: [win32] - '@mui/base@5.0.0-beta.40': resolution: {integrity: sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==} engines: {node: '>=12.0.0'} @@ -7915,9 +7879,6 @@ packages: builtin-status-codes@3.0.0: resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} - bullmq@5.64.0: - resolution: {integrity: sha512-4o+RWWayu/yiRzETY7rP4Ol/iRh4YpMn37kRrIR0UkbxHVwQyuj3ReAgAEpPeHmGRXsMnnI1+lA/zxMSJZQ3tA==} - byline@5.0.0: resolution: {integrity: sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==} engines: {node: '>=0.10.0'} @@ -8278,10 +8239,6 @@ packages: crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} - cron-parser@4.9.0: - resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==} - engines: {node: '>=12.0.0'} - cross-fetch@3.2.0: resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==} @@ -10941,10 +10898,6 @@ packages: peerDependencies: svelte: ^3 || ^4 || ^5.0.0-next.42 - luxon@3.7.2: - resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} - engines: {node: '>=12'} - lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -11343,13 +11296,6 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - msgpackr-extract@3.0.3: - resolution: {integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==} - hasBin: true - - msgpackr@1.11.5: - resolution: {integrity: sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==} - multiformats@13.4.1: resolution: {integrity: sha512-VqO6OSvLrFVAYYjgsr8tyv62/rCQhPgsZUXLTqoFLSgdkgiUYKYeArbt1uWLlEpkjxQe+P0+sHlbPEte1Bi06Q==} @@ -11443,9 +11389,6 @@ packages: resolution: {integrity: sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==} engines: {node: '>=10'} - node-abort-controller@3.1.1: - resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} - node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} @@ -11484,10 +11427,6 @@ packages: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} - node-gyp-build-optional-packages@5.2.2: - resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} - hasBin: true - node-gyp-build@4.8.4: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true @@ -16325,7 +16264,8 @@ snapshots: transitivePeerDependencies: - babel-plugin-macros - '@ioredis/commands@1.4.0': {} + '@ioredis/commands@1.4.0': + optional: true '@isaacs/cliui@8.0.2': dependencies: @@ -17120,24 +17060,6 @@ snapshots: '@mixmark-io/domino@2.2.0': {} - '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': - optional: true - - '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3': - optional: true - - '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3': - optional: true - - '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3': - optional: true - - '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3': - optional: true - - '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': - optional: true - '@mui/base@5.0.0-beta.40(@types/react@18.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.28.4 @@ -21186,18 +21108,6 @@ snapshots: builtin-status-codes@3.0.0: {} - bullmq@5.64.0: - dependencies: - cron-parser: 4.9.0 - ioredis: 5.8.2 - msgpackr: 1.11.5 - node-abort-controller: 3.1.1 - semver: 7.7.3 - tslib: 2.8.1 - uuid: 11.1.0 - transitivePeerDependencies: - - supports-color - byline@5.0.0: {} bytes@3.1.2: {} @@ -21389,7 +21299,8 @@ snapshots: clsx@2.1.1: {} - cluster-key-slot@1.1.2: {} + cluster-key-slot@1.1.2: + optional: true cmdk@1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: @@ -21596,10 +21507,6 @@ snapshots: crelt@1.0.6: {} - cron-parser@4.9.0: - dependencies: - luxon: 3.7.2 - cross-fetch@3.2.0(encoding@0.1.13): dependencies: node-fetch: 2.7.0(encoding@0.1.13) @@ -21863,7 +21770,8 @@ snapshots: delegates@1.0.0: optional: true - denque@2.1.0: {} + denque@2.1.0: + optional: true depd@2.0.0: {} @@ -24050,6 +23958,7 @@ snapshots: standard-as-callback: 2.1.0 transitivePeerDependencies: - supports-color + optional: true ip-address@10.1.0: optional: true @@ -25354,11 +25263,13 @@ snapshots: lodash.clonedeep@4.5.0: {} - lodash.defaults@4.2.0: {} + lodash.defaults@4.2.0: + optional: true lodash.includes@4.3.0: {} - lodash.isarguments@3.1.0: {} + lodash.isarguments@3.1.0: + optional: true lodash.isboolean@3.0.3: {} @@ -25438,8 +25349,6 @@ snapshots: dependencies: svelte: 5.43.12 - luxon@3.7.2: {} - lz-string@1.5.0: {} magic-string@0.30.21: @@ -26071,22 +25980,6 @@ snapshots: ms@2.1.3: {} - msgpackr-extract@3.0.3: - dependencies: - node-gyp-build-optional-packages: 5.2.2 - optionalDependencies: - '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.3 - '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.3 - '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.3 - '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.3 - '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.3 - '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3 - optional: true - - msgpackr@1.11.5: - optionalDependencies: - msgpackr-extract: 3.0.3 - multiformats@13.4.1: {} mz@2.7.0: @@ -26197,8 +26090,6 @@ snapshots: dependencies: semver: 7.7.3 - node-abort-controller@3.1.1: {} - node-addon-api@7.1.1: {} node-cron@3.0.3: @@ -26223,11 +26114,6 @@ snapshots: node-forge@1.3.1: {} - node-gyp-build-optional-packages@5.2.2: - dependencies: - detect-libc: 2.1.2 - optional: true - node-gyp-build@4.8.4: optional: true @@ -27386,11 +27272,13 @@ snapshots: indent-string: 4.0.0 strip-indent: 3.0.0 - redis-errors@1.2.0: {} + redis-errors@1.2.0: + optional: true redis-parser@3.0.0: dependencies: redis-errors: 1.2.0 + optional: true reflect-metadata@0.2.2: {} @@ -27956,7 +27844,8 @@ snapshots: stackback@0.0.2: {} - standard-as-callback@2.1.0: {} + standard-as-callback@2.1.0: + optional: true statuses@2.0.1: {} @@ -29824,4 +29713,4 @@ snapshots: react: 18.3.1 use-sync-external-store: 1.6.0(react@18.3.1) - zwitch@2.0.4: {} \ No newline at end of file + zwitch@2.0.4: {}