UNPKG

warframe-worldstate-parser

Version:

An Open parser for Warframe's Worldstate in Javascript

539 lines (538 loc) 17.4 kB
import { n as __decorateMetadata, t as __decorate } from "../decorate-BCC26nnB.mjs"; import { Alert } from "./models/Alert.mjs"; import { Archimedea } from "./models/Archimedea.mjs"; import { Calendar } from "./models/Calendar.mjs"; import { CambionCycle } from "./models/CambionCycle.mjs"; import { CetusCycle } from "./models/CetusCycle.mjs"; import { ClanInitiativeRewards } from "./models/ClanInitiativeRewards.mjs"; import { ConclaveChallenge } from "./models/ConclaveChallenge.mjs"; import { ConstructionProgress } from "./models/ConstructionProgress.mjs"; import { DailyDeal } from "./models/DailyDeal.mjs"; import { DarkSector } from "./models/DarkSector.mjs"; import { DuviriChoice } from "./supporting/DuviriChoice.mjs"; import { DuviriCycle } from "./models/DuviriCycle.mjs"; import { EarthCycle } from "./models/EarthCycle.mjs"; import { Fissure } from "./models/Fissure.mjs"; import { FlashSale } from "./models/FlashSale.mjs"; import { GlobalUpgrade } from "./models/GlobalUpgrade.mjs"; import { Invasion } from "./models/Invasion.mjs"; import { ExternalMission } from "./supporting/ExternalMission.mjs"; import "./supporting/index.mjs"; import { Kuva } from "./models/Kuva.mjs"; import { News } from "./models/News.mjs"; import { Nightwave } from "./models/Nightwave.mjs"; import { PersistentEnemy } from "./models/PersistentEnemy.mjs"; import { Simaris } from "./models/Simaris.mjs"; import { Sortie } from "./models/Sortie.mjs"; import { SteelPathOfferings } from "./models/SteelPathOffering.mjs"; import { SyndicateMission } from "./models/SyndicateMission.mjs"; import { Tmp } from "./models/Tmp.mjs"; import { VallisCycle } from "./models/VallisCycle.mjs"; import { VoidTrader } from "./models/VoidTrader.mjs"; import { WeeklyChallenge } from "./models/WeeklyChallenge.mjs"; import { WorldEvent } from "./models/WorldEvent.mjs"; import { ZarimanCycle } from "./models/ZarimanCycle.mjs"; import "./models/index.mjs"; import { createHash } from "node:crypto"; import { Type } from "class-transformer"; import { IsArray, IsDate, IsOptional, IsString, ValidateNested } from "class-validator"; import wsData from "warframe-worldstate-data"; import { parseDate } from "warframe-worldstate-data/utilities"; //#region lib/WorldState.ts const { sortie } = wsData; const safeArray = (arr) => arr ?? []; const safeObj = (obj) => obj ?? {}; /** * Default Dependency object * @type {Dependency} */ const defaultDeps = { sortieData: sortie, locale: "en", logger: console }; /** * * @param ParserClass class for parsing data * @param dataArray array of raw data * @param deps shared dependency object * @param uniqueField field to treat as unique * @returns array of parsed objects */ function parseArray(ParserClass, dataArray, deps, uniqueField) { const arr = (dataArray || []).map((d) => new ParserClass(d, deps)); if (uniqueField) { const utemp = {}; arr.sort((a, b) => (a.id || "").localeCompare(b.id || "")); arr.forEach((obj) => { const key = String(obj[uniqueField]); utemp[key] = obj; }); return Array.from(arr).filter((obj) => { if (obj?.active && typeof obj.active !== "undefined") return obj.active; return true; }); } return arr; } /** * Parse array of objects that requires async parsing * @param ParserClass class for parsing data - must expose a static build method * @param dataArray array of raw data * @param deps shared dependency object * @param uniqueField field to treat as unique * @returns array of parsed objects */ async function parseAsyncArray(ParserClass, dataArray, deps, uniqueField) { const arr = []; for await (const d of dataArray ?? []) arr.push(await ParserClass.build(d, deps)); if (uniqueField) { const utemp = {}; arr.sort((a, b) => (a.id ?? "").localeCompare(b.id ?? "")); arr.forEach((obj) => { const key = String(obj[uniqueField]); utemp[key] = obj; }); return Array.from(arr).filter((obj) => { if (obj?.active && typeof obj.active !== "undefined") return obj.active; return true; }); } return arr; } /** * Parses Warframe Worldstate JSON */ var WorldState = class WorldState { /** * The date and time at which the World State was generated */ timestamp; /** * Current Warframe version */ buildLabel; /** * The in-game news */ news; /** * The current events */ events; /** * The current alerts */ alerts; /** * The current sortie */ sortie; /** * The current syndicate missions */ syndicateMissions; /** * The current fissures: 'ActiveMissions' & 'VoidStorms' */ fissures; /** * The current global upgrades */ globalUpgrades; /** * The current flash sales */ flashSales; /** * The current invasions */ invasions; /** * The state of the dark sectors */ darkSectors; /** * The state of all Void Traders */ voidTraders; /** * The first entry for voidTraders * @deprecated */ voidTrader; /** * The current daily deals */ dailyDeals; /** * The state of the sanctuary synthesis targets */ simaris; /** * The current conclave challenges */ conclaveChallenges; /** * The currently active persistent enemies */ persistentEnemies; /** * The current earth cycle */ earthCycle; /** * The current Cetus cycle */ cetusCycle; /** * Cambion Drift Cycle */ cambionCycle; /** * The current Zariman cycle based off current time */ zarimanCycle; /** * Midrath cycle (soulframe) * Game seems to desync while you play and appearntly it changes between updates. */ /** * Weekly challenges */ weeklyChallenges; /** * The Current construction progress for Fomorians/Razorback/etc. */ constructionProgress; /** * The current Orb Vallis cycle state */ vallisCycle; /** * The current nightwave season */ nightwave; /** * Kuva missions array */ kuva; /** * Arbitration mission */ arbitration; /** * Current sentient outposts */ sentientOutposts; /** * Steel path offering rotation */ steelPath; /** * The current prime resurgence */ vaultTrader; /** * The current archon hunt */ archonHunt; /** * Current Duviri circuit choices */ duviriCycle; /** * Current kinepage message */ kinepage; /** * The current Archimedea missions and modifiers */ archimedeas; /** * The current calendar for 1999 */ calendar; /** * Faceoff bonus current state */ faceoffBonus; /** * Warframe's annual Quest to Conquer Cancer donation count and next tier goal */ questToConquerCancer; /** * The current week's clan initiative rewards */ clanWeeklyInitiative; /** * Generates the worldstate json as a string into usable objects */ static async build(json, deps = defaultDeps) { if (typeof json !== "string") throw new TypeError(`json needs to be a string, provided ${typeof json} : ${JSON.stringify(json)}`); const data = JSON.parse(json); const ws = new WorldState(data, deps); ws.events = await parseAsyncArray(WorldEvent, data.Goals, deps); ws.syndicateMissions = await parseAsyncArray(SyndicateMission, data.SyndicateMissions, deps, "syndicate"); return ws; } /** * @param data The worldstate JSON string * @param deps The options object */ constructor(data, deps = defaultDeps) { deps = { ...defaultDeps, ...deps }; this.timestamp = /* @__PURE__ */ new Date(data.Time * 1e3); this.buildLabel = data.BuildLabel; this.news = parseArray(News, safeArray(data.Events).filter((e) => typeof e.Messages.find((msg) => msg.LanguageCode === deps.locale) !== "undefined"), deps); this.events = []; this.alerts = parseArray(Alert, data.Alerts, deps); [this.sortie] = parseArray(Sortie, data.Sorties, deps); this.syndicateMissions = []; this.fissures = parseArray(Fissure, data.ActiveMissions, deps).concat(parseArray(Fissure, data.VoidStorms, deps)); this.globalUpgrades = parseArray(GlobalUpgrade, data.GlobalUpgrades, deps); this.flashSales = parseArray(FlashSale, data.FlashSales, deps); this.invasions = parseArray(Invasion, data.Invasions, deps); this.darkSectors = parseArray(DarkSector, data.BadlandNodes, deps); this.voidTraders = parseArray(VoidTrader, data.VoidTraders, deps).sort((a, b) => a.activation.getTime() - b.activation.getTime()); [this.voidTrader] = this.voidTraders; this.dailyDeals = parseArray(DailyDeal, data.DailyDeals, deps); this.simaris = new Simaris(safeObj(data.LibraryInfo), deps); this.conclaveChallenges = parseArray(ConclaveChallenge, data.PVPChallengeInstances, deps); this.persistentEnemies = parseArray(PersistentEnemy, data.PersistentEnemies, deps); this.earthCycle = new EarthCycle(); const cetusSynd = safeArray(data.SyndicateMissions).filter((syndicate) => syndicate.Tag === "CetusSyndicate"); const bountyEnd = parseDate(cetusSynd.length > 0 ? cetusSynd[0].Expiry : { $date: { $numberLong: 0 } }); this.cetusCycle = new CetusCycle(bountyEnd); this.cambionCycle = new CambionCycle(this.cetusCycle); this.zarimanCycle = new ZarimanCycle(bountyEnd); this.weeklyChallenges = data.WeeklyChallenges ? new WeeklyChallenge(data.WeeklyChallenges) : void 0; this.constructionProgress = new ConstructionProgress(data.ProjectPct); this.vallisCycle = new VallisCycle(); if (data.SeasonInfo) this.nightwave = new Nightwave(data.SeasonInfo, deps); const externalMissions = new Kuva(deps); ({kuva: this.kuva, arbitration: this.arbitration} = externalMissions); if (!this.arbitration || !Object.keys(this.arbitration).length) this.arbitration = { id: createHash("sha256").update("SolNode000", "utf8").digest("hex"), node: "SolNode000", nodeKey: "SolNode000", activation: /* @__PURE__ */ new Date(0), expiry: /* @__PURE__ */ new Date(864e13), enemy: "Tenno", type: "Unknown", typeKey: "Unknown", archwing: false, sharkwing: false, expired: true }; this.steelPath = new SteelPathOfferings(deps); [this.vaultTrader] = parseArray(VoidTrader, data.PrimeVaultTraders, { ...deps, character: "Varzia" }); [this.archonHunt] = parseArray(Sortie, data.LiteSorties, deps); const choices = parseArray(DuviriChoice, safeArray(data.EndlessXpSchedule?.[0]?.CategoryChoices), deps); this.duviriCycle = new DuviriCycle(choices); [this.calendar] = parseArray(Calendar, data.KnownCalendarSeasons, deps); this.archimedeas = parseArray(Archimedea, data.Conquests, deps); ({kinepage: this.kinepage, sentientOutposts: this.sentientOutposts, faceoffBonus: this.faceoffBonus, questToConquerCancer: this.questToConquerCancer} = new Tmp(data.Tmp, deps)); const clanWeeklyInitiative = parseArray(ClanInitiativeRewards, data.WeeklyVaultBonusRewards, deps); this.clanWeeklyInitiative = clanWeeklyInitiative?.[0]; } }; __decorate([ IsDate(), Type(() => Date), __decorateMetadata("design:type", typeof Date === "undefined" ? Object : Date) ], WorldState.prototype, "timestamp", void 0); __decorate([IsString(), __decorateMetadata("design:type", String)], WorldState.prototype, "buildLabel", void 0); __decorate([ IsArray(), ValidateNested({ each: true }), Type(() => News), __decorateMetadata("design:type", Array) ], WorldState.prototype, "news", void 0); __decorate([ IsArray(), ValidateNested({ each: true }), Type(() => WorldEvent), __decorateMetadata("design:type", Array) ], WorldState.prototype, "events", void 0); __decorate([ IsArray(), ValidateNested({ each: true }), Type(() => Alert), __decorateMetadata("design:type", Array) ], WorldState.prototype, "alerts", void 0); __decorate([ ValidateNested(), Type(() => Sortie), __decorateMetadata("design:type", typeof Sortie === "undefined" ? Object : Sortie) ], WorldState.prototype, "sortie", void 0); __decorate([ IsArray(), ValidateNested({ each: true }), Type(() => SyndicateMission), __decorateMetadata("design:type", Array) ], WorldState.prototype, "syndicateMissions", void 0); __decorate([ IsArray(), ValidateNested({ each: true }), Type(() => Fissure), __decorateMetadata("design:type", Array) ], WorldState.prototype, "fissures", void 0); __decorate([ IsArray(), ValidateNested({ each: true }), Type(() => GlobalUpgrade), __decorateMetadata("design:type", Array) ], WorldState.prototype, "globalUpgrades", void 0); __decorate([ IsArray(), ValidateNested({ each: true }), Type(() => FlashSale), __decorateMetadata("design:type", Array) ], WorldState.prototype, "flashSales", void 0); __decorate([ IsArray(), ValidateNested({ each: true }), Type(() => Invasion), __decorateMetadata("design:type", Array) ], WorldState.prototype, "invasions", void 0); __decorate([ IsArray(), ValidateNested({ each: true }), Type(() => DarkSector), __decorateMetadata("design:type", Array) ], WorldState.prototype, "darkSectors", void 0); __decorate([ IsArray(), ValidateNested({ each: true }), Type(() => VoidTrader), __decorateMetadata("design:type", Array) ], WorldState.prototype, "voidTraders", void 0); __decorate([ ValidateNested(), Type(() => VoidTrader), __decorateMetadata("design:type", typeof VoidTrader === "undefined" ? Object : VoidTrader) ], WorldState.prototype, "voidTrader", void 0); __decorate([ IsArray(), ValidateNested({ each: true }), Type(() => DailyDeal), __decorateMetadata("design:type", Array) ], WorldState.prototype, "dailyDeals", void 0); __decorate([ ValidateNested(), Type(() => Simaris), __decorateMetadata("design:type", typeof Simaris === "undefined" ? Object : Simaris) ], WorldState.prototype, "simaris", void 0); __decorate([ IsArray(), ValidateNested({ each: true }), Type(() => ConclaveChallenge), __decorateMetadata("design:type", Array) ], WorldState.prototype, "conclaveChallenges", void 0); __decorate([ IsArray(), ValidateNested({ each: true }), Type(() => PersistentEnemy), __decorateMetadata("design:type", Array) ], WorldState.prototype, "persistentEnemies", void 0); __decorate([ ValidateNested(), Type(() => EarthCycle), __decorateMetadata("design:type", typeof EarthCycle === "undefined" ? Object : EarthCycle) ], WorldState.prototype, "earthCycle", void 0); __decorate([ ValidateNested(), Type(() => CetusCycle), __decorateMetadata("design:type", typeof CetusCycle === "undefined" ? Object : CetusCycle) ], WorldState.prototype, "cetusCycle", void 0); __decorate([ ValidateNested(), Type(() => CambionCycle), __decorateMetadata("design:type", typeof CambionCycle === "undefined" ? Object : CambionCycle) ], WorldState.prototype, "cambionCycle", void 0); __decorate([ ValidateNested(), Type(() => ZarimanCycle), __decorateMetadata("design:type", typeof ZarimanCycle === "undefined" ? Object : ZarimanCycle) ], WorldState.prototype, "zarimanCycle", void 0); __decorate([ IsOptional(), ValidateNested(), Type(() => WeeklyChallenge), __decorateMetadata("design:type", typeof WeeklyChallenge === "undefined" ? Object : WeeklyChallenge) ], WorldState.prototype, "weeklyChallenges", void 0); __decorate([ ValidateNested(), Type(() => ConstructionProgress), __decorateMetadata("design:type", typeof ConstructionProgress === "undefined" ? Object : ConstructionProgress) ], WorldState.prototype, "constructionProgress", void 0); __decorate([ ValidateNested(), Type(() => VallisCycle), __decorateMetadata("design:type", typeof VallisCycle === "undefined" ? Object : VallisCycle) ], WorldState.prototype, "vallisCycle", void 0); __decorate([ IsOptional(), ValidateNested(), Type(() => Nightwave), __decorateMetadata("design:type", typeof Nightwave === "undefined" ? Object : Nightwave) ], WorldState.prototype, "nightwave", void 0); __decorate([ IsOptional(), IsArray(), ValidateNested({ each: true }), Type(() => ExternalMission), __decorateMetadata("design:type", Array) ], WorldState.prototype, "kuva", void 0); __decorate([ IsOptional(), ValidateNested(), Type(() => ExternalMission), __decorateMetadata("design:type", typeof ExternalMission === "undefined" ? Object : ExternalMission) ], WorldState.prototype, "arbitration", void 0); __decorate([ ValidateNested(), Type(() => SteelPathOfferings), __decorateMetadata("design:type", typeof SteelPathOfferings === "undefined" ? Object : SteelPathOfferings) ], WorldState.prototype, "steelPath", void 0); __decorate([ ValidateNested(), Type(() => VoidTrader), __decorateMetadata("design:type", typeof VoidTrader === "undefined" ? Object : VoidTrader) ], WorldState.prototype, "vaultTrader", void 0); __decorate([ ValidateNested(), Type(() => Sortie), __decorateMetadata("design:type", typeof Sortie === "undefined" ? Object : Sortie) ], WorldState.prototype, "archonHunt", void 0); __decorate([ ValidateNested(), Type(() => DuviriCycle), __decorateMetadata("design:type", typeof DuviriCycle === "undefined" ? Object : DuviriCycle) ], WorldState.prototype, "duviriCycle", void 0); __decorate([ IsArray(), ValidateNested({ each: true }), Type(() => Archimedea), __decorateMetadata("design:type", Array) ], WorldState.prototype, "archimedeas", void 0); __decorate([ ValidateNested(), Type(() => Calendar), __decorateMetadata("design:type", typeof Calendar === "undefined" ? Object : Calendar) ], WorldState.prototype, "calendar", void 0); __decorate([ ValidateNested(), Type(() => ClanInitiativeRewards), __decorateMetadata("design:type", typeof ClanInitiativeRewards === "undefined" ? Object : ClanInitiativeRewards) ], WorldState.prototype, "clanWeeklyInitiative", void 0); var WorldState_default = async (json, deps) => WorldState.build(json, deps); //#endregion export { WorldState, WorldState_default as default, parseArray, parseAsyncArray };