@wfcd/relics 1.0.1 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,235 @@
1
- export * from './Types';
2
- export * from './Generator';
3
- export * from './VersionManager';
1
+ interface WarframeMarketRoot {
2
+ payload: {
3
+ items: Array<WarframeMarketItem>;
4
+ };
5
+ }
6
+ interface WarframeMarketItem {
7
+ /**
8
+ * WFM Item ID
9
+ */
10
+ id: string;
11
+ /**
12
+ * Url name for querying WFM
13
+ */
14
+ url_name: string;
15
+ /**
16
+ * Thumbnail URL relative to wfm api base
17
+ */
18
+ thumb: string;
19
+ /**
20
+ * Item Name
21
+ */
22
+ item_name: string;
23
+ }
24
+ interface WFCDRelic {
25
+ /**
26
+ * Relic Tier (Axi, Neo, etc.)
27
+ */
28
+ tier: string;
29
+ /**
30
+ * Relic Name (A1, A10, etc.)
31
+ */
32
+ relicName: string;
33
+ /**
34
+ * Relic Refinement state
35
+ */
36
+ state: 'Intact' | 'Exceptional' | 'Flawless' | 'Radiant';
37
+ /**
38
+ * Relic Rewards
39
+ */
40
+ rewards: Array<WFCDRelicReward>;
41
+ /**
42
+ * Internal WFCD id
43
+ */
44
+ _id: string;
45
+ }
46
+ interface WFCDRelicReward {
47
+ /**
48
+ * Dropped Item name
49
+ */
50
+ itemName: string;
51
+ /**
52
+ * Dropchance Rarity (Uncommon/Rare ?)
53
+ */
54
+ rarity: 'Uncommon' | 'Rare';
55
+ /**
56
+ * Actual Dropchance in %
57
+ */
58
+ chance: number;
59
+ /**
60
+ * Internal ID
61
+ */
62
+ _id: string;
63
+ }
64
+ interface WFCDItem {
65
+ /**
66
+ * Item Name
67
+ */
68
+ name: string;
69
+ /** Unique identifying name */
70
+ uniqueName: string;
71
+ /**
72
+ * Item Drop Location
73
+ */
74
+ drops?: Array<WFCDItemDropLocation>;
75
+ }
76
+ interface WFCDItemDropLocation {
77
+ /**
78
+ * Dropchance in %
79
+ */
80
+ chance: number;
81
+ /**
82
+ * Mission location
83
+ */
84
+ location: string;
85
+ /**
86
+ * Drop rarity
87
+ */
88
+ rarity: string;
89
+ /**
90
+ * Relic Type
91
+ */
92
+ type: string;
93
+ }
94
+ interface TitaniaRelic {
95
+ /**
96
+ * Relic Combined Name (Ex: Axi A1)
97
+ */
98
+ name: string;
99
+ /**
100
+ * Relic Rewards when opened
101
+ */
102
+ rewards: Array<TitaniaRelicReward>;
103
+ /**
104
+ * Drop Locations for the relics
105
+ */
106
+ locations: Array<TitaniaRelicLocation>;
107
+ /**
108
+ * Warframe Market Information
109
+ * undefined for untradable
110
+ */
111
+ warframeMarket?: TitaniaWFMInfo;
112
+ /**
113
+ * Relic Vault Information
114
+ */
115
+ vaultInfo: TitaniaRelicVaultedInfo;
116
+ /** unique name for corresponding warframe-items Item */
117
+ uniqueName: string;
118
+ }
119
+ interface TitaniaRelicReward {
120
+ /**
121
+ * Relic Rarity (Uncommon,Rare ?)
122
+ */
123
+ rarity: 'Uncommon' | 'Rare';
124
+ /**
125
+ * Reward Drop Chance in %
126
+ */
127
+ chance: number;
128
+ /**
129
+ * Item Information
130
+ */
131
+ item: TitaniaRelicRewardItem;
132
+ }
133
+ interface TitaniaRelicRewardItem {
134
+ /**
135
+ * Item Name
136
+ */
137
+ name: string;
138
+ /** unique name for corresponding warframe-items Item */
139
+ uniqueName: string;
140
+ /**
141
+ * WarframeMarket Info
142
+ */
143
+ warframeMarket?: TitaniaWFMInfo;
144
+ }
145
+ interface TitaniaRelicLocation {
146
+ /** Location Info $planet-$node (Ex: Eris - Phalan) */
147
+ location: string;
148
+ /**
149
+ * Rarity (Uncommon, Rare ?)
150
+ */
151
+ rarity: 'Uncommon' | 'Rare' | 'Legendary' | 'Common' | string;
152
+ /**
153
+ * Dropchance in %
154
+ */
155
+ chance: number;
156
+ }
157
+ interface TitaniaWFMInfo {
158
+ /**
159
+ * Warframe Market ID
160
+ */
161
+ id: string;
162
+ /**
163
+ * Warframe market URL parameter
164
+ */
165
+ urlName: string;
166
+ }
167
+ interface TitaniaRelicVaultedInfo {
168
+ /**
169
+ * If the relic is vaulted
170
+ */
171
+ vaulted: boolean;
172
+ }
173
+
174
+ declare class Generator {
175
+ relicsRaw: Array<WFCDRelic> | undefined;
176
+ wfcdItems: Array<WFCDItem> | undefined;
177
+ wfmItems: WarframeMarketRoot | undefined;
178
+ relics: Array<TitaniaRelic>;
179
+ constructor();
180
+ /**
181
+ * Main function to fetch and generate the relic data
182
+ * @returns {Promise<Array<TitaniaRelic>>} The Relics data array
183
+ */
184
+ generate(): Promise<Array<TitaniaRelic>>;
185
+ /**
186
+ * Fetches all required data from WFCD and WFM.
187
+ */
188
+ fetchRawData(): Promise<void>;
189
+ /**
190
+ * Generates the relic data
191
+ * uses WFCD/warframe-drop-data to check what relics exist,
192
+ * and adds information from WFCD/warframe-items and WFM
193
+ */
194
+ generateTitaniaRelics(): void;
195
+ /**
196
+ * Writes the fully generated data to disk.
197
+ * @param {string} dataDir Directory to store the relic data in. Default: ../data/
198
+ * @param {string} fileName Filename base ex: "Relics" becomes "Relics.json" and "Relics.min.json". Default: "Relics"
199
+ * @param {boolean} generateMin True if a minified json should be generated too. Default: true
200
+ */
201
+ writeData(dataDir?: string, fileName?: string, generateMin?: boolean): Promise<void>;
202
+ /**
203
+ * Generates a single relic from all available data
204
+ * @param {WFCDRelic} rawRelic relic to pull Titania data from
205
+ * @returns {TitaniaRelicReward}
206
+ */
207
+ private generateTitaniaRelic;
208
+ /**
209
+ * Filters WFCD's relic data to only include Intact variants, since we just need the base.
210
+ */
211
+ private filterWFCDRelics;
212
+ }
213
+
214
+ declare class VersionManager {
215
+ versionPath: string;
216
+ versionRawPath: string;
217
+ hashPath: string;
218
+ /**
219
+ * Creates a new VersionManager instance.
220
+ * @param {string} dataDir Folder to write version information to.
221
+ * @constructor
222
+ */
223
+ constructor(dataDir?: string);
224
+ /**
225
+ * Checks if the current data needs an update
226
+ */
227
+ updateNeeded(): Promise<boolean>;
228
+ /**
229
+ * Writes both game and drop version metadata
230
+ * @param {number} timestamp Timestamp the build was started at
231
+ */
232
+ writeVersion(timestamp: number): Promise<void>;
233
+ }
234
+
235
+ export { Generator, TitaniaRelic, TitaniaRelicLocation, TitaniaRelicReward, TitaniaRelicRewardItem, TitaniaRelicVaultedInfo, TitaniaWFMInfo, VersionManager, WFCDItem, WFCDItemDropLocation, WFCDRelic, WFCDRelicReward, WarframeMarketItem, WarframeMarketRoot };
package/dist/index.js CHANGED
@@ -1,20 +1,308 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
15
12
  };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./Types"), exports);
18
- __exportStar(require("./Generator"), exports);
19
- __exportStar(require("./VersionManager"), exports);
20
- //# sourceMappingURL=index.js.map
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/index.ts
32
+ var src_exports = {};
33
+ __export(src_exports, {
34
+ Generator: () => Generator,
35
+ VersionManager: () => VersionManager
36
+ });
37
+ module.exports = __toCommonJS(src_exports);
38
+
39
+ // src/Generator.ts
40
+ var import_node_fetch = __toESM(require("node-fetch"));
41
+ var import_promises = __toESM(require("fs/promises"));
42
+ var import_node_path = __toESM(require("path"));
43
+
44
+ // src/Config.ts
45
+ var Config = {
46
+ warframeRelicDropUrl: "https://drops.warframestat.us/data/relics.json",
47
+ warframeMarketItemUrl: "https://api.warframe.market/v1/items",
48
+ warframeItemsUrl: "https://api.warframestat.us/items/search/Relics?by=category",
49
+ warframeRelicDropInfoUrl: "https://drops.warframestat.us/data/info.json",
50
+ warframePatchlogsUrl: "https://raw.githubusercontent.com/WFCD/warframe-patchlogs/master/data/patchlogs.json"
51
+ };
52
+ var Config_default = Config;
53
+
54
+ // src/Logger.ts
55
+ var console = __toESM(require("console"));
56
+ var fromString = /* @__PURE__ */ __name((logLevelIsh) => {
57
+ switch (logLevelIsh == null ? void 0 : logLevelIsh.toLowerCase()) {
58
+ case "fatal":
59
+ return -1 /* FATAL */;
60
+ case "error":
61
+ case "bad":
62
+ return 0 /* ERROR */;
63
+ case "info":
64
+ case "log":
65
+ return 1 /* LOG */;
66
+ case "debug":
67
+ return 2 /* DEBUG */;
68
+ default:
69
+ return -1 /* FATAL */;
70
+ }
71
+ }, "fromString");
72
+ var Logger = class {
73
+ logLevel = fromString(process.env.LOG_LEVEL || "fatal");
74
+ log(message) {
75
+ if (this.logLevel >= 1 /* LOG */)
76
+ console.log(message);
77
+ }
78
+ error(message) {
79
+ if (this.logLevel >= 0 /* ERROR */)
80
+ console.error(message);
81
+ }
82
+ debug(message) {
83
+ if (this.logLevel === 2 /* DEBUG */)
84
+ console.debug(message);
85
+ }
86
+ fatal(message) {
87
+ if (this.logLevel >= -1 /* FATAL */) {
88
+ console.error(`FATAL: ${message}`);
89
+ throw new Error(message);
90
+ }
91
+ }
92
+ };
93
+ __name(Logger, "Logger");
94
+ var Logger_default = new Logger();
95
+
96
+ // src/Generator.ts
97
+ var Generator = class {
98
+ relicsRaw;
99
+ wfcdItems;
100
+ wfmItems;
101
+ relics;
102
+ constructor() {
103
+ this.relics = [];
104
+ }
105
+ /**
106
+ * Main function to fetch and generate the relic data
107
+ * @returns {Promise<Array<TitaniaRelic>>} The Relics data array
108
+ */
109
+ async generate() {
110
+ Logger_default.log("Starting Generation");
111
+ await this.fetchRawData();
112
+ this.filterWFCDRelics();
113
+ this.generateTitaniaRelics();
114
+ return this.relics;
115
+ }
116
+ /**
117
+ * Fetches all required data from WFCD and WFM.
118
+ */
119
+ async fetchRawData() {
120
+ var _a;
121
+ const relicRequest = await (0, import_node_fetch.default)(Config_default.warframeRelicDropUrl);
122
+ if (!relicRequest.ok) {
123
+ Logger_default.error("Failed to fetch Warframe relics from WFCD!");
124
+ return;
125
+ }
126
+ this.relicsRaw = (_a = await relicRequest.json()) == null ? void 0 : _a.relics;
127
+ const wfmRequest = await (0, import_node_fetch.default)(Config_default.warframeMarketItemUrl);
128
+ if (!wfmRequest.ok) {
129
+ Logger_default.error("Failed to fetch items from WFM!");
130
+ return;
131
+ }
132
+ this.wfmItems = await wfmRequest.json();
133
+ const wfcdItemRequest = await (0, import_node_fetch.default)(Config_default.warframeItemsUrl);
134
+ if (!wfcdItemRequest.ok) {
135
+ Logger_default.error("Failed to fetch items from WFCD! ");
136
+ return;
137
+ }
138
+ this.wfcdItems = await wfcdItemRequest.json();
139
+ }
140
+ /**
141
+ * Generates the relic data
142
+ * uses WFCD/warframe-drop-data to check what relics exist,
143
+ * and adds information from WFCD/warframe-items and WFM
144
+ */
145
+ generateTitaniaRelics() {
146
+ if (typeof this.relicsRaw === "undefined" || typeof this.wfmItems === "undefined") {
147
+ Logger_default.log("Failed to load relics/item data");
148
+ return;
149
+ }
150
+ const { length } = this.relicsRaw;
151
+ for (let i = 0; i < length; i += 1) {
152
+ const rawRelic = this.relicsRaw[i];
153
+ Logger_default.debug(`[${i + 1}/${length}] ${rawRelic.tier} ${rawRelic.relicName}`);
154
+ const relic = this.generateTitaniaRelic(rawRelic);
155
+ this.relics.push(relic);
156
+ }
157
+ Logger_default.debug(`Finished parsing ${this.relics.length} relics`);
158
+ }
159
+ /**
160
+ * Writes the fully generated data to disk.
161
+ * @param {string} dataDir Directory to store the relic data in. Default: ../data/
162
+ * @param {string} fileName Filename base ex: "Relics" becomes "Relics.json" and "Relics.min.json". Default: "Relics"
163
+ * @param {boolean} generateMin True if a minified json should be generated too. Default: true
164
+ */
165
+ async writeData(dataDir, fileName, generateMin) {
166
+ const DataDir = dataDir ?? import_node_path.default.join(__dirname, "..", "data");
167
+ const RelicPath = fileName ? import_node_path.default.join(DataDir, `${fileName}.json`) : import_node_path.default.join(DataDir, "Relics.json");
168
+ await import_promises.default.writeFile(RelicPath, JSON.stringify(this.relics, void 0, 4));
169
+ if (generateMin) {
170
+ const RelicMinPath = fileName ? import_node_path.default.join(DataDir, `${fileName}.min.json`) : import_node_path.default.join(DataDir, "Relics.min.json");
171
+ await import_promises.default.writeFile(RelicMinPath, JSON.stringify(this.relics));
172
+ }
173
+ }
174
+ /**
175
+ * Generates a single relic from all available data
176
+ * @param {WFCDRelic} rawRelic relic to pull Titania data from
177
+ * @returns {TitaniaRelicReward}
178
+ */
179
+ generateTitaniaRelic(rawRelic) {
180
+ var _a, _b;
181
+ const name = `${rawRelic.tier} ${rawRelic.relicName}`;
182
+ const rewards = rawRelic.rewards.map((rawReward) => {
183
+ var _a2, _b2, _c;
184
+ const { chance } = rawReward;
185
+ const { rarity } = rawReward;
186
+ const wfmInfo = (_a2 = this.wfmItems) == null ? void 0 : _a2.payload.items.find((x) => x.item_name === rawReward.itemName);
187
+ const isSpecial = ["Forma", "Kuva", "Exilus", "Riven"].find(
188
+ (x) => (
189
+ // eslint-disable-next-line @typescript-eslint/comma-dangle
190
+ rawReward.itemName.toLowerCase().includes(x.toLowerCase())
191
+ )
192
+ );
193
+ if (!(wfmInfo || isSpecial)) {
194
+ Logger_default.debug(`Failed to find wfm item for ${rawReward.itemName}`);
195
+ }
196
+ const item = {
197
+ name: rawReward.itemName,
198
+ uniqueName: ((_c = (_b2 = this.wfcdItems) == null ? void 0 : _b2.find((x) => x.name.toLowerCase() === `${name.trim()} Intact`.toLowerCase())) == null ? void 0 : _c.uniqueName) || "",
199
+ warframeMarket: void 0
200
+ };
201
+ if (wfmInfo) {
202
+ item.warframeMarket = { id: wfmInfo.id, urlName: wfmInfo.url_name };
203
+ }
204
+ return { rarity, chance, item };
205
+ });
206
+ let drops = [];
207
+ const wfcdItem = (_a = this.wfcdItems) == null ? void 0 : _a.find((x) => x.name.toLowerCase() === `${name.trim()} Intact`.toLowerCase());
208
+ if (!wfcdItem) {
209
+ Logger_default.error(`Failed to get WFCD item for relic: ${name}`);
210
+ }
211
+ if (wfcdItem && wfcdItem.drops) {
212
+ drops = wfcdItem.drops.map((rawDrop) => {
213
+ return { rarity: rawDrop.rarity, chance: rawDrop.chance, location: rawDrop.location };
214
+ });
215
+ }
216
+ const wfm = (_b = this.wfmItems) == null ? void 0 : _b.payload.items.find((x) => x.item_name === `${name.trim()} Relic`);
217
+ if (!wfm) {
218
+ Logger_default.error(`Failed to get relic item from wfm: ${name}`);
219
+ }
220
+ return {
221
+ name,
222
+ rewards,
223
+ locations: drops,
224
+ uniqueName: (wfcdItem == null ? void 0 : wfcdItem.uniqueName) || "",
225
+ vaultInfo: { vaulted: drops.length === 0 },
226
+ ...(wfm == null ? void 0 : wfm.id) && (wfm == null ? void 0 : wfm.url_name) && { warframeMarket: { id: wfm == null ? void 0 : wfm.id, urlName: wfm == null ? void 0 : wfm.url_name } }
227
+ };
228
+ }
229
+ /**
230
+ * Filters WFCD's relic data to only include Intact variants, since we just need the base.
231
+ */
232
+ filterWFCDRelics() {
233
+ var _a, _b, _c;
234
+ const before = ((_a = this.relicsRaw) == null ? void 0 : _a.length) || 0;
235
+ this.relicsRaw = (_b = this.relicsRaw) == null ? void 0 : _b.filter((x) => x.state === "Intact");
236
+ Logger_default.log(`Filtered relics to intact variants. Before: ${before} After: ${((_c = this.relicsRaw) == null ? void 0 : _c.length) || 0}`);
237
+ }
238
+ };
239
+ __name(Generator, "Generator");
240
+
241
+ // src/VersionManager.ts
242
+ var import_node_path2 = __toESM(require("path"));
243
+ var import_promises2 = __toESM(require("fs/promises"));
244
+ var import_node_fetch2 = __toESM(require("node-fetch"));
245
+ var VersionManager = class {
246
+ versionPath;
247
+ versionRawPath;
248
+ hashPath;
249
+ /**
250
+ * Creates a new VersionManager instance.
251
+ * @param {string} dataDir Folder to write version information to.
252
+ * @constructor
253
+ */
254
+ constructor(dataDir) {
255
+ const DataDir = dataDir ?? import_node_path2.default.join(__dirname, "..", "data");
256
+ this.versionPath = import_node_path2.default.join(DataDir, "version.json");
257
+ this.versionRawPath = import_node_path2.default.join(DataDir, "version.txt");
258
+ this.hashPath = import_node_path2.default.join(DataDir, "hash.json");
259
+ }
260
+ /**
261
+ * Checks if the current data needs an update
262
+ */
263
+ async updateNeeded() {
264
+ const infoReq = await (0, import_node_fetch2.default)(Config_default.warframeRelicDropInfoUrl);
265
+ if (!infoReq.ok) {
266
+ Logger_default.fatal("Failed to fetch version info!");
267
+ }
268
+ const info = await infoReq.json();
269
+ try {
270
+ await import_promises2.default.access(this.hashPath);
271
+ const infoFile = JSON.parse(await import_promises2.default.readFile(this.hashPath, "utf-8"));
272
+ return infoFile.hash !== info.hash;
273
+ } catch (ex) {
274
+ return true;
275
+ }
276
+ }
277
+ /**
278
+ * Writes both game and drop version metadata
279
+ * @param {number} timestamp Timestamp the build was started at
280
+ */
281
+ async writeVersion(timestamp) {
282
+ const patchLogsReq = await (0, import_node_fetch2.default)(Config_default.warframePatchlogsUrl);
283
+ if (!patchLogsReq.ok) {
284
+ Logger_default.error("Failed to fetch patchlogs");
285
+ return;
286
+ }
287
+ const patchlogs = await patchLogsReq.json();
288
+ const version = patchlogs[0].name.replace(/ \+ /g, "--").replace(/[^0-9\-.]/g, "").trim();
289
+ const hashReq = await (0, import_node_fetch2.default)(Config_default.warframeRelicDropInfoUrl);
290
+ if (!hashReq.ok) {
291
+ Logger_default.error("Failed to fetch hashInfo");
292
+ return;
293
+ }
294
+ const hashInfo = await hashReq.json();
295
+ const versionInfo = { version, title: patchlogs[0].name };
296
+ const hashFile = { hash: hashInfo.hash, deUpdated: hashInfo.modified, timestamp };
297
+ await import_promises2.default.writeFile(this.hashPath, JSON.stringify(hashFile, void 0, 2), "utf-8");
298
+ await import_promises2.default.writeFile(this.versionPath, JSON.stringify(versionInfo, void 0, 2), "utf-8");
299
+ await import_promises2.default.writeFile(this.versionRawPath, version, "utf-8");
300
+ Logger_default.debug("Finished writing version info");
301
+ }
302
+ };
303
+ __name(VersionManager, "VersionManager");
304
+ // Annotate the CommonJS export names for ESM import in node:
305
+ 0 && (module.exports = {
306
+ Generator,
307
+ VersionManager
308
+ });