@creeperhost/modlens-mcp 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (382) hide show
  1. package/README.md +938 -0
  2. package/dist/access-flags.d.ts +58 -0
  3. package/dist/access-flags.d.ts.map +1 -0
  4. package/dist/access-flags.js +79 -0
  5. package/dist/access-flags.js.map +1 -0
  6. package/dist/access-flags.test.d.ts +2 -0
  7. package/dist/access-flags.test.d.ts.map +1 -0
  8. package/dist/access-flags.test.js +189 -0
  9. package/dist/access-flags.test.js.map +1 -0
  10. package/dist/batch-ingest.d.ts +2 -0
  11. package/dist/batch-ingest.d.ts.map +1 -0
  12. package/dist/batch-ingest.js +54 -0
  13. package/dist/batch-ingest.js.map +1 -0
  14. package/dist/batch-resolve-mixins.d.ts +2 -0
  15. package/dist/batch-resolve-mixins.d.ts.map +1 -0
  16. package/dist/batch-resolve-mixins.js +36 -0
  17. package/dist/batch-resolve-mixins.js.map +1 -0
  18. package/dist/cache.d.ts +16 -0
  19. package/dist/cache.d.ts.map +1 -0
  20. package/dist/cache.js +36 -0
  21. package/dist/cache.js.map +1 -0
  22. package/dist/cli.d.ts +2 -0
  23. package/dist/cli.d.ts.map +1 -0
  24. package/dist/cli.js +1318 -0
  25. package/dist/cli.js.map +1 -0
  26. package/dist/curseforge.d.ts +53 -0
  27. package/dist/curseforge.d.ts.map +1 -0
  28. package/dist/curseforge.js +104 -0
  29. package/dist/curseforge.js.map +1 -0
  30. package/dist/db-backend.d.ts +17 -0
  31. package/dist/db-backend.d.ts.map +1 -0
  32. package/dist/db-backend.js +40 -0
  33. package/dist/db-backend.js.map +1 -0
  34. package/dist/db.d.ts +11 -0
  35. package/dist/db.d.ts.map +1 -0
  36. package/dist/db.js +55 -0
  37. package/dist/db.js.map +1 -0
  38. package/dist/embed-queue.d.ts +12 -0
  39. package/dist/embed-queue.d.ts.map +1 -0
  40. package/dist/embed-queue.js +103 -0
  41. package/dist/embed-queue.js.map +1 -0
  42. package/dist/embeddings.d.ts +21 -0
  43. package/dist/embeddings.d.ts.map +1 -0
  44. package/dist/embeddings.js +55 -0
  45. package/dist/embeddings.js.map +1 -0
  46. package/dist/env-path.d.ts +19 -0
  47. package/dist/env-path.d.ts.map +1 -0
  48. package/dist/env-path.js +40 -0
  49. package/dist/env-path.js.map +1 -0
  50. package/dist/fetch-utils.d.ts +24 -0
  51. package/dist/fetch-utils.d.ts.map +1 -0
  52. package/dist/fetch-utils.js +73 -0
  53. package/dist/fetch-utils.js.map +1 -0
  54. package/dist/fetch-utils.test.d.ts +2 -0
  55. package/dist/fetch-utils.test.d.ts.map +1 -0
  56. package/dist/fetch-utils.test.js +133 -0
  57. package/dist/fetch-utils.test.js.map +1 -0
  58. package/dist/generated/sqlite/browser.d.ts +55 -0
  59. package/dist/generated/sqlite/browser.d.ts.map +1 -0
  60. package/dist/generated/sqlite/browser.js +18 -0
  61. package/dist/generated/sqlite/browser.js.map +1 -0
  62. package/dist/generated/sqlite/client.d.ts +72 -0
  63. package/dist/generated/sqlite/client.d.ts.map +1 -0
  64. package/dist/generated/sqlite/client.js +33 -0
  65. package/dist/generated/sqlite/client.js.map +1 -0
  66. package/dist/generated/sqlite/commonInputTypes.d.ts +387 -0
  67. package/dist/generated/sqlite/commonInputTypes.d.ts.map +1 -0
  68. package/dist/generated/sqlite/commonInputTypes.js +11 -0
  69. package/dist/generated/sqlite/commonInputTypes.js.map +1 -0
  70. package/dist/generated/sqlite/enums.d.ts +2 -0
  71. package/dist/generated/sqlite/enums.d.ts.map +1 -0
  72. package/dist/generated/sqlite/enums.js +11 -0
  73. package/dist/generated/sqlite/enums.js.map +1 -0
  74. package/dist/generated/sqlite/internal/class.d.ts +226 -0
  75. package/dist/generated/sqlite/internal/class.d.ts.map +1 -0
  76. package/dist/generated/sqlite/internal/class.js +84 -0
  77. package/dist/generated/sqlite/internal/class.js.map +1 -0
  78. package/dist/generated/sqlite/internal/prismaNamespace.d.ts +1344 -0
  79. package/dist/generated/sqlite/internal/prismaNamespace.d.ts.map +1 -0
  80. package/dist/generated/sqlite/internal/prismaNamespace.js +220 -0
  81. package/dist/generated/sqlite/internal/prismaNamespace.js.map +1 -0
  82. package/dist/generated/sqlite/internal/prismaNamespaceBrowser.d.ts +204 -0
  83. package/dist/generated/sqlite/internal/prismaNamespaceBrowser.d.ts.map +1 -0
  84. package/dist/generated/sqlite/internal/prismaNamespaceBrowser.js +191 -0
  85. package/dist/generated/sqlite/internal/prismaNamespaceBrowser.js.map +1 -0
  86. package/dist/generated/sqlite/models/DocEntry.d.ts +1223 -0
  87. package/dist/generated/sqlite/models/DocEntry.d.ts.map +1 -0
  88. package/dist/generated/sqlite/models/DocEntry.js +2 -0
  89. package/dist/generated/sqlite/models/DocEntry.js.map +1 -0
  90. package/dist/generated/sqlite/models/McSourceFile.d.ts +1289 -0
  91. package/dist/generated/sqlite/models/McSourceFile.d.ts.map +1 -0
  92. package/dist/generated/sqlite/models/McSourceFile.js +2 -0
  93. package/dist/generated/sqlite/models/McSourceFile.js.map +1 -0
  94. package/dist/generated/sqlite/models/McVersion.d.ts +1315 -0
  95. package/dist/generated/sqlite/models/McVersion.d.ts.map +1 -0
  96. package/dist/generated/sqlite/models/McVersion.js +2 -0
  97. package/dist/generated/sqlite/models/McVersion.js.map +1 -0
  98. package/dist/generated/sqlite/models/McVersionDiff.d.ts +1061 -0
  99. package/dist/generated/sqlite/models/McVersionDiff.d.ts.map +1 -0
  100. package/dist/generated/sqlite/models/McVersionDiff.js +2 -0
  101. package/dist/generated/sqlite/models/McVersionDiff.js.map +1 -0
  102. package/dist/generated/sqlite/models/Mod.d.ts +2396 -0
  103. package/dist/generated/sqlite/models/Mod.d.ts.map +1 -0
  104. package/dist/generated/sqlite/models/Mod.js +2 -0
  105. package/dist/generated/sqlite/models/Mod.js.map +1 -0
  106. package/dist/generated/sqlite/models/ModClass.d.ts +1254 -0
  107. package/dist/generated/sqlite/models/ModClass.d.ts.map +1 -0
  108. package/dist/generated/sqlite/models/ModClass.js +2 -0
  109. package/dist/generated/sqlite/models/ModClass.js.map +1 -0
  110. package/dist/generated/sqlite/models/ModSourceFile.d.ts +1283 -0
  111. package/dist/generated/sqlite/models/ModSourceFile.d.ts.map +1 -0
  112. package/dist/generated/sqlite/models/ModSourceFile.js +2 -0
  113. package/dist/generated/sqlite/models/ModSourceFile.js.map +1 -0
  114. package/dist/generated/sqlite/models/ModTag.d.ts +1278 -0
  115. package/dist/generated/sqlite/models/ModTag.d.ts.map +1 -0
  116. package/dist/generated/sqlite/models/ModTag.js +2 -0
  117. package/dist/generated/sqlite/models/ModTag.js.map +1 -0
  118. package/dist/generated/sqlite/models/ModVersionDiff.d.ts +1073 -0
  119. package/dist/generated/sqlite/models/ModVersionDiff.d.ts.map +1 -0
  120. package/dist/generated/sqlite/models/ModVersionDiff.js +2 -0
  121. package/dist/generated/sqlite/models/ModVersionDiff.js.map +1 -0
  122. package/dist/generated/sqlite/models/Primer.d.ts +1319 -0
  123. package/dist/generated/sqlite/models/Primer.d.ts.map +1 -0
  124. package/dist/generated/sqlite/models/Primer.js +2 -0
  125. package/dist/generated/sqlite/models/Primer.js.map +1 -0
  126. package/dist/generated/sqlite/models.d.ts +12 -0
  127. package/dist/generated/sqlite/models.d.ts.map +1 -0
  128. package/dist/generated/sqlite/models.js +2 -0
  129. package/dist/generated/sqlite/models.js.map +1 -0
  130. package/dist/jar.d.ts +7 -0
  131. package/dist/jar.d.ts.map +1 -0
  132. package/dist/jar.js +52 -0
  133. package/dist/jar.js.map +1 -0
  134. package/dist/java-tools.d.ts +46 -0
  135. package/dist/java-tools.d.ts.map +1 -0
  136. package/dist/java-tools.js +263 -0
  137. package/dist/java-tools.js.map +1 -0
  138. package/dist/launcher.d.ts +3 -0
  139. package/dist/launcher.d.ts.map +1 -0
  140. package/dist/launcher.js +105 -0
  141. package/dist/launcher.js.map +1 -0
  142. package/dist/mappings.d.ts +95 -0
  143. package/dist/mappings.d.ts.map +1 -0
  144. package/dist/mappings.js +1094 -0
  145. package/dist/mappings.js.map +1 -0
  146. package/dist/mappings.test.d.ts +2 -0
  147. package/dist/mappings.test.d.ts.map +1 -0
  148. package/dist/mappings.test.js +161 -0
  149. package/dist/mappings.test.js.map +1 -0
  150. package/dist/minecraft.d.ts +21 -0
  151. package/dist/minecraft.d.ts.map +1 -0
  152. package/dist/minecraft.js +70 -0
  153. package/dist/minecraft.js.map +1 -0
  154. package/dist/modpacks-ch.d.ts +224 -0
  155. package/dist/modpacks-ch.d.ts.map +1 -0
  156. package/dist/modpacks-ch.js +146 -0
  157. package/dist/modpacks-ch.js.map +1 -0
  158. package/dist/modrinth.d.ts +67 -0
  159. package/dist/modrinth.d.ts.map +1 -0
  160. package/dist/modrinth.js +88 -0
  161. package/dist/modrinth.js.map +1 -0
  162. package/dist/platform-adapter.d.ts +23 -0
  163. package/dist/platform-adapter.d.ts.map +1 -0
  164. package/dist/platform-adapter.js +2 -0
  165. package/dist/platform-adapter.js.map +1 -0
  166. package/dist/platform.d.ts +47 -0
  167. package/dist/platform.d.ts.map +1 -0
  168. package/dist/platform.js +175 -0
  169. package/dist/platform.js.map +1 -0
  170. package/dist/processor.d.ts +51 -0
  171. package/dist/processor.d.ts.map +1 -0
  172. package/dist/processor.js +655 -0
  173. package/dist/processor.js.map +1 -0
  174. package/dist/processor.test.d.ts +2 -0
  175. package/dist/processor.test.d.ts.map +1 -0
  176. package/dist/processor.test.js +629 -0
  177. package/dist/processor.test.js.map +1 -0
  178. package/dist/repositories/embeddings-sqlite.d.ts +38 -0
  179. package/dist/repositories/embeddings-sqlite.d.ts.map +1 -0
  180. package/dist/repositories/embeddings-sqlite.js +208 -0
  181. package/dist/repositories/embeddings-sqlite.js.map +1 -0
  182. package/dist/repositories/embeddings.d.ts +40 -0
  183. package/dist/repositories/embeddings.d.ts.map +1 -0
  184. package/dist/repositories/embeddings.js +136 -0
  185. package/dist/repositories/embeddings.js.map +1 -0
  186. package/dist/repositories/index.d.ts +2 -0
  187. package/dist/repositories/index.d.ts.map +1 -0
  188. package/dist/repositories/index.js +15 -0
  189. package/dist/repositories/index.js.map +1 -0
  190. package/dist/repositories/mcVersion.d.ts +16 -0
  191. package/dist/repositories/mcVersion.d.ts.map +1 -0
  192. package/dist/repositories/mcVersion.js +52 -0
  193. package/dist/repositories/mcVersion.js.map +1 -0
  194. package/dist/repositories/mod.d.ts +241 -0
  195. package/dist/repositories/mod.d.ts.map +1 -0
  196. package/dist/repositories/mod.js +342 -0
  197. package/dist/repositories/mod.js.map +1 -0
  198. package/dist/repositories/packs.d.ts +44 -0
  199. package/dist/repositories/packs.d.ts.map +1 -0
  200. package/dist/repositories/packs.js +138 -0
  201. package/dist/repositories/packs.js.map +1 -0
  202. package/dist/search-adapter.d.ts +34 -0
  203. package/dist/search-adapter.d.ts.map +1 -0
  204. package/dist/search-adapter.js +195 -0
  205. package/dist/search-adapter.js.map +1 -0
  206. package/dist/search.d.ts +6 -0
  207. package/dist/search.d.ts.map +1 -0
  208. package/dist/search.js +54 -0
  209. package/dist/search.js.map +1 -0
  210. package/dist/search.test.d.ts +2 -0
  211. package/dist/search.test.d.ts.map +1 -0
  212. package/dist/search.test.js +71 -0
  213. package/dist/search.test.js.map +1 -0
  214. package/dist/security.d.ts +98 -0
  215. package/dist/security.d.ts.map +1 -0
  216. package/dist/security.js +446 -0
  217. package/dist/security.js.map +1 -0
  218. package/dist/security.test.d.ts +2 -0
  219. package/dist/security.test.d.ts.map +1 -0
  220. package/dist/security.test.js +687 -0
  221. package/dist/security.test.js.map +1 -0
  222. package/dist/server.d.ts +2 -0
  223. package/dist/server.d.ts.map +1 -0
  224. package/dist/server.js +1465 -0
  225. package/dist/server.js.map +1 -0
  226. package/dist/setup.d.ts +2 -0
  227. package/dist/setup.d.ts.map +1 -0
  228. package/dist/setup.js +1113 -0
  229. package/dist/setup.js.map +1 -0
  230. package/dist/tools/bytecode.d.ts +129 -0
  231. package/dist/tools/bytecode.d.ts.map +1 -0
  232. package/dist/tools/bytecode.js +679 -0
  233. package/dist/tools/bytecode.js.map +1 -0
  234. package/dist/tools/catalog.d.ts +54 -0
  235. package/dist/tools/catalog.d.ts.map +1 -0
  236. package/dist/tools/catalog.js +249 -0
  237. package/dist/tools/catalog.js.map +1 -0
  238. package/dist/tools/compat-check.d.ts +23 -0
  239. package/dist/tools/compat-check.d.ts.map +1 -0
  240. package/dist/tools/compat-check.js +250 -0
  241. package/dist/tools/compat-check.js.map +1 -0
  242. package/dist/tools/compat-check.test.d.ts +2 -0
  243. package/dist/tools/compat-check.test.d.ts.map +1 -0
  244. package/dist/tools/compat-check.test.js +179 -0
  245. package/dist/tools/compat-check.test.js.map +1 -0
  246. package/dist/tools/diagnostics.d.ts +10 -0
  247. package/dist/tools/diagnostics.d.ts.map +1 -0
  248. package/dist/tools/diagnostics.js +133 -0
  249. package/dist/tools/diagnostics.js.map +1 -0
  250. package/dist/tools/diagnostics.test.d.ts +2 -0
  251. package/dist/tools/diagnostics.test.d.ts.map +1 -0
  252. package/dist/tools/diagnostics.test.js +168 -0
  253. package/dist/tools/diagnostics.test.js.map +1 -0
  254. package/dist/tools/docs.d.ts +19 -0
  255. package/dist/tools/docs.d.ts.map +1 -0
  256. package/dist/tools/docs.js +230 -0
  257. package/dist/tools/docs.js.map +1 -0
  258. package/dist/tools/embed-registry.d.ts +125 -0
  259. package/dist/tools/embed-registry.d.ts.map +1 -0
  260. package/dist/tools/embed-registry.js +560 -0
  261. package/dist/tools/embed-registry.js.map +1 -0
  262. package/dist/tools/gradle.d.ts +16 -0
  263. package/dist/tools/gradle.d.ts.map +1 -0
  264. package/dist/tools/gradle.js +182 -0
  265. package/dist/tools/gradle.js.map +1 -0
  266. package/dist/tools/graphify.d.ts +144 -0
  267. package/dist/tools/graphify.d.ts.map +1 -0
  268. package/dist/tools/graphify.js +798 -0
  269. package/dist/tools/graphify.js.map +1 -0
  270. package/dist/tools/graphify.test.d.ts +2 -0
  271. package/dist/tools/graphify.test.d.ts.map +1 -0
  272. package/dist/tools/graphify.test.js +39 -0
  273. package/dist/tools/graphify.test.js.map +1 -0
  274. package/dist/tools/ingest.d.ts +85 -0
  275. package/dist/tools/ingest.d.ts.map +1 -0
  276. package/dist/tools/ingest.js +477 -0
  277. package/dist/tools/ingest.js.map +1 -0
  278. package/dist/tools/ingest.test.d.ts +2 -0
  279. package/dist/tools/ingest.test.d.ts.map +1 -0
  280. package/dist/tools/ingest.test.js +340 -0
  281. package/dist/tools/ingest.test.js.map +1 -0
  282. package/dist/tools/kubejs.d.ts +37 -0
  283. package/dist/tools/kubejs.d.ts.map +1 -0
  284. package/dist/tools/kubejs.js +245 -0
  285. package/dist/tools/kubejs.js.map +1 -0
  286. package/dist/tools/mappings.d.ts +17 -0
  287. package/dist/tools/mappings.d.ts.map +1 -0
  288. package/dist/tools/mappings.js +85 -0
  289. package/dist/tools/mappings.js.map +1 -0
  290. package/dist/tools/mc-fts.d.ts +101 -0
  291. package/dist/tools/mc-fts.d.ts.map +1 -0
  292. package/dist/tools/mc-fts.js +279 -0
  293. package/dist/tools/mc-fts.js.map +1 -0
  294. package/dist/tools/mcmeta.d.ts +41 -0
  295. package/dist/tools/mcmeta.d.ts.map +1 -0
  296. package/dist/tools/mcmeta.js +365 -0
  297. package/dist/tools/mcmeta.js.map +1 -0
  298. package/dist/tools/mixin-scan.d.ts +113 -0
  299. package/dist/tools/mixin-scan.d.ts.map +1 -0
  300. package/dist/tools/mixin-scan.js +433 -0
  301. package/dist/tools/mixin-scan.js.map +1 -0
  302. package/dist/tools/mod-data.d.ts +83 -0
  303. package/dist/tools/mod-data.d.ts.map +1 -0
  304. package/dist/tools/mod-data.js +630 -0
  305. package/dist/tools/mod-data.js.map +1 -0
  306. package/dist/tools/mod-tags.d.ts +59 -0
  307. package/dist/tools/mod-tags.d.ts.map +1 -0
  308. package/dist/tools/mod-tags.js +279 -0
  309. package/dist/tools/mod-tags.js.map +1 -0
  310. package/dist/tools/mod-tags.test.d.ts +2 -0
  311. package/dist/tools/mod-tags.test.d.ts.map +1 -0
  312. package/dist/tools/mod-tags.test.js +75 -0
  313. package/dist/tools/mod-tags.test.js.map +1 -0
  314. package/dist/tools/modpacks-ch.d.ts +257 -0
  315. package/dist/tools/modpacks-ch.d.ts.map +1 -0
  316. package/dist/tools/modpacks-ch.js +516 -0
  317. package/dist/tools/modpacks-ch.js.map +1 -0
  318. package/dist/tools/packtools.d.ts +113 -0
  319. package/dist/tools/packtools.d.ts.map +1 -0
  320. package/dist/tools/packtools.js +809 -0
  321. package/dist/tools/packtools.js.map +1 -0
  322. package/dist/tools/packtools.test.d.ts +2 -0
  323. package/dist/tools/packtools.test.d.ts.map +1 -0
  324. package/dist/tools/packtools.test.js +99 -0
  325. package/dist/tools/packtools.test.js.map +1 -0
  326. package/dist/tools/platform.d.ts +68 -0
  327. package/dist/tools/platform.d.ts.map +1 -0
  328. package/dist/tools/platform.js +452 -0
  329. package/dist/tools/platform.js.map +1 -0
  330. package/dist/tools/primers.d.ts +36 -0
  331. package/dist/tools/primers.d.ts.map +1 -0
  332. package/dist/tools/primers.js +451 -0
  333. package/dist/tools/primers.js.map +1 -0
  334. package/dist/tools/reports.d.ts +19 -0
  335. package/dist/tools/reports.d.ts.map +1 -0
  336. package/dist/tools/reports.js +573 -0
  337. package/dist/tools/reports.js.map +1 -0
  338. package/dist/tools/source.d.ts +10 -0
  339. package/dist/tools/source.d.ts.map +1 -0
  340. package/dist/tools/source.js +101 -0
  341. package/dist/tools/source.js.map +1 -0
  342. package/dist/tools/vanilla-data.d.ts +127 -0
  343. package/dist/tools/vanilla-data.d.ts.map +1 -0
  344. package/dist/tools/vanilla-data.js +824 -0
  345. package/dist/tools/vanilla-data.js.map +1 -0
  346. package/dist/tools/vanilla.d.ts +171 -0
  347. package/dist/tools/vanilla.d.ts.map +1 -0
  348. package/dist/tools/vanilla.js +612 -0
  349. package/dist/tools/vanilla.js.map +1 -0
  350. package/dist/tools/version-diff.d.ts +113 -0
  351. package/dist/tools/version-diff.d.ts.map +1 -0
  352. package/dist/tools/version-diff.js +519 -0
  353. package/dist/tools/version-diff.js.map +1 -0
  354. package/dist/tools/version-diff.test.d.ts +2 -0
  355. package/dist/tools/version-diff.test.d.ts.map +1 -0
  356. package/dist/tools/version-diff.test.js +102 -0
  357. package/dist/tools/version-diff.test.js.map +1 -0
  358. package/dist/validate.d.ts +19 -0
  359. package/dist/validate.d.ts.map +1 -0
  360. package/dist/validate.js +54 -0
  361. package/dist/validate.js.map +1 -0
  362. package/dist/validate.test.d.ts +2 -0
  363. package/dist/validate.test.d.ts.map +1 -0
  364. package/dist/validate.test.js +73 -0
  365. package/dist/validate.test.js.map +1 -0
  366. package/package.json +62 -0
  367. package/prisma/backends/schema.sqlite.prisma +215 -0
  368. package/prisma/backends/template.db +0 -0
  369. package/prisma/schema.prisma +303 -0
  370. package/scripts/backup.mjs +151 -0
  371. package/scripts/build-template-db.mjs +38 -0
  372. package/scripts/check-atm10.mjs +27 -0
  373. package/scripts/check-sync.mjs +13 -0
  374. package/scripts/create-fts-index.mjs +50 -0
  375. package/scripts/enable-pgvector.mjs +90 -0
  376. package/scripts/enable-sqlite-vec.mjs +158 -0
  377. package/scripts/migrate-backend.mjs +188 -0
  378. package/scripts/migrate-embed-provenance.mjs +80 -0
  379. package/scripts/migrate-metadata-source.mjs +62 -0
  380. package/scripts/migrate-mod-source-files.mjs +67 -0
  381. package/scripts/post-update.mjs +77 -0
  382. package/scripts/verify-atm10.mjs +63 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processor.d.ts","sourceRoot":"","sources":["../src/processor.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,SAAS,CAAC;AAM7B,MAAM,MAAM,cAAc,GAAG,iBAAiB,GAAG,gBAAgB,GAAG,WAAW,GAAG,YAAY,GAAG,iBAAiB,GAAG,UAAU,CAAC;AAEhI,qGAAqG;AACrG,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAO3D,CAAC;AAEF,MAAM,WAAW,cAAc;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAC;KAAE,CAAC,CAAC;IACzE,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,EAAE,cAAc,CAAC;CAClC;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CA2GvE;AA4MD,UAAU,wBAAwB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAqBtF;AAED,sEAAsE;AACtE,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAuEvF;AA4ID,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAKxD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAKxD;AAeD,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;CAAE,CAAC,CAMlH;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyBnD"}
@@ -0,0 +1,655 @@
1
+ import AdmZip from "adm-zip";
2
+ import { createHash } from "crypto";
3
+ import { readFile } from "fs/promises";
4
+ import { parse as parseToml } from "smol-toml";
5
+ import { assertJarPath } from "./security.js";
6
+ /** Higher = better quality metadata. Used to decide whether re-parse upgrades an existing record. */
7
+ export const METADATA_QUALITY = {
8
+ "filename": 0,
9
+ "@Mod annotation": 1,
10
+ "mcmod.info": 2,
11
+ "mods.toml": 3,
12
+ "quilt.mod.json": 3,
13
+ "fabric.mod.json": 3,
14
+ };
15
+ export async function parseJar(jarPath) {
16
+ assertJarPath(jarPath);
17
+ const zip = new AdmZip(jarPath);
18
+ const entries = zip.getEntries().map((e) => e.entryName);
19
+ const readEntry = (name) => {
20
+ const e = zip.getEntry(name);
21
+ return e ? zip.readFile(e)?.toString("utf8") ?? null : null;
22
+ };
23
+ // Detect loader
24
+ const fabricJson = readEntry("fabric.mod.json");
25
+ const quiltJson = readEntry("quilt.mod.json");
26
+ const neoforgeToml = readEntry("META-INF/neoforge.mods.toml");
27
+ const forgeToml = readEntry("META-INF/mods.toml");
28
+ let manifest;
29
+ if (fabricJson) {
30
+ manifest = parseFabric(fabricJson, entries);
31
+ }
32
+ else if (quiltJson) {
33
+ manifest = parseQuilt(quiltJson, entries);
34
+ }
35
+ else if (neoforgeToml) {
36
+ manifest = parseNeoForge(neoforgeToml, entries);
37
+ }
38
+ else if (forgeToml) {
39
+ manifest = parseForge(forgeToml, entries);
40
+ }
41
+ else {
42
+ // Legacy Forge (1.7.10–1.12.2) uses mcmod.info at the JAR root
43
+ const mcmodInfoRaw = readEntry("mcmod.info");
44
+ if (mcmodInfoRaw) {
45
+ manifest = parseMcModInfo(mcmodInfoRaw, entries);
46
+ }
47
+ else {
48
+ // Pre-mcmod.info era (1.2.5–1.6) — try @Mod annotation from bytecode
49
+ let modAnnotation = null;
50
+ try {
51
+ modAnnotation = extractForgeModAnnotation(zip);
52
+ }
53
+ catch {
54
+ // Malformed class files (obfuscators, Kotlin metadata, etc.) — degrade gracefully
55
+ }
56
+ if (modAnnotation) {
57
+ const mixinConfigs = entries.filter((e) => e.endsWith(".mixins.json"));
58
+ manifest = {
59
+ modId: modAnnotation.modId,
60
+ displayName: modAnnotation.name,
61
+ version: modAnnotation.version,
62
+ mcVersion: "",
63
+ loader: "forge",
64
+ description: "",
65
+ sourceUrl: null,
66
+ dependencies: [],
67
+ mixinConfigs,
68
+ hasMixins: mixinConfigs.length > 0,
69
+ hasAt: entries.includes("META-INF/accesstransformer.cfg"),
70
+ hasAw: false,
71
+ atEntries: [],
72
+ awEntries: [],
73
+ mixinTargets: [],
74
+ metadataSource: "@Mod annotation",
75
+ };
76
+ }
77
+ else {
78
+ manifest = unknownMod(jarPath);
79
+ }
80
+ }
81
+ }
82
+ // AT entries
83
+ const atContent = readEntry("META-INF/accesstransformer.cfg");
84
+ if (atContent) {
85
+ manifest.hasAt = true;
86
+ manifest.atEntries = parseAtEntries(atContent);
87
+ }
88
+ // AW entries — scan all entries for *.accesswidener
89
+ const awEntry = entries.find((e) => e.endsWith(".accesswidener"));
90
+ if (awEntry) {
91
+ const awContent = readEntry(awEntry);
92
+ if (awContent) {
93
+ manifest.hasAw = true;
94
+ manifest.awEntries = parseAwEntries(awContent);
95
+ }
96
+ }
97
+ // Mixin targets — scan *.mixins.json configs
98
+ for (const cfg of manifest.mixinConfigs) {
99
+ const cfgContent = readEntry(cfg);
100
+ if (!cfgContent)
101
+ continue;
102
+ try {
103
+ const json = JSON.parse(cfgContent);
104
+ const pkg = json.package ? json.package + "." : "";
105
+ const allMixins = [
106
+ ...(json.mixins ?? []),
107
+ ...(json.client ?? []),
108
+ ...(json.server ?? []),
109
+ ];
110
+ // We store the config class names; actual targets resolved after decompile
111
+ manifest.mixinTargets.push(...allMixins.map((m) => pkg + m));
112
+ }
113
+ catch {
114
+ // malformed JSON — skip
115
+ }
116
+ }
117
+ return manifest;
118
+ }
119
+ function parseFabric(raw, entries) {
120
+ let json;
121
+ try {
122
+ json = JSON.parse(raw);
123
+ }
124
+ catch {
125
+ json = {};
126
+ }
127
+ const mixinConfigs = entries.filter((e) => e.endsWith(".mixins.json"));
128
+ const deps = [];
129
+ const rawDeps = (json.depends ?? {});
130
+ for (const [id, ver] of Object.entries(rawDeps)) {
131
+ deps.push({ id, version: ver, required: true });
132
+ }
133
+ return {
134
+ modId: String(json.id ?? "unknown"),
135
+ displayName: String(json.name ?? json.id ?? "unknown"),
136
+ version: String(json.version ?? "0.0.0"),
137
+ mcVersion: extractFabricMcVersion(rawDeps),
138
+ loader: "fabric",
139
+ description: String(json.description ?? ""),
140
+ sourceUrl: extractString(json, "contact", "sources") ?? extractString(json, "contact", "source"),
141
+ dependencies: deps,
142
+ mixinConfigs,
143
+ hasMixins: mixinConfigs.length > 0,
144
+ hasAt: false,
145
+ hasAw: false,
146
+ atEntries: [],
147
+ awEntries: [],
148
+ mixinTargets: [],
149
+ metadataSource: "fabric.mod.json",
150
+ };
151
+ }
152
+ function parseQuilt(raw, entries) {
153
+ let json;
154
+ try {
155
+ json = JSON.parse(raw);
156
+ }
157
+ catch {
158
+ json = {};
159
+ }
160
+ const ql = (json.quilt_loader ?? {});
161
+ const mixinConfigs = entries.filter((e) => e.endsWith(".mixins.json"));
162
+ return {
163
+ modId: String(ql.id ?? "unknown"),
164
+ displayName: String(ql.metadata?.name ?? ql.id ?? "unknown"),
165
+ version: String(ql.version ?? "0.0.0"),
166
+ mcVersion: "",
167
+ loader: "quilt",
168
+ description: "",
169
+ sourceUrl: null,
170
+ dependencies: [],
171
+ mixinConfigs,
172
+ hasMixins: mixinConfigs.length > 0,
173
+ hasAt: false,
174
+ hasAw: false,
175
+ atEntries: [],
176
+ awEntries: [],
177
+ mixinTargets: [],
178
+ metadataSource: "quilt.mod.json",
179
+ };
180
+ }
181
+ function parseNeoForge(raw, entries) {
182
+ return parseForgeToml(raw, "neoforge", entries);
183
+ }
184
+ function parseForge(raw, entries) {
185
+ return parseForgeToml(raw, "forge", entries);
186
+ }
187
+ function parseForgeToml(raw, loader, entries) {
188
+ let doc;
189
+ try {
190
+ doc = parseToml(raw);
191
+ }
192
+ catch {
193
+ doc = {};
194
+ }
195
+ const str = (v, fallback = "") => (typeof v === "string" ? v : fallback);
196
+ // [[mods]] array — first entry holds the primary mod info
197
+ const mods = Array.isArray(doc.mods) ? doc.mods : [];
198
+ const mod = mods[0] ?? {};
199
+ const modId = str(mod.modId, "unknown");
200
+ const version = str(mod.version, "0.0.0");
201
+ const displayName = str(mod.displayName, modId);
202
+ const description = str(mod.description);
203
+ const displayUrl = str(mod.displayURL);
204
+ const issueUrl = str(mod.issueTrackerURL);
205
+ const ghMatch = raw.match(/https:\/\/github\.com\/[^\s"']+/);
206
+ const sourceUrl = displayUrl || issueUrl || (ghMatch ? ghMatch[0] : null);
207
+ // [[dependencies.<modId>]] — flatten all dep arrays, find minecraft range
208
+ const depsTable = (typeof doc.dependencies === "object" && doc.dependencies !== null)
209
+ ? doc.dependencies
210
+ : {};
211
+ const allDepObjs = [];
212
+ for (const v of Object.values(depsTable)) {
213
+ if (Array.isArray(v))
214
+ allDepObjs.push(...v);
215
+ }
216
+ const mcDepEntry = allDepObjs.find((d) => str(d.modId) === "minecraft");
217
+ const mcVersion = str(mcDepEntry?.versionRange);
218
+ const dependencies = allDepObjs
219
+ .filter((d) => {
220
+ const id = str(d.modId);
221
+ return id && id !== "minecraft" && id !== "neoforge" && id !== "forge";
222
+ })
223
+ .map((d) => ({
224
+ id: str(d.modId),
225
+ version: str(d.versionRange, "*"),
226
+ required: d.mandatory !== false,
227
+ }));
228
+ const mixinConfigs = entries.filter((e) => e.endsWith(".mixins.json"));
229
+ return {
230
+ modId,
231
+ displayName,
232
+ version,
233
+ mcVersion,
234
+ loader,
235
+ description,
236
+ sourceUrl,
237
+ dependencies,
238
+ mixinConfigs,
239
+ hasMixins: mixinConfigs.length > 0,
240
+ hasAt: entries.includes("META-INF/accesstransformer.cfg"),
241
+ hasAw: false,
242
+ atEntries: [],
243
+ awEntries: [],
244
+ mixinTargets: [],
245
+ metadataSource: "mods.toml",
246
+ };
247
+ }
248
+ function parseMcModInfo(raw, entries) {
249
+ let modList;
250
+ try {
251
+ const parsed = JSON.parse(raw);
252
+ if (Array.isArray(parsed)) {
253
+ modList = parsed;
254
+ }
255
+ else if (parsed?.modList && Array.isArray(parsed.modList)) {
256
+ modList = parsed.modList;
257
+ }
258
+ else if (parsed?.modid || parsed?.modId) {
259
+ // Bare object format (some 1.6-era mods)
260
+ modList = [parsed];
261
+ }
262
+ else {
263
+ modList = [];
264
+ }
265
+ }
266
+ catch {
267
+ return unknownMod("mcmod.info");
268
+ }
269
+ const mod = modList[0];
270
+ if (!mod)
271
+ return unknownMod("mcmod.info");
272
+ const str = (v, fallback = "") => (typeof v === "string" ? v : fallback);
273
+ const modId = str(mod.modid ?? mod.modId, "unknown");
274
+ const mixinConfigs = entries.filter((e) => e.endsWith(".mixins.json"));
275
+ // Dependencies — handle multiple legacy formats
276
+ const rawDeps = Array.isArray(mod.dependencies) ? mod.dependencies : [];
277
+ const rawRequired = Array.isArray(mod.requiredMods) ? mod.requiredMods : [];
278
+ const allDeps = [...rawDeps, ...rawRequired];
279
+ const dependencies = allDeps
280
+ .filter((d) => typeof d === "string")
281
+ .filter((d) => d !== "Forge" && d !== "forge" && d !== "FML" && d !== "mcp" && d !== "minecraft")
282
+ // Strip version ranges from dependency strings like "required-after:SomeLib@[1.0,)"
283
+ .map((d) => {
284
+ const depMatch = d.match(/^(?:required-after|after|required-before|before|required):?\s*([^@\s;]+)/i);
285
+ return depMatch ? depMatch[1] : d;
286
+ })
287
+ .filter((d) => d !== "Forge" && d !== "forge" && d !== "FML")
288
+ .map((d) => ({ id: d, version: "*", required: true }));
289
+ return {
290
+ modId,
291
+ displayName: str(mod.name, modId),
292
+ version: str(mod.version, "0.0.0"),
293
+ mcVersion: str(mod.mcversion),
294
+ loader: "forge",
295
+ description: str(mod.description),
296
+ sourceUrl: str(mod.url) || null,
297
+ dependencies,
298
+ mixinConfigs,
299
+ hasMixins: mixinConfigs.length > 0,
300
+ hasAt: entries.includes("META-INF/accesstransformer.cfg"),
301
+ hasAw: false,
302
+ atEntries: [],
303
+ awEntries: [],
304
+ mixinTargets: [],
305
+ metadataSource: "mcmod.info",
306
+ };
307
+ }
308
+ // ── @Mod annotation extraction from bytecode ──────────────────────────────────
309
+ const FORGE_MOD_DESCRIPTORS = new Set([
310
+ "Lcpw/mods/fml/common/Mod;", // Forge 1.7.10 and earlier
311
+ "Lnet/minecraftforge/fml/common/Mod;", // Forge 1.8–1.12.2
312
+ ]);
313
+ /**
314
+ * Scan class entries in a JAR for the Forge @Mod annotation.
315
+ * Parses the constant pool and RuntimeVisibleAnnotations attribute
316
+ * to extract modid/name/version without requiring javap.
317
+ */
318
+ export function extractForgeModAnnotation(zip) {
319
+ for (const entry of zip.getEntries()) {
320
+ if (!entry.entryName.endsWith(".class"))
321
+ continue;
322
+ // Skip inner classes — main mod class is almost never an inner class
323
+ if (entry.entryName.includes("$"))
324
+ continue;
325
+ // Depth heuristic: @Mod entry points live in the first few package levels.
326
+ // Skip classes nested more than 3 directories deep to avoid scanning
327
+ // hundreds of utility/mixin classes in large mods.
328
+ const slashes = entry.entryName.split("/").length - 1;
329
+ if (slashes > 4)
330
+ continue;
331
+ const buf = zip.readFile(entry);
332
+ if (!buf || buf.length < 10)
333
+ continue;
334
+ try {
335
+ const result = parseClassForModAnnotation(buf);
336
+ if (result)
337
+ return result;
338
+ }
339
+ catch {
340
+ // Malformed class file (obfuscator artifacts, Kotlin metadata, etc.) — skip it
341
+ continue;
342
+ }
343
+ }
344
+ return null;
345
+ }
346
+ /** Parse a single .class file's bytes for a Forge @Mod annotation. */
347
+ export function parseClassForModAnnotation(buf) {
348
+ if (buf.readUInt32BE(0) !== 0xCAFEBABE)
349
+ return null;
350
+ // ── Parse constant pool ──
351
+ let offset = 8; // skip magic(4) + minor(2) + major(2)
352
+ const cpCount = buf.readUInt16BE(offset);
353
+ offset += 2;
354
+ const cpUtf8 = new Map();
355
+ let hasModDescriptor = false;
356
+ for (let i = 1; i < cpCount; i++) {
357
+ if (offset >= buf.length)
358
+ return null;
359
+ const tag = buf[offset++];
360
+ switch (tag) {
361
+ case 1: { // CONSTANT_Utf8
362
+ if (offset + 2 > buf.length)
363
+ return null;
364
+ const len = buf.readUInt16BE(offset);
365
+ offset += 2;
366
+ if (offset + len > buf.length)
367
+ return null;
368
+ const str = buf.toString("utf8", offset, offset + len);
369
+ cpUtf8.set(i, str);
370
+ if (FORGE_MOD_DESCRIPTORS.has(str))
371
+ hasModDescriptor = true;
372
+ offset += len;
373
+ break;
374
+ }
375
+ case 3:
376
+ case 4:
377
+ offset += 4;
378
+ break; // Integer, Float
379
+ case 5:
380
+ case 6:
381
+ offset += 8;
382
+ i++;
383
+ break; // Long, Double (2 slots)
384
+ case 7:
385
+ case 8:
386
+ case 16:
387
+ case 19:
388
+ case 20: // Class, String, MethodType, Module, Package
389
+ offset += 2;
390
+ break;
391
+ case 9:
392
+ case 10:
393
+ case 11:
394
+ case 12:
395
+ case 17:
396
+ case 18: // refs + Dynamic
397
+ offset += 4;
398
+ break;
399
+ case 15:
400
+ offset += 3;
401
+ break; // MethodHandle
402
+ default: return null; // unknown tag — bail
403
+ }
404
+ }
405
+ if (!hasModDescriptor)
406
+ return null;
407
+ // ── Skip class header: access_flags, this_class, super_class, interfaces ──
408
+ if (offset + 8 > buf.length)
409
+ return null;
410
+ offset += 6; // access_flags(2) + this_class(2) + super_class(2)
411
+ const interfaceCount = buf.readUInt16BE(offset);
412
+ offset += 2 + interfaceCount * 2;
413
+ // ── Skip fields ──
414
+ offset = skipClassMembers(buf, offset);
415
+ if (offset < 0)
416
+ return null;
417
+ // ── Skip methods ──
418
+ offset = skipClassMembers(buf, offset);
419
+ if (offset < 0)
420
+ return null;
421
+ // ── Parse class-level attributes for RuntimeVisibleAnnotations ──
422
+ if (offset + 2 > buf.length)
423
+ return null;
424
+ const attrCount = buf.readUInt16BE(offset);
425
+ offset += 2;
426
+ for (let a = 0; a < attrCount; a++) {
427
+ if (offset + 6 > buf.length)
428
+ return null;
429
+ const nameIdx = buf.readUInt16BE(offset);
430
+ const attrLen = buf.readUInt32BE(offset + 2);
431
+ offset += 6;
432
+ if (cpUtf8.get(nameIdx) === "RuntimeVisibleAnnotations") {
433
+ const result = parseModAnnotationAttr(buf, offset, cpUtf8);
434
+ if (result)
435
+ return result;
436
+ }
437
+ offset += attrLen;
438
+ }
439
+ return null;
440
+ }
441
+ function skipClassMembers(buf, offset) {
442
+ if (offset + 2 > buf.length)
443
+ return -1;
444
+ const count = buf.readUInt16BE(offset);
445
+ offset += 2;
446
+ for (let i = 0; i < count; i++) {
447
+ if (offset + 8 > buf.length)
448
+ return -1;
449
+ offset += 6; // access_flags(2) + name_index(2) + descriptor_index(2)
450
+ const attrCount = buf.readUInt16BE(offset);
451
+ offset += 2;
452
+ for (let a = 0; a < attrCount; a++) {
453
+ if (offset + 6 > buf.length)
454
+ return -1;
455
+ const attrLen = buf.readUInt32BE(offset + 2);
456
+ offset += 6 + attrLen;
457
+ }
458
+ }
459
+ return offset;
460
+ }
461
+ function parseModAnnotationAttr(buf, start, cpUtf8) {
462
+ if (start + 2 > buf.length)
463
+ return null;
464
+ let offset = start;
465
+ const numAnnotations = buf.readUInt16BE(offset);
466
+ offset += 2;
467
+ for (let a = 0; a < numAnnotations; a++) {
468
+ if (offset + 4 > buf.length)
469
+ return null;
470
+ const typeIdx = buf.readUInt16BE(offset);
471
+ offset += 2;
472
+ const numPairs = buf.readUInt16BE(offset);
473
+ offset += 2;
474
+ const typeStr = cpUtf8.get(typeIdx) ?? "";
475
+ if (FORGE_MOD_DESCRIPTORS.has(typeStr)) {
476
+ // Extract element-value pairs
477
+ const values = {};
478
+ for (let p = 0; p < numPairs; p++) {
479
+ if (offset + 3 > buf.length)
480
+ return null;
481
+ const nameIdx = buf.readUInt16BE(offset);
482
+ offset += 2;
483
+ const elementName = cpUtf8.get(nameIdx) ?? "";
484
+ const ev = readAnnotationElementValue(buf, offset, cpUtf8);
485
+ if (ev.offset < 0)
486
+ return null;
487
+ offset = ev.offset;
488
+ if (ev.stringValue !== null)
489
+ values[elementName] = ev.stringValue;
490
+ }
491
+ const modId = values["modid"] ?? values["value"] ?? "";
492
+ if (modId) {
493
+ return {
494
+ modId,
495
+ name: values["name"] ?? modId,
496
+ version: values["version"] ?? "0.0.0",
497
+ };
498
+ }
499
+ }
500
+ else {
501
+ // Skip non-@Mod annotation pairs
502
+ for (let p = 0; p < numPairs; p++) {
503
+ if (offset + 3 > buf.length)
504
+ return null;
505
+ offset += 2; // element_name_index
506
+ const ev = readAnnotationElementValue(buf, offset, cpUtf8);
507
+ if (ev.offset < 0)
508
+ return null;
509
+ offset = ev.offset;
510
+ }
511
+ }
512
+ }
513
+ return null;
514
+ }
515
+ function readAnnotationElementValue(buf, offset, cpUtf8) {
516
+ if (offset >= buf.length)
517
+ return { offset: -1, stringValue: null };
518
+ const tag = buf[offset++];
519
+ switch (tag) {
520
+ case 0x73: { // 's' — String constant
521
+ if (offset + 2 > buf.length)
522
+ return { offset: -1, stringValue: null };
523
+ const idx = buf.readUInt16BE(offset);
524
+ return { offset: offset + 2, stringValue: cpUtf8.get(idx) ?? null };
525
+ }
526
+ case 0x42:
527
+ case 0x43:
528
+ case 0x44:
529
+ case 0x46: // B, C, D, F
530
+ case 0x49:
531
+ case 0x4A:
532
+ case 0x53:
533
+ case 0x5A: // I, J, S, Z
534
+ return { offset: offset + 2, stringValue: null };
535
+ case 0x65: // 'e' — Enum
536
+ return { offset: offset + 4, stringValue: null };
537
+ case 0x63: // 'c' — Class
538
+ return { offset: offset + 2, stringValue: null };
539
+ case 0x40: { // '@' — Nested annotation
540
+ if (offset + 4 > buf.length)
541
+ return { offset: -1, stringValue: null };
542
+ offset += 2; // type_index
543
+ const numPairs = buf.readUInt16BE(offset);
544
+ offset += 2;
545
+ for (let i = 0; i < numPairs; i++) {
546
+ offset += 2; // element_name_index
547
+ const ev = readAnnotationElementValue(buf, offset, cpUtf8);
548
+ if (ev.offset < 0)
549
+ return { offset: -1, stringValue: null };
550
+ offset = ev.offset;
551
+ }
552
+ return { offset, stringValue: null };
553
+ }
554
+ case 0x5B: { // '[' — Array
555
+ if (offset + 2 > buf.length)
556
+ return { offset: -1, stringValue: null };
557
+ const numValues = buf.readUInt16BE(offset);
558
+ offset += 2;
559
+ for (let i = 0; i < numValues; i++) {
560
+ const ev = readAnnotationElementValue(buf, offset, cpUtf8);
561
+ if (ev.offset < 0)
562
+ return { offset: -1, stringValue: null };
563
+ offset = ev.offset;
564
+ }
565
+ return { offset, stringValue: null };
566
+ }
567
+ default:
568
+ return { offset: -1, stringValue: null };
569
+ }
570
+ }
571
+ function unknownMod(jarPath) {
572
+ const name = jarPath.split(/[\\/]/).pop() ?? "unknown";
573
+ return {
574
+ modId: name.replace(/\.jar$/, ""),
575
+ displayName: name,
576
+ version: "0.0.0",
577
+ mcVersion: "",
578
+ loader: "unknown",
579
+ description: "",
580
+ sourceUrl: null,
581
+ dependencies: [],
582
+ mixinConfigs: [],
583
+ hasMixins: false,
584
+ hasAt: false,
585
+ hasAw: false,
586
+ atEntries: [],
587
+ awEntries: [],
588
+ mixinTargets: [],
589
+ metadataSource: "filename",
590
+ };
591
+ }
592
+ export function parseAtEntries(content) {
593
+ return content
594
+ .split("\n")
595
+ .map((l) => l.trim())
596
+ .filter((l) => l && !l.startsWith("#"));
597
+ }
598
+ export function parseAwEntries(content) {
599
+ return content
600
+ .split("\n")
601
+ .map((l) => l.trim())
602
+ .filter((l) => l && !l.startsWith("#") && !l.startsWith("accessWidener"));
603
+ }
604
+ function extractFabricMcVersion(deps) {
605
+ return deps["minecraft"] ?? "";
606
+ }
607
+ function extractString(obj, ...keys) {
608
+ let cur = obj;
609
+ for (const k of keys) {
610
+ if (typeof cur !== "object" || cur === null)
611
+ return null;
612
+ cur = cur[k];
613
+ }
614
+ return typeof cur === "string" ? cur : null;
615
+ }
616
+ export async function computeHashes(jarPath) {
617
+ const buf = await readFile(jarPath);
618
+ const sha256 = createHash("sha256").update(buf).digest("hex");
619
+ const sha512 = createHash("sha512").update(buf).digest("hex");
620
+ const murmur2 = computeMurmur2(buf).toString();
621
+ return { sha256, sha512, murmur2 };
622
+ }
623
+ /** CurseForge Murmur2 hash — matches CF API fingerprint (whitespace-normalized). */
624
+ export function computeMurmur2(data) {
625
+ // Filter whitespace bytes as CF does (9, 10, 13, 32)
626
+ const filtered = Buffer.from(data.filter((b) => b !== 9 && b !== 10 && b !== 13 && b !== 32));
627
+ const seed = 1;
628
+ const m = 0x5bd1e995;
629
+ const r = 24;
630
+ let h = (seed ^ filtered.length) >>> 0;
631
+ let i = 0;
632
+ while (i <= filtered.length - 4) {
633
+ let k = filtered.readUInt32LE(i);
634
+ k = Math.imul(k, m) >>> 0;
635
+ k ^= k >>> r;
636
+ k = Math.imul(k, m) >>> 0;
637
+ h = Math.imul(h, m) >>> 0;
638
+ h ^= k;
639
+ i += 4;
640
+ }
641
+ const remaining = filtered.length - i;
642
+ if (remaining >= 3)
643
+ h ^= filtered[i + 2] << 16;
644
+ if (remaining >= 2)
645
+ h ^= filtered[i + 1] << 8;
646
+ if (remaining >= 1) {
647
+ h ^= filtered[i];
648
+ h = Math.imul(h, m) >>> 0;
649
+ }
650
+ h ^= h >>> 13;
651
+ h = Math.imul(h, m) >>> 0;
652
+ h ^= h >>> 15;
653
+ return h >>> 0;
654
+ }
655
+ //# sourceMappingURL=processor.js.map