@nekosuneprojects/gaming-infos 2.2.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 (277) hide show
  1. package/CHANGELOG.md +77 -3
  2. package/README.md +62 -495
  3. package/index.js +3 -223
  4. package/package.json +53 -46
  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 -72
  11. package/CACHE_SYNC.md +0 -172
  12. package/CONTRIBUTING.md +0 -217
  13. package/DATA.md +0 -292
  14. package/data/arknightsendfield/meta.json +0 -14
  15. package/data/fortnite/meta.json +0 -14
  16. package/data/game-codes/.gitkeep +0 -0
  17. package/data/genshinimpact/characters/albedo.json +0 -11
  18. package/data/genshinimpact/characters/alhaitham.json +0 -12
  19. package/data/genshinimpact/characters/aloy.json +0 -11
  20. package/data/genshinimpact/characters/amber.json +0 -12
  21. package/data/genshinimpact/characters/aratakiitto.json +0 -12
  22. package/data/genshinimpact/characters/arlecchino.json +0 -12
  23. package/data/genshinimpact/characters/baizhu.json +0 -12
  24. package/data/genshinimpact/characters/barbara.json +0 -11
  25. package/data/genshinimpact/characters/beidou.json +0 -12
  26. package/data/genshinimpact/characters/bennett.json +0 -11
  27. package/data/genshinimpact/characters/candace.json +0 -12
  28. package/data/genshinimpact/characters/charlotte.json +0 -11
  29. package/data/genshinimpact/characters/chasca.json +0 -11
  30. package/data/genshinimpact/characters/chevreuse.json +0 -11
  31. package/data/genshinimpact/characters/chiori.json +0 -11
  32. package/data/genshinimpact/characters/chongyun.json +0 -12
  33. package/data/genshinimpact/characters/citlali.json +0 -11
  34. package/data/genshinimpact/characters/clorinde.json +0 -11
  35. package/data/genshinimpact/characters/collei.json +0 -12
  36. package/data/genshinimpact/characters/cyno.json +0 -12
  37. package/data/genshinimpact/characters/dahlia.json +0 -10
  38. package/data/genshinimpact/characters/dehya.json +0 -11
  39. package/data/genshinimpact/characters/diluc.json +0 -11
  40. package/data/genshinimpact/characters/diona.json +0 -11
  41. package/data/genshinimpact/characters/dori.json +0 -11
  42. package/data/genshinimpact/characters/durin.json +0 -11
  43. package/data/genshinimpact/characters/emilie.json +0 -11
  44. package/data/genshinimpact/characters/escoffier.json +0 -12
  45. package/data/genshinimpact/characters/eula.json +0 -11
  46. package/data/genshinimpact/characters/faruzan.json +0 -12
  47. package/data/genshinimpact/characters/fischl.json +0 -12
  48. package/data/genshinimpact/characters/freminet.json +0 -11
  49. package/data/genshinimpact/characters/furina.json +0 -12
  50. package/data/genshinimpact/characters/gaming.json +0 -11
  51. package/data/genshinimpact/characters/ganyu.json +0 -11
  52. package/data/genshinimpact/characters/gorou.json +0 -12
  53. package/data/genshinimpact/characters/hutao.json +0 -12
  54. package/data/genshinimpact/characters/iansan.json +0 -11
  55. package/data/genshinimpact/characters/ineffa.json +0 -11
  56. package/data/genshinimpact/characters/jean.json +0 -11
  57. package/data/genshinimpact/characters/kachina.json +0 -11
  58. package/data/genshinimpact/characters/kaedeharakazuha.json +0 -12
  59. package/data/genshinimpact/characters/kaeya.json +0 -11
  60. package/data/genshinimpact/characters/kamisatoayaka.json +0 -11
  61. package/data/genshinimpact/characters/kamisatoayato.json +0 -11
  62. package/data/genshinimpact/characters/kaveh.json +0 -12
  63. package/data/genshinimpact/characters/keqing.json +0 -11
  64. package/data/genshinimpact/characters/kinich.json +0 -11
  65. package/data/genshinimpact/characters/kirara.json +0 -11
  66. package/data/genshinimpact/characters/klee.json +0 -11
  67. package/data/genshinimpact/characters/kujousara.json +0 -11
  68. package/data/genshinimpact/characters/kukishinobu.json +0 -12
  69. package/data/genshinimpact/characters/lanyan.json +0 -11
  70. package/data/genshinimpact/characters/layla.json +0 -11
  71. package/data/genshinimpact/characters/lisa.json +0 -12
  72. package/data/genshinimpact/characters/lohen.json +0 -11
  73. package/data/genshinimpact/characters/lynette.json +0 -11
  74. package/data/genshinimpact/characters/lyney.json +0 -11
  75. package/data/genshinimpact/characters/mavuika.json +0 -11
  76. package/data/genshinimpact/characters/mikaschmidt.json +0 -11
  77. package/data/genshinimpact/characters/mona.json +0 -12
  78. package/data/genshinimpact/characters/mualani.json +0 -11
  79. package/data/genshinimpact/characters/nahida.json +0 -12
  80. package/data/genshinimpact/characters/navia.json +0 -11
  81. package/data/genshinimpact/characters/neuvillette.json +0 -11
  82. package/data/genshinimpact/characters/nilou.json +0 -11
  83. package/data/genshinimpact/characters/ningguang.json +0 -11
  84. package/data/genshinimpact/characters/noelle.json +0 -12
  85. package/data/genshinimpact/characters/ororon.json +0 -11
  86. package/data/genshinimpact/characters/prune.json +0 -10
  87. package/data/genshinimpact/characters/qiqi.json +0 -12
  88. package/data/genshinimpact/characters/raidenshogun.json +0 -12
  89. package/data/genshinimpact/characters/razor.json +0 -11
  90. package/data/genshinimpact/characters/rosaria.json +0 -12
  91. package/data/genshinimpact/characters/sangonomiyakokomi.json +0 -12
  92. package/data/genshinimpact/characters/sayu.json +0 -11
  93. package/data/genshinimpact/characters/sethos.json +0 -11
  94. package/data/genshinimpact/characters/shenhe.json +0 -12
  95. package/data/genshinimpact/characters/shikanoinheizou.json +0 -12
  96. package/data/genshinimpact/characters/sigewinne.json +0 -11
  97. package/data/genshinimpact/characters/skirk.json +0 -11
  98. package/data/genshinimpact/characters/sucrose.json +0 -12
  99. package/data/genshinimpact/characters/thoma.json +0 -11
  100. package/data/genshinimpact/characters/tighnari.json +0 -12
  101. package/data/genshinimpact/characters/varesa.json +0 -11
  102. package/data/genshinimpact/characters/varka.json +0 -10
  103. package/data/genshinimpact/characters/venti.json +0 -12
  104. package/data/genshinimpact/characters/wanderer.json +0 -11
  105. package/data/genshinimpact/characters/wriothesley.json +0 -12
  106. package/data/genshinimpact/characters/xiangling.json +0 -12
  107. package/data/genshinimpact/characters/xianyun.json +0 -11
  108. package/data/genshinimpact/characters/xiao.json +0 -11
  109. package/data/genshinimpact/characters/xilonen.json +0 -11
  110. package/data/genshinimpact/characters/xingqiu.json +0 -12
  111. package/data/genshinimpact/characters/xinyan.json +0 -12
  112. package/data/genshinimpact/characters/yaemiko.json +0 -12
  113. package/data/genshinimpact/characters/yanfei.json +0 -12
  114. package/data/genshinimpact/characters/yaoyao.json +0 -12
  115. package/data/genshinimpact/characters/yelan.json +0 -11
  116. package/data/genshinimpact/characters/yoimiya.json +0 -12
  117. package/data/genshinimpact/characters/yumemizukimizuki.json +0 -11
  118. package/data/genshinimpact/characters/yunjin.json +0 -11
  119. package/data/genshinimpact/characters/zhongli.json +0 -11
  120. package/data/genshinimpact/characters/zibai.json +0 -11
  121. package/data/genshinimpact/meta.json +0 -14
  122. package/data/honkaistarrail/characters/acheron.json +0 -12
  123. package/data/honkaistarrail/characters/aglaea.json +0 -12
  124. package/data/honkaistarrail/characters/anaxa.json +0 -12
  125. package/data/honkaistarrail/characters/argenti.json +0 -12
  126. package/data/honkaistarrail/characters/arlan.json +0 -12
  127. package/data/honkaistarrail/characters/ashveil.json +0 -12
  128. package/data/honkaistarrail/characters/asta.json +0 -12
  129. package/data/honkaistarrail/characters/aventurine.json +0 -12
  130. package/data/honkaistarrail/characters/bailu.json +0 -12
  131. package/data/honkaistarrail/characters/blackswan.json +0 -12
  132. package/data/honkaistarrail/characters/blade.json +0 -12
  133. package/data/honkaistarrail/characters/boothill.json +0 -12
  134. package/data/honkaistarrail/characters/bronya.json +0 -12
  135. package/data/honkaistarrail/characters/castorice.json +0 -12
  136. package/data/honkaistarrail/characters/cerydra.json +0 -12
  137. package/data/honkaistarrail/characters/cipher.json +0 -12
  138. package/data/honkaistarrail/characters/clara.json +0 -12
  139. package/data/honkaistarrail/characters/constance.json +0 -12
  140. package/data/honkaistarrail/characters/cyrene.json +0 -12
  141. package/data/honkaistarrail/characters/danheng.json +0 -12
  142. package/data/honkaistarrail/characters/drratio.json +0 -12
  143. package/data/honkaistarrail/characters/feixiao.json +0 -12
  144. package/data/honkaistarrail/characters/firefly.json +0 -12
  145. package/data/honkaistarrail/characters/fuxuan.json +0 -12
  146. package/data/honkaistarrail/characters/gallagher.json +0 -12
  147. package/data/honkaistarrail/characters/gepard.json +0 -12
  148. package/data/honkaistarrail/characters/guinaifen.json +0 -12
  149. package/data/honkaistarrail/characters/hanya.json +0 -12
  150. package/data/honkaistarrail/characters/herta.json +0 -12
  151. package/data/honkaistarrail/characters/himeko.json +0 -13
  152. package/data/honkaistarrail/characters/hook.json +0 -12
  153. package/data/honkaistarrail/characters/huohuo.json +0 -12
  154. package/data/honkaistarrail/characters/hyacine.json +0 -12
  155. package/data/honkaistarrail/characters/hysilens.json +0 -12
  156. package/data/honkaistarrail/characters/jade.json +0 -12
  157. package/data/honkaistarrail/characters/jiaoqiu.json +0 -12
  158. package/data/honkaistarrail/characters/jingliu.json +0 -12
  159. package/data/honkaistarrail/characters/jingyuan.json +0 -12
  160. package/data/honkaistarrail/characters/kafka.json +0 -12
  161. package/data/honkaistarrail/characters/lingsha.json +0 -12
  162. package/data/honkaistarrail/characters/lisushang.json +0 -12
  163. package/data/honkaistarrail/characters/luka.json +0 -12
  164. package/data/honkaistarrail/characters/luocha.json +0 -12
  165. package/data/honkaistarrail/characters/lynx.json +0 -12
  166. package/data/honkaistarrail/characters/march7th.json +0 -12
  167. package/data/honkaistarrail/characters/misha.json +0 -12
  168. package/data/honkaistarrail/characters/moze.json +0 -12
  169. package/data/honkaistarrail/characters/mydei.json +0 -12
  170. package/data/honkaistarrail/characters/natasha.json +0 -12
  171. package/data/honkaistarrail/characters/pela.json +0 -12
  172. package/data/honkaistarrail/characters/phainon.json +0 -12
  173. package/data/honkaistarrail/characters/qingque.json +0 -12
  174. package/data/honkaistarrail/characters/rappa.json +0 -12
  175. package/data/honkaistarrail/characters/robin.json +0 -12
  176. package/data/honkaistarrail/characters/ruanmei.json +0 -12
  177. package/data/honkaistarrail/characters/sampo.json +0 -12
  178. package/data/honkaistarrail/characters/seele.json +0 -12
  179. package/data/honkaistarrail/characters/serval.json +0 -12
  180. package/data/honkaistarrail/characters/silverwolf.json +0 -12
  181. package/data/honkaistarrail/characters/sparkle.json +0 -12
  182. package/data/honkaistarrail/characters/tingyun.json +0 -12
  183. package/data/honkaistarrail/characters/topaz.json +0 -12
  184. package/data/honkaistarrail/characters/tribbie.json +0 -12
  185. package/data/honkaistarrail/characters/weltyang.json +0 -12
  186. package/data/honkaistarrail/characters/xueyi.json +0 -12
  187. package/data/honkaistarrail/characters/yanqing.json +0 -12
  188. package/data/honkaistarrail/characters/yaoguang.json +0 -12
  189. package/data/honkaistarrail/characters/yukong.json +0 -12
  190. package/data/honkaistarrail/characters/yunli.json +0 -12
  191. package/data/honkaistarrail/meta.json +0 -14
  192. package/data/nte/characters/adler.json +0 -14
  193. package/data/nte/characters/aurelia.json +0 -14
  194. package/data/nte/characters/baicang.json +0 -14
  195. package/data/nte/characters/chaos.json +0 -14
  196. package/data/nte/characters/chiz.json +0 -14
  197. package/data/nte/characters/daffodill.json +0 -14
  198. package/data/nte/characters/edgar.json +0 -14
  199. package/data/nte/characters/esperzero.json +0 -14
  200. package/data/nte/characters/fadia.json +0 -14
  201. package/data/nte/characters/haniel.json +0 -14
  202. package/data/nte/characters/hathor.json +0 -14
  203. package/data/nte/characters/hotori.json +0 -14
  204. package/data/nte/characters/iroi.json +0 -14
  205. package/data/nte/characters/jiuyuan.json +0 -14
  206. package/data/nte/characters/lacrimosa.json +0 -14
  207. package/data/nte/characters/mint.json +0 -14
  208. package/data/nte/characters/nanally.json +0 -14
  209. package/data/nte/characters/sakiri.json +0 -14
  210. package/data/nte/characters/shinku.json +0 -14
  211. package/data/nte/characters/skia.json +0 -14
  212. package/data/nte/meta.json +0 -14
  213. package/data/toweroffantasy/meta.json +0 -14
  214. package/data/vrchat/avatars/.gitkeep +0 -0
  215. package/data/vrchat/groups/clubzodiac.json +0 -7
  216. package/data/vrchat/groups/dirtydancers.json +0 -7
  217. package/data/vrchat/groups/drumsynews.json +0 -7
  218. package/data/vrchat/groups/ebola20.json +0 -7
  219. package/data/vrchat/groups/internationaldancersassociation.json +0 -7
  220. package/data/vrchat/groups/kannagang.json +0 -6
  221. package/data/vrchat/groups/lolisquad.json +0 -7
  222. package/data/vrchat/groups/nekonightsnightclub.json +0 -7
  223. package/data/vrchat/groups/nekostudios.json +0 -7
  224. package/data/vrchat/groups/nekosunecommunity.json +0 -7
  225. package/data/vrchat/groups/voidclub.json +0 -7
  226. package/data/vrchat/groups/voltdanceclub.json +0 -7
  227. package/data/vrchat/groups/vrceventsgroup.json +0 -7
  228. package/data/vrchat/groups/vrchatcommunitydiscord.json +0 -6
  229. package/data/vrchat/meta.json +0 -13
  230. package/data/vrchat/players/alto.json +0 -9
  231. package/data/vrchat/players/arcadum.json +0 -10
  232. package/data/vrchat/players/chairhandler.json +0 -9
  233. package/data/vrchat/players/chipz.json +0 -9
  234. package/data/vrchat/players/hikarivr.json +0 -10
  235. package/data/vrchat/players/kimple.json +0 -10
  236. package/data/vrchat/players/linkzr.json +0 -8
  237. package/data/vrchat/players/nagzz21.json +0 -9
  238. package/data/vrchat/players/nebride.json +0 -10
  239. package/data/vrchat/players/nekosunevr.json +0 -10
  240. package/data/vrchat/players/pokelawls.json +0 -9
  241. package/data/vrchat/players/qwonk.json +0 -8
  242. package/data/vrchat/players/roflgator.json +0 -10
  243. package/data/vrchat/players/scifri.json +0 -7
  244. package/data/vrchat/players/sodapoppin.json +0 -9
  245. package/data/vrchat/players/woops.json +0 -9
  246. package/data/vrchat/players/zentreya.json +0 -10
  247. package/data/vrchat/worlds/ascensionacademy.json +0 -7
  248. package/data/vrchat/worlds/clubvgl.json +0 -8
  249. package/data/vrchat/worlds/fightfinder.json +0 -8
  250. package/data/vrchat/worlds/hangouthouse.json +0 -7
  251. package/data/vrchat/worlds/nekostudioshalloween.json +0 -9
  252. package/data/vrchat/worlds/nekostudiosnewyear.json +0 -9
  253. package/data/vrchat/worlds/nekostudiosxmas.json +0 -9
  254. package/data/vrchat/worlds/nekosunevranimations2023.json +0 -9
  255. package/data/vrchat/worlds/nekosunevranimations2024.json +0 -9
  256. package/data/vrchat/worlds/nekosunevranimations2025.json +0 -9
  257. package/data/vrchat/worlds/rumhamsavatarworld.json +0 -7
  258. package/data/vrchat/worlds/smewsranch.json +0 -7
  259. package/data/vrchat/worlds/smewsroom.json +0 -7
  260. package/data/vrchat/worlds/sunsetbar.json +0 -7
  261. package/data/vrchat/worlds/theblackcat.json +0 -9
  262. package/data/vrchat/worlds/thegreatpug.json +0 -8
  263. package/data/vrchat/worlds/themidnightbar.json +0 -7
  264. package/data/vrchat/worlds/voidclub.json +0 -7
  265. package/data/vrchat/worlds/voltdanceclub.json +0 -7
  266. package/data/vrchat/worlds/vrchathome.json +0 -8
  267. package/data/vrchat/worlds/whatalegend.json +0 -6
  268. package/data/warframe/meta.json +0 -14
  269. package/data/wutheringwaves/meta.json +0 -14
  270. package/data/zenlesszonezero/meta.json +0 -14
  271. package/gamecodes.js +0 -178
  272. package/scripts/cache-sync-smoke.js +0 -92
  273. package/scripts/game-code-cache-smoke.js +0 -85
  274. package/scripts/sync-all-cache.js +0 -18
  275. package/scripts/sync-api-cache.js +0 -319
  276. package/scripts/sync-game-code-cache.js +0 -244
  277. package/scripts/sync-gaming-info-cache.js +0 -46
package/index.js CHANGED
@@ -1,224 +1,4 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const gameCodes = require('./gamecodes');
1
+ 'use strict';
2
+ const { createClient, createWarframe, createVRChat, listProviders, providers } = require('./src/registry');
4
3
 
5
- const DATA_DIR = path.join(__dirname, 'data');
6
- const DEFAULT_API_BASE = 'https://api.nekosunevr.co.uk';
7
- const DEFAULT_API_PATH = '/v5/games/api/gaming-infos';
8
- const DEFAULT_TIMEOUT_MS = 4000;
9
-
10
- function apiBase() {
11
- return (process.env.GAMING_INFOS_API_BASE || DEFAULT_API_BASE).replace(/\/+$/, '');
12
- }
13
-
14
- function apiPath() {
15
- return process.env.GAMING_INFOS_API_PATH || DEFAULT_API_PATH;
16
- }
17
-
18
- function apiDisabled() {
19
- return process.env.GAMING_INFOS_DISABLE_API === '1' || process.env.GAMING_INFOS_DISABLE_API === 'true';
20
- }
21
-
22
- function timeoutMs() {
23
- const raw = Number(process.env.GAMING_INFOS_TIMEOUT_MS);
24
- return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_TIMEOUT_MS;
25
- }
26
-
27
- function withLocalSlug(filePath, data) {
28
- if (!data || Array.isArray(data) || typeof data !== 'object' || data.slug) return data;
29
- return { ...data, slug: path.basename(filePath, '.json').toLowerCase() };
30
- }
31
-
32
- // Live lookups go through the NekoSuneVR V5 API first so data can be updated
33
- // in real time without republishing this package. The bundled JSON under
34
- // data/ is the offline fallback and is mirrored from APINODE by the scheduled
35
- // sync workflow.
36
- async function fetchFromApi(game, type, name) {
37
- if (apiDisabled() || typeof fetch !== 'function') return null;
38
-
39
- const url = `${apiBase()}${apiPath()}/${encodeURIComponent(game.toLowerCase())}/${encodeURIComponent(type)}/${encodeURIComponent(name.toLowerCase())}`;
40
- const controller = new AbortController();
41
- const timer = setTimeout(() => controller.abort(), timeoutMs());
42
-
43
- try {
44
- const res = await fetch(url, { signal: controller.signal });
45
- if (!res.ok) return null;
46
- const body = await res.json();
47
- if (!body || body.success === false) return null;
48
- return body.data !== undefined ? body.data : body;
49
- } catch (err) {
50
- return null;
51
- } finally {
52
- clearTimeout(timer);
53
- }
54
- }
55
-
56
- async function loadLocal(game, type, name) {
57
- const filePath = path.join(DATA_DIR, game.toLowerCase(), type, `${name.toLowerCase()}.json`);
58
- if (!fs.existsSync(filePath)) {
59
- throw new Error(`${type} "${name}" not found for game "${game}"`);
60
- }
61
-
62
- const raw = await fs.promises.readFile(filePath, 'utf8');
63
- return withLocalSlug(filePath, JSON.parse(raw));
64
- }
65
-
66
- async function fetchListFromApi(game, type) {
67
- if (apiDisabled() || typeof fetch !== 'function') return null;
68
-
69
- const url = `${apiBase()}${apiPath()}/${encodeURIComponent(game.toLowerCase())}/${encodeURIComponent(type)}`;
70
- const controller = new AbortController();
71
- const timer = setTimeout(() => controller.abort(), timeoutMs());
72
-
73
- try {
74
- const res = await fetch(url, { signal: controller.signal });
75
- if (!res.ok) return null;
76
- const body = await res.json();
77
- if (!body || body.success === false) return null;
78
- const data = body.data !== undefined ? body.data : body;
79
- return Array.isArray(data) ? data : null;
80
- } catch (err) {
81
- return null;
82
- } finally {
83
- clearTimeout(timer);
84
- }
85
- }
86
-
87
- async function listLocal(game, type) {
88
- const dir = path.join(DATA_DIR, game.toLowerCase(), type);
89
- if (!fs.existsSync(dir)) return [];
90
-
91
- const files = (await fs.promises.readdir(dir)).filter((file) => file.endsWith('.json')).sort((a, b) => a.localeCompare(b));
92
- const items = [];
93
- for (const file of files) {
94
- const filePath = path.join(dir, file);
95
- const raw = await fs.promises.readFile(filePath, 'utf8');
96
- items.push(withLocalSlug(filePath, JSON.parse(raw)));
97
- }
98
- return items;
99
- }
100
-
101
- async function list(game, type) {
102
- if (!game || !type) {
103
- return { error: 'game and type are both required' };
104
- }
105
-
106
- const fromApi = await fetchListFromApi(game, type);
107
- if (fromApi) return fromApi;
108
-
109
- try {
110
- return await listLocal(game, type);
111
- } catch (err) {
112
- return { error: err.message };
113
- }
114
- }
115
-
116
- async function fetchGamesFromApi() {
117
- if (apiDisabled() || typeof fetch !== 'function') return null;
118
-
119
- const url = `${apiBase()}${apiPath()}`;
120
- const controller = new AbortController();
121
- const timer = setTimeout(() => controller.abort(), timeoutMs());
122
-
123
- try {
124
- const res = await fetch(url, { signal: controller.signal });
125
- if (!res.ok) return null;
126
- const body = await res.json();
127
- if (!body || body.success === false) return null;
128
- const data = body.data !== undefined ? body.data : body;
129
- return Array.isArray(data) ? data : null;
130
- } catch (err) {
131
- return null;
132
- } finally {
133
- clearTimeout(timer);
134
- }
135
- }
136
-
137
- async function listGamesLocal() {
138
- const entries = await fs.promises.readdir(DATA_DIR, { withFileTypes: true });
139
- const games = [];
140
- for (const entry of entries) {
141
- if (!entry.isDirectory() || entry.name.startsWith('.') || entry.name === 'game-codes') continue;
142
- const metaPath = path.join(DATA_DIR, entry.name, 'meta.json');
143
- if (!fs.existsSync(metaPath)) continue;
144
- const raw = await fs.promises.readFile(metaPath, 'utf8');
145
- games.push(JSON.parse(raw));
146
- }
147
- return games;
148
- }
149
-
150
- async function games() {
151
- const fromApi = await fetchGamesFromApi();
152
- if (fromApi) return fromApi;
153
-
154
- try {
155
- return await listGamesLocal();
156
- } catch (err) {
157
- return { error: err.message };
158
- }
159
- }
160
-
161
- async function load(game, type, name) {
162
- if (!game || !type || !name) {
163
- return { error: 'game, type, and name are all required' };
164
- }
165
-
166
- const fromApi = await fetchFromApi(game, type, name);
167
- if (fromApi) return fromApi;
168
-
169
- try {
170
- return await loadLocal(game, type, name);
171
- } catch (err) {
172
- return { error: err.message };
173
- }
174
- }
175
-
176
- async function loadGameMeta(game) {
177
- if (!game) return { error: 'game is required' };
178
-
179
- const fromApi = await fetchFromApi(game, 'meta', game);
180
- if (fromApi) return fromApi;
181
-
182
- try {
183
- const filePath = path.join(DATA_DIR, game.toLowerCase(), 'meta.json');
184
- if (!fs.existsSync(filePath)) {
185
- throw new Error(`meta info for game "${game}" not found`);
186
- }
187
-
188
- const raw = await fs.promises.readFile(filePath, 'utf8');
189
- return JSON.parse(raw);
190
- } catch (err) {
191
- return { error: err.message };
192
- }
193
- }
194
-
195
- async function cacheInfo() {
196
- try {
197
- const filePath = path.join(DATA_DIR, '.cache-manifest.json');
198
- if (!fs.existsSync(filePath)) return null;
199
- return JSON.parse(await fs.promises.readFile(filePath, 'utf8'));
200
- } catch (err) {
201
- return { error: err.message };
202
- }
203
- }
204
-
205
- module.exports = {
206
- Games: () => games(),
207
- Game: (game) => loadGameMeta(game),
208
- Worlds: (game, name) => load(game, 'worlds', name),
209
- Groups: (game, name) => load(game, 'groups', name),
210
- Players: (game, name) => load(game, 'players', name),
211
- Avatars: (game, name) => load(game, 'avatars', name),
212
- Characters: (game, name) => load(game, 'characters', name),
213
- Get: (game, type, name) => load(game, type, name),
214
- List: (game, type) => list(game, type),
215
- CacheInfo: () => cacheInfo(),
216
-
217
- // Game redeem/creator code API helpers. These also use live APINODE first and
218
- // automatically fall back to the daily mirrored data/game-codes snapshot.
219
- Codes: gameCodes.Codes,
220
- CodesStatus: gameCodes.CodesStatus,
221
- GameCodes: gameCodes.GameCodes,
222
- GameCode: gameCodes.GameCode,
223
- CodeCacheInfo: gameCodes.CodeCacheInfo
224
- };
4
+ module.exports = Object.freeze({ createClient, createWarframe, createVRChat, listProviders, providers });
package/package.json CHANGED
@@ -1,48 +1,55 @@
1
1
  {
2
- "name": "@nekosuneprojects/gaming-infos",
3
- "version": "2.2.0",
4
- "description": "Multi-game data loader for VRChat, character datasets, and game redeem/creator codes. Uses the NekoSuneVR V5 API first with automatically mirrored local JSON fallbacks.",
5
- "main": "index.js",
6
- "type": "commonjs",
7
- "engines": {
8
- "node": ">=18"
9
- },
10
- "scripts": {
11
- "sync:cache": "node scripts/sync-all-cache.js",
12
- "sync:gaming-infos-cache": "node scripts/sync-gaming-info-cache.js",
13
- "sync:game-codes-cache": "node scripts/sync-game-code-cache.js",
14
- "test:cache-sync": "node scripts/cache-sync-smoke.js",
15
- "test:game-code-cache": "node scripts/game-code-cache-smoke.js",
16
- "test:all-cache": "npm run test:cache-sync && npm run test:game-code-cache"
17
- },
18
- "repository": {
19
- "type": "git",
20
- "url": "https://github.com/NekoSuneProjects/gaming-infos.git"
21
- },
22
- "bugs": {
23
- "url": "https://github.com/NekoSuneProjects/gaming-infos/issues"
24
- },
25
- "funding": "https://github.com/NekoSuneProjects/gaming-infos?sponsor",
26
- "keywords": [
27
- "gaming",
28
- "infos",
29
- "game-codes",
30
- "redeem-codes",
31
- "creator-codes",
32
- "vrchat",
33
- "genshin-impact",
34
- "wuthering-waves",
35
- "warframe",
36
- "fortnite",
37
- "zenless-zone-zero",
38
- "tower-of-fantasy",
39
- "arknights-endfield",
40
- "worlds",
41
- "groups",
42
- "players",
43
- "avatars",
44
- "characters"
45
- ],
46
- "author": "NekoSuneVR",
47
- "license": "MIT"
2
+ "name": "@nekosuneprojects/gaming-infos",
3
+ "version": "3.0.1",
4
+ "description": "Modular multi-game information SDK using independently versioned Warframe and VRChat providers.",
5
+ "main": "index.js",
6
+ "type": "commonjs",
7
+ "engines": {
8
+ "node": ">=18"
9
+ },
10
+ "scripts": {
11
+ "test": "node --test",
12
+ "check": "node --check index.js && node --check src/registry.js && node --check src/providers/warframe.js && node --check src/providers/vrchat.js",
13
+ "prepack": "npm run check && npm test"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/NekoSuneProjectsNPM/gaming-infos.git"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/NekoSuneProjectsNPM/gaming-infos/issues"
21
+ },
22
+ "funding": "https://github.com/NekoSuneProjectsNPM/gaming-infos?sponsor",
23
+ "keywords": [
24
+ "gaming",
25
+ "game-data",
26
+ "modular",
27
+ "warframe",
28
+ "warframe-api",
29
+ "worldstate",
30
+ "redeem-codes",
31
+ "vrchat",
32
+ "vrchat-api",
33
+ "worlds",
34
+ "groups",
35
+ "avatars",
36
+ "avatar-search"
37
+ ],
38
+ "author": "NekoSuneVR",
39
+ "license": "MIT",
40
+ "dependencies": {
41
+ "@nekosuneprojects/warframe-api": "1.0.1",
42
+ "@nekosuneprojects/vrchat-api": "1.0.0"
43
+ },
44
+ "files": [
45
+ "index.js",
46
+ "src/",
47
+ "README.md",
48
+ "CHANGELOG.md",
49
+ "LICENSE"
50
+ ],
51
+ "publishConfig": {
52
+ "access": "public",
53
+ "registry": "https://registry.npmjs.org/"
54
+ }
48
55
  }
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+ const VRChat = require('@nekosuneprojects/vrchat-api');
3
+
4
+ function create(options = {}) {
5
+ if (!options || typeof options !== 'object' || Array.isArray(options)) {
6
+ throw new TypeError('VRChat options must be an object');
7
+ }
8
+ return VRChat(options);
9
+ }
10
+
11
+ module.exports = Object.freeze({ id: 'vrchat', create });
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+ const Warframe = require('@nekosuneprojects/warframe-api');
3
+ function create(options = {}) {
4
+ if (!options || typeof options !== 'object' || Array.isArray(options)) throw new TypeError('Warframe options must be an object');
5
+ return Warframe(options);
6
+ }
7
+ module.exports = Object.freeze({ id: 'warframe', create });
@@ -0,0 +1,23 @@
1
+ 'use strict';
2
+ const warframe = require('./providers/warframe');
3
+ const vrchat = require('./providers/vrchat');
4
+
5
+ const providers = Object.freeze({ warframe, vrchat });
6
+
7
+ function listProviders() { return Object.keys(providers); }
8
+
9
+ function createClient(game, options = {}) {
10
+ if (typeof game !== 'string' || !game.trim()) {
11
+ throw new TypeError('Game must be a non-empty string');
12
+ }
13
+ const key = game.trim().toLowerCase();
14
+ if (!Object.hasOwn(providers, key)) {
15
+ throw new RangeError(`Game provider not installed: ${game}`);
16
+ }
17
+ return providers[key].create(options);
18
+ }
19
+
20
+ function createWarframe(options = {}) { return createClient('warframe', options); }
21
+ function createVRChat(options = {}) { return createClient('vrchat', options); }
22
+
23
+ module.exports = { createClient, createWarframe, createVRChat, listProviders, providers };
@@ -1,56 +0,0 @@
1
- name: Node.js Package GitHub Mode
2
-
3
- on:
4
- release:
5
- types:
6
- - published
7
-
8
- permissions:
9
- contents: write
10
- issues: write
11
- pull-requests: write
12
- packages: write
13
-
14
- jobs:
15
- build:
16
- runs-on: ubuntu-latest
17
- steps:
18
- - name: Checkout repository
19
- uses: actions/checkout@v4
20
-
21
- - name: Setup Node.js
22
- uses: actions/setup-node@v4
23
- with:
24
- node-version: 24
25
-
26
- - name: Install dependencies
27
- run: npm ci
28
-
29
- publish-gpr:
30
- needs: build
31
- runs-on: ubuntu-latest
32
- steps:
33
- - name: Checkout repository
34
- uses: actions/checkout@v4
35
-
36
- - name: Setup Node.js for GitHub Packages
37
- uses: actions/setup-node@v4
38
- with:
39
- node-version: 24
40
- registry-url: https://npm.pkg.github.com/
41
-
42
- - name: Install dependencies
43
- run: npm ci
44
-
45
- # Read version from package.json
46
- - name: Read version from package.json
47
- id: read_version
48
- run: |
49
- VERSION=$(node -p "require('./package.json').version")
50
- echo "VERSION=$VERSION" >> $GITHUB_ENV
51
-
52
- # Publish package to GitHub Packages
53
- - name: Publish to GitHub Packages
54
- run: npm publish
55
- env:
56
- NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -1,71 +0,0 @@
1
- name: Node.js Package NPMJS
2
-
3
- on:
4
- release:
5
- types:
6
- - published
7
-
8
- permissions:
9
- contents: write
10
- issues: write
11
- pull-requests: write
12
- packages: write
13
-
14
- jobs:
15
- release:
16
- runs-on: ubuntu-latest
17
- steps:
18
- # Checkout project repository
19
- - name: Checkout
20
- uses: actions/checkout@v4
21
-
22
- # Setup Node.js environment
23
- - name: Setup Node.js
24
- uses: actions/setup-node@v4
25
- with:
26
- node-version: '24'
27
- registry-url: 'https://registry.npmjs.org/'
28
-
29
- # Read current package version
30
- - name: Read version from package.json
31
- id: read_version
32
- run: |
33
- VERSION=$(node -p "require('./package.json').version")
34
- echo "VERSION=$VERSION" >> $GITHUB_ENV
35
-
36
- # Publish version to npm
37
- - name: Publish to npm
38
- run: npm publish --access public
39
- env:
40
- NODE_AUTH_TOKEN: ${{ secrets.npm_token }}
41
-
42
- # Read the release notes from the already-versioned changelog.
43
- - id: get_changelog
44
- name: Get version changelog
45
- shell: bash
46
- run: |
47
- CHANGELOG=$(awk -v version="${VERSION}" '
48
- $0 ~ "^## \\[?" version "\\]?([[:space:]]+-|$)" { found=1; next }
49
- found && /^## / { exit }
50
- found { print }
51
- ' CHANGELOG.md)
52
-
53
- if [[ -z "${CHANGELOG}" ]]; then
54
- echo "No changelog section found for version ${VERSION}" >&2
55
- exit 1
56
- fi
57
-
58
- {
59
- echo 'changelog<<CHANGELOG_EOF'
60
- echo "${CHANGELOG}"
61
- echo 'CHANGELOG_EOF'
62
- } >> "${GITHUB_OUTPUT}"
63
-
64
- # Update GitHub release
65
- - name: Create or update GitHub Release
66
- uses: softprops/action-gh-release@v2
67
- with:
68
- tag_name: v${{ env.VERSION }}
69
- body: ${{ steps.get_changelog.outputs.changelog }}
70
- env:
71
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -1,72 +0,0 @@
1
- name: Sync APINODE fallback caches
2
-
3
- on:
4
- workflow_dispatch:
5
- schedule:
6
- # Daily at 03:23 UTC. GitHub Actions cron uses UTC.
7
- - cron: "23 3 * * *"
8
- push:
9
- branches:
10
- - main
11
- paths:
12
- - "scripts/sync-api-cache.js"
13
- - "scripts/sync-gaming-info-cache.js"
14
- - "scripts/sync-game-code-cache.js"
15
- - "scripts/sync-all-cache.js"
16
- - "scripts/cache-sync-smoke.js"
17
- - "scripts/game-code-cache-smoke.js"
18
- - "gamecodes.js"
19
- - "index.js"
20
- - "package.json"
21
- - "CACHE_SYNC.md"
22
- - ".github/workflows/sync-api-cache.yml"
23
-
24
- permissions:
25
- contents: write
26
-
27
- concurrency:
28
- group: gaming-infos-api-cache
29
- cancel-in-progress: false
30
-
31
- jobs:
32
- sync:
33
- runs-on: ubuntu-latest
34
- steps:
35
- - name: Checkout
36
- uses: actions/checkout@v4
37
- with:
38
- fetch-depth: 0
39
-
40
- - name: Use Node.js 22
41
- uses: actions/setup-node@v4
42
- with:
43
- node-version: 22
44
-
45
- - name: Test atomic cache behavior
46
- run: npm run test:all-cache
47
-
48
- - name: Mirror APINODE gaming-infos and game codes
49
- run: npm run sync:cache
50
- env:
51
- GAMING_INFOS_API_BASE: https://api.nekosunevr.co.uk
52
- GAMING_INFOS_API_PATH: /v5/games/api/gaming-infos
53
- GAME_CODES_API_PATH: /v5/games/api/codes
54
- GAMING_INFOS_CACHE_TIMEOUT_MS: 20000
55
- GAMING_INFOS_CACHE_RETRIES: 2
56
- GAME_CODES_CACHE_TIMEOUT_MS: 20000
57
- GAME_CODES_CACHE_RETRIES: 2
58
- GAME_CODES_CACHE_GAME_DELAY_MS: 150
59
-
60
- - name: Commit fallback changes
61
- shell: bash
62
- run: |
63
- git add -A data
64
- if git diff --cached --quiet; then
65
- echo "Fallback caches already match APINODE."
66
- exit 0
67
- fi
68
-
69
- git config user.name "github-actions[bot]"
70
- git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
71
- git commit -m "chore(cache): mirror APINODE fallback data [skip ci]"
72
- git push