From 9e55bc5708eaaf69a6359bd790092c560a226d18 Mon Sep 17 00:00:00 2001 From: Sainan Date: Sat, 8 Mar 2025 11:36:47 +0100 Subject: [PATCH 1/5] rename rivenFingerprintHelper to rivenHelper --- src/controllers/api/activateRandomModController.ts | 2 +- src/controllers/api/completeRandomModChallengeController.ts | 2 +- src/controllers/api/rerollRandomModController.ts | 6 +----- src/helpers/{rivenFingerprintHelper.ts => rivenHelper.ts} | 0 4 files changed, 3 insertions(+), 7 deletions(-) rename src/helpers/{rivenFingerprintHelper.ts => rivenHelper.ts} (100%) diff --git a/src/controllers/api/activateRandomModController.ts b/src/controllers/api/activateRandomModController.ts index bdf67212..5a9d80c5 100644 --- a/src/controllers/api/activateRandomModController.ts +++ b/src/controllers/api/activateRandomModController.ts @@ -1,5 +1,5 @@ import { toOid } from "@/src/helpers/inventoryHelpers"; -import { IRivenChallenge } from "@/src/helpers/rivenFingerprintHelper"; +import { IRivenChallenge } from "@/src/helpers/rivenHelper"; import { getJSONfromString } from "@/src/helpers/stringHelpers"; import { addMods, getInventory } from "@/src/services/inventoryService"; import { getAccountIdForRequest } from "@/src/services/loginService"; diff --git a/src/controllers/api/completeRandomModChallengeController.ts b/src/controllers/api/completeRandomModChallengeController.ts index ef5e7d2a..a4e3cf08 100644 --- a/src/controllers/api/completeRandomModChallengeController.ts +++ b/src/controllers/api/completeRandomModChallengeController.ts @@ -4,7 +4,7 @@ import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inven import { IInventoryChanges } from "@/src/types/purchaseTypes"; import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes"; import { getJSONfromString } from "@/src/helpers/stringHelpers"; -import { createUnveiledRivenFingerprint } from "@/src/helpers/rivenFingerprintHelper"; +import { createUnveiledRivenFingerprint } from "@/src/helpers/rivenHelper"; import { ExportUpgrades } from "warframe-public-export-plus"; export const completeRandomModChallengeController: RequestHandler = async (req, res) => { diff --git a/src/controllers/api/rerollRandomModController.ts b/src/controllers/api/rerollRandomModController.ts index 9dc84e5f..20e7218a 100644 --- a/src/controllers/api/rerollRandomModController.ts +++ b/src/controllers/api/rerollRandomModController.ts @@ -2,11 +2,7 @@ import { RequestHandler } from "express"; import { getAccountIdForRequest } from "@/src/services/loginService"; import { addMiscItems, getInventory } from "@/src/services/inventoryService"; import { getJSONfromString } from "@/src/helpers/stringHelpers"; -import { - createUnveiledRivenFingerprint, - randomiseRivenStats, - RivenFingerprint -} from "@/src/helpers/rivenFingerprintHelper"; +import { createUnveiledRivenFingerprint, randomiseRivenStats, RivenFingerprint } from "@/src/helpers/rivenHelper"; import { ExportUpgrades } from "warframe-public-export-plus"; import { IOid } from "@/src/types/commonTypes"; diff --git a/src/helpers/rivenFingerprintHelper.ts b/src/helpers/rivenHelper.ts similarity index 100% rename from src/helpers/rivenFingerprintHelper.ts rename to src/helpers/rivenHelper.ts -- 2.47.2 From 143e0f77fa28df4954c2d6b978da4a03ca4ff530 Mon Sep 17 00:00:00 2001 From: Sainan Date: Sat, 8 Mar 2025 11:53:15 +0100 Subject: [PATCH 2/5] move rivenRawToRealWeighted into rivenHelper --- .../api/activateRandomModController.ts | 36 +------------------ src/helpers/rivenHelper.ts | 34 ++++++++++++++++++ 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/controllers/api/activateRandomModController.ts b/src/controllers/api/activateRandomModController.ts index 5a9d80c5..79947d7b 100644 --- a/src/controllers/api/activateRandomModController.ts +++ b/src/controllers/api/activateRandomModController.ts @@ -1,5 +1,5 @@ import { toOid } from "@/src/helpers/inventoryHelpers"; -import { IRivenChallenge } from "@/src/helpers/rivenHelper"; +import { IRivenChallenge, rivenRawToRealWeighted } from "@/src/helpers/rivenHelper"; import { getJSONfromString } from "@/src/helpers/stringHelpers"; import { addMods, getInventory } from "@/src/services/inventoryService"; import { getAccountIdForRequest } from "@/src/services/loginService"; @@ -61,37 +61,3 @@ export const activateRandomModController: RequestHandler = async (req, res) => { interface IActiveRandomModRequest { ItemType: string; } - -const rivenRawToRealWeighted: Record = { - "/Lotus/Upgrades/Mods/Randomized/RawArchgunRandomMod": [ - "/Lotus/Upgrades/Mods/Randomized/LotusArchgunRandomModRare" - ], - "/Lotus/Upgrades/Mods/Randomized/RawMeleeRandomMod": [ - "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare" - ], - "/Lotus/Upgrades/Mods/Randomized/RawModularMeleeRandomMod": [ - "/Lotus/Upgrades/Mods/Randomized/LotusModularMeleeRandomModRare" - ], - "/Lotus/Upgrades/Mods/Randomized/RawModularPistolRandomMod": [ - "/Lotus/Upgrades/Mods/Randomized/LotusModularPistolRandomModRare" - ], - "/Lotus/Upgrades/Mods/Randomized/RawPistolRandomMod": ["/Lotus/Upgrades/Mods/Randomized/LotusPistolRandomModRare"], - "/Lotus/Upgrades/Mods/Randomized/RawRifleRandomMod": ["/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare"], - "/Lotus/Upgrades/Mods/Randomized/RawShotgunRandomMod": [ - "/Lotus/Upgrades/Mods/Randomized/LotusShotgunRandomModRare" - ], - "/Lotus/Upgrades/Mods/Randomized/RawSentinelWeaponRandomMod": [ - "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", - "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", - "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", - "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", - "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", - "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", - "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", - "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", - "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", - "/Lotus/Upgrades/Mods/Randomized/LotusShotgunRandomModRare", - "/Lotus/Upgrades/Mods/Randomized/LotusPistolRandomModRare", - "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare" - ] -}; diff --git a/src/helpers/rivenHelper.ts b/src/helpers/rivenHelper.ts index e5fa261d..006d4ce4 100644 --- a/src/helpers/rivenHelper.ts +++ b/src/helpers/rivenHelper.ts @@ -63,3 +63,37 @@ export const randomiseRivenStats = (meta: IUpgrade, fingerprint: IUnveiledRivenF fingerprint.curses.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) }); } }; + +export const rivenRawToRealWeighted: Record = { + "/Lotus/Upgrades/Mods/Randomized/RawArchgunRandomMod": [ + "/Lotus/Upgrades/Mods/Randomized/LotusArchgunRandomModRare" + ], + "/Lotus/Upgrades/Mods/Randomized/RawMeleeRandomMod": [ + "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare" + ], + "/Lotus/Upgrades/Mods/Randomized/RawModularMeleeRandomMod": [ + "/Lotus/Upgrades/Mods/Randomized/LotusModularMeleeRandomModRare" + ], + "/Lotus/Upgrades/Mods/Randomized/RawModularPistolRandomMod": [ + "/Lotus/Upgrades/Mods/Randomized/LotusModularPistolRandomModRare" + ], + "/Lotus/Upgrades/Mods/Randomized/RawPistolRandomMod": ["/Lotus/Upgrades/Mods/Randomized/LotusPistolRandomModRare"], + "/Lotus/Upgrades/Mods/Randomized/RawRifleRandomMod": ["/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare"], + "/Lotus/Upgrades/Mods/Randomized/RawShotgunRandomMod": [ + "/Lotus/Upgrades/Mods/Randomized/LotusShotgunRandomModRare" + ], + "/Lotus/Upgrades/Mods/Randomized/RawSentinelWeaponRandomMod": [ + "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", + "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", + "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", + "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", + "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", + "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", + "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", + "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", + "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare", + "/Lotus/Upgrades/Mods/Randomized/LotusShotgunRandomModRare", + "/Lotus/Upgrades/Mods/Randomized/LotusPistolRandomModRare", + "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare" + ] +}; -- 2.47.2 From aa7a809e6d5dbe31b9a5f5b4c62aa2f717c549fd Mon Sep 17 00:00:00 2001 From: Sainan Date: Sat, 8 Mar 2025 11:53:57 +0100 Subject: [PATCH 3/5] add createVeiledRivenFingerprint to rivenHelper --- .../api/activateRandomModController.ts | 33 +++---------------- src/helpers/rivenHelper.ts | 24 +++++++++++++- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/controllers/api/activateRandomModController.ts b/src/controllers/api/activateRandomModController.ts index 79947d7b..85b12fb9 100644 --- a/src/controllers/api/activateRandomModController.ts +++ b/src/controllers/api/activateRandomModController.ts @@ -1,10 +1,9 @@ import { toOid } from "@/src/helpers/inventoryHelpers"; -import { IRivenChallenge, rivenRawToRealWeighted } from "@/src/helpers/rivenHelper"; +import { createVeiledRivenFingerprint, rivenRawToRealWeighted } from "@/src/helpers/rivenHelper"; import { getJSONfromString } from "@/src/helpers/stringHelpers"; import { addMods, getInventory } from "@/src/services/inventoryService"; import { getAccountIdForRequest } from "@/src/services/loginService"; -import { getRandomElement, getRandomInt, getRandomReward } from "@/src/services/rngService"; -import { logger } from "@/src/utils/logger"; +import { getRandomElement } from "@/src/services/rngService"; import { RequestHandler } from "express"; import { ExportUpgrades } from "warframe-public-export-plus"; @@ -19,39 +18,17 @@ export const activateRandomModController: RequestHandler = async (req, res) => { } ]); const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType]); - const challenge = getRandomElement(ExportUpgrades[rivenType].availableChallenges!); - const fingerprintChallenge: IRivenChallenge = { - Type: challenge.fullName, - Progress: 0, - Required: getRandomInt(challenge.countRange[0], challenge.countRange[1]) - }; - if (Math.random() < challenge.complicationChance) { - const complications: { type: string; probability: number }[] = []; - for (const complication of challenge.complications) { - complications.push({ - type: complication.fullName, - probability: complication.weight - }); - } - fingerprintChallenge.Complication = getRandomReward(complications)!.type; - logger.debug( - `riven rolled challenge ${fingerprintChallenge.Type} with complication ${fingerprintChallenge.Complication}` - ); - const complication = challenge.complications.find(x => x.fullName == fingerprintChallenge.Complication)!; - fingerprintChallenge.Required *= complication.countMultiplier; - } else { - logger.debug(`riven rolled challenge ${fingerprintChallenge.Type}`); - } + const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]); const upgradeIndex = inventory.Upgrades.push({ ItemType: rivenType, - UpgradeFingerprint: JSON.stringify({ challenge: fingerprintChallenge }) + UpgradeFingerprint: JSON.stringify(fingerprint) }) - 1; await inventory.save(); // For some reason, in this response, the UpgradeFingerprint is simply a nested object and not a string res.json({ NewMod: { - UpgradeFingerprint: { challenge: fingerprintChallenge }, + UpgradeFingerprint: fingerprint, ItemType: inventory.Upgrades[upgradeIndex].ItemType, ItemId: toOid(inventory.Upgrades[upgradeIndex]._id) } diff --git a/src/helpers/rivenHelper.ts b/src/helpers/rivenHelper.ts index 006d4ce4..e3819b64 100644 --- a/src/helpers/rivenHelper.ts +++ b/src/helpers/rivenHelper.ts @@ -1,5 +1,5 @@ import { IUpgrade } from "warframe-public-export-plus"; -import { getRandomElement, getRandomInt } from "../services/rngService"; +import { getRandomElement, getRandomInt, getRandomReward } from "../services/rngService"; export type RivenFingerprint = IVeiledRivenFingerprint | IUnveiledRivenFingerprint; @@ -30,6 +30,28 @@ interface IRivenStat { Value: number; } +export const createVeiledRivenFingerprint = (meta: IUpgrade): IVeiledRivenFingerprint => { + const challenge = getRandomElement(meta.availableChallenges!); + const fingerprintChallenge: IRivenChallenge = { + Type: challenge.fullName, + Progress: 0, + Required: getRandomInt(challenge.countRange[0], challenge.countRange[1]) + }; + if (Math.random() < challenge.complicationChance) { + const complications: { type: string; probability: number }[] = []; + for (const complication of challenge.complications) { + complications.push({ + type: complication.fullName, + probability: complication.weight + }); + } + fingerprintChallenge.Complication = getRandomReward(complications)!.type; + const complication = challenge.complications.find(x => x.fullName == fingerprintChallenge.Complication)!; + fingerprintChallenge.Required *= complication.countMultiplier; + } + return { challenge: fingerprintChallenge }; +}; + export const createUnveiledRivenFingerprint = (meta: IUpgrade): IUnveiledRivenFingerprint => { const fingerprint: IUnveiledRivenFingerprint = { compat: getRandomElement(meta.compatibleItems!), -- 2.47.2 From 6478481d418eabc6de973f481fc1ff012cbe1f7b Mon Sep 17 00:00:00 2001 From: Sainan Date: Sat, 8 Mar 2025 12:23:30 +0100 Subject: [PATCH 4/5] avoid lookup --- src/controllers/api/activateRandomModController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/api/activateRandomModController.ts b/src/controllers/api/activateRandomModController.ts index 85b12fb9..4ac822c7 100644 --- a/src/controllers/api/activateRandomModController.ts +++ b/src/controllers/api/activateRandomModController.ts @@ -29,7 +29,7 @@ export const activateRandomModController: RequestHandler = async (req, res) => { res.json({ NewMod: { UpgradeFingerprint: fingerprint, - ItemType: inventory.Upgrades[upgradeIndex].ItemType, + ItemType: rivenType, ItemId: toOid(inventory.Upgrades[upgradeIndex]._id) } }); -- 2.47.2 From 4b0915bd8028dc540c599c8bf6e653c65f12d0b1 Mon Sep 17 00:00:00 2001 From: Sainan Date: Sat, 8 Mar 2025 12:23:42 +0100 Subject: [PATCH 5/5] feat: transmutation --- package-lock.json | 8 +- package.json | 2 +- .../api/artifactTransmutationController.ts | 124 ++++++++++++++++++ src/routes/api.ts | 2 + 4 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 src/controllers/api/artifactTransmutationController.ts diff --git a/package-lock.json b/package-lock.json index 13edcb84..99bdfa62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "copyfiles": "^2.4.1", "express": "^5", "mongoose": "^8.11.0", - "warframe-public-export-plus": "^0.5.40", + "warframe-public-export-plus": "^0.5.41", "warframe-riven-info": "^0.1.2", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" @@ -4083,9 +4083,9 @@ } }, "node_modules/warframe-public-export-plus": { - "version": "0.5.40", - "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.40.tgz", - "integrity": "sha512-/qr46LE/KqDdEkW4z52EG0vZP0Z8U26FscFJ2G5K5ewbQdlSVxtf5fpOnzRkAO7jWWKfgoqx7l5WUgaLSPDj0g==" + "version": "0.5.41", + "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.41.tgz", + "integrity": "sha512-qVOUY4UjF1cyBrBbMwD25xHSdSf9q57/CJgjHsfSE7NUu/6pBDSZzwS0iAetAukws/1V2kDvsuy8AGtOec2L1w==" }, "node_modules/warframe-riven-info": { "version": "0.1.2", diff --git a/package.json b/package.json index 6fcb225d..50710c25 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "copyfiles": "^2.4.1", "express": "^5", "mongoose": "^8.11.0", - "warframe-public-export-plus": "^0.5.40", + "warframe-public-export-plus": "^0.5.41", "warframe-riven-info": "^0.1.2", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" diff --git a/src/controllers/api/artifactTransmutationController.ts b/src/controllers/api/artifactTransmutationController.ts new file mode 100644 index 00000000..3fd52535 --- /dev/null +++ b/src/controllers/api/artifactTransmutationController.ts @@ -0,0 +1,124 @@ +import { toOid } from "@/src/helpers/inventoryHelpers"; +import { createVeiledRivenFingerprint, rivenRawToRealWeighted } from "@/src/helpers/rivenHelper"; +import { addMiscItems, addMods, getInventory } from "@/src/services/inventoryService"; +import { getAccountIdForRequest } from "@/src/services/loginService"; +import { getRandomElement, getRandomWeightedReward, getRandomWeightedRewardUc } from "@/src/services/rngService"; +import { IOid } from "@/src/types/commonTypes"; +import { RequestHandler } from "express"; +import { ExportBoosterPacks, ExportUpgrades, TRarity } from "warframe-public-export-plus"; + +export const artifactTransmutationController: RequestHandler = async (req, res) => { + const accountId = await getAccountIdForRequest(req); + const inventory = await getInventory(accountId); + const payload = JSON.parse(String(req.body)) as IArtifactTransmutationRequest; + + inventory.RegularCredits -= payload.Cost; + inventory.FusionPoints -= payload.FusionPointCost; + + if (payload.RivenTransmute) { + addMiscItems(inventory, [ + { + ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientSecretItem", + ItemCount: -1 + } + ]); + + payload.Consumed.forEach(upgrade => { + inventory.Upgrades.pull({ _id: upgrade.ItemId.$oid }); + }); + + const rawRivenType = getRandomRawRivenType(); + const rivenType = getRandomElement(rivenRawToRealWeighted[rawRivenType]); + const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]); + + const upgradeIndex = + inventory.Upgrades.push({ + ItemType: rivenType, + UpgradeFingerprint: JSON.stringify(fingerprint) + }) - 1; + await inventory.save(); + res.json({ + NewMods: [ + { + ItemId: toOid(inventory.Upgrades[upgradeIndex]._id), + ItemType: rivenType, + UpgradeFingerprint: fingerprint + } + ] + }); + } else { + const counts: Record = { + COMMON: 0, + UNCOMMON: 0, + RARE: 0, + LEGENDARY: 0 + }; + payload.Consumed.forEach(upgrade => { + const meta = ExportUpgrades[upgrade.ItemType]; + counts[meta.rarity] += upgrade.ItemCount; + addMods(inventory, [ + { + ItemType: upgrade.ItemType, + ItemCount: upgrade.ItemCount * -1 + } + ]); + }); + + // Based on the table on https://wiki.warframe.com/w/Transmutation + const weights: Record = { + COMMON: counts.COMMON * 95 + counts.UNCOMMON * 15 + counts.RARE * 4, + UNCOMMON: counts.COMMON * 4 + counts.UNCOMMON * 80 + counts.RARE * 10, + RARE: counts.COMMON * 1 + counts.UNCOMMON * 5 + counts.RARE * 50, + LEGENDARY: 0 + }; + + const options: { uniqueName: string; rarity: TRarity }[] = []; + Object.entries(ExportUpgrades).forEach(([uniqueName, upgrade]) => { + if (upgrade.canBeTransmutation) { + options.push({ uniqueName, rarity: upgrade.rarity }); + } + }); + + const newModType = getRandomWeightedReward(options, weights)!.uniqueName; + addMods(inventory, [ + { + ItemType: newModType, + ItemCount: 1 + } + ]); + + await inventory.save(); + res.json({ + NewMods: [ + { + ItemType: newModType, + ItemCount: 1 + } + ] + }); + } +}; + +const getRandomRawRivenType = (): string => { + const pack = ExportBoosterPacks["/Lotus/Types/BoosterPacks/CalendarRivenPack"]; + return getRandomWeightedRewardUc(pack.components, pack.rarityWeightsPerRoll[0])!.Item; +}; + +interface IArtifactTransmutationRequest { + Upgrade: IAgnosticUpgradeClient; + LevelDiff: number; + Consumed: IAgnosticUpgradeClient[]; + Cost: number; + FusionPointCost: number; + RivenTransmute?: boolean; +} + +interface IAgnosticUpgradeClient { + ItemType: string; + ItemId: IOid; + FromSKU: boolean; + UpgradeFingerprint: string; + PendingRerollFingerprint: string; + ItemCount: number; + LastAdded: IOid; +} diff --git a/src/routes/api.ts b/src/routes/api.ts index bb63982e..964ebd5d 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -7,6 +7,7 @@ import { addFriendImageController } from "@/src/controllers/api/addFriendImageCo import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController"; import { archonFusionController } from "@/src/controllers/api/archonFusionController"; import { artifactsController } from "@/src/controllers/api/artifactsController"; +import { artifactTransmutationController } from "@/src/controllers/api/artifactTransmutationController"; import { changeDojoRootController } from "@/src/controllers/api/changeDojoRootController"; import { checkDailyMissionBonusController } from "@/src/controllers/api/checkDailyMissionBonusController"; import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController"; @@ -150,6 +151,7 @@ apiRouter.post("/addFriendImage.php", addFriendImageController); apiRouter.post("/arcaneCommon.php", arcaneCommonController); apiRouter.post("/archonFusion.php", archonFusionController); apiRouter.post("/artifacts.php", artifactsController); +apiRouter.post("/artifactTransmutation.php", artifactTransmutationController); apiRouter.post("/changeDojoRoot.php", changeDojoRootController); apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController); apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController); -- 2.47.2