UNPKG

wisdom-sdk

Version:

Core business logic and data access layer for prediction markets

950 lines (943 loc) 31.4 kB
'use strict'; var kv = require('@vercel/kv'); var transactions = require('@stacks/transactions'); var network = require('@stacks/network'); var backend = require('@clerk/backend'); // src/kv-store.ts // src/logger.ts var createLogger = () => { const logLevel = process.env.LOG_LEVEL || "info"; const logLevels = { debug: 0, info: 1, warn: 2, error: 3 }; const currentLevelValue = logLevel in logLevels ? logLevels[logLevel] : logLevels.info; const formatLog = (level, obj, msg) => { const timestamp = (/* @__PURE__ */ new Date()).toISOString(); const service = "wisdom-sdk"; const objStr = JSON.stringify(obj); return `[${timestamp}] ${level.toUpperCase()} [${service}] ${msg || ""} ${objStr}`; }; return { debug: (obj, msg) => { if (currentLevelValue <= 0) { console.debug(formatLog("debug", obj, msg)); } }, info: (obj, msg) => { if (currentLevelValue <= 1) { console.info(formatLog("info", obj, msg)); } }, warn: (obj, msg) => { if (currentLevelValue <= 2) { console.warn(formatLog("warn", obj, msg)); } }, error: (obj, msg) => { if (currentLevelValue <= 3) { console.error(formatLog("error", obj, msg)); } }, child: (bindings) => { const childLogger = createLogger(); return { debug: (obj, msg) => childLogger.debug({ ...obj, ...bindings }, msg), info: (obj, msg) => childLogger.info({ ...obj, ...bindings }, msg), warn: (obj, msg) => childLogger.warn({ ...obj, ...bindings }, msg), error: (obj, msg) => childLogger.error({ ...obj, ...bindings }, msg), child: (nestedBindings) => childLogger.child({ ...bindings, ...nestedBindings }) }; } }; }; var logger = createLogger(); function getContextLogger(context) { return logger.child({ context }); } var AppError = class extends Error { constructor({ message, context = "general", code = "INTERNAL_ERROR", originalError, data }) { super(message); this.name = "AppError"; this.context = context; this.code = code; this.originalError = originalError; this.data = data; Error.captureStackTrace(this, this.constructor); } // Logs this error with appropriate context and returns it log() { const contextLogger = getContextLogger(this.context); const logObj = { code: this.code, error: this.message, ...this.originalError && { originalError: this.originalError.message }, ...this.data && { data: this.data } }; contextLogger.error(logObj, this.message); return this; } }; // src/kv-store.ts var kvLogger = logger.child({ context: "kv-store" }); var KV_PREFIXES = { MARKET: "market", MARKET_IDS: "market_ids", USER_MARKETS: "user_markets", MARKET_PARTICIPANTS: "market_participants", MARKET_CATEGORY: "market_category", // Index for markets by category MARKET_STATUS: "market_status", // Index for markets by status PREDICTION: "prediction", USER_PREDICTIONS: "user_predictions", MARKET_PREDICTIONS: "market_predictions", PREDICTION_NFT: "prediction_nft", USER_BALANCE: "user_balance", USER_STATS: "user_stats", LEADERBOARD: "leaderboard", LEADERBOARD_EARNINGS: "leaderboard_earnings", LEADERBOARD_ACCURACY: "leaderboard_accuracy", BUG_REPORT: "bug_report", BUG_REPORT_IDS: "bug_report_ids", USER_BUG_REPORTS: "user_bug_reports", // Transaction custody-related prefixes CUSTODY_TRANSACTION: "custody_transaction", CUSTODY_TRANSACTION_IDS: "custody_transaction_ids", USER_TRANSACTIONS: "user_transactions", SIGNER_TRANSACTIONS: "signer_transactions", MARKET_TRANSACTIONS: "market_transactions", CUSTODY_NFT_RECEIPT: "custody_nft_receipt", // Claim reward transaction prefixes CLAIM_REWARD_TRANSACTION: "claim_reward_transaction", USER_CLAIM_REWARDS: "user_claim_rewards" }; function getKey(entityType, id) { const prefix = KV_PREFIXES[entityType]; if (entityType === "MARKET_IDS" && !id) { return prefix; } return id ? `${prefix}:${id}` : prefix; } async function storeEntity(entityType, id, data) { try { const key = getKey(entityType, id); await kv.kv.set(key, JSON.stringify(data)); return data; } catch (error) { throw new AppError({ message: `Failed to store ${entityType} with ID ${id}`, context: "kv-store", code: "KV_STORE_ERROR", originalError: error instanceof Error ? error : new Error(String(error)), data: { entityType, id, operation: "store" } }).log(); } } async function getEntity(entityType, id) { try { const key = getKey(entityType, id); let data = await kv.kv.get(key); if (!data && entityType === "MARKET") { data = await kv.kv.get(`markets:${id}`); } if (!data) { kvLogger.debug({ entityType, id }, `Entity not found: ${entityType}:${id}`); return null; } if (typeof data !== "string") { return data; } try { return JSON.parse(data); } catch (e) { throw new AppError({ message: `Error parsing JSON for ${entityType} with ID ${id}`, context: "kv-store", code: "KV_JSON_PARSE_ERROR", originalError: e instanceof Error ? e : new Error(String(e)), data: { entityType, id, operation: "parse" } }).log(); } } catch (error) { if (error instanceof AppError) { throw error; } throw new AppError({ message: `Failed to retrieve ${entityType} with ID ${id}`, context: "kv-store", code: "KV_RETRIEVE_ERROR", originalError: error instanceof Error ? error : new Error(String(error)), data: { entityType, id, operation: "get" } }).log(); } } async function deleteEntity(entityType, id) { try { const key = getKey(entityType, id); await kv.kv.del(key); if (entityType === "MARKET") ; return true; } catch (error) { new AppError({ message: `Failed to delete ${entityType} with ID ${id}`, context: "kv-store", code: "KV_DELETE_ERROR", originalError: error instanceof Error ? error : new Error(String(error)), data: { entityType, id, operation: "delete" } }).log(); return false; } } async function addToSet(setType, id, memberId) { try { const key = getKey(setType, id); await kv.kv.sadd(key, memberId); if (setType === "MARKET_IDS") { await kv.kv.sadd("market_ids", memberId); } return true; } catch (error) { new AppError({ message: `Failed to add member ${memberId} to set ${setType}:${id}`, context: "kv-store", code: "KV_SET_ADD_ERROR", originalError: error instanceof Error ? error : new Error(String(error)), data: { setType, id, memberId, operation: "sadd" } }).log(); return false; } } async function removeFromSet(setType, id, memberId) { try { const key = getKey(setType, id); await kv.kv.srem(key, memberId); if (setType === "MARKET_IDS") { await kv.kv.srem("market_ids", memberId); } return true; } catch (error) { new AppError({ message: `Failed to remove member ${memberId} from set ${setType}:${id}`, context: "kv-store", code: "KV_SET_REMOVE_ERROR", originalError: error instanceof Error ? error : new Error(String(error)), data: { setType, id, memberId, operation: "srem" } }).log(); return false; } } async function getSetMembers(setType, id) { try { const key = getKey(setType, id); let members = await kv.kv.smembers(key); if (setType === "MARKET_IDS" && members.length === 0) { const legacyMembers = await kv.kv.smembers("market_ids"); if (legacyMembers.length > 0) { for (const marketId of legacyMembers) { await addToSet("MARKET_IDS", "", marketId); } members = legacyMembers; } } return members; } catch (error) { new AppError({ message: `Failed to get members from set ${setType}:${id}`, context: "kv-store", code: "KV_SET_MEMBERS_ERROR", originalError: error instanceof Error ? error : new Error(String(error)), data: { setType, id, operation: "smembers" } }).log(); return []; } } async function startTransaction() { try { const transaction = kv.kv.multi(); const operations = []; const txObject = { operations, // Add entity to transaction async addEntity(entityType, id, data) { const key = getKey(entityType, id); transaction.set(key, JSON.stringify(data)); operations.push({ type: "entity", entityType, id, data }); }, // Add to set in transaction async addToSetInTransaction(setType, id, memberId) { const key = getKey(setType, id); transaction.sadd(key, memberId); operations.push({ type: "set", entityType: setType, id: memberId }); if (setType === "MARKET_IDS") { transaction.sadd("market_ids", memberId); } }, // Add to sorted set in transaction async addToSortedSetInTransaction(setType, memberId, score) { const key = getKey(setType); transaction.zadd(key, { score, member: memberId }); operations.push({ type: "sortedSet", entityType: setType, id: memberId, data: score }); }, // Execute all queued commands atomically async execute() { try { kvLogger.debug( { operationCount: operations.length }, `Executing transaction with ${operations.length} operations` ); await transaction.exec(); return true; } catch (error) { const appError = new AppError({ message: "Transaction execution failed", context: "kv-store", code: "TRANSACTION_FAILED", originalError: error instanceof Error ? error : new Error(String(error)), data: { operationCount: operations.length } }); appError.log(); return false; } } }; return txObject; } catch (error) { throw new AppError({ message: "Failed to start transaction", context: "kv-store", code: "TRANSACTION_START_ERROR", originalError: error instanceof Error ? error : new Error(String(error)) }).log(); } } // src/utils.ts function generateUUID() { if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") { return crypto.randomUUID(); } const getRandomBytes = (n) => { const bytes = new Uint8Array(n); if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") { crypto.getRandomValues(bytes); } else { for (let i = 0; i < n; i++) { bytes[i] = Math.floor(Math.random() * 256); } } return bytes; }; const randomBytes = getRandomBytes(16); randomBytes[6] = randomBytes[6] & 15 | 64; randomBytes[8] = randomBytes[8] & 63 | 128; let hex = ""; for (let i = 0; i < 16; i++) { hex += randomBytes[i].toString(16).padStart(2, "0"); if (i === 3 || i === 5 || i === 7 || i === 9) { hex += "-"; } } return hex; } var CONTRACT_ADDRESS = "SP2ZNGJ85ENDY6QRHQ5P2D4FXKGZWCKTB2T0Z55KS"; var CONTRACT_NAME = "blaze-welsh-v1"; var clerkClient = backend.createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY, publishableKey: process.env.CLERK_PUBLISHABLE_KEY }); var userBalanceStore = { /** * Get the user's Stacks address from Clerk's publicMetadata */ async getUserStacksAddress(userId) { try { const user = await clerkClient.users.getUser(userId); if (user.publicMetadata && typeof user.publicMetadata === "object") { const metadata = user.publicMetadata; if (metadata.stacksAddress) { return metadata.stacksAddress; } } console.warn(`No Stacks address found for user ${userId}`); return null; } catch (error) { console.error(`Error getting Stacks address for user ${userId}:`, error); return null; } }, /** * Fetch a user's on-chain balance from the contract */ async fetchContractBalance(user) { try { const result = await transactions.fetchCallReadOnlyFunction({ contractAddress: CONTRACT_ADDRESS, contractName: CONTRACT_NAME, functionName: "get-balance", functionArgs: [transactions.Cl.principal(user)], network: network.STACKS_MAINNET, senderAddress: user }); const balance = result.type === transactions.ClarityType.UInt ? Number(result.value) : 0; return balance; } catch (error) { console.error("Failed to fetch contract balance:", error); return 0; } }, /** * Get user balance using their Clerk ID * Fetches directly from blockchain if Stacks address is available */ async getUserBalance(userId) { try { if (!userId) return null; const stacksAddress = await this.getUserStacksAddress(userId); let balance = await kvStore.getEntity("USER_BALANCE", userId); if (!balance) { balance = { userId, availableBalance: 0, totalDeposited: 0, totalWithdrawn: 0, inPredictions: 0, lastUpdated: (/* @__PURE__ */ new Date()).toISOString(), stacksAddress: null }; } if (stacksAddress) { balance.stacksAddress = stacksAddress; const contractBalance = await this.fetchContractBalance(stacksAddress); balance.availableBalance = contractBalance; } return balance; } catch (error) { console.error(`Error getting user balance for ${userId}:`, error); return null; } }, // Update user balance when making a prediction async updateBalanceForPrediction(userId, amount) { try { const balance = await this.getUserBalance(userId); if (!balance) return null; if (balance.availableBalance < amount) { throw new Error("Insufficient balance"); } const updatedBalance = { ...balance, availableBalance: balance.availableBalance - amount, inPredictions: balance.inPredictions + amount, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; await kvStore.storeEntity("USER_BALANCE", userId, updatedBalance); return updatedBalance; } catch (error) { console.error(`Error updating balance for prediction, user ${userId}:`, error); throw error; } }, // Update user balance when a prediction is resolved async updateBalanceForResolvedPrediction(userId, originalAmount, winnings = 0) { try { const balance = await this.getUserBalance(userId); if (!balance) return null; const updatedBalance = { ...balance, availableBalance: balance.availableBalance + winnings, inPredictions: balance.inPredictions - originalAmount, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; await kvStore.storeEntity("USER_BALANCE", userId, updatedBalance); return updatedBalance; } catch (error) { console.error(`Error updating balance for resolved prediction, user ${userId}:`, error); throw error; } }, // Add funds to user balance (for deposit functionality) async addFunds(userId, amount) { try { const balance = await this.getUserBalance(userId); if (!balance) return null; const updatedBalance = { ...balance, availableBalance: balance.availableBalance + amount, totalDeposited: balance.totalDeposited + amount, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; await kvStore.storeEntity("USER_BALANCE", userId, updatedBalance); return updatedBalance; } catch (error) { console.error(`Error adding funds for user ${userId}:`, error); throw error; } }, // Withdraw funds from user balance async withdrawFunds(userId, amount) { try { const balance = await this.getUserBalance(userId); if (!balance) return null; if (balance.availableBalance < amount) { throw new Error("Insufficient balance"); } const updatedBalance = { ...balance, availableBalance: balance.availableBalance - amount, totalWithdrawn: balance.totalWithdrawn + amount, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; await kvStore.storeEntity("USER_BALANCE", userId, updatedBalance); return updatedBalance; } catch (error) { console.error(`Error withdrawing funds for user ${userId}:`, error); throw error; } }, // Force refresh a user's balance from the blockchain async refreshBalance(userId) { try { const stacksAddress = await this.getUserStacksAddress(userId); if (!stacksAddress) { throw new Error(`No Stacks address found for user ${userId}`); } const contractBalance = await this.fetchContractBalance(stacksAddress); const balance = await kvStore.getEntity("USER_BALANCE", userId) || { userId, availableBalance: 0, totalDeposited: 0, totalWithdrawn: 0, inPredictions: 0, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; const updatedBalance = { ...balance, availableBalance: contractBalance, stacksAddress, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; await kvStore.storeEntity("USER_BALANCE", userId, updatedBalance); return updatedBalance; } catch (error) { console.error(`Error refreshing balance for user ${userId}:`, error); throw error; } } }; var kvStore = { async getEntity(collection, id) { console.log({ collection, id }); const stacksAddress = await userBalanceStore.getUserStacksAddress(id); let availableBalance = 0; if (stacksAddress) { availableBalance = await userBalanceStore.fetchContractBalance(stacksAddress); } const balance = { userId: id, availableBalance, totalDeposited: 0, totalWithdrawn: 0, inPredictions: 0, lastUpdated: (/* @__PURE__ */ new Date()).toISOString(), stacksAddress }; return balance; }, async storeEntity(collection, id, entity) { console.log({ collection, id, entity }); return null; } }; // src/bug-report-store.ts var bugReportLogger = logger.child({ context: "bug-report-store" }); var DEFAULT_INITIAL_REWARD = 10; var DEFAULT_CONFIRMATION_REWARD = 90; var BugReportStore = class { /** * Get all bug reports */ async getAllBugReports() { try { const reportIds = await getSetMembers("BUG_REPORT_IDS", ""); if (!reportIds || reportIds.length === 0) { return []; } const reports = await Promise.all( reportIds.map(async (id) => { const report = await getEntity("BUG_REPORT", id); return report; }) ); return reports.filter((report) => report !== null); } catch (error) { throw new AppError({ message: "Failed to retrieve bug reports", context: "bug-report-store", code: "BUG_REPORT_FETCH_ERROR", originalError: error instanceof Error ? error : new Error(String(error)) }).log(); } } /** * Get specific bug report by ID */ async getBugReport(id) { if (!id) { bugReportLogger.warn({}, "Attempted to get bug report with empty ID"); return null; } const report = await getEntity("BUG_REPORT", id); if (!report) { bugReportLogger.debug({ reportId: id }, `Bug report ${id} not found`); } return report; } /** * Get all bug reports for a specific user */ async getUserBugReports(userId) { try { if (!userId) { return []; } const reportIds = await getSetMembers("USER_BUG_REPORTS", userId); if (reportIds.length === 0) { return []; } const reports = await Promise.all( reportIds.map((id) => this.getBugReport(id)) ); return reports.filter((report) => report !== null); } catch (error) { throw new AppError({ message: `Failed to retrieve bug reports for user ${userId}`, context: "bug-report-store", code: "USER_BUG_REPORTS_ERROR", originalError: error instanceof Error ? error : new Error(String(error)), data: { userId } }).log(); } } /** * Create a new bug report */ async createBugReport(data) { try { if (!data.title || !data.description || !data.createdBy) { throw new AppError({ message: "Missing required bug report data", context: "bug-report-store", code: "BUG_REPORT_VALIDATION_ERROR", data: { hasTitle: !!data.title, hasDescription: !!data.description, hasCreatedBy: !!data.createdBy } }).log(); } const id = generateUUID(); const now = (/* @__PURE__ */ new Date()).toISOString(); const bugReport = { id, title: data.title, description: data.description, severity: data.severity, url: data.url, createdBy: data.createdBy, createdAt: now, status: "open" }; const tx = await startTransaction(); try { await tx.addEntity("BUG_REPORT", id, bugReport); await tx.addToSetInTransaction("BUG_REPORT_IDS", "", id); await tx.addToSetInTransaction("USER_BUG_REPORTS", data.createdBy, id); const success = await tx.execute(); if (!success) { throw new AppError({ message: "Failed to create bug report - transaction failed", context: "bug-report-store", code: "BUG_REPORT_TRANSACTION_ERROR", data: { reportId: id } }).log(); } bugReportLogger.info( { reportId: id, userId: data.createdBy }, `Bug report created: ${data.title}` ); return bugReport; } catch (error) { if (error instanceof AppError) { throw error; } else { throw new AppError({ message: "Error during bug report creation transaction", context: "bug-report-store", code: "BUG_REPORT_CREATE_TRANSACTION_ERROR", originalError: error instanceof Error ? error : new Error(String(error)), data: { title: data.title } }).log(); } } } catch (error) { if (error instanceof AppError) { throw error; } else { throw new AppError({ message: "Failed to create bug report", context: "bug-report-store", code: "BUG_REPORT_CREATE_ERROR", originalError: error instanceof Error ? error : new Error(String(error)), data: { title: data.title } }).log(); } } } /** * Update an existing bug report */ async updateBugReport(id, data) { try { const existingReport = await this.getBugReport(id); if (!existingReport) { bugReportLogger.warn({ reportId: id }, `Cannot update non-existent bug report with ID ${id}`); return null; } const safeData = { ...data }; if (safeData.id && safeData.id !== id) { delete safeData.id; bugReportLogger.warn( { reportId: id, attemptedId: data.id }, "Attempted to change bug report ID during update - ignoring" ); } const updatedReport = { ...existingReport, ...safeData, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }; await storeEntity("BUG_REPORT", id, updatedReport); bugReportLogger.debug( { reportId: id }, `Bug report updated: ${existingReport.title}` ); return updatedReport; } catch (error) { throw new AppError({ message: `Failed to update bug report ${id}`, context: "bug-report-store", code: "BUG_REPORT_UPDATE_ERROR", originalError: error instanceof Error ? error : new Error(String(error)), data: { reportId: id } }).log(); } } async deleteBugReport(id) { try { const report = await this.getBugReport(id); if (!report) { throw new Error(`Bug report ${id} not found`); } await deleteEntity("BUG_REPORT", id); await removeFromSet("BUG_REPORT_IDS", "", id); await removeFromSet("USER_BUG_REPORTS", report.createdBy, id); return true; } catch (error) { console.error(`Error deleting bug report ${id}:`, error); return false; } } /** * Process a reward payment for a bug report * This handles giving the initial or confirmation reward to a user * * @param reportId Bug report ID * @param userId User ID to receive the reward * @param rewardType Type of reward (initial or confirmation) * @param customAmount Optional custom amount (overrides defaults) * @returns Result object with success/error status */ /** * Confirm a bug report (mark as verified by admin) * @param id Bug report ID * @param adminId ID of the admin confirming the report */ async confirmBugReport(id, adminId) { try { const report = await this.getBugReport(id); if (!report) { bugReportLogger.warn({ reportId: id }, `Cannot confirm non-existent bug report: ${id}`); return null; } if (report.status === "resolved") { bugReportLogger.warn({ reportId: id }, `Bug report ${id} is already resolved`); return report; } const now = (/* @__PURE__ */ new Date()).toISOString(); const updatedReport = await this.updateBugReport(id, { status: "resolved", confirmedBy: adminId, confirmedAt: now, updatedBy: adminId, updatedAt: now }); bugReportLogger.info( { reportId: id, adminId }, `Bug report confirmed: ${report.title}` ); return updatedReport; } catch (error) { throw new AppError({ message: `Failed to confirm bug report ${id}`, context: "bug-report-store", code: "BUG_REPORT_CONFIRM_ERROR", originalError: error instanceof Error ? error : new Error(String(error)), data: { reportId: id, adminId } }).log(); } } /** * Pay a reward for a bug report * @param id Bug report ID * @param isInitialReward Whether to pay the initial (true) or confirmation (false) reward */ async payReward(id, isInitialReward) { try { const report = await this.getBugReport(id); if (!report) { bugReportLogger.warn({ reportId: id }, `Cannot pay reward for non-existent bug report: ${id}`); return null; } const recipientId = report.createdBy; const rewardType = isInitialReward ? "initial" : "confirmation"; const result = await this.processRewardPayment(id, recipientId, rewardType); if (!result.success) { throw new AppError({ message: result.error || "Failed to pay reward", context: "bug-report-store", code: "REWARD_PAYMENT_FAILED", data: { reportId: id, userId: recipientId, rewardType, error: result.error } }); } return result.report || null; } catch (error) { if (error instanceof AppError) { throw error; } else { throw new AppError({ message: `Failed to pay ${isInitialReward ? "initial" : "confirmation"} reward for bug report ${id}`, context: "bug-report-store", code: "REWARD_PAYMENT_ERROR", originalError: error instanceof Error ? error : new Error(String(error)), data: { reportId: id, isInitialReward } }).log(); } } } /** * Internal helper method to process reward payments * This handles giving the initial or confirmation reward to a user */ async processRewardPayment(reportId, userId, rewardType, customAmount) { try { const opLogger = bugReportLogger.child({ operation: "processRewardPayment", reportId, userId, rewardType }); opLogger.info({}, `Processing ${rewardType} reward payment`); const report = await this.getBugReport(reportId); if (!report) { return { success: false, error: "Bug report not found" }; } const amount = customAmount || (rewardType === "initial" ? DEFAULT_INITIAL_REWARD : DEFAULT_CONFIRMATION_REWARD); if (rewardType === "initial" && report.initialRewardPaid) { opLogger.warn({}, "Initial reward already paid for this report"); return { success: false, error: "Initial reward already paid for this report", report }; } if (rewardType === "confirmation" && report.confirmationRewardPaid) { opLogger.warn({}, "Confirmation reward already paid for this report"); return { success: false, error: "Confirmation reward already paid for this report", report }; } opLogger.debug({ amount }, `Processing payment of ${amount} tokens`); const updatedBalance = await userBalanceStore.addFunds(userId, amount); if (!updatedBalance) { throw new AppError({ message: "Failed to update user balance", context: "bug-report-store", code: "BALANCE_UPDATE_FAILED", data: { userId, amount, reportId } }); } const updateData = {}; if (rewardType === "initial") { updateData.initialRewardPaid = true; } else { updateData.confirmationRewardPaid = true; if (report.status !== "resolved") { updateData.status = "resolved"; updateData.confirmedAt = (/* @__PURE__ */ new Date()).toISOString(); } } const updatedReport = await this.updateBugReport(reportId, updateData); if (!updatedReport) { throw new AppError({ message: "Failed to update bug report after payment", context: "bug-report-store", code: "REPORT_UPDATE_FAILED", data: { reportId, rewardType } }); } opLogger.info( { amount, reportId, userId }, `Successfully processed ${rewardType} reward payment` ); return { success: true, amount, report: updatedReport }; } catch (error) { if (error instanceof AppError) { error.log(); return { success: false, error: error.message }; } else { const appError = new AppError({ message: `Error processing reward payment for report ${reportId}`, context: "bug-report-store", code: "REWARD_PROCESS_ERROR", originalError: error instanceof Error ? error : new Error(String(error)), data: { reportId, userId, rewardType } }).log(); return { success: false, error: appError.message }; } } } }; var bugReportStore = new BugReportStore(); exports.BugReportStore = BugReportStore; exports.bugReportStore = bugReportStore; //# sourceMappingURL=bug-report-store.cjs.map //# sourceMappingURL=bug-report-store.cjs.map