@nekosuneprojects/gaming-infos 2.4.0 → 3.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.
Files changed (729) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +62 -334
  3. package/index.js +3 -225
  4. package/package.json +53 -58
  5. package/src/providers/vrchat.js +11 -0
  6. package/src/providers/warframe.js +7 -0
  7. package/src/registry.js +23 -0
  8. package/.github/workflows/npm-publish-github-packages.yml +0 -56
  9. package/.github/workflows/npm-publish.yml +0 -71
  10. package/.github/workflows/sync-api-cache.yml +0 -73
  11. package/CACHE_SYNC.md +0 -202
  12. package/CONTRIBUTING.md +0 -217
  13. package/DATA.md +0 -292
  14. package/data/.cache-manifest.json +0 -112
  15. package/data/arknightsendfield/characters/akekuri.json +0 -75
  16. package/data/arknightsendfield/characters/alesh.json +0 -75
  17. package/data/arknightsendfield/characters/antal.json +0 -75
  18. package/data/arknightsendfield/characters/arcane.json +0 -75
  19. package/data/arknightsendfield/characters/arclight.json +0 -75
  20. package/data/arknightsendfield/characters/ardelia.json +0 -75
  21. package/data/arknightsendfield/characters/avywenna.json +0 -76
  22. package/data/arknightsendfield/characters/camille.json +0 -77
  23. package/data/arknightsendfield/characters/catcher.json +0 -76
  24. package/data/arknightsendfield/characters/chenqianyu.json +0 -76
  25. package/data/arknightsendfield/characters/dapan.json +0 -76
  26. package/data/arknightsendfield/characters/ember.json +0 -76
  27. package/data/arknightsendfield/characters/endministrator.json +0 -63
  28. package/data/arknightsendfield/characters/estella.json +0 -76
  29. package/data/arknightsendfield/characters/fluorite.json +0 -75
  30. package/data/arknightsendfield/characters/gilberta.json +0 -76
  31. package/data/arknightsendfield/characters/laevatain.json +0 -76
  32. package/data/arknightsendfield/characters/lastrite.json +0 -76
  33. package/data/arknightsendfield/characters/lifeng.json +0 -75
  34. package/data/arknightsendfield/characters/liino.json +0 -76
  35. package/data/arknightsendfield/characters/mifu.json +0 -75
  36. package/data/arknightsendfield/characters/perlica.json +0 -76
  37. package/data/arknightsendfield/characters/pogranichnik.json +0 -75
  38. package/data/arknightsendfield/characters/purrchena.json +0 -50
  39. package/data/arknightsendfield/characters/rossi.json +0 -77
  40. package/data/arknightsendfield/characters/snowshine.json +0 -75
  41. package/data/arknightsendfield/characters/tangtang.json +0 -76
  42. package/data/arknightsendfield/characters/typhoeus.json +0 -57
  43. package/data/arknightsendfield/characters/wulfgard.json +0 -77
  44. package/data/arknightsendfield/characters/xaihi.json +0 -76
  45. package/data/arknightsendfield/characters/yvonne.json +0 -76
  46. package/data/arknightsendfield/characters/zhuangfangyi.json +0 -76
  47. package/data/arknightsendfield/meta.json +0 -14
  48. package/data/fortnite/characters/agentjones.json +0 -43
  49. package/data/fortnite/characters/agentpeely.json +0 -43
  50. package/data/fortnite/characters/andyfangerson.json +0 -42
  51. package/data/fortnite/characters/antonia.json +0 -43
  52. package/data/fortnite/characters/anwar.json +0 -44
  53. package/data/fortnite/characters/aphrodite.json +0 -43
  54. package/data/fortnite/characters/apollo.json +0 -36
  55. package/data/fortnite/characters/arcticassassin.json +0 -43
  56. package/data/fortnite/characters/artemis.json +0 -36
  57. package/data/fortnite/characters/battlewoodboulevard.json +0 -43
  58. package/data/fortnite/characters/beastmode.json +0 -45
  59. package/data/fortnite/characters/bogstick.json +0 -43
  60. package/data/fortnite/characters/boxy.json +0 -44
  61. package/data/fortnite/characters/bravoleader.json +0 -44
  62. package/data/fortnite/characters/briteraider.json +0 -43
  63. package/data/fortnite/characters/brutalboxcars.json +0 -46
  64. package/data/fortnite/characters/bryne.json +0 -44
  65. package/data/fortnite/characters/buildersbarracks.json +0 -38
  66. package/data/fortnite/characters/bullshark.json +0 -43
  67. package/data/fortnite/characters/bumpybay.json +0 -44
  68. package/data/fortnite/characters/burd.json +0 -44
  69. package/data/fortnite/characters/burdemart.json +0 -39
  70. package/data/fortnite/characters/burdtogo.json +0 -42
  71. package/data/fortnite/characters/busansanctuary.json +0 -39
  72. package/data/fortnite/characters/calamaricanyon.json +0 -41
  73. package/data/fortnite/characters/canyoncrossing.json +0 -45
  74. package/data/fortnite/characters/captainjones.json +0 -40
  75. package/data/fortnite/characters/centurion.json +0 -44
  76. package/data/fortnite/characters/cerberus.json +0 -43
  77. package/data/fortnite/characters/charon.json +0 -43
  78. package/data/fortnite/characters/chiara.json +0 -43
  79. package/data/fortnite/characters/clara.json +0 -43
  80. package/data/fortnite/characters/classifiedcanyon.json +0 -43
  81. package/data/fortnite/characters/clawsylodge.json +0 -41
  82. package/data/fortnite/characters/cletuscornhole.json +0 -43
  83. package/data/fortnite/characters/contractgiller.json +0 -44
  84. package/data/fortnite/characters/corruptioncorners.json +0 -42
  85. package/data/fortnite/characters/countessdaraku.json +0 -45
  86. package/data/fortnite/characters/crackshotscabin.json +0 -40
  87. package/data/fortnite/characters/creepycamps.json +0 -36
  88. package/data/fortnite/characters/crimecity.json +0 -47
  89. package/data/fortnite/characters/dara.json +0 -42
  90. package/data/fortnite/characters/darkruby.json +0 -43
  91. package/data/fortnite/characters/demonsdojo.json +0 -46
  92. package/data/fortnite/characters/diamonddiva.json +0 -43
  93. package/data/fortnite/characters/donutdistrict.json +0 -43
  94. package/data/fortnite/characters/drakonsteelrider.json +0 -43
  95. package/data/fortnite/characters/dummy.json +0 -45
  96. package/data/fortnite/characters/edwardscissorhands.json +0 -39
  97. package/data/fortnite/characters/etheria.json +0 -43
  98. package/data/fortnite/characters/evergreenterrace.json +0 -41
  99. package/data/fortnite/characters/fishmarket.json +0 -39
  100. package/data/fortnite/characters/fishstick.json +0 -45
  101. package/data/fortnite/characters/fishthicc.json +0 -43
  102. package/data/fortnite/characters/fortressofsolitude.json +0 -37
  103. package/data/fortnite/characters/foxyfloodgate.json +0 -43
  104. package/data/fortnite/characters/freakyfields.json +0 -38
  105. package/data/fortnite/characters/goldengrove.json +0 -41
  106. package/data/fortnite/characters/graveheart.json +0 -43
  107. package/data/fortnite/characters/grievouscampsite.json +0 -38
  108. package/data/fortnite/characters/guardianamara.json +0 -44
  109. package/data/fortnite/characters/gwenpool.json +0 -41
  110. package/data/fortnite/characters/hanamuracourtyard.json +0 -27
  111. package/data/fortnite/characters/heartbreakranger.json +0 -42
  112. package/data/fortnite/characters/heatwaveharbor.json +0 -41
  113. package/data/fortnite/characters/heroichope.json +0 -44
  114. package/data/fortnite/characters/hope.json +0 -43
  115. package/data/fortnite/characters/hopefulheights.json +0 -46
  116. package/data/fortnite/characters/humblehills.json +0 -41
  117. package/data/fortnite/characters/innovatorslone.json +0 -43
  118. package/data/fortnite/characters/insight.json +0 -43
  119. package/data/fortnite/characters/ironman.json +0 -40
  120. package/data/fortnite/characters/jittershock.json +0 -44
  121. package/data/fortnite/characters/joeycaliente.json +0 -44
  122. package/data/fortnite/characters/jonithescarlet.json +0 -43
  123. package/data/fortnite/characters/khabylame.json +0 -40
  124. package/data/fortnite/characters/khari.json +0 -44
  125. package/data/fortnite/characters/kitbash.json +0 -44
  126. package/data/fortnite/characters/kitesflight.json +0 -41
  127. package/data/fortnite/characters/knightmare.json +0 -43
  128. package/data/fortnite/characters/laguna.json +0 -43
  129. package/data/fortnite/characters/lakespringfield.json +0 -35
  130. package/data/fortnite/characters/lakespringfieldgasstation.json +0 -39
  131. package/data/fortnite/characters/lanallane.json +0 -42
  132. package/data/fortnite/characters/lattelanding.json +0 -41
  133. package/data/fortnite/characters/lavendra.json +0 -44
  134. package/data/fortnite/characters/leelah.json +0 -45
  135. package/data/fortnite/characters/liftylodge.json +0 -42
  136. package/data/fortnite/characters/lonewolflair.json +0 -42
  137. package/data/fortnite/characters/longshot.json +0 -41
  138. package/data/fortnite/characters/lostlake.json +0 -44
  139. package/data/fortnite/characters/loveranger.json +0 -44
  140. package/data/fortnite/characters/mae.json +0 -43
  141. package/data/fortnite/characters/magicmosses.json +0 -42
  142. package/data/fortnite/characters/maskedmeadows.json +0 -48
  143. package/data/fortnite/characters/mechateamshadow.json +0 -44
  144. package/data/fortnite/characters/medusa.json +0 -43
  145. package/data/fortnite/characters/meowscles.json +0 -42
  146. package/data/fortnite/characters/mephisto.json +0 -41
  147. package/data/fortnite/characters/metalmouth.json +0 -44
  148. package/data/fortnite/characters/mincemeat.json +0 -43
  149. package/data/fortnite/characters/munitionsexpert.json +0 -42
  150. package/data/fortnite/characters/myna.json +0 -42
  151. package/data/fortnite/characters/newsanctuary.json +0 -43
  152. package/data/fortnite/characters/nia.json +0 -42
  153. package/data/fortnite/characters/nightshiftforest.json +0 -43
  154. package/data/fortnite/characters/nisha.json +0 -42
  155. package/data/fortnite/characters/nolanchance.json +0 -43
  156. package/data/fortnite/characters/noorah.json +0 -44
  157. package/data/fortnite/characters/odyssey.json +0 -43
  158. package/data/fortnite/characters/openaironsen.json +0 -40
  159. package/data/fortnite/characters/oscar.json +0 -42
  160. package/data/fortnite/characters/outlawoasis.json +0 -40
  161. package/data/fortnite/characters/outpostenclave.json +0 -27
  162. package/data/fortnite/characters/oxrhq.json +0 -37
  163. package/data/fortnite/characters/paintedpalms.json +0 -41
  164. package/data/fortnite/characters/peabody.json +0 -42
  165. package/data/fortnite/characters/peelosopherbananocrates.json +0 -43
  166. package/data/fortnite/characters/peely.json +0 -41
  167. package/data/fortnite/characters/peelybone.json +0 -43
  168. package/data/fortnite/characters/persephone.json +0 -42
  169. package/data/fortnite/characters/phaedra.json +0 -42
  170. package/data/fortnite/characters/phantommeowscles.json +0 -43
  171. package/data/fortnite/characters/piperpace.json +0 -43
  172. package/data/fortnite/characters/poseidon.json +0 -42
  173. package/data/fortnite/characters/pumpedpower.json +0 -40
  174. package/data/fortnite/characters/pumpinpipes.json +0 -39
  175. package/data/fortnite/characters/pumpkinking.json +0 -40
  176. package/data/fortnite/characters/purradisemeowscles.json +0 -43
  177. package/data/fortnite/characters/rangersrest.json +0 -36
  178. package/data/fortnite/characters/rebeloutpost.json +0 -37
  179. package/data/fortnite/characters/renegadeshadow.json +0 -44
  180. package/data/fortnite/characters/resistancebase.json +0 -27
  181. package/data/fortnite/characters/rippedtides.json +0 -43
  182. package/data/fortnite/characters/rollingblossomsfarm.json +0 -41
  183. package/data/fortnite/characters/royalebomber.json +0 -38
  184. package/data/fortnite/characters/ruckus.json +0 -42
  185. package/data/fortnite/characters/rust.json +0 -41
  186. package/data/fortnite/characters/sakuracircle.json +0 -36
  187. package/data/fortnite/characters/sandystrip.json +0 -44
  188. package/data/fortnite/characters/saskia.json +0 -45
  189. package/data/fortnite/characters/seaportcity.json +0 -48
  190. package/data/fortnite/characters/shakensanctuary.json +0 -42
  191. package/data/fortnite/characters/shimmerdusk.json +0 -41
  192. package/data/fortnite/characters/shinyshafts.json +0 -38
  193. package/data/fortnite/characters/shogunssolitude.json +0 -46
  194. package/data/fortnite/characters/shuri.json +0 -39
  195. package/data/fortnite/characters/silashesk.json +0 -42
  196. package/data/fortnite/characters/slurproom.json +0 -40
  197. package/data/fortnite/characters/snowheart.json +0 -44
  198. package/data/fortnite/characters/snowstriker.json +0 -43
  199. package/data/fortnite/characters/solidsnake.json +0 -39
  200. package/data/fortnite/characters/sonor.json +0 -46
  201. package/data/fortnite/characters/spartanassassin.json +0 -43
  202. package/data/fortnite/characters/spirithuntersaeko.json +0 -41
  203. package/data/fortnite/characters/springfieldnationalparkstore.json +0 -38
  204. package/data/fortnite/characters/springfieldnuclearpowerplant.json +0 -39
  205. package/data/fortnite/characters/springfieldslurpworks.json +0 -40
  206. package/data/fortnite/characters/squibblyshores.json +0 -42
  207. package/data/fortnite/characters/squibblyspointlighthouse.json +0 -37
  208. package/data/fortnite/characters/starroakley.json +0 -45
  209. package/data/fortnite/characters/steelsight.json +0 -43
  210. package/data/fortnite/characters/sticks.json +0 -35
  211. package/data/fortnite/characters/sunkenshores.json +0 -42
  212. package/data/fortnite/characters/sunstrider.json +0 -42
  213. package/data/fortnite/characters/suntanspecialist.json +0 -43
  214. package/data/fortnite/characters/supernovaacademy.json +0 -27
  215. package/data/fortnite/characters/t60powerarmor.json +0 -39
  216. package/data/fortnite/characters/thebattlewoods.json +0 -44
  217. package/data/fortnite/characters/thegreatturtle.json +0 -37
  218. package/data/fortnite/characters/theoperator.json +0 -42
  219. package/data/fortnite/characters/thequackaway.json +0 -39
  220. package/data/fortnite/characters/thestabilizer.json +0 -38
  221. package/data/fortnite/characters/theunderwriter.json +0 -36
  222. package/data/fortnite/characters/toyboxdocks.json +0 -40
  223. package/data/fortnite/characters/trace.json +0 -43
  224. package/data/fortnite/characters/triagetrooper.json +0 -43
  225. package/data/fortnite/characters/triggerfish.json +0 -44
  226. package/data/fortnite/characters/trogscave.json +0 -38
  227. package/data/fortnite/characters/utopiacity.json +0 -27
  228. package/data/fortnite/characters/vengeancejones.json +0 -42
  229. package/data/fortnite/characters/victoriasaint.json +0 -43
  230. package/data/fortnite/characters/vineyshafts.json +0 -35
  231. package/data/fortnite/characters/volpez.json +0 -41
  232. package/data/fortnite/characters/warmachine.json +0 -40
  233. package/data/fortnite/characters/wastelandermagneto.json +0 -40
  234. package/data/fortnite/characters/wonkeeland.json +0 -41
  235. package/data/fortnite/meta.json +0 -14
  236. package/data/game-codes/.cache-manifest.json +0 -148
  237. package/data/game-codes/directory.json +0 -1196
  238. package/data/game-codes/games/arknights-endfield.json +0 -958
  239. package/data/game-codes/games/borderlands-1.json +0 -414
  240. package/data/game-codes/games/borderlands-2.json +0 -340
  241. package/data/game-codes/games/borderlands-3.json +0 -1025
  242. package/data/game-codes/games/borderlands-4.json +0 -3128
  243. package/data/game-codes/games/borderlands-the-pre-sequel.json +0 -599
  244. package/data/game-codes/games/brawl-stars.json +0 -4766
  245. package/data/game-codes/games/clash-of-clans.json +0 -4766
  246. package/data/game-codes/games/clash-royale.json +0 -5
  247. package/data/game-codes/games/cookie-run-kingdom.json +0 -5366
  248. package/data/game-codes/games/fortnite.json +0 -897
  249. package/data/game-codes/games/genshin-impact.json +0 -8520
  250. package/data/game-codes/games/honkai-impact-3rd.json +0 -405
  251. package/data/game-codes/games/honkai-star-rail.json +0 -9863
  252. package/data/game-codes/games/neverness-to-everness.json +0 -1695
  253. package/data/game-codes/games/roblox-doors.json +0 -1842
  254. package/data/game-codes/games/roblox-rivals.json +0 -2919
  255. package/data/game-codes/games/tower-of-fantasy.json +0 -2839
  256. package/data/game-codes/games/warframe.json +0 -20824
  257. package/data/game-codes/games/wuthering-waves.json +0 -2477
  258. package/data/game-codes/games/zenless-zone-zero.json +0 -3681
  259. package/data/game-codes/status.json +0 -580
  260. package/data/genshinimpact/characters/aino.json +0 -34
  261. package/data/genshinimpact/characters/albedo.json +0 -12
  262. package/data/genshinimpact/characters/alhaitham.json +0 -13
  263. package/data/genshinimpact/characters/aloy.json +0 -12
  264. package/data/genshinimpact/characters/alyosha.json +0 -34
  265. package/data/genshinimpact/characters/amber.json +0 -13
  266. package/data/genshinimpact/characters/aratakiitto.json +0 -13
  267. package/data/genshinimpact/characters/arlecchino.json +0 -13
  268. package/data/genshinimpact/characters/baizhu.json +0 -13
  269. package/data/genshinimpact/characters/barbara.json +0 -12
  270. package/data/genshinimpact/characters/beidou.json +0 -13
  271. package/data/genshinimpact/characters/bennett.json +0 -12
  272. package/data/genshinimpact/characters/candace.json +0 -13
  273. package/data/genshinimpact/characters/charlotte.json +0 -12
  274. package/data/genshinimpact/characters/chasca.json +0 -12
  275. package/data/genshinimpact/characters/chevreuse.json +0 -12
  276. package/data/genshinimpact/characters/chiori.json +0 -12
  277. package/data/genshinimpact/characters/chongyun.json +0 -13
  278. package/data/genshinimpact/characters/citlali.json +0 -12
  279. package/data/genshinimpact/characters/clorinde.json +0 -12
  280. package/data/genshinimpact/characters/collei.json +0 -13
  281. package/data/genshinimpact/characters/columbina.json +0 -34
  282. package/data/genshinimpact/characters/cyno.json +0 -13
  283. package/data/genshinimpact/characters/dahlia.json +0 -11
  284. package/data/genshinimpact/characters/dehya.json +0 -12
  285. package/data/genshinimpact/characters/diluc.json +0 -12
  286. package/data/genshinimpact/characters/diona.json +0 -12
  287. package/data/genshinimpact/characters/dori.json +0 -12
  288. package/data/genshinimpact/characters/durin.json +0 -12
  289. package/data/genshinimpact/characters/emilie.json +0 -12
  290. package/data/genshinimpact/characters/escoffier.json +0 -13
  291. package/data/genshinimpact/characters/eula.json +0 -12
  292. package/data/genshinimpact/characters/faruzan.json +0 -13
  293. package/data/genshinimpact/characters/fischl.json +0 -13
  294. package/data/genshinimpact/characters/flins.json +0 -34
  295. package/data/genshinimpact/characters/freminet.json +0 -12
  296. package/data/genshinimpact/characters/furina.json +0 -13
  297. package/data/genshinimpact/characters/gaming.json +0 -12
  298. package/data/genshinimpact/characters/ganyu.json +0 -12
  299. package/data/genshinimpact/characters/gorou.json +0 -13
  300. package/data/genshinimpact/characters/hutao.json +0 -13
  301. package/data/genshinimpact/characters/iansan.json +0 -12
  302. package/data/genshinimpact/characters/ifa.json +0 -34
  303. package/data/genshinimpact/characters/illuga.json +0 -34
  304. package/data/genshinimpact/characters/ineffa.json +0 -12
  305. package/data/genshinimpact/characters/jahoda.json +0 -34
  306. package/data/genshinimpact/characters/jean.json +0 -12
  307. package/data/genshinimpact/characters/kachina.json +0 -12
  308. package/data/genshinimpact/characters/kaedeharakazuha.json +0 -13
  309. package/data/genshinimpact/characters/kaeya.json +0 -12
  310. package/data/genshinimpact/characters/kamisatoayaka.json +0 -12
  311. package/data/genshinimpact/characters/kamisatoayato.json +0 -12
  312. package/data/genshinimpact/characters/kaveh.json +0 -13
  313. package/data/genshinimpact/characters/keqing.json +0 -12
  314. package/data/genshinimpact/characters/kinich.json +0 -12
  315. package/data/genshinimpact/characters/kirara.json +0 -12
  316. package/data/genshinimpact/characters/klee.json +0 -12
  317. package/data/genshinimpact/characters/kujousara.json +0 -12
  318. package/data/genshinimpact/characters/kukishinobu.json +0 -13
  319. package/data/genshinimpact/characters/lanyan.json +0 -12
  320. package/data/genshinimpact/characters/lauma.json +0 -34
  321. package/data/genshinimpact/characters/layla.json +0 -12
  322. package/data/genshinimpact/characters/linnea.json +0 -34
  323. package/data/genshinimpact/characters/lisa.json +0 -13
  324. package/data/genshinimpact/characters/lohen.json +0 -12
  325. package/data/genshinimpact/characters/lynette.json +0 -12
  326. package/data/genshinimpact/characters/lyney.json +0 -12
  327. package/data/genshinimpact/characters/mavuika.json +0 -12
  328. package/data/genshinimpact/characters/mika.json +0 -34
  329. package/data/genshinimpact/characters/mikaschmidt.json +0 -12
  330. package/data/genshinimpact/characters/mona.json +0 -13
  331. package/data/genshinimpact/characters/mualani.json +0 -12
  332. package/data/genshinimpact/characters/nahida.json +0 -13
  333. package/data/genshinimpact/characters/navia.json +0 -12
  334. package/data/genshinimpact/characters/nefer.json +0 -34
  335. package/data/genshinimpact/characters/neuvillette.json +0 -12
  336. package/data/genshinimpact/characters/nicole.json +0 -34
  337. package/data/genshinimpact/characters/nilou.json +0 -12
  338. package/data/genshinimpact/characters/ningguang.json +0 -12
  339. package/data/genshinimpact/characters/noelle.json +0 -13
  340. package/data/genshinimpact/characters/odette.json +0 -34
  341. package/data/genshinimpact/characters/ororon.json +0 -12
  342. package/data/genshinimpact/characters/prune.json +0 -11
  343. package/data/genshinimpact/characters/qiqi.json +0 -13
  344. package/data/genshinimpact/characters/raidenshogun.json +0 -13
  345. package/data/genshinimpact/characters/razor.json +0 -12
  346. package/data/genshinimpact/characters/rosaria.json +0 -13
  347. package/data/genshinimpact/characters/sandrone.json +0 -34
  348. package/data/genshinimpact/characters/sangonomiyakokomi.json +0 -13
  349. package/data/genshinimpact/characters/sayu.json +0 -12
  350. package/data/genshinimpact/characters/sethos.json +0 -12
  351. package/data/genshinimpact/characters/shenhe.json +0 -13
  352. package/data/genshinimpact/characters/shikanoinheizou.json +0 -13
  353. package/data/genshinimpact/characters/sigewinne.json +0 -12
  354. package/data/genshinimpact/characters/skirk.json +0 -12
  355. package/data/genshinimpact/characters/sucrose.json +0 -13
  356. package/data/genshinimpact/characters/tartaglia.json +0 -34
  357. package/data/genshinimpact/characters/thoma.json +0 -12
  358. package/data/genshinimpact/characters/tighnari.json +0 -13
  359. package/data/genshinimpact/characters/traveler.json +0 -34
  360. package/data/genshinimpact/characters/varesa.json +0 -12
  361. package/data/genshinimpact/characters/varka.json +0 -11
  362. package/data/genshinimpact/characters/venti.json +0 -13
  363. package/data/genshinimpact/characters/wanderer.json +0 -12
  364. package/data/genshinimpact/characters/wonderlandmanekin.json +0 -34
  365. package/data/genshinimpact/characters/wriothesley.json +0 -13
  366. package/data/genshinimpact/characters/xiangling.json +0 -13
  367. package/data/genshinimpact/characters/xianyun.json +0 -12
  368. package/data/genshinimpact/characters/xiao.json +0 -12
  369. package/data/genshinimpact/characters/xilonen.json +0 -12
  370. package/data/genshinimpact/characters/xingqiu.json +0 -13
  371. package/data/genshinimpact/characters/xinyan.json +0 -13
  372. package/data/genshinimpact/characters/yaemiko.json +0 -13
  373. package/data/genshinimpact/characters/yanfei.json +0 -13
  374. package/data/genshinimpact/characters/yaoyao.json +0 -13
  375. package/data/genshinimpact/characters/yelan.json +0 -12
  376. package/data/genshinimpact/characters/yoimiya.json +0 -13
  377. package/data/genshinimpact/characters/yumemizukimizuki.json +0 -12
  378. package/data/genshinimpact/characters/yunjin.json +0 -12
  379. package/data/genshinimpact/characters/zhongli.json +0 -12
  380. package/data/genshinimpact/characters/zibai.json +0 -12
  381. package/data/genshinimpact/meta.json +0 -14
  382. package/data/honkaistarrail/characters/acheron.json +0 -13
  383. package/data/honkaistarrail/characters/aglaea.json +0 -13
  384. package/data/honkaistarrail/characters/anaxa.json +0 -13
  385. package/data/honkaistarrail/characters/archer.json +0 -29
  386. package/data/honkaistarrail/characters/argenti.json +0 -13
  387. package/data/honkaistarrail/characters/arlan.json +0 -13
  388. package/data/honkaistarrail/characters/ashveil.json +0 -13
  389. package/data/honkaistarrail/characters/asta.json +0 -13
  390. package/data/honkaistarrail/characters/aventurine.json +0 -13
  391. package/data/honkaistarrail/characters/bailu.json +0 -13
  392. package/data/honkaistarrail/characters/blackswan.json +0 -13
  393. package/data/honkaistarrail/characters/blade.json +0 -13
  394. package/data/honkaistarrail/characters/boothill.json +0 -13
  395. package/data/honkaistarrail/characters/bronya.json +0 -13
  396. package/data/honkaistarrail/characters/castorice.json +0 -13
  397. package/data/honkaistarrail/characters/cerydra.json +0 -13
  398. package/data/honkaistarrail/characters/cipher.json +0 -13
  399. package/data/honkaistarrail/characters/clara.json +0 -13
  400. package/data/honkaistarrail/characters/constance.json +0 -13
  401. package/data/honkaistarrail/characters/cyrene.json +0 -13
  402. package/data/honkaistarrail/characters/danheng.json +0 -13
  403. package/data/honkaistarrail/characters/danhengimbibitorlunae.json +0 -29
  404. package/data/honkaistarrail/characters/danhengpermansorterrae.json +0 -29
  405. package/data/honkaistarrail/characters/drratio.json +0 -13
  406. package/data/honkaistarrail/characters/evanescia.json +0 -29
  407. package/data/honkaistarrail/characters/evernight.json +0 -29
  408. package/data/honkaistarrail/characters/feixiao.json +0 -13
  409. package/data/honkaistarrail/characters/firefly.json +0 -13
  410. package/data/honkaistarrail/characters/fugue.json +0 -29
  411. package/data/honkaistarrail/characters/fuxuan.json +0 -13
  412. package/data/honkaistarrail/characters/gallagher.json +0 -13
  413. package/data/honkaistarrail/characters/gepard.json +0 -13
  414. package/data/honkaistarrail/characters/gilgamesh.json +0 -29
  415. package/data/honkaistarrail/characters/guinaifen.json +0 -13
  416. package/data/honkaistarrail/characters/hanya.json +0 -13
  417. package/data/honkaistarrail/characters/herta.json +0 -13
  418. package/data/honkaistarrail/characters/himeko.json +0 -14
  419. package/data/honkaistarrail/characters/himekonova.json +0 -29
  420. package/data/honkaistarrail/characters/hook.json +0 -13
  421. package/data/honkaistarrail/characters/huohuo.json +0 -13
  422. package/data/honkaistarrail/characters/hyacine.json +0 -13
  423. package/data/honkaistarrail/characters/hysilens.json +0 -13
  424. package/data/honkaistarrail/characters/jade.json +0 -13
  425. package/data/honkaistarrail/characters/jiaoqiu.json +0 -13
  426. package/data/honkaistarrail/characters/jingliu.json +0 -13
  427. package/data/honkaistarrail/characters/jingyuan.json +0 -13
  428. package/data/honkaistarrail/characters/kafka.json +0 -13
  429. package/data/honkaistarrail/characters/lingsha.json +0 -13
  430. package/data/honkaistarrail/characters/lisushang.json +0 -13
  431. package/data/honkaistarrail/characters/luka.json +0 -13
  432. package/data/honkaistarrail/characters/luocha.json +0 -13
  433. package/data/honkaistarrail/characters/lynx.json +0 -13
  434. package/data/honkaistarrail/characters/march7th.json +0 -13
  435. package/data/honkaistarrail/characters/misha.json +0 -13
  436. package/data/honkaistarrail/characters/mortenaxblade.json +0 -29
  437. package/data/honkaistarrail/characters/moze.json +0 -13
  438. package/data/honkaistarrail/characters/mydei.json +0 -13
  439. package/data/honkaistarrail/characters/natasha.json +0 -13
  440. package/data/honkaistarrail/characters/pela.json +0 -13
  441. package/data/honkaistarrail/characters/phainon.json +0 -13
  442. package/data/honkaistarrail/characters/qingque.json +0 -13
  443. package/data/honkaistarrail/characters/rappa.json +0 -13
  444. package/data/honkaistarrail/characters/rintohsaka.json +0 -29
  445. package/data/honkaistarrail/characters/robin.json +0 -13
  446. package/data/honkaistarrail/characters/ruanmei.json +0 -13
  447. package/data/honkaistarrail/characters/saber.json +0 -29
  448. package/data/honkaistarrail/characters/sampo.json +0 -13
  449. package/data/honkaistarrail/characters/seele.json +0 -13
  450. package/data/honkaistarrail/characters/serval.json +0 -13
  451. package/data/honkaistarrail/characters/silverwolf.json +0 -13
  452. package/data/honkaistarrail/characters/silverwolflv999.json +0 -29
  453. package/data/honkaistarrail/characters/sparkle.json +0 -13
  454. package/data/honkaistarrail/characters/sparxie.json +0 -29
  455. package/data/honkaistarrail/characters/sunday.json +0 -29
  456. package/data/honkaistarrail/characters/thedahlia.json +0 -29
  457. package/data/honkaistarrail/characters/theherta.json +0 -29
  458. package/data/honkaistarrail/characters/tingyun.json +0 -13
  459. package/data/honkaistarrail/characters/topaz.json +0 -13
  460. package/data/honkaistarrail/characters/topaznumby.json +0 -29
  461. package/data/honkaistarrail/characters/trailblazer.json +0 -29
  462. package/data/honkaistarrail/characters/tribbie.json +0 -13
  463. package/data/honkaistarrail/characters/welt.json +0 -29
  464. package/data/honkaistarrail/characters/weltyang.json +0 -13
  465. package/data/honkaistarrail/characters/xueyi.json +0 -13
  466. package/data/honkaistarrail/characters/yanqing.json +0 -13
  467. package/data/honkaistarrail/characters/yaoguang.json +0 -13
  468. package/data/honkaistarrail/characters/yukong.json +0 -13
  469. package/data/honkaistarrail/characters/yunli.json +0 -13
  470. package/data/honkaistarrail/meta.json +0 -14
  471. package/data/nte/characters/adler.json +0 -15
  472. package/data/nte/characters/aurelia.json +0 -15
  473. package/data/nte/characters/baicang.json +0 -15
  474. package/data/nte/characters/chaos.json +0 -15
  475. package/data/nte/characters/chiz.json +0 -15
  476. package/data/nte/characters/daffodill.json +0 -15
  477. package/data/nte/characters/edgar.json +0 -15
  478. package/data/nte/characters/esperzero.json +0 -15
  479. package/data/nte/characters/fadia.json +0 -15
  480. package/data/nte/characters/haniel.json +0 -15
  481. package/data/nte/characters/hathor.json +0 -15
  482. package/data/nte/characters/hotori.json +0 -15
  483. package/data/nte/characters/iroi.json +0 -15
  484. package/data/nte/characters/jiuyuan.json +0 -15
  485. package/data/nte/characters/lacrimosa.json +0 -15
  486. package/data/nte/characters/mint.json +0 -15
  487. package/data/nte/characters/nanally.json +0 -15
  488. package/data/nte/characters/sakiri.json +0 -15
  489. package/data/nte/characters/shinku.json +0 -15
  490. package/data/nte/characters/skia.json +0 -15
  491. package/data/nte/characters/zankou.json +0 -51
  492. package/data/nte/meta.json +0 -14
  493. package/data/toweroffantasy/characters/alyss.json +0 -27
  494. package/data/toweroffantasy/characters/annabella.json +0 -23
  495. package/data/toweroffantasy/characters/asuka.json +0 -23
  496. package/data/toweroffantasy/characters/bailing.json +0 -23
  497. package/data/toweroffantasy/characters/brevey.json +0 -23
  498. package/data/toweroffantasy/characters/claudia.json +0 -23
  499. package/data/toweroffantasy/characters/cobaltb.json +0 -23
  500. package/data/toweroffantasy/characters/cocoritter.json +0 -23
  501. package/data/toweroffantasy/characters/crow.json +0 -23
  502. package/data/toweroffantasy/characters/echo.json +0 -23
  503. package/data/toweroffantasy/characters/ene.json +0 -23
  504. package/data/toweroffantasy/characters/feise.json +0 -25
  505. package/data/toweroffantasy/characters/fenrir.json +0 -23
  506. package/data/toweroffantasy/characters/fiona.json +0 -25
  507. package/data/toweroffantasy/characters/frigg.json +0 -23
  508. package/data/toweroffantasy/characters/gnonno.json +0 -23
  509. package/data/toweroffantasy/characters/hilda.json +0 -23
  510. package/data/toweroffantasy/characters/huang.json +0 -25
  511. package/data/toweroffantasy/characters/huma.json +0 -25
  512. package/data/toweroffantasy/characters/icarus.json +0 -23
  513. package/data/toweroffantasy/characters/jiyu.json +0 -25
  514. package/data/toweroffantasy/characters/king.json +0 -23
  515. package/data/toweroffantasy/characters/lan.json +0 -25
  516. package/data/toweroffantasy/characters/lin.json +0 -23
  517. package/data/toweroffantasy/characters/linghan.json +0 -23
  518. package/data/toweroffantasy/characters/liuhuo.json +0 -23
  519. package/data/toweroffantasy/characters/lyra.json +0 -23
  520. package/data/toweroffantasy/characters/meryl.json +0 -23
  521. package/data/toweroffantasy/characters/mingjing.json +0 -27
  522. package/data/toweroffantasy/characters/nanyin.json +0 -25
  523. package/data/toweroffantasy/characters/nemesis.json +0 -25
  524. package/data/toweroffantasy/characters/pepper.json +0 -23
  525. package/data/toweroffantasy/characters/plotti.json +0 -25
  526. package/data/toweroffantasy/characters/roslyn.json +0 -23
  527. package/data/toweroffantasy/characters/rubilia.json +0 -25
  528. package/data/toweroffantasy/characters/ruby.json +0 -25
  529. package/data/toweroffantasy/characters/sakifuwa.json +0 -23
  530. package/data/toweroffantasy/characters/samir.json +0 -23
  531. package/data/toweroffantasy/characters/shiro.json +0 -25
  532. package/data/toweroffantasy/characters/tianlang.json +0 -25
  533. package/data/toweroffantasy/characters/tsubasa.json +0 -23
  534. package/data/toweroffantasy/characters/umi.json +0 -23
  535. package/data/toweroffantasy/characters/yanmiao.json +0 -25
  536. package/data/toweroffantasy/characters/yanuo.json +0 -23
  537. package/data/toweroffantasy/characters/yulan.json +0 -23
  538. package/data/toweroffantasy/characters/zero.json +0 -23
  539. package/data/toweroffantasy/meta.json +0 -14
  540. package/data/vrchat/groups/clubzodiac.json +0 -8
  541. package/data/vrchat/groups/dirtydancers.json +0 -8
  542. package/data/vrchat/groups/drumsynews.json +0 -8
  543. package/data/vrchat/groups/ebola20.json +0 -8
  544. package/data/vrchat/groups/internationaldancersassociation.json +0 -8
  545. package/data/vrchat/groups/kannagang.json +0 -7
  546. package/data/vrchat/groups/lolisquad.json +0 -8
  547. package/data/vrchat/groups/nekonightsnightclub.json +0 -8
  548. package/data/vrchat/groups/nekostudios.json +0 -8
  549. package/data/vrchat/groups/nekosunecommunity.json +0 -8
  550. package/data/vrchat/groups/voidclub.json +0 -8
  551. package/data/vrchat/groups/voltdanceclub.json +0 -8
  552. package/data/vrchat/groups/vrceventsgroup.json +0 -8
  553. package/data/vrchat/groups/vrchatcommunitydiscord.json +0 -7
  554. package/data/vrchat/meta.json +0 -13
  555. package/data/vrchat/players/alto.json +0 -10
  556. package/data/vrchat/players/arcadum.json +0 -11
  557. package/data/vrchat/players/chairhandler.json +0 -10
  558. package/data/vrchat/players/chipz.json +0 -10
  559. package/data/vrchat/players/hikarivr.json +0 -11
  560. package/data/vrchat/players/kimple.json +0 -11
  561. package/data/vrchat/players/linkzr.json +0 -9
  562. package/data/vrchat/players/nagzz21.json +0 -10
  563. package/data/vrchat/players/nebride.json +0 -11
  564. package/data/vrchat/players/nekosunevr.json +0 -11
  565. package/data/vrchat/players/pokelawls.json +0 -10
  566. package/data/vrchat/players/qwonk.json +0 -9
  567. package/data/vrchat/players/roflgator.json +0 -11
  568. package/data/vrchat/players/scifri.json +0 -8
  569. package/data/vrchat/players/sodapoppin.json +0 -10
  570. package/data/vrchat/players/woops.json +0 -10
  571. package/data/vrchat/players/zentreya.json +0 -11
  572. package/data/vrchat/worlds/ascensionacademy.json +0 -8
  573. package/data/vrchat/worlds/clubvgl.json +0 -9
  574. package/data/vrchat/worlds/fightfinder.json +0 -9
  575. package/data/vrchat/worlds/hangouthouse.json +0 -8
  576. package/data/vrchat/worlds/nekostudioshalloween.json +0 -10
  577. package/data/vrchat/worlds/nekostudiosnewyear.json +0 -10
  578. package/data/vrchat/worlds/nekostudiosxmas.json +0 -10
  579. package/data/vrchat/worlds/nekosunevranimations2023.json +0 -10
  580. package/data/vrchat/worlds/nekosunevranimations20232024.json +0 -10
  581. package/data/vrchat/worlds/nekosunevranimations2024.json +0 -10
  582. package/data/vrchat/worlds/nekosunevranimations2025.json +0 -10
  583. package/data/vrchat/worlds/rumhamsavatarworld.json +0 -8
  584. package/data/vrchat/worlds/smewsranch.json +0 -8
  585. package/data/vrchat/worlds/smewsroom.json +0 -8
  586. package/data/vrchat/worlds/sunsetbar.json +0 -8
  587. package/data/vrchat/worlds/theblackcat.json +0 -10
  588. package/data/vrchat/worlds/thegreatpug.json +0 -9
  589. package/data/vrchat/worlds/themidnightbar.json +0 -8
  590. package/data/vrchat/worlds/voidclub.json +0 -8
  591. package/data/vrchat/worlds/voltdanceclub.json +0 -8
  592. package/data/vrchat/worlds/vrchathome.json +0 -9
  593. package/data/vrchat/worlds/whatalegend.json +0 -7
  594. package/data/warframe/characters/amesha.json +0 -226
  595. package/data/warframe/characters/ash.json +0 -1354
  596. package/data/warframe/characters/ashprime.json +0 -1994
  597. package/data/warframe/characters/atlas.json +0 -916
  598. package/data/warframe/characters/atlasprime.json +0 -1632
  599. package/data/warframe/characters/banshee.json +0 -1036
  600. package/data/warframe/characters/bansheeprime.json +0 -1750
  601. package/data/warframe/characters/baruuk.json +0 -555
  602. package/data/warframe/characters/baruukprime.json +0 -1298
  603. package/data/warframe/characters/bonewidow.json +0 -354
  604. package/data/warframe/characters/caliban.json +0 -434
  605. package/data/warframe/characters/calibanprime.json +0 -683
  606. package/data/warframe/characters/chroma.json +0 -1344
  607. package/data/warframe/characters/chromaprime.json +0 -1977
  608. package/data/warframe/characters/citrine.json +0 -220
  609. package/data/warframe/characters/cyte09.json +0 -218
  610. package/data/warframe/characters/dagath.json +0 -194
  611. package/data/warframe/characters/dante.json +0 -223
  612. package/data/warframe/characters/elytron.json +0 -300
  613. package/data/warframe/characters/ember.json +0 -1209
  614. package/data/warframe/characters/emberprime.json +0 -1678
  615. package/data/warframe/characters/equinox.json +0 -958
  616. package/data/warframe/characters/equinoxprime.json +0 -1644
  617. package/data/warframe/characters/excalibur.json +0 -1603
  618. package/data/warframe/characters/excaliburprime.json +0 -1524
  619. package/data/warframe/characters/excaliburumbra.json +0 -397
  620. package/data/warframe/characters/follie.json +0 -246
  621. package/data/warframe/characters/frost.json +0 -1330
  622. package/data/warframe/characters/frostprime.json +0 -1686
  623. package/data/warframe/characters/gara.json +0 -925
  624. package/data/warframe/characters/garaprime.json +0 -1494
  625. package/data/warframe/characters/garuda.json +0 -851
  626. package/data/warframe/characters/garudaprime.json +0 -1449
  627. package/data/warframe/characters/gauss.json +0 -506
  628. package/data/warframe/characters/gaussprime.json +0 -1077
  629. package/data/warframe/characters/grendel.json +0 -463
  630. package/data/warframe/characters/grendelprime.json +0 -772
  631. package/data/warframe/characters/gyre.json +0 -381
  632. package/data/warframe/characters/gyreprime.json +0 -403
  633. package/data/warframe/characters/harrow.json +0 -916
  634. package/data/warframe/characters/harrowprime.json +0 -1700
  635. package/data/warframe/characters/helminth.json +0 -220
  636. package/data/warframe/characters/hildryn.json +0 -627
  637. package/data/warframe/characters/hildrynprime.json +0 -996
  638. package/data/warframe/characters/hydroid.json +0 -1028
  639. package/data/warframe/characters/hydroidprime.json +0 -1621
  640. package/data/warframe/characters/inaros.json +0 -976
  641. package/data/warframe/characters/inarosprime.json +0 -1721
  642. package/data/warframe/characters/itzal.json +0 -465
  643. package/data/warframe/characters/ivara.json +0 -1349
  644. package/data/warframe/characters/ivaraprime.json +0 -1921
  645. package/data/warframe/characters/jade.json +0 -240
  646. package/data/warframe/characters/khora.json +0 -804
  647. package/data/warframe/characters/khoraprime.json +0 -1403
  648. package/data/warframe/characters/koumei.json +0 -221
  649. package/data/warframe/characters/kullervo.json +0 -191
  650. package/data/warframe/characters/lavos.json +0 -511
  651. package/data/warframe/characters/lavosprime.json +0 -711
  652. package/data/warframe/characters/limbo.json +0 -1363
  653. package/data/warframe/characters/limboprime.json +0 -2084
  654. package/data/warframe/characters/loki.json +0 -1209
  655. package/data/warframe/characters/lokiprime.json +0 -1457
  656. package/data/warframe/characters/mag.json +0 -2089
  657. package/data/warframe/characters/magprime.json +0 -2532
  658. package/data/warframe/characters/mesa.json +0 -1195
  659. package/data/warframe/characters/mesaprime.json +0 -2059
  660. package/data/warframe/characters/mirage.json +0 -1561
  661. package/data/warframe/characters/mirageprime.json +0 -2257
  662. package/data/warframe/characters/nekros.json +0 -1235
  663. package/data/warframe/characters/nekrosprime.json +0 -1882
  664. package/data/warframe/characters/nezha.json +0 -868
  665. package/data/warframe/characters/nezhaprime.json +0 -1695
  666. package/data/warframe/characters/nidus.json +0 -1027
  667. package/data/warframe/characters/nidusprime.json +0 -1706
  668. package/data/warframe/characters/nokko.json +0 -308
  669. package/data/warframe/characters/nova.json +0 -1226
  670. package/data/warframe/characters/novaprime.json +0 -1667
  671. package/data/warframe/characters/nyx.json +0 -1610
  672. package/data/warframe/characters/nyxprime.json +0 -1967
  673. package/data/warframe/characters/oberon.json +0 -1249
  674. package/data/warframe/characters/oberonprime.json +0 -1872
  675. package/data/warframe/characters/octavia.json +0 -1049
  676. package/data/warframe/characters/octaviaprime.json +0 -1735
  677. package/data/warframe/characters/odonata.json +0 -336
  678. package/data/warframe/characters/odonataprime.json +0 -787
  679. package/data/warframe/characters/oraxia.json +0 -246
  680. package/data/warframe/characters/orionsirius.json +0 -134
  681. package/data/warframe/characters/protea.json +0 -521
  682. package/data/warframe/characters/proteaprime.json +0 -992
  683. package/data/warframe/characters/qorvex.json +0 -214
  684. package/data/warframe/characters/revenant.json +0 -931
  685. package/data/warframe/characters/revenantprime.json +0 -1494
  686. package/data/warframe/characters/rhino.json +0 -1344
  687. package/data/warframe/characters/rhinoprime.json +0 -1675
  688. package/data/warframe/characters/saryn.json +0 -1210
  689. package/data/warframe/characters/sarynprime.json +0 -2042
  690. package/data/warframe/characters/sevagoth.json +0 -478
  691. package/data/warframe/characters/sevagothprime.json +0 -910
  692. package/data/warframe/characters/siriusorion.json +0 -247
  693. package/data/warframe/characters/styanax.json +0 -320
  694. package/data/warframe/characters/styanaxprime.json +0 -321
  695. package/data/warframe/characters/temple.json +0 -271
  696. package/data/warframe/characters/titania.json +0 -1227
  697. package/data/warframe/characters/titaniaprime.json +0 -2000
  698. package/data/warframe/characters/trinity.json +0 -1097
  699. package/data/warframe/characters/trinityprime.json +0 -1849
  700. package/data/warframe/characters/uriel.json +0 -215
  701. package/data/warframe/characters/valkyr.json +0 -1165
  702. package/data/warframe/characters/valkyrprime.json +0 -1969
  703. package/data/warframe/characters/vauban.json +0 -1067
  704. package/data/warframe/characters/vaubanprime.json +0 -1614
  705. package/data/warframe/characters/voidrig.json +0 -355
  706. package/data/warframe/characters/volt.json +0 -1324
  707. package/data/warframe/characters/voltprime.json +0 -1843
  708. package/data/warframe/characters/voruna.json +0 -293
  709. package/data/warframe/characters/vorunaprime.json +0 -431
  710. package/data/warframe/characters/wisp.json +0 -824
  711. package/data/warframe/characters/wispprime.json +0 -908
  712. package/data/warframe/characters/wukong.json +0 -927
  713. package/data/warframe/characters/wukongprime.json +0 -1754
  714. package/data/warframe/characters/xaku.json +0 -620
  715. package/data/warframe/characters/xakuprime.json +0 -879
  716. package/data/warframe/characters/yareli.json +0 -409
  717. package/data/warframe/characters/yareliprime.json +0 -683
  718. package/data/warframe/characters/zephyr.json +0 -1149
  719. package/data/warframe/characters/zephyrprime.json +0 -1864
  720. package/data/warframe/meta.json +0 -14
  721. package/data/wutheringwaves/meta.json +0 -14
  722. package/data/zenlesszonezero/meta.json +0 -14
  723. package/gamecodes.js +0 -204
  724. package/scripts/cache-sync-smoke.js +0 -139
  725. package/scripts/game-code-cache-smoke.js +0 -125
  726. package/scripts/sync-all-cache.js +0 -18
  727. package/scripts/sync-api-cache.js +0 -368
  728. package/scripts/sync-game-code-cache.js +0 -283
  729. package/scripts/sync-gaming-info-cache.js +0 -46
@@ -1,368 +0,0 @@
1
- 'use strict';
2
-
3
- const crypto = require('crypto');
4
- const fs = require('fs');
5
- const path = require('path');
6
-
7
- const ROOT_DIR = path.resolve(__dirname, '..');
8
- const DEFAULT_DATA_DIR = path.join(ROOT_DIR, 'data');
9
- const DEFAULT_API_BASE = 'https://api.nekosunevr.co.uk';
10
- const DEFAULT_API_PATH = '/v5/games/api/gaming-infos';
11
-
12
- // Safety baseline for older APINODE deployments. Newer APINODE root responses
13
- // expose { slug, types } for every game, so the mirror automatically adds any
14
- // newly published datasets (including the full Call of Duty catalog) without a
15
- // package-code change. Explicit GAMING_INFOS_CACHE_MANIFEST_JSON still works.
16
- const DEFAULT_MANIFEST = Object.freeze({
17
- vrchat: ['players', 'groups', 'worlds', 'avatars'],
18
- genshinimpact: ['characters'],
19
- honkaistarrail: ['characters'],
20
- nte: ['characters'],
21
- wutheringwaves: ['characters'],
22
- warframe: ['characters'],
23
- fortnite: ['characters', 'npcs', 'maps'],
24
- zenlesszonezero: ['characters'],
25
- toweroffantasy: ['characters'],
26
- arknightsendfield: ['characters']
27
- });
28
-
29
- function numberOption(value, fallback, min = 0, max = Number.MAX_SAFE_INTEGER) {
30
- const parsed = Number(value);
31
- return Number.isFinite(parsed) ? Math.min(max, Math.max(min, parsed)) : fallback;
32
- }
33
-
34
- function sleep(ms) {
35
- return new Promise((resolve) => setTimeout(resolve, ms));
36
- }
37
-
38
- function normalizeBase(value) {
39
- return String(value || DEFAULT_API_BASE).replace(/\/+$/, '');
40
- }
41
-
42
- function normalizeApiPath(value) {
43
- const raw = String(value || DEFAULT_API_PATH).trim();
44
- return `/${raw.replace(/^\/+|\/+$/g, '')}`;
45
- }
46
-
47
- function safeSlug(value, label = 'slug') {
48
- const slug = String(value || '').trim().toLowerCase();
49
- if (!slug || !/^[a-z0-9][a-z0-9._-]*$/.test(slug)) {
50
- throw new Error(`Invalid ${label}: ${JSON.stringify(value)}`);
51
- }
52
- return slug;
53
- }
54
-
55
- function fallbackSlug(name) {
56
- const slug = String(name || '')
57
- .normalize('NFKD')
58
- .replace(/[\u0300-\u036f]/g, '')
59
- .toLowerCase()
60
- .replace(/[^a-z0-9]+/g, '')
61
- .trim();
62
- return safeSlug(slug, 'derived slug');
63
- }
64
-
65
- function normalizeManifestObject(parsed) {
66
- if (!parsed || Array.isArray(parsed) || typeof parsed !== 'object') {
67
- throw new Error('Gaming Infos cache manifest must be a JSON object');
68
- }
69
- const result = {};
70
- for (const [gameRaw, typesRaw] of Object.entries(parsed)) {
71
- const game = safeSlug(gameRaw, 'game');
72
- if (!Array.isArray(typesRaw) || !typesRaw.length) throw new Error(`No types configured for ${game}`);
73
- result[game] = [...new Set(typesRaw.map((type) => safeSlug(type, 'type')))];
74
- }
75
- return result;
76
- }
77
-
78
- function loadManifest(raw = process.env.GAMING_INFOS_CACHE_MANIFEST_JSON) {
79
- if (!raw) return { ...DEFAULT_MANIFEST };
80
- return normalizeManifestObject(typeof raw === 'string' ? JSON.parse(raw) : raw);
81
- }
82
-
83
- function mergeDiscoveredManifest(rootData, configuredManifest = DEFAULT_MANIFEST) {
84
- const result = normalizeManifestObject(configuredManifest);
85
- for (const row of Array.isArray(rootData) ? rootData : []) {
86
- if (!row || typeof row !== 'object' || Array.isArray(row)) continue;
87
- if (!row.slug || !Array.isArray(row.types) || !row.types.length) continue;
88
- const game = safeSlug(row.slug, 'root game slug');
89
- const types = [...new Set(row.types.map((type) => safeSlug(type, `type for ${game}`)))];
90
- if (types.length) result[game] = types;
91
- }
92
- return result;
93
- }
94
-
95
- async function requestJson(url, options = {}) {
96
- const timeoutMs = numberOption(options.timeoutMs ?? process.env.GAMING_INFOS_CACHE_TIMEOUT_MS, 15000, 1000, 120000);
97
- const retries = numberOption(options.retries ?? process.env.GAMING_INFOS_CACHE_RETRIES, 2, 0, 5);
98
- const retryDelayMs = numberOption(options.retryDelayMs ?? process.env.GAMING_INFOS_CACHE_RETRY_DELAY_MS, 750, 0, 30000);
99
- let lastError;
100
-
101
- for (let attempt = 0; attempt <= retries; attempt += 1) {
102
- const controller = new AbortController();
103
- const timer = setTimeout(() => controller.abort(), timeoutMs);
104
- try {
105
- const response = await fetch(url, {
106
- signal: controller.signal,
107
- headers: {
108
- Accept: 'application/json',
109
- 'User-Agent': process.env.GAMING_INFOS_CACHE_USER_AGENT || 'NekoSuneProjects-gaming-infos-cache/1.0'
110
- }
111
- });
112
-
113
- if (!response.ok) {
114
- const error = new Error(`HTTP ${response.status} from ${url}`);
115
- error.status = response.status;
116
- throw error;
117
- }
118
-
119
- const body = await response.json();
120
- if (!body || body.success === false) {
121
- throw new Error(`API returned an unsuccessful response for ${url}`);
122
- }
123
- if (options.rawEnvelope) return body;
124
- return body.data !== undefined ? body.data : body;
125
- } catch (error) {
126
- lastError = error;
127
- const status = Number(error.status || 0);
128
- const retryable = !status || status === 408 || status === 425 || status === 429 || status >= 500;
129
- if (attempt >= retries || !retryable) break;
130
- await sleep(retryDelayMs * (attempt + 1));
131
- } finally {
132
- clearTimeout(timer);
133
- }
134
- }
135
-
136
- throw lastError || new Error(`Failed to fetch ${url}`);
137
- }
138
-
139
- function apiUrl(base, apiPath, suffix = '') {
140
- return `${normalizeBase(base)}${normalizeApiPath(apiPath)}${suffix}`;
141
- }
142
-
143
- function validateRootSyncState(rootEnvelope) {
144
- const sync = rootEnvelope && typeof rootEnvelope === 'object' ? rootEnvelope.sync : null;
145
- if (!sync || typeof sync !== 'object') return;
146
-
147
- const state = sync.state && typeof sync.state === 'object' ? sync.state : null;
148
- const status = String(state?.lastStatus || '').toLowerCase();
149
- if (sync.running || status === 'running') {
150
- throw new Error('APINODE content synchronization is currently running; preserving the previous fallback until it is idle');
151
- }
152
- if (state && ['never-run', 'failed'].includes(status)) {
153
- throw new Error(`APINODE content synchronization state is ${status}; preserving the previous fallback`);
154
- }
155
-
156
- const persistedSchema = Number(state?.syncSchemaVersion || 0);
157
- const requiredSchema = Number(state?.requiredSyncSchemaVersion || sync.syncSchemaVersion || 0);
158
- if (requiredSchema > 0 && persistedSchema < requiredSchema) {
159
- throw new Error(`APINODE content schema catch-up is incomplete (${persistedSchema}/${requiredSchema}); preserving the previous fallback`);
160
- }
161
- }
162
-
163
- async function writeJson(filePath, value) {
164
- await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
165
- await fs.promises.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
166
- }
167
-
168
- async function walkFiles(dir, root = dir, out = new Map()) {
169
- if (!fs.existsSync(dir)) return out;
170
- const entries = await fs.promises.readdir(dir, { withFileTypes: true });
171
- for (const entry of entries) {
172
- const full = path.join(dir, entry.name);
173
- if (entry.isDirectory()) await walkFiles(full, root, out);
174
- else if (entry.isFile() && entry.name !== '.cache-manifest.json') {
175
- const relative = path.relative(root, full).split(path.sep).join('/');
176
- out.set(relative, await fs.promises.readFile(full));
177
- }
178
- }
179
- return out;
180
- }
181
-
182
- function hashFiles(files) {
183
- const hash = crypto.createHash('sha256');
184
- for (const [name, content] of [...files.entries()].sort(([a], [b]) => a.localeCompare(b))) {
185
- hash.update(name);
186
- hash.update('\0');
187
- hash.update(content);
188
- hash.update('\0');
189
- }
190
- return hash.digest('hex');
191
- }
192
-
193
- async function snapshotHash(dir) {
194
- return hashFiles(await walkFiles(dir));
195
- }
196
-
197
- function diffStats(oldFiles, newFiles) {
198
- let added = 0;
199
- let removed = 0;
200
- let changed = 0;
201
- let unchanged = 0;
202
-
203
- for (const [name, content] of newFiles) {
204
- if (!oldFiles.has(name)) added += 1;
205
- else if (!oldFiles.get(name).equals(content)) changed += 1;
206
- else unchanged += 1;
207
- }
208
- for (const name of oldFiles.keys()) if (!newFiles.has(name)) removed += 1;
209
- return { added, changed, removed, unchanged, total: newFiles.size };
210
- }
211
-
212
- async function replaceSnapshot(nextDir, dataDir) {
213
- const backupDir = `${dataDir}.cache-backup-${process.pid}`;
214
- await fs.promises.rm(backupDir, { recursive: true, force: true });
215
- const hadCurrent = fs.existsSync(dataDir);
216
-
217
- if (hadCurrent) await fs.promises.rename(dataDir, backupDir);
218
- try {
219
- await fs.promises.rename(nextDir, dataDir);
220
- await fs.promises.rm(backupDir, { recursive: true, force: true });
221
- } catch (error) {
222
- if (!fs.existsSync(dataDir) && hadCurrent && fs.existsSync(backupDir)) {
223
- await fs.promises.rename(backupDir, dataDir);
224
- }
225
- throw error;
226
- }
227
- }
228
-
229
- function normalizedEntry(item) {
230
- if (!item || Array.isArray(item) || typeof item !== 'object') throw new Error('API list contained a non-object entry');
231
- const slug = safeSlug(item.slug || fallbackSlug(item.name), 'entry slug');
232
- return { ...item, slug };
233
- }
234
-
235
- async function buildNextSnapshot(options) {
236
- const { apiBase, apiPath, dataDir, manifest: configuredManifest } = options;
237
- const parentDir = path.dirname(dataDir);
238
- const nextDir = path.join(parentDir, `.gaming-infos-cache-next-${process.pid}-${Date.now()}`);
239
- await fs.promises.rm(nextDir, { recursive: true, force: true });
240
- await fs.promises.mkdir(nextDir, { recursive: true });
241
-
242
- try {
243
- const rootEnvelope = await requestJson(apiUrl(apiBase, apiPath), { ...options, rawEnvelope: true });
244
- validateRootSyncState(rootEnvelope);
245
- const rootData = rootEnvelope.data !== undefined ? rootEnvelope.data : rootEnvelope;
246
- if (!Array.isArray(rootData) || !rootData.length) {
247
- throw new Error('Gaming-infos root endpoint returned no games; refusing to replace the fallback cache');
248
- }
249
- const manifest = mergeDiscoveredManifest(rootData, configuredManifest);
250
-
251
- const counts = {};
252
- for (const [game, types] of Object.entries(manifest)) {
253
- const meta = await requestJson(apiUrl(apiBase, apiPath, `/${encodeURIComponent(game)}/meta/${encodeURIComponent(game)}`), options);
254
- if (!meta || Array.isArray(meta) || typeof meta !== 'object') throw new Error(`Invalid meta payload for ${game}`);
255
- await writeJson(path.join(nextDir, game, 'meta.json'), meta);
256
- counts[game] = { meta: 1 };
257
-
258
- for (const type of types) {
259
- const list = await requestJson(apiUrl(apiBase, apiPath, `/${encodeURIComponent(game)}/${encodeURIComponent(type)}`), options);
260
- if (!Array.isArray(list)) throw new Error(`Expected an array for ${game}/${type}`);
261
-
262
- const seen = new Set();
263
- counts[game][type] = list.length;
264
- for (const rawItem of list) {
265
- const item = normalizedEntry(rawItem);
266
- if (seen.has(item.slug)) throw new Error(`Duplicate slug ${item.slug} in ${game}/${type}`);
267
- seen.add(item.slug);
268
- await writeJson(path.join(nextDir, game, type, `${item.slug}.json`), item);
269
- }
270
- }
271
- }
272
-
273
- return { nextDir, rootGameCount: rootData.length, counts, manifest };
274
- } catch (error) {
275
- await fs.promises.rm(nextDir, { recursive: true, force: true }).catch(() => {});
276
- throw error;
277
- }
278
- }
279
-
280
- async function syncApiCache(options = {}) {
281
- if (typeof fetch !== 'function') throw new Error('Node.js 18+ is required because this sync uses the built-in fetch API');
282
-
283
- const dataDir = path.resolve(options.dataDir || process.env.GAMING_INFOS_CACHE_DIR || DEFAULT_DATA_DIR);
284
- const apiBase = options.apiBase || process.env.GAMING_INFOS_API_BASE || DEFAULT_API_BASE;
285
- const apiPath = options.apiPath || process.env.GAMING_INFOS_API_PATH || DEFAULT_API_PATH;
286
- const manifest = options.manifest || loadManifest();
287
- const requestOptions = {
288
- ...options,
289
- apiBase,
290
- apiPath,
291
- dataDir,
292
- manifest
293
- };
294
-
295
- let nextDir;
296
- try {
297
- const built = await buildNextSnapshot(requestOptions);
298
- nextDir = built.nextDir;
299
- const effectiveManifest = built.manifest;
300
- const oldFiles = await walkFiles(dataDir);
301
- const newFiles = await walkFiles(nextDir);
302
- const oldHash = hashFiles(oldFiles);
303
- const newHash = hashFiles(newFiles);
304
- const stats = diffStats(oldFiles, newFiles);
305
-
306
- if (oldFiles.size && oldHash === newHash) {
307
- await fs.promises.rm(nextDir, { recursive: true, force: true });
308
- return {
309
- success: true,
310
- changed: false,
311
- contentHash: newHash,
312
- source: apiUrl(apiBase, apiPath),
313
- games: Object.keys(effectiveManifest),
314
- counts: built.counts,
315
- stats
316
- };
317
- }
318
-
319
- const cacheManifest = {
320
- schemaVersion: 2,
321
- source: apiUrl(apiBase, apiPath),
322
- syncedAt: new Date().toISOString(),
323
- contentHash: newHash,
324
- rootGameCount: built.rootGameCount,
325
- autoDiscoveredTypes: true,
326
- games: Object.fromEntries(Object.entries(effectiveManifest).map(([game, types]) => [game, { types, counts: built.counts[game] }])),
327
- stats
328
- };
329
- await writeJson(path.join(nextDir, '.cache-manifest.json'), cacheManifest);
330
- await replaceSnapshot(nextDir, dataDir);
331
- nextDir = null;
332
-
333
- return {
334
- success: true,
335
- changed: true,
336
- contentHash: newHash,
337
- source: cacheManifest.source,
338
- games: Object.keys(effectiveManifest),
339
- counts: built.counts,
340
- stats
341
- };
342
- } catch (error) {
343
- if (nextDir) await fs.promises.rm(nextDir, { recursive: true, force: true }).catch(() => {});
344
- throw error;
345
- }
346
- }
347
-
348
- async function main() {
349
- const result = await syncApiCache();
350
- console.log(JSON.stringify(result, null, 2));
351
- }
352
-
353
- if (require.main === module) {
354
- main().catch((error) => {
355
- console.error(`[gaming-infos cache] ${error.stack || error.message || error}`);
356
- process.exitCode = 1;
357
- });
358
- }
359
-
360
- module.exports = {
361
- DEFAULT_MANIFEST,
362
- loadManifest,
363
- mergeDiscoveredManifest,
364
- validateRootSyncState,
365
- normalizedEntry,
366
- snapshotHash,
367
- syncApiCache
368
- };
@@ -1,283 +0,0 @@
1
- 'use strict';
2
-
3
- const crypto = require('crypto');
4
- const fs = require('fs');
5
- const path = require('path');
6
-
7
- const ROOT_DIR = path.resolve(__dirname, '..');
8
- const DEFAULT_DATA_DIR = path.join(ROOT_DIR, 'data', 'game-codes');
9
- const DEFAULT_API_BASE = 'https://api.nekosunevr.co.uk';
10
- const DEFAULT_API_PATH = '/v5/games/api/codes';
11
-
12
- function numberOption(value, fallback, min = 0, max = Number.MAX_SAFE_INTEGER) {
13
- const parsed = Number(value);
14
- return Number.isFinite(parsed) ? Math.min(max, Math.max(min, parsed)) : fallback;
15
- }
16
-
17
- function sleep(ms) {
18
- return new Promise((resolve) => setTimeout(resolve, ms));
19
- }
20
-
21
- function normalizeBase(value) {
22
- return String(value || DEFAULT_API_BASE).replace(/\/+$/, '');
23
- }
24
-
25
- function normalizeApiPath(value) {
26
- const raw = String(value || DEFAULT_API_PATH).trim();
27
- return `/${raw.replace(/^\/+|\/+$/g, '')}`;
28
- }
29
-
30
- async function requestJson(url, options = {}) {
31
- const timeoutMs = numberOption(options.timeoutMs ?? process.env.GAME_CODES_CACHE_TIMEOUT_MS, 15000, 1000, 120000);
32
- const retries = numberOption(options.retries ?? process.env.GAME_CODES_CACHE_RETRIES, 2, 0, 5);
33
- const retryDelayMs = numberOption(options.retryDelayMs ?? process.env.GAME_CODES_CACHE_RETRY_DELAY_MS, 750, 0, 30000);
34
- let lastError;
35
-
36
- for (let attempt = 0; attempt <= retries; attempt += 1) {
37
- const controller = new AbortController();
38
- const timer = setTimeout(() => controller.abort(), timeoutMs);
39
- try {
40
- const response = await fetch(url, {
41
- signal: controller.signal,
42
- headers: {
43
- Accept: 'application/json',
44
- 'User-Agent': process.env.GAME_CODES_CACHE_USER_AGENT || 'NekoSuneProjects-gaming-infos-game-codes-cache/1.0'
45
- }
46
- });
47
- if (!response.ok) {
48
- const error = new Error(`HTTP ${response.status} from ${url}`);
49
- error.status = response.status;
50
- throw error;
51
- }
52
- const body = await response.json();
53
- if (!body || body.success === false) throw new Error(`API returned an unsuccessful response for ${url}`);
54
- return body;
55
- } catch (error) {
56
- lastError = error;
57
- const status = Number(error.status || 0);
58
- const retryable = !status || status === 408 || status === 425 || status === 429 || status >= 500;
59
- if (attempt >= retries || !retryable) break;
60
- await sleep(retryDelayMs * (attempt + 1));
61
- } finally {
62
- clearTimeout(timer);
63
- }
64
- }
65
-
66
- throw lastError || new Error(`Failed to fetch ${url}`);
67
- }
68
-
69
- function apiUrl(base, apiPath, suffix = '', query = {}) {
70
- const url = new URL(`${normalizeBase(base)}${normalizeApiPath(apiPath)}${suffix}`);
71
- for (const [key, value] of Object.entries(query)) {
72
- if (value !== undefined && value !== null && value !== '') url.searchParams.set(key, String(value));
73
- }
74
- return url.href;
75
- }
76
-
77
- async function writeJson(filePath, value) {
78
- await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
79
- await fs.promises.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
80
- }
81
-
82
- async function walkFiles(dir, root = dir, out = new Map()) {
83
- if (!fs.existsSync(dir)) return out;
84
- const entries = await fs.promises.readdir(dir, { withFileTypes: true });
85
- for (const entry of entries) {
86
- const full = path.join(dir, entry.name);
87
- if (entry.isDirectory()) await walkFiles(full, root, out);
88
- else if (entry.isFile() && entry.name !== '.cache-manifest.json') {
89
- const relative = path.relative(root, full).split(path.sep).join('/');
90
- out.set(relative, await fs.promises.readFile(full));
91
- }
92
- }
93
- return out;
94
- }
95
-
96
- function hashFiles(files) {
97
- const hash = crypto.createHash('sha256');
98
- for (const [name, content] of [...files.entries()].sort(([a], [b]) => a.localeCompare(b))) {
99
- hash.update(name);
100
- hash.update('\0');
101
- hash.update(content);
102
- hash.update('\0');
103
- }
104
- return hash.digest('hex');
105
- }
106
-
107
- function diffStats(oldFiles, newFiles) {
108
- let added = 0;
109
- let removed = 0;
110
- let changed = 0;
111
- let unchanged = 0;
112
- for (const [name, content] of newFiles) {
113
- if (!oldFiles.has(name)) added += 1;
114
- else if (!oldFiles.get(name).equals(content)) changed += 1;
115
- else unchanged += 1;
116
- }
117
- for (const name of oldFiles.keys()) if (!newFiles.has(name)) removed += 1;
118
- return { added, changed, removed, unchanged, total: newFiles.size };
119
- }
120
-
121
- async function replaceSnapshot(nextDir, dataDir) {
122
- const backupDir = `${dataDir}.cache-backup-${process.pid}`;
123
- await fs.promises.rm(backupDir, { recursive: true, force: true });
124
- const hadCurrent = fs.existsSync(dataDir);
125
- if (hadCurrent) await fs.promises.rename(dataDir, backupDir);
126
- try {
127
- await fs.promises.rename(nextDir, dataDir);
128
- await fs.promises.rm(backupDir, { recursive: true, force: true });
129
- } catch (error) {
130
- if (!fs.existsSync(dataDir) && hadCurrent && fs.existsSync(backupDir)) await fs.promises.rename(backupDir, dataDir);
131
- throw error;
132
- }
133
- }
134
-
135
- function gameSlug(row) {
136
- const slug = String(row?.game || '').trim().toLowerCase();
137
- if (!slug || !/^[a-z0-9][a-z0-9-]*$/.test(slug)) throw new Error(`Invalid game slug in code directory: ${JSON.stringify(row?.game)}`);
138
- return slug;
139
- }
140
-
141
- function validateCodeList(game, payload) {
142
- if (!payload || Array.isArray(payload) || typeof payload !== 'object') throw new Error(`Invalid code payload for ${game}`);
143
- if (!Array.isArray(payload.Active) || !Array.isArray(payload.Expired)) throw new Error(`Code payload for ${game} is missing Active/Expired arrays`);
144
- if (payload.Unknown !== undefined && !Array.isArray(payload.Unknown)) throw new Error(`Unknown codes for ${game} must be an array`);
145
- return payload;
146
- }
147
-
148
- function stableDirectorySnapshot(directory) {
149
- const stable = JSON.parse(JSON.stringify(directory));
150
- const updatedTimes = (stable.games || [])
151
- .map((game) => new Date(game?.lastUpdatedAt || 0).getTime())
152
- .filter((value) => Number.isFinite(value) && value > 0);
153
-
154
- // APINODE's root `updatedAt` describes when the HTTP directory response was
155
- // generated, so it changes every request. Keep a meaningful stable timestamp
156
- // based on actual per-game data updates instead.
157
- if (updatedTimes.length) stable.updatedAt = new Date(Math.max(...updatedTimes)).toISOString();
158
- else delete stable.updatedAt;
159
- return stable;
160
- }
161
-
162
- function stableCodeRow(row) {
163
- const stable = JSON.parse(JSON.stringify(row));
164
- if (stable.expiry && typeof stable.expiry === 'object' && !Array.isArray(stable.expiry)) {
165
- // These values are calculated from Date.now() on every API request. The
166
- // fallback retains expiresAt/local/expired, while consumers can calculate
167
- // a live countdown themselves when needed.
168
- delete stable.expiry.expiresInSeconds;
169
- delete stable.expiry.countdown;
170
- }
171
- return stable;
172
- }
173
-
174
- function stableCodePayload(payload) {
175
- const stable = {};
176
- for (const bucket of ['Active', 'Expired', 'Unknown']) {
177
- if (Array.isArray(payload[bucket])) stable[bucket] = payload[bucket].map(stableCodeRow);
178
- }
179
- return stable;
180
- }
181
-
182
- async function buildNextSnapshot(options) {
183
- const { apiBase, apiPath, dataDir } = options;
184
- const nextDir = path.join(path.dirname(dataDir), `.game-codes-cache-next-${process.pid}-${Date.now()}`);
185
- await fs.promises.rm(nextDir, { recursive: true, force: true });
186
- await fs.promises.mkdir(nextDir, { recursive: true });
187
-
188
- const rawDirectory = await requestJson(apiUrl(apiBase, apiPath), options);
189
- if (!Array.isArray(rawDirectory.games) || !rawDirectory.games.length) {
190
- throw new Error('Game code directory returned no games; refusing to replace fallback cache');
191
- }
192
- const directory = stableDirectorySnapshot(rawDirectory);
193
- await writeJson(path.join(nextDir, 'directory.json'), directory);
194
-
195
- // /status is cache-only on APINODE and does not trigger source website requests.
196
- const statusResponse = await requestJson(apiUrl(apiBase, apiPath, '/status'), options);
197
- const status = statusResponse.data !== undefined ? statusResponse.data : statusResponse;
198
- if (!status || typeof status !== 'object') throw new Error('Invalid game code status payload');
199
- await writeJson(path.join(nextDir, 'status.json'), status);
200
-
201
- const counts = {};
202
- const delayMs = numberOption(options.delayMs ?? process.env.GAME_CODES_CACHE_GAME_DELAY_MS, 150, 0, 10000);
203
- for (let i = 0; i < directory.games.length; i += 1) {
204
- const game = gameSlug(directory.games[i]);
205
- const rawPayload = validateCodeList(
206
- game,
207
- await requestJson(apiUrl(apiBase, apiPath, `/${encodeURIComponent(game)}`, { includeUnknown: 'true' }), options)
208
- );
209
- const payload = stableCodePayload(rawPayload);
210
- await writeJson(path.join(nextDir, 'games', `${game}.json`), payload);
211
- counts[game] = {
212
- active: payload.Active.length,
213
- expired: payload.Expired.length,
214
- unknown: Array.isArray(payload.Unknown) ? payload.Unknown.length : 0,
215
- total: payload.Active.length + payload.Expired.length + (Array.isArray(payload.Unknown) ? payload.Unknown.length : 0)
216
- };
217
- if (i < directory.games.length - 1 && delayMs) await sleep(delayMs);
218
- }
219
-
220
- return { nextDir, directory, counts };
221
- }
222
-
223
- async function syncGameCodeCache(options = {}) {
224
- if (typeof fetch !== 'function') throw new Error('Node.js 18+ is required because this sync uses the built-in fetch API');
225
-
226
- const dataDir = path.resolve(options.dataDir || process.env.GAME_CODES_CACHE_DIR || DEFAULT_DATA_DIR);
227
- const apiBase = options.apiBase || process.env.GAMING_INFOS_API_BASE || DEFAULT_API_BASE;
228
- const apiPath = options.apiPath || process.env.GAME_CODES_API_PATH || DEFAULT_API_PATH;
229
- let nextDir;
230
-
231
- try {
232
- const built = await buildNextSnapshot({ ...options, dataDir, apiBase, apiPath });
233
- nextDir = built.nextDir;
234
- const oldFiles = await walkFiles(dataDir);
235
- const newFiles = await walkFiles(nextDir);
236
- const oldHash = hashFiles(oldFiles);
237
- const newHash = hashFiles(newFiles);
238
- const stats = diffStats(oldFiles, newFiles);
239
-
240
- if (oldFiles.size && oldHash === newHash) {
241
- await fs.promises.rm(nextDir, { recursive: true, force: true });
242
- return { success: true, changed: false, contentHash: newHash, source: apiUrl(apiBase, apiPath), counts: built.counts, stats };
243
- }
244
-
245
- const manifest = {
246
- schemaVersion: 1,
247
- source: apiUrl(apiBase, apiPath),
248
- syncedAt: new Date().toISOString(),
249
- contentHash: newHash,
250
- gameCount: built.directory.games.length,
251
- counts: built.counts,
252
- statusIsCacheOnly: true,
253
- volatileFieldsRemoved: ['directory.updatedAt(request-time)', 'expiry.expiresInSeconds', 'expiry.countdown'],
254
- stats
255
- };
256
- await writeJson(path.join(nextDir, '.cache-manifest.json'), manifest);
257
- await replaceSnapshot(nextDir, dataDir);
258
- nextDir = null;
259
- return { success: true, changed: true, contentHash: newHash, source: manifest.source, counts: built.counts, stats };
260
- } catch (error) {
261
- if (nextDir) await fs.promises.rm(nextDir, { recursive: true, force: true }).catch(() => {});
262
- throw error;
263
- }
264
- }
265
-
266
- async function main() {
267
- const result = await syncGameCodeCache();
268
- console.log(JSON.stringify(result, null, 2));
269
- }
270
-
271
- if (require.main === module) {
272
- main().catch((error) => {
273
- console.error(`[game-codes cache] ${error.stack || error.message || error}`);
274
- process.exitCode = 1;
275
- });
276
- }
277
-
278
- module.exports = {
279
- stableDirectorySnapshot,
280
- stableCodePayload,
281
- syncGameCodeCache,
282
- validateCodeList
283
- };
@@ -1,46 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
- const { syncApiCache } = require('./sync-api-cache');
6
-
7
- const ROOT_DIR = path.resolve(__dirname, '..');
8
- const DATA_DIR = path.join(ROOT_DIR, 'data');
9
- const GAME_CODES_DIR = path.join(DATA_DIR, 'game-codes');
10
-
11
- async function syncGamingInfoCacheSafely(options = {}) {
12
- const dataDir = path.resolve(options.dataDir || process.env.GAMING_INFOS_CACHE_DIR || DATA_DIR);
13
- const gameCodesDir = path.join(dataDir, 'game-codes');
14
- const preserveDir = path.join(path.dirname(dataDir), `.game-codes-preserve-${process.pid}-${Date.now()}`);
15
- let preserved = false;
16
-
17
- try {
18
- if (fs.existsSync(gameCodesDir)) {
19
- await fs.promises.rm(preserveDir, { recursive: true, force: true });
20
- await fs.promises.rename(gameCodesDir, preserveDir);
21
- preserved = true;
22
- }
23
-
24
- return await syncApiCache({ ...options, dataDir });
25
- } finally {
26
- if (preserved && fs.existsSync(preserveDir)) {
27
- await fs.promises.mkdir(dataDir, { recursive: true });
28
- await fs.promises.rm(gameCodesDir, { recursive: true, force: true });
29
- await fs.promises.rename(preserveDir, gameCodesDir);
30
- }
31
- }
32
- }
33
-
34
- async function main() {
35
- const result = await syncGamingInfoCacheSafely();
36
- console.log(JSON.stringify(result, null, 2));
37
- }
38
-
39
- if (require.main === module) {
40
- main().catch((error) => {
41
- console.error(`[gaming-infos cache] ${error.stack || error.message || error}`);
42
- process.exitCode = 1;
43
- });
44
- }
45
-
46
- module.exports = { syncGamingInfoCacheSafely };