Compare commits

...

No commits in common. "main" and "fix-currency-sync" have entirely different histories.

6 changed files with 77 additions and 7 deletions

0
UPDATE AND START SERVER.sh Executable file → Normal file
View File

0
docker-entrypoint.sh Executable file → Normal file
View File

3
package-lock.json generated
View File

@ -33,6 +33,9 @@
"prettier": "^3.5.3",
"tree-kill": "^1.2.2"
},
"engines": {
"node": ">=20.18.1"
},
"optionalDependencies": {
"@types/express": "^5",
"@types/morgan": "^1.9.9",

View File

@ -4,14 +4,64 @@ import type { IPurchaseRequest } from "../../types/purchaseTypes.ts";
import { handlePurchase } from "../../services/purchaseService.ts";
import { getInventory } from "../../services/inventoryService.ts";
import { sendWsBroadcastTo } from "../../services/wsService.ts";
import { logger } from "../../utils/logger.ts";
export const purchaseController: RequestHandler = async (req, res) => {
const purchaseRequest = JSON.parse(String(req.body)) as IPurchaseRequest;
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId);
const response = await handlePurchase(purchaseRequest, inventory);
await inventory.save();
//console.log(JSON.stringify(response, null, 2));
res.json(response);
sendWsBroadcastTo(accountId, { update_inventory: true });
try {
const inventory = await getInventory(accountId);
const beforePurchase = {
RegularCredits: inventory.RegularCredits,
PremiumCredits: inventory.PremiumCredits,
PremiumCreditsFree: inventory.PremiumCreditsFree
};
logger.debug(`Purchase attempt - Account: ${accountId}, Item: ${purchaseRequest.PurchaseParams.StoreItem}, Price: ${purchaseRequest.PurchaseParams.ExpectedPrice}, UsePremium: ${purchaseRequest.PurchaseParams.UsePremium}`);
logger.debug(`Currency before purchase:`, beforePurchase);
const response = await handlePurchase(purchaseRequest, inventory);
await inventory.save();
const afterPurchase = {
RegularCredits: inventory.RegularCredits,
PremiumCredits: inventory.PremiumCredits,
PremiumCreditsFree: inventory.PremiumCreditsFree
};
logger.debug(`Currency after purchase:`, afterPurchase);
res.json(response);
sendWsBroadcastTo(accountId, {
update_inventory: true,
currency_update: {
RegularCredits: inventory.RegularCredits,
PremiumCredits: inventory.PremiumCredits,
PremiumCreditsFree: inventory.PremiumCreditsFree
}
});
} catch (error) {
logger.error(`Purchase failed for account ${accountId}:`, error);
if (error instanceof Error && error.message.includes('Insufficient')) {
res.status(400).json({
error: 'INSUFFICIENT_CURRENCY',
message: error.message,
details: {
item: purchaseRequest.PurchaseParams.StoreItem,
price: purchaseRequest.PurchaseParams.ExpectedPrice,
usePremium: purchaseRequest.PurchaseParams.UsePremium
}
});
} else {
res.status(500).json({
error: 'PURCHASE_FAILED',
message: error instanceof Error ? error.message : 'Unknown error occurred'
});
}
}
};

View File

@ -1254,10 +1254,18 @@ export const updateCurrency = (
inventory: TInventoryDatabaseDocument,
price: number,
usePremium: boolean,
inventoryChanges: IInventoryChanges = {}
inventoryChanges: IInventoryChanges = {},
validateBalance: boolean = true
): IInventoryChanges => {
if (price != 0 && isCurrencyTracked(inventory, usePremium)) {
if (usePremium) {
if (validateBalance) {
const totalPlatinum = inventory.PremiumCredits + inventory.PremiumCreditsFree;
if (totalPlatinum < price) {
throw new Error(`Insufficient platinum balance. Required: ${price}, Available: ${totalPlatinum}`);
}
}
if (inventory.PremiumCreditsFree > 0) {
const premiumCreditsFreeDelta = Math.min(price, inventory.PremiumCreditsFree) * -1;
inventoryChanges.PremiumCreditsFree ??= 0;
@ -1269,6 +1277,10 @@ export const updateCurrency = (
inventory.PremiumCredits -= price;
logger.debug(`currency changes `, { PremiumCredits: -price });
} else {
if (validateBalance && inventory.RegularCredits < price) {
throw new Error(`Insufficient credits balance. Required: ${price}, Available: ${inventory.RegularCredits}`);
}
inventoryChanges.RegularCredits ??= 0;
inventoryChanges.RegularCredits -= price;
inventory.RegularCredits -= price;

View File

@ -77,6 +77,11 @@ interface IWsMsgToClient {
nonce_updated?: boolean;
update_inventory?: boolean;
logged_out?: boolean;
currency_update?: {
RegularCredits: number;
PremiumCredits: number;
PremiumCreditsFree: number;
};
}
const wsOnConnect = (ws: ws, req: http.IncomingMessage): void => {