koishi-plugin-warframe 1.3.0 → 1.4.0

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/README.md CHANGED
@@ -18,6 +18,7 @@ Toolkit for warframe. **(In development)**
18
18
  | relic [name:string] | 遗物, 核桃 | Relic rewards with corresponding data, including wfm medium price and ducats value. |
19
19
  | weekly | 周常 | Weekly mission info (archon hunt, deep archimedea, temporal archimedea) |
20
20
  | environment | env, 地球, 福尔图娜 | Region environment (time) |
21
+ | voidtrader | 虚空商人, 奸商 | Void trader info |
21
22
 
22
23
  ## Install
23
24
 
package/lib/index.d.ts CHANGED
@@ -8,7 +8,15 @@ export const toTimeStamp: (timeStr: string) => number;
8
8
  /**
9
9
  * 毫秒转「X小时X分钟X秒」格式(0单位不显示)
10
10
  * @param {number} ms - 待转换的毫秒数(非负)
11
- * @returns {string} 示例:3661000ms → "1小时1分钟1秒";61000ms → "1分钟1秒";500ms → "0秒"
11
+ * @returns {string} 示例:
12
+ *
13
+ * 90061000ms → "1天1小时1分钟1秒"
14
+ *
15
+ * 3661000ms → "1小时1分钟1秒"
16
+ *
17
+ * 61000ms → "1分钟1秒"
18
+ *
19
+ * 500ms → "0秒"
12
20
  */
13
21
  export const msToHumanReadable: (ms: number) => string;
14
22
  /**
@@ -48,18 +56,6 @@ export const hexToRgb: (hex: string) => {
48
56
  b: number;
49
57
  };
50
58
  export const rgbToHex: (r: number, g: number, b: number) => string;
51
- export const getSolNodeKey: (name: string) => Promise<string>;
52
- export const getMissionTypeKey: (name: string) => Promise<string>;
53
- export const fissureTierName: {
54
- 1: string;
55
- 2: string;
56
- 3: string;
57
- 4: string;
58
- 5: string;
59
- 6: string;
60
- 7: string;
61
- };
62
- export const fissureTierNumToNumber: (a: number | string) => number;
63
59
  export const regionToShort: (region: IRegion, dict: any) => {
64
60
  name: any;
65
61
  system: any;
@@ -82,6 +78,29 @@ export const relicQualityToTransKey: (quality: string) => string;
82
78
  */
83
79
  export const relicEraToTransKey: (era: string) => string;
84
80
  export const fixRelicRewardKey: (item: string) => string;
81
+ export const relicToFullNameZH: (tier: string, category: string) => string;
82
+ export const getSolNodeKey: (name: string) => Promise<string>;
83
+ export const getMissionTypeKey: (name: string) => Promise<string>;
84
+ export const fissureTierName: {
85
+ 1: string;
86
+ 2: string;
87
+ 3: string;
88
+ 4: string;
89
+ 5: string;
90
+ 6: string;
91
+ 7: string;
92
+ };
93
+ export const fissureTierNumToNumber: (a: number | string) => number;
94
+ export const getVoidTraderItem: (i: {
95
+ item: string;
96
+ uniqueName: string;
97
+ ducats: number;
98
+ credits: number;
99
+ }) => {
100
+ name: string;
101
+ ducats: number;
102
+ credits: number;
103
+ };
85
104
  export const getWFMItemList: () => Promise<WFMResponse<ItemShort[] | null>>;
86
105
  export const getWFMOrderList: (itemId: string) => Promise<WFMResponse<OrderWithUser[] | null>>;
87
106
  export const getWFMRivenItemList: () => Promise<WFMResponse<RivenItem[] | null>>;
@@ -133,7 +152,8 @@ export const FissureTable: (fissures: Fissure[], type: "fissure" | "sp-fissure"
133
152
  export const WeeklyTable: (archon: string, deepArchimedea: ArchiMedea, temporalArchimedea: ArchiMedea) => Promise<string>;
134
153
  export const RelicComponent: (relic: OutputRelic) => Element;
135
154
  export const RivenComponent: (data: RivenStatAnalyzeResult) => Element;
136
- export const getWorldState: () => Promise<WorldState>;
155
+ export const VoidTraderComponent: (data: VoidTrader) => Element;
156
+ export const getWorldState: (json?: string) => Promise<WorldState>;
137
157
  export const extractTextFromImage: (image: string | Blob, secret: OcrAPISecret) => Promise<GeneralBasicOCRResponse | undefined>;
138
158
  export const rivenAttrValueDict: Record<string, Record<string, number>>;
139
159
  export const wfOnReady: () => Promise<void>;
@@ -191,6 +211,8 @@ export const analyzeRivenStat: (parseResult: {
191
211
  prefix: string;
192
212
  }[];
193
213
  }) => RivenStatAnalyzeResult | string;
214
+ export const getVoidTrader: () => Promise<string | VoidTrader>;
215
+ export const generateVoidTraderOutput: (puppe: Puppeteer, data: VoidTrader) => Promise<import("koishi").Element>;
194
216
  export const wmCommand: (action: Argv, input: string) => Promise<string | import("koishi").Element>;
195
217
  export const wmrCommand: (action: Argv, input: string) => Promise<string | import("koishi").Element>;
196
218
  export const aboutCommand: (action: Argv) => Promise<string>;
@@ -203,6 +225,7 @@ export const environmentCommand: () => Promise<string>;
203
225
  export const weeklyCommand: (action: Argv) => Promise<string>;
204
226
  export const relicCommand: (action: Argv, input: string) => Promise<string | import("koishi").Element>;
205
227
  export const rivenCommand: (action: Argv, input: Dict, secret: OcrAPISecret) => Promise<string | import("koishi").Element>;
228
+ export const voidtraderCommand: (action: Argv) => Promise<string | import("koishi").Element>;
206
229
  export const onReadyHandler: () => Promise<void>;
207
230
  export const name = "warframe";
208
231
  export interface Config {
package/lib/index.js CHANGED
@@ -44,10 +44,12 @@ var toTimeStamp = /* @__PURE__ */ __name((timeStr) => {
44
44
  var msToHumanReadable = /* @__PURE__ */ __name((ms) => {
45
45
  const totalMs = Math.max(Number(ms) || 0, 0);
46
46
  const totalSeconds = Math.floor(totalMs / 1e3);
47
- const hours = Math.floor(totalSeconds / 3600);
47
+ const days = Math.floor(totalSeconds / 86400);
48
+ const hours = Math.floor(totalSeconds % 86400 / 3600);
48
49
  const minutes = Math.floor(totalSeconds % 3600 / 60);
49
50
  const seconds = totalSeconds % 60;
50
51
  const parts = [];
52
+ if (days > 0) parts.push(`${days}天`);
51
53
  if (hours > 0) parts.push(`${hours}小时`);
52
54
  if (minutes > 0) parts.push(`${minutes}分钟`);
53
55
  parts.push(`${seconds}秒`);
@@ -91,6 +93,7 @@ var fullWidthToHalfWidth = /* @__PURE__ */ __name((text) => text.replace(/[\uFF0
91
93
  }).replace(/\u3000/g, " "), "fullWidthToHalfWidth");
92
94
  var removeSpace = /* @__PURE__ */ __name((text) => text.replace(/\s/g, ""), "removeSpace");
93
95
  var pascalToSpaced = /* @__PURE__ */ __name((text) => text.replace(/([A-Z])/g, " $1").trim(), "pascalToSpaced");
96
+ var toPascalCase = /* @__PURE__ */ __name((text) => text.toLowerCase().split(/[^a-zA-Z0-9]+/).filter(Boolean).map((word) => word[0].toUpperCase() + word.slice(1)).join(""), "toPascalCase");
94
97
  function normalSimilarity(a, b) {
95
98
  const distance = levenshtein(a, b);
96
99
  return 1 - distance / Math.max(a.length, b.length);
@@ -214,7 +217,36 @@ var hexToRgb = /* @__PURE__ */ __name((hex) => {
214
217
  }, "hexToRgb");
215
218
  var rgbToHex = /* @__PURE__ */ __name((r, g, b) => `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`, "rgbToHex");
216
219
 
220
+ // src/utils/translation.ts
221
+ var import_warframe_public_export_plus2 = require("warframe-public-export-plus");
222
+
223
+ // src/utils/wf-export-adapter.ts
224
+ var import_warframe_public_export_plus = require("warframe-public-export-plus");
225
+ var regionToShort = /* @__PURE__ */ __name((region, dict) => {
226
+ return {
227
+ name: dict[region.name],
228
+ system: dict[region.systemName],
229
+ type: dict[region.missionName],
230
+ faction: dict[import_warframe_public_export_plus.ExportFactions[region.faction].name],
231
+ maxLevel: region.maxEnemyLevel,
232
+ minLevel: region.minEnemyLevel
233
+ };
234
+ }, "regionToShort");
235
+ var relicEraToTransKey = /* @__PURE__ */ __name((era) => {
236
+ const prefix = "/Lotus/Language/Relics/Era_";
237
+ return prefix + era.toUpperCase();
238
+ }, "relicEraToTransKey");
239
+ var fixRelicRewardKey = /* @__PURE__ */ __name((item) => {
240
+ return item.replace("StoreItems/", "");
241
+ }, "fixRelicRewardKey");
242
+
243
+ // src/utils/translation.ts
244
+ var relicToFullNameZH = /* @__PURE__ */ __name((tier, category) => {
245
+ return `${import_warframe_public_export_plus2.dict_zh[relicEraToTransKey(tier)] ?? toPascalCase(tier)} ${category} 遗物`;
246
+ }, "relicToFullNameZH");
247
+
217
248
  // src/utils/wfcd-adapter.ts
249
+ var import_warframe_public_export_plus3 = require("warframe-public-export-plus");
218
250
  var solNodesEnDict = null;
219
251
  var getSolNodeKey = /* @__PURE__ */ __name(async (name2) => {
220
252
  const worldstateData = await import("warframe-worldstate-data");
@@ -249,22 +281,57 @@ var fissureTierName = {
249
281
  var fissureTierNumToNumber = /* @__PURE__ */ __name((a) => {
250
282
  return typeof a === "string" ? a.charCodeAt(5) : a;
251
283
  }, "fissureTierNumToNumber");
252
-
253
- // src/utils/wf-export-adapter.ts
254
- var import_warframe_public_export_plus = require("warframe-public-export-plus");
255
- var regionToShort = /* @__PURE__ */ __name((region, dict) => {
256
- return {
257
- name: dict[region.name],
258
- system: dict[region.systemName],
259
- type: dict[region.missionName],
260
- faction: dict[import_warframe_public_export_plus.ExportFactions[region.faction].name],
261
- maxLevel: region.maxEnemyLevel,
262
- minLevel: region.minEnemyLevel
263
- };
264
- }, "regionToShort");
265
- var fixRelicRewardKey = /* @__PURE__ */ __name((item) => {
266
- return item.replace("StoreItems/", "");
267
- }, "fixRelicRewardKey");
284
+ var getVoidTraderItem = /* @__PURE__ */ __name((i) => {
285
+ const itemNameKey = getVoidTraderItemName(i.uniqueName);
286
+ const itemName = !itemNameKey ? i.item : typeof itemNameKey === "string" ? import_warframe_public_export_plus3.dict_zh[itemNameKey] ?? (itemNameKey.includes("/") ? i.item : itemNameKey) : relicToFullNameZH(itemNameKey.era, itemNameKey.category);
287
+ return { name: itemName, ducats: i.ducats, credits: i.credits };
288
+ }, "getVoidTraderItem");
289
+ var getVoidTraderItemName = /* @__PURE__ */ __name((sourceKey) => {
290
+ const fixedKey = sourceKey.replace("/StoreItems", "");
291
+ const flavour = import_warframe_public_export_plus3.ExportFlavour[fixedKey];
292
+ if (flavour) {
293
+ return flavour.name;
294
+ }
295
+ const weapon = import_warframe_public_export_plus3.ExportWeapons[fixedKey];
296
+ if (weapon) {
297
+ return weapon.name;
298
+ }
299
+ const mod = import_warframe_public_export_plus3.ExportUpgrades[fixedKey];
300
+ if (mod) {
301
+ return mod.name;
302
+ }
303
+ const relic = import_warframe_public_export_plus3.ExportRelics[fixedKey];
304
+ if (relic) {
305
+ return { era: relic.era, category: relic.category };
306
+ }
307
+ const skin = import_warframe_public_export_plus3.ExportCustoms[fixedKey];
308
+ if (skin) {
309
+ return skin.name;
310
+ }
311
+ const recipe = import_warframe_public_export_plus3.ExportRecipes[fixedKey];
312
+ if (recipe) {
313
+ const recipeResult = import_warframe_public_export_plus3.ExportKeys[recipe.resultType];
314
+ if (recipeResult) {
315
+ return recipeResult.name;
316
+ }
317
+ }
318
+ const virtual = import_warframe_public_export_plus3.ExportVirtuals[fixedKey];
319
+ if (virtual) {
320
+ return virtual.name;
321
+ }
322
+ const resource = import_warframe_public_export_plus3.ExportResources[fixedKey];
323
+ if (resource) {
324
+ return resource.name;
325
+ }
326
+ const booster = import_warframe_public_export_plus3.ExportBundles[sourceKey];
327
+ if (booster) {
328
+ return booster.name;
329
+ }
330
+ const boosterPack = import_warframe_public_export_plus3.ExportBoosterPacks[fixedKey];
331
+ if (boosterPack) {
332
+ return boosterPack.name;
333
+ }
334
+ }, "getVoidTraderItemName");
268
335
 
269
336
  // src/api/wfm-api.ts
270
337
  var wfmApiV1Base = "https://api.warframe.market/v1/";
@@ -657,7 +724,7 @@ var RivenAttributeComponent = /* @__PURE__ */ __name((attr, index) => {
657
724
  }, "RivenAttributeComponent");
658
725
 
659
726
  // src/services/wfm-service.ts
660
- var import_warframe_public_export_plus2 = require("warframe-public-export-plus");
727
+ var import_warframe_public_export_plus4 = require("warframe-public-export-plus");
661
728
  var globalDucatnatorIDDict = createAsyncCache(
662
729
  async () => {
663
730
  const data = await getWFMDucatnator();
@@ -872,7 +939,7 @@ var generateRivenOrderOutput = /* @__PURE__ */ __name(async (puppe, item, orders
872
939
  return OutputImage(imgBase64);
873
940
  }, "generateRivenOrderOutput");
874
941
  var applyRelicData = /* @__PURE__ */ __name(async (relic) => {
875
- const tier = import_warframe_public_export_plus2.dict_zh[relic.tierKey] ?? relic.tier;
942
+ const tier = import_warframe_public_export_plus4.dict_zh[relic.tierKey] ?? relic.tier;
876
943
  const wfmDict = await globalDucatnatorIDDict.get();
877
944
  const loadedItems = relic.items.map((element) => {
878
945
  const item = globalItemGameRefDict[element.name];
@@ -1048,7 +1115,7 @@ var compareRivenItemName = /* @__PURE__ */ __name((input, standard) => {
1048
1115
  }, "compareRivenItemName");
1049
1116
 
1050
1117
  // src/services/wf-service.ts
1051
- var import_warframe_public_export_plus3 = require("warframe-public-export-plus");
1118
+ var import_warframe_public_export_plus5 = require("warframe-public-export-plus");
1052
1119
 
1053
1120
  // src/assets/zh.json
1054
1121
  var zh_default = {
@@ -50148,13 +50215,64 @@ var RivenComponent = /* @__PURE__ */ __name((data) => {
50148
50215
  }
50149
50216
  ) });
50150
50217
  }, "RivenComponent");
50218
+ var VoidTraderComponent = /* @__PURE__ */ __name((data) => {
50219
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
50220
+ "div",
50221
+ {
50222
+ style: `width: 400px; padding: 10px; font-family: sans-serif; font-size: 14px;`,
50223
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { style: `width: 100%; border-collapse: collapse;`, children: [
50224
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
50225
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
50226
+ "th",
50227
+ {
50228
+ style: `border-bottom: 1px solid #ccc; text-align: left; padding: 6px;`,
50229
+ children: "名称"
50230
+ }
50231
+ ),
50232
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
50233
+ "th",
50234
+ {
50235
+ style: `border-bottom: 1px solid #ccc; text-align: left; padding: 6px;`,
50236
+ children: "价格"
50237
+ }
50238
+ )
50239
+ ] }) }),
50240
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: data.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
50241
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: `padding: 6px; border-bottom: 1px solid #eee;`, children: item.name }),
50242
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
50243
+ "td",
50244
+ {
50245
+ style: `padding: 6px; border-bottom: 1px solid #eee; text-align: center;line-height: 1;`,
50246
+ children: [
50247
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: item.ducats }),
50248
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
50249
+ "svg",
50250
+ {
50251
+ viewBox: "0 0 18 18",
50252
+ style: "\n color: rgb(64 64 64 / 75%);\n height: 1em;\n width: 1em;\n vertical-align: -.125em;\n fill: currentcolor;",
50253
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("use", { href: `#icon-ducats` })
50254
+ }
50255
+ ),
50256
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "+" }),
50257
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: item.credits }),
50258
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "现金" })
50259
+ ]
50260
+ }
50261
+ )
50262
+ ] })) })
50263
+ ] })
50264
+ }
50265
+ );
50266
+ }, "VoidTraderComponent");
50151
50267
 
50152
50268
  // src/api/wf-api.ts
50153
50269
  var apiBase = "https://api.warframe.com/cdn/";
50154
- var getWorldState = /* @__PURE__ */ __name(async () => {
50155
- const response = await fetchAsyncText(apiBase + "worldState.php");
50270
+ var getWorldState = /* @__PURE__ */ __name(async (json = "") => {
50271
+ if (!json) {
50272
+ json = await fetchAsyncText(apiBase + "worldState.php");
50273
+ }
50156
50274
  const WorldStateParser = await import("warframe-worldstate-parser");
50157
- const ws = await WorldStateParser.WorldState.build(response);
50275
+ const ws = await WorldStateParser.WorldState.build(json);
50158
50276
  return ws;
50159
50277
  }, "getWorldState");
50160
50278
 
@@ -50208,8 +50326,8 @@ var globalWorldState = createAsyncCache(async () => {
50208
50326
  hard: fissure.isHard,
50209
50327
  activation: fissure.activation.getTime(),
50210
50328
  expiry: fissure.expiry.getTime(),
50211
- node: regionToShort(import_warframe_public_export_plus3.ExportRegions[nodeKey], import_warframe_public_export_plus3.dict_zh),
50212
- tier: import_warframe_public_export_plus3.dict_zh[fissureTierName[fissure.tierNum]],
50329
+ node: regionToShort(import_warframe_public_export_plus5.ExportRegions[nodeKey], import_warframe_public_export_plus5.dict_zh),
50330
+ tier: import_warframe_public_export_plus5.dict_zh[fissureTierName[fissure.tierNum]],
50213
50331
  tierNum: fissureTierNumToNumber(fissure.tierNum)
50214
50332
  };
50215
50333
  if (fissure.isStorm) {
@@ -50227,9 +50345,9 @@ var globalWorldState = createAsyncCache(async () => {
50227
50345
  }, 12e4);
50228
50346
  var loadRelics = /* @__PURE__ */ __name(() => {
50229
50347
  const result = {};
50230
- for (const key in import_warframe_public_export_plus3.ExportRelics) {
50231
- const exportRelic = import_warframe_public_export_plus3.ExportRelics[key];
50232
- const exportRewards = import_warframe_public_export_plus3.ExportRewards[exportRelic.rewardManifest];
50348
+ for (const key in import_warframe_public_export_plus5.ExportRelics) {
50349
+ const exportRelic = import_warframe_public_export_plus5.ExportRelics[key];
50350
+ const exportRewards = import_warframe_public_export_plus5.ExportRewards[exportRelic.rewardManifest];
50233
50351
  const era = "/Lotus/Language/Relics/Era_" + exportRelic.era.toUpperCase();
50234
50352
  const relicKey = normalizeName(exportRelic.era + exportRelic.category);
50235
50353
  const rewards = (exportRewards[0] ?? []).map((r) => {
@@ -50281,8 +50399,8 @@ var rivenAttrValueDict = (function() {
50281
50399
  var weaponRivenDispositionDict = (function() {
50282
50400
  const mapped = rivencalc_default.weapons.reduce((prev, element) => {
50283
50401
  let mapped2 = void 0;
50284
- for (const weaponKey in import_warframe_public_export_plus3.ExportWeapons) {
50285
- const weapon = import_warframe_public_export_plus3.ExportWeapons[weaponKey];
50402
+ for (const weaponKey in import_warframe_public_export_plus5.ExportWeapons) {
50403
+ const weapon = import_warframe_public_export_plus5.ExportWeapons[weaponKey];
50286
50404
  const splited = weapon.name.split("/");
50287
50405
  if (splited.length <= 0) {
50288
50406
  continue;
@@ -50293,7 +50411,7 @@ var weaponRivenDispositionDict = (function() {
50293
50411
  mapped2 = weapon;
50294
50412
  break;
50295
50413
  }
50296
- const weaponEN2 = import_warframe_public_export_plus3.dict_en[weapon.name];
50414
+ const weaponEN2 = import_warframe_public_export_plus5.dict_en[weapon.name];
50297
50415
  if (weaponEN2 && normalizeName(weaponEN2) === normalizedCalcName) {
50298
50416
  mapped2 = weapon;
50299
50417
  break;
@@ -50302,8 +50420,8 @@ var weaponRivenDispositionDict = (function() {
50302
50420
  if (!mapped2) {
50303
50421
  return prev;
50304
50422
  }
50305
- const weaponEN = import_warframe_public_export_plus3.dict_en[mapped2.name];
50306
- const weaponZH = import_warframe_public_export_plus3.dict_zh[mapped2.name];
50423
+ const weaponEN = import_warframe_public_export_plus5.dict_en[mapped2.name];
50424
+ const weaponZH = import_warframe_public_export_plus5.dict_zh[mapped2.name];
50307
50425
  const result = {
50308
50426
  name: {
50309
50427
  en: weaponEN,
@@ -50392,7 +50510,7 @@ var getArbitrations = /* @__PURE__ */ __name((day = 3) => {
50392
50510
  currentHourIndex + 24 * day
50393
50511
  );
50394
50512
  return weekArbys.filter((a) => arbyRewards_default[a.node]).map((a) => {
50395
- const obj = regionToShort(import_warframe_public_export_plus3.ExportRegions[a.node], import_warframe_public_export_plus3.dict_zh);
50513
+ const obj = regionToShort(import_warframe_public_export_plus5.ExportRegions[a.node], import_warframe_public_export_plus5.dict_zh);
50396
50514
  return {
50397
50515
  ...obj,
50398
50516
  time: new Date(a.time * 1e3).toLocaleString("zh-cn", {
@@ -50421,7 +50539,7 @@ var getWeekly = /* @__PURE__ */ __name(async () => {
50421
50539
  if (!worldState) {
50422
50540
  return "内部错误,获取最新信息失败";
50423
50541
  }
50424
- const archon = import_warframe_public_export_plus3.dict_zh["/Lotus/Language/Narmer/" + removeSpace(worldState.archonHunt.boss)];
50542
+ const archon = import_warframe_public_export_plus5.dict_zh["/Lotus/Language/Narmer/" + removeSpace(worldState.archonHunt.boss)];
50425
50543
  const stringToDebuff = /* @__PURE__ */ __name((key, name2, prefix) => {
50426
50544
  const keyToName = zh_default[`${prefix}${key}`];
50427
50545
  if (!keyToName) {
@@ -50444,7 +50562,7 @@ var getWeekly = /* @__PURE__ */ __name(async () => {
50444
50562
  const deepArchimMissions = await Promise.all(
50445
50563
  deepArchim.missions.map(async (m) => {
50446
50564
  const receivedType = await getMissionTypeKey(m.missionType);
50447
- const type = import_warframe_public_export_plus3.dict_zh[import_warframe_public_export_plus3.ExportMissionTypes[receivedType]?.name] ?? m.missionType;
50565
+ const type = import_warframe_public_export_plus5.dict_zh[import_warframe_public_export_plus5.ExportMissionTypes[receivedType]?.name] ?? m.missionType;
50448
50566
  const diviation = stringToDebuff(
50449
50567
  m.diviation.key,
50450
50568
  m.diviation.name,
@@ -50472,7 +50590,7 @@ var getWeekly = /* @__PURE__ */ __name(async () => {
50472
50590
  const temporalArchimMissions = await Promise.all(
50473
50591
  temporalArchim.missions.map(async (m) => {
50474
50592
  const receivedType = await getMissionTypeKey(m.missionType);
50475
- const type = import_warframe_public_export_plus3.dict_zh[import_warframe_public_export_plus3.ExportMissionTypes[receivedType]?.name] ?? receivedType;
50593
+ const type = import_warframe_public_export_plus5.dict_zh[import_warframe_public_export_plus5.ExportMissionTypes[receivedType]?.name] ?? receivedType;
50476
50594
  const diviation = stringToDebuff(
50477
50595
  m.diviation.key,
50478
50596
  m.diviation.name,
@@ -50539,10 +50657,10 @@ var getCircuitWeek = /* @__PURE__ */ __name(() => {
50539
50657
  const EPOCH = 1734307200 * 1e3;
50540
50658
  const week = Math.trunc((Date.now() - EPOCH) / 6048e5);
50541
50659
  const incarnons = incarnonRewards[week % incarnonRewards.length].map(
50542
- (i) => import_warframe_public_export_plus3.dict_zh[i]
50660
+ (i) => import_warframe_public_export_plus5.dict_zh[i]
50543
50661
  );
50544
50662
  const warframes = warframeRewards[week % warframeRewards.length].map(
50545
- (i) => import_warframe_public_export_plus3.dict_zh[i]
50663
+ (i) => import_warframe_public_export_plus5.dict_zh[i]
50546
50664
  );
50547
50665
  return {
50548
50666
  incarnons,
@@ -50791,6 +50909,25 @@ var analyzeRivenStat = /* @__PURE__ */ __name((parseResult) => {
50791
50909
  curses
50792
50910
  };
50793
50911
  }, "analyzeRivenStat");
50912
+ var getVoidTrader = /* @__PURE__ */ __name(async () => {
50913
+ const { raw: worldState } = await globalWorldState.get();
50914
+ if (worldState.voidTraders.length === 0) {
50915
+ return "虚空商人仍在未知地带漂流...";
50916
+ }
50917
+ if (worldState.voidTraders[0].activation.getTime() > Date.now()) {
50918
+ const diff2 = worldState.voidTraders[0].activation.getTime() - Date.now();
50919
+ return "距离虚空商人到达还有: " + msToHumanReadable(diff2);
50920
+ }
50921
+ const diff = worldState.voidTraders[0].expiry.getTime() - Date.now();
50922
+ const trader = worldState.voidTraders[0];
50923
+ const items = trader.inventory.map(getVoidTraderItem);
50924
+ return { expiry: msToHumanReadable(diff), items };
50925
+ }, "getVoidTrader");
50926
+ var generateVoidTraderOutput = /* @__PURE__ */ __name(async (puppe, data) => {
50927
+ const element = VoidTraderComponent(data);
50928
+ const imgBase64 = await getHtmlImageBase64(puppe, element.toString());
50929
+ return OutputImage(imgBase64);
50930
+ }, "generateVoidTraderOutput");
50794
50931
 
50795
50932
  // src/commands/wfm/wm.ts
50796
50933
  var wmCommand = /* @__PURE__ */ __name(async (action, input) => {
@@ -50921,6 +51058,15 @@ var rivenCommand = /* @__PURE__ */ __name(async (action, input, secret) => {
50921
51058
  );
50922
51059
  }, "rivenCommand");
50923
51060
 
51061
+ // src/commands/wf/voidtrader.ts
51062
+ var voidtraderCommand = /* @__PURE__ */ __name(async (action) => {
51063
+ const result = await getVoidTrader();
51064
+ if (typeof result === "string") {
51065
+ return result;
51066
+ }
51067
+ return await generateVoidTraderOutput(action.session.app.puppeteer, result);
51068
+ }, "voidtraderCommand");
51069
+
50924
51070
  // src/hooks/on-ready.ts
50925
51071
  var onReadyHandler = /* @__PURE__ */ __name(async () => {
50926
51072
  await wmOnReady();
@@ -50984,6 +51130,7 @@ var setupCommands = /* @__PURE__ */ __name((ctx) => {
50984
51130
  ctx.command("riven <img:image>", "分析紫卡截图").action((a, b) => {
50985
51131
  return rivenCommand(a, b, ctx.config.ocrAPISecret);
50986
51132
  });
51133
+ ctx.command("voidtrader", "虚空商人").alias("虚空商人").alias("奸商").action(voidtraderCommand);
50987
51134
  }, "setupCommands");
50988
51135
  var inDevelopment = /* @__PURE__ */ __name(() => {
50989
51136
  return "功能暂未开放";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-warframe",
3
- "description": "WFMToolkit",
4
- "version": "1.3.0",
3
+ "description": "WF Toolkit",
4
+ "version": "1.4.0",
5
5
  "license": "GPL-3.0",
6
6
  "scripts": {
7
7
  "build": "yakumo build",
@@ -53,10 +53,17 @@
53
53
  "@koishijs/plugin-help": "^2.4.6",
54
54
  "@koishijs/plugin-mock": "^2.6.6",
55
55
  "@satorijs/element": "^3.1.8",
56
+ "@semantic-release/changelog": "^6.0.3",
57
+ "@semantic-release/commit-analyzer": "^13.0.1",
58
+ "@semantic-release/git": "^10.0.1",
59
+ "@semantic-release/github": "^12.0.2",
60
+ "@semantic-release/npm": "^13.1.3",
61
+ "@semantic-release/release-notes-generator": "^14.1.0",
56
62
  "@types/chai": "^5.2.3",
57
63
  "@types/mocha": "^10.0.10",
58
64
  "@types/node": "^25.0.3",
59
65
  "chai": "^6.2.1",
66
+ "conventional-changelog-conventionalcommits": "^9.1.0",
60
67
  "dtsc": "^3.1.0",
61
68
  "esbuild": "^0.27.1",
62
69
  "esbuild-register": "^3.6.0",
@@ -69,16 +76,9 @@
69
76
  "yakumo-tsc": "^1.0.0"
70
77
  },
71
78
  "dependencies": {
72
- "@semantic-release/changelog": "^6.0.3",
73
- "@semantic-release/commit-analyzer": "^13.0.1",
74
- "@semantic-release/git": "^10.0.1",
75
- "@semantic-release/github": "^12.0.2",
76
- "@semantic-release/npm": "^13.1.3",
77
- "@semantic-release/release-notes-generator": "^14.1.0",
78
- "conventional-changelog-conventionalcommits": "^9.1.0",
79
79
  "tencentcloud-sdk-nodejs-ocr": "^4.1.155",
80
- "warframe-public-export-plus": "^0.5.96",
81
- "warframe-worldstate-data": "^3.1.16",
82
- "warframe-worldstate-parser": "^5.2.12"
80
+ "warframe-public-export-plus": "^0.5.97",
81
+ "warframe-worldstate-data": "^3.1.18",
82
+ "warframe-worldstate-parser": "^5.2.13"
83
83
  }
84
84
  }