@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.
- package/README.md +938 -0
- package/dist/access-flags.d.ts +58 -0
- package/dist/access-flags.d.ts.map +1 -0
- package/dist/access-flags.js +79 -0
- package/dist/access-flags.js.map +1 -0
- package/dist/access-flags.test.d.ts +2 -0
- package/dist/access-flags.test.d.ts.map +1 -0
- package/dist/access-flags.test.js +189 -0
- package/dist/access-flags.test.js.map +1 -0
- package/dist/batch-ingest.d.ts +2 -0
- package/dist/batch-ingest.d.ts.map +1 -0
- package/dist/batch-ingest.js +54 -0
- package/dist/batch-ingest.js.map +1 -0
- package/dist/batch-resolve-mixins.d.ts +2 -0
- package/dist/batch-resolve-mixins.d.ts.map +1 -0
- package/dist/batch-resolve-mixins.js +36 -0
- package/dist/batch-resolve-mixins.js.map +1 -0
- package/dist/cache.d.ts +16 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +36 -0
- package/dist/cache.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1318 -0
- package/dist/cli.js.map +1 -0
- package/dist/curseforge.d.ts +53 -0
- package/dist/curseforge.d.ts.map +1 -0
- package/dist/curseforge.js +104 -0
- package/dist/curseforge.js.map +1 -0
- package/dist/db-backend.d.ts +17 -0
- package/dist/db-backend.d.ts.map +1 -0
- package/dist/db-backend.js +40 -0
- package/dist/db-backend.js.map +1 -0
- package/dist/db.d.ts +11 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +55 -0
- package/dist/db.js.map +1 -0
- package/dist/embed-queue.d.ts +12 -0
- package/dist/embed-queue.d.ts.map +1 -0
- package/dist/embed-queue.js +103 -0
- package/dist/embed-queue.js.map +1 -0
- package/dist/embeddings.d.ts +21 -0
- package/dist/embeddings.d.ts.map +1 -0
- package/dist/embeddings.js +55 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/env-path.d.ts +19 -0
- package/dist/env-path.d.ts.map +1 -0
- package/dist/env-path.js +40 -0
- package/dist/env-path.js.map +1 -0
- package/dist/fetch-utils.d.ts +24 -0
- package/dist/fetch-utils.d.ts.map +1 -0
- package/dist/fetch-utils.js +73 -0
- package/dist/fetch-utils.js.map +1 -0
- package/dist/fetch-utils.test.d.ts +2 -0
- package/dist/fetch-utils.test.d.ts.map +1 -0
- package/dist/fetch-utils.test.js +133 -0
- package/dist/fetch-utils.test.js.map +1 -0
- package/dist/generated/sqlite/browser.d.ts +55 -0
- package/dist/generated/sqlite/browser.d.ts.map +1 -0
- package/dist/generated/sqlite/browser.js +18 -0
- package/dist/generated/sqlite/browser.js.map +1 -0
- package/dist/generated/sqlite/client.d.ts +72 -0
- package/dist/generated/sqlite/client.d.ts.map +1 -0
- package/dist/generated/sqlite/client.js +33 -0
- package/dist/generated/sqlite/client.js.map +1 -0
- package/dist/generated/sqlite/commonInputTypes.d.ts +387 -0
- package/dist/generated/sqlite/commonInputTypes.d.ts.map +1 -0
- package/dist/generated/sqlite/commonInputTypes.js +11 -0
- package/dist/generated/sqlite/commonInputTypes.js.map +1 -0
- package/dist/generated/sqlite/enums.d.ts +2 -0
- package/dist/generated/sqlite/enums.d.ts.map +1 -0
- package/dist/generated/sqlite/enums.js +11 -0
- package/dist/generated/sqlite/enums.js.map +1 -0
- package/dist/generated/sqlite/internal/class.d.ts +226 -0
- package/dist/generated/sqlite/internal/class.d.ts.map +1 -0
- package/dist/generated/sqlite/internal/class.js +84 -0
- package/dist/generated/sqlite/internal/class.js.map +1 -0
- package/dist/generated/sqlite/internal/prismaNamespace.d.ts +1344 -0
- package/dist/generated/sqlite/internal/prismaNamespace.d.ts.map +1 -0
- package/dist/generated/sqlite/internal/prismaNamespace.js +220 -0
- package/dist/generated/sqlite/internal/prismaNamespace.js.map +1 -0
- package/dist/generated/sqlite/internal/prismaNamespaceBrowser.d.ts +204 -0
- package/dist/generated/sqlite/internal/prismaNamespaceBrowser.d.ts.map +1 -0
- package/dist/generated/sqlite/internal/prismaNamespaceBrowser.js +191 -0
- package/dist/generated/sqlite/internal/prismaNamespaceBrowser.js.map +1 -0
- package/dist/generated/sqlite/models/DocEntry.d.ts +1223 -0
- package/dist/generated/sqlite/models/DocEntry.d.ts.map +1 -0
- package/dist/generated/sqlite/models/DocEntry.js +2 -0
- package/dist/generated/sqlite/models/DocEntry.js.map +1 -0
- package/dist/generated/sqlite/models/McSourceFile.d.ts +1289 -0
- package/dist/generated/sqlite/models/McSourceFile.d.ts.map +1 -0
- package/dist/generated/sqlite/models/McSourceFile.js +2 -0
- package/dist/generated/sqlite/models/McSourceFile.js.map +1 -0
- package/dist/generated/sqlite/models/McVersion.d.ts +1315 -0
- package/dist/generated/sqlite/models/McVersion.d.ts.map +1 -0
- package/dist/generated/sqlite/models/McVersion.js +2 -0
- package/dist/generated/sqlite/models/McVersion.js.map +1 -0
- package/dist/generated/sqlite/models/McVersionDiff.d.ts +1061 -0
- package/dist/generated/sqlite/models/McVersionDiff.d.ts.map +1 -0
- package/dist/generated/sqlite/models/McVersionDiff.js +2 -0
- package/dist/generated/sqlite/models/McVersionDiff.js.map +1 -0
- package/dist/generated/sqlite/models/Mod.d.ts +2396 -0
- package/dist/generated/sqlite/models/Mod.d.ts.map +1 -0
- package/dist/generated/sqlite/models/Mod.js +2 -0
- package/dist/generated/sqlite/models/Mod.js.map +1 -0
- package/dist/generated/sqlite/models/ModClass.d.ts +1254 -0
- package/dist/generated/sqlite/models/ModClass.d.ts.map +1 -0
- package/dist/generated/sqlite/models/ModClass.js +2 -0
- package/dist/generated/sqlite/models/ModClass.js.map +1 -0
- package/dist/generated/sqlite/models/ModSourceFile.d.ts +1283 -0
- package/dist/generated/sqlite/models/ModSourceFile.d.ts.map +1 -0
- package/dist/generated/sqlite/models/ModSourceFile.js +2 -0
- package/dist/generated/sqlite/models/ModSourceFile.js.map +1 -0
- package/dist/generated/sqlite/models/ModTag.d.ts +1278 -0
- package/dist/generated/sqlite/models/ModTag.d.ts.map +1 -0
- package/dist/generated/sqlite/models/ModTag.js +2 -0
- package/dist/generated/sqlite/models/ModTag.js.map +1 -0
- package/dist/generated/sqlite/models/ModVersionDiff.d.ts +1073 -0
- package/dist/generated/sqlite/models/ModVersionDiff.d.ts.map +1 -0
- package/dist/generated/sqlite/models/ModVersionDiff.js +2 -0
- package/dist/generated/sqlite/models/ModVersionDiff.js.map +1 -0
- package/dist/generated/sqlite/models/Primer.d.ts +1319 -0
- package/dist/generated/sqlite/models/Primer.d.ts.map +1 -0
- package/dist/generated/sqlite/models/Primer.js +2 -0
- package/dist/generated/sqlite/models/Primer.js.map +1 -0
- package/dist/generated/sqlite/models.d.ts +12 -0
- package/dist/generated/sqlite/models.d.ts.map +1 -0
- package/dist/generated/sqlite/models.js +2 -0
- package/dist/generated/sqlite/models.js.map +1 -0
- package/dist/jar.d.ts +7 -0
- package/dist/jar.d.ts.map +1 -0
- package/dist/jar.js +52 -0
- package/dist/jar.js.map +1 -0
- package/dist/java-tools.d.ts +46 -0
- package/dist/java-tools.d.ts.map +1 -0
- package/dist/java-tools.js +263 -0
- package/dist/java-tools.js.map +1 -0
- package/dist/launcher.d.ts +3 -0
- package/dist/launcher.d.ts.map +1 -0
- package/dist/launcher.js +105 -0
- package/dist/launcher.js.map +1 -0
- package/dist/mappings.d.ts +95 -0
- package/dist/mappings.d.ts.map +1 -0
- package/dist/mappings.js +1094 -0
- package/dist/mappings.js.map +1 -0
- package/dist/mappings.test.d.ts +2 -0
- package/dist/mappings.test.d.ts.map +1 -0
- package/dist/mappings.test.js +161 -0
- package/dist/mappings.test.js.map +1 -0
- package/dist/minecraft.d.ts +21 -0
- package/dist/minecraft.d.ts.map +1 -0
- package/dist/minecraft.js +70 -0
- package/dist/minecraft.js.map +1 -0
- package/dist/modpacks-ch.d.ts +224 -0
- package/dist/modpacks-ch.d.ts.map +1 -0
- package/dist/modpacks-ch.js +146 -0
- package/dist/modpacks-ch.js.map +1 -0
- package/dist/modrinth.d.ts +67 -0
- package/dist/modrinth.d.ts.map +1 -0
- package/dist/modrinth.js +88 -0
- package/dist/modrinth.js.map +1 -0
- package/dist/platform-adapter.d.ts +23 -0
- package/dist/platform-adapter.d.ts.map +1 -0
- package/dist/platform-adapter.js +2 -0
- package/dist/platform-adapter.js.map +1 -0
- package/dist/platform.d.ts +47 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +175 -0
- package/dist/platform.js.map +1 -0
- package/dist/processor.d.ts +51 -0
- package/dist/processor.d.ts.map +1 -0
- package/dist/processor.js +655 -0
- package/dist/processor.js.map +1 -0
- package/dist/processor.test.d.ts +2 -0
- package/dist/processor.test.d.ts.map +1 -0
- package/dist/processor.test.js +629 -0
- package/dist/processor.test.js.map +1 -0
- package/dist/repositories/embeddings-sqlite.d.ts +38 -0
- package/dist/repositories/embeddings-sqlite.d.ts.map +1 -0
- package/dist/repositories/embeddings-sqlite.js +208 -0
- package/dist/repositories/embeddings-sqlite.js.map +1 -0
- package/dist/repositories/embeddings.d.ts +40 -0
- package/dist/repositories/embeddings.d.ts.map +1 -0
- package/dist/repositories/embeddings.js +136 -0
- package/dist/repositories/embeddings.js.map +1 -0
- package/dist/repositories/index.d.ts +2 -0
- package/dist/repositories/index.d.ts.map +1 -0
- package/dist/repositories/index.js +15 -0
- package/dist/repositories/index.js.map +1 -0
- package/dist/repositories/mcVersion.d.ts +16 -0
- package/dist/repositories/mcVersion.d.ts.map +1 -0
- package/dist/repositories/mcVersion.js +52 -0
- package/dist/repositories/mcVersion.js.map +1 -0
- package/dist/repositories/mod.d.ts +241 -0
- package/dist/repositories/mod.d.ts.map +1 -0
- package/dist/repositories/mod.js +342 -0
- package/dist/repositories/mod.js.map +1 -0
- package/dist/repositories/packs.d.ts +44 -0
- package/dist/repositories/packs.d.ts.map +1 -0
- package/dist/repositories/packs.js +138 -0
- package/dist/repositories/packs.js.map +1 -0
- package/dist/search-adapter.d.ts +34 -0
- package/dist/search-adapter.d.ts.map +1 -0
- package/dist/search-adapter.js +195 -0
- package/dist/search-adapter.js.map +1 -0
- package/dist/search.d.ts +6 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +54 -0
- package/dist/search.js.map +1 -0
- package/dist/search.test.d.ts +2 -0
- package/dist/search.test.d.ts.map +1 -0
- package/dist/search.test.js +71 -0
- package/dist/search.test.js.map +1 -0
- package/dist/security.d.ts +98 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +446 -0
- package/dist/security.js.map +1 -0
- package/dist/security.test.d.ts +2 -0
- package/dist/security.test.d.ts.map +1 -0
- package/dist/security.test.js +687 -0
- package/dist/security.test.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +1465 -0
- package/dist/server.js.map +1 -0
- package/dist/setup.d.ts +2 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +1113 -0
- package/dist/setup.js.map +1 -0
- package/dist/tools/bytecode.d.ts +129 -0
- package/dist/tools/bytecode.d.ts.map +1 -0
- package/dist/tools/bytecode.js +679 -0
- package/dist/tools/bytecode.js.map +1 -0
- package/dist/tools/catalog.d.ts +54 -0
- package/dist/tools/catalog.d.ts.map +1 -0
- package/dist/tools/catalog.js +249 -0
- package/dist/tools/catalog.js.map +1 -0
- package/dist/tools/compat-check.d.ts +23 -0
- package/dist/tools/compat-check.d.ts.map +1 -0
- package/dist/tools/compat-check.js +250 -0
- package/dist/tools/compat-check.js.map +1 -0
- package/dist/tools/compat-check.test.d.ts +2 -0
- package/dist/tools/compat-check.test.d.ts.map +1 -0
- package/dist/tools/compat-check.test.js +179 -0
- package/dist/tools/compat-check.test.js.map +1 -0
- package/dist/tools/diagnostics.d.ts +10 -0
- package/dist/tools/diagnostics.d.ts.map +1 -0
- package/dist/tools/diagnostics.js +133 -0
- package/dist/tools/diagnostics.js.map +1 -0
- package/dist/tools/diagnostics.test.d.ts +2 -0
- package/dist/tools/diagnostics.test.d.ts.map +1 -0
- package/dist/tools/diagnostics.test.js +168 -0
- package/dist/tools/diagnostics.test.js.map +1 -0
- package/dist/tools/docs.d.ts +19 -0
- package/dist/tools/docs.d.ts.map +1 -0
- package/dist/tools/docs.js +230 -0
- package/dist/tools/docs.js.map +1 -0
- package/dist/tools/embed-registry.d.ts +125 -0
- package/dist/tools/embed-registry.d.ts.map +1 -0
- package/dist/tools/embed-registry.js +560 -0
- package/dist/tools/embed-registry.js.map +1 -0
- package/dist/tools/gradle.d.ts +16 -0
- package/dist/tools/gradle.d.ts.map +1 -0
- package/dist/tools/gradle.js +182 -0
- package/dist/tools/gradle.js.map +1 -0
- package/dist/tools/graphify.d.ts +144 -0
- package/dist/tools/graphify.d.ts.map +1 -0
- package/dist/tools/graphify.js +798 -0
- package/dist/tools/graphify.js.map +1 -0
- package/dist/tools/graphify.test.d.ts +2 -0
- package/dist/tools/graphify.test.d.ts.map +1 -0
- package/dist/tools/graphify.test.js +39 -0
- package/dist/tools/graphify.test.js.map +1 -0
- package/dist/tools/ingest.d.ts +85 -0
- package/dist/tools/ingest.d.ts.map +1 -0
- package/dist/tools/ingest.js +477 -0
- package/dist/tools/ingest.js.map +1 -0
- package/dist/tools/ingest.test.d.ts +2 -0
- package/dist/tools/ingest.test.d.ts.map +1 -0
- package/dist/tools/ingest.test.js +340 -0
- package/dist/tools/ingest.test.js.map +1 -0
- package/dist/tools/kubejs.d.ts +37 -0
- package/dist/tools/kubejs.d.ts.map +1 -0
- package/dist/tools/kubejs.js +245 -0
- package/dist/tools/kubejs.js.map +1 -0
- package/dist/tools/mappings.d.ts +17 -0
- package/dist/tools/mappings.d.ts.map +1 -0
- package/dist/tools/mappings.js +85 -0
- package/dist/tools/mappings.js.map +1 -0
- package/dist/tools/mc-fts.d.ts +101 -0
- package/dist/tools/mc-fts.d.ts.map +1 -0
- package/dist/tools/mc-fts.js +279 -0
- package/dist/tools/mc-fts.js.map +1 -0
- package/dist/tools/mcmeta.d.ts +41 -0
- package/dist/tools/mcmeta.d.ts.map +1 -0
- package/dist/tools/mcmeta.js +365 -0
- package/dist/tools/mcmeta.js.map +1 -0
- package/dist/tools/mixin-scan.d.ts +113 -0
- package/dist/tools/mixin-scan.d.ts.map +1 -0
- package/dist/tools/mixin-scan.js +433 -0
- package/dist/tools/mixin-scan.js.map +1 -0
- package/dist/tools/mod-data.d.ts +83 -0
- package/dist/tools/mod-data.d.ts.map +1 -0
- package/dist/tools/mod-data.js +630 -0
- package/dist/tools/mod-data.js.map +1 -0
- package/dist/tools/mod-tags.d.ts +59 -0
- package/dist/tools/mod-tags.d.ts.map +1 -0
- package/dist/tools/mod-tags.js +279 -0
- package/dist/tools/mod-tags.js.map +1 -0
- package/dist/tools/mod-tags.test.d.ts +2 -0
- package/dist/tools/mod-tags.test.d.ts.map +1 -0
- package/dist/tools/mod-tags.test.js +75 -0
- package/dist/tools/mod-tags.test.js.map +1 -0
- package/dist/tools/modpacks-ch.d.ts +257 -0
- package/dist/tools/modpacks-ch.d.ts.map +1 -0
- package/dist/tools/modpacks-ch.js +516 -0
- package/dist/tools/modpacks-ch.js.map +1 -0
- package/dist/tools/packtools.d.ts +113 -0
- package/dist/tools/packtools.d.ts.map +1 -0
- package/dist/tools/packtools.js +809 -0
- package/dist/tools/packtools.js.map +1 -0
- package/dist/tools/packtools.test.d.ts +2 -0
- package/dist/tools/packtools.test.d.ts.map +1 -0
- package/dist/tools/packtools.test.js +99 -0
- package/dist/tools/packtools.test.js.map +1 -0
- package/dist/tools/platform.d.ts +68 -0
- package/dist/tools/platform.d.ts.map +1 -0
- package/dist/tools/platform.js +452 -0
- package/dist/tools/platform.js.map +1 -0
- package/dist/tools/primers.d.ts +36 -0
- package/dist/tools/primers.d.ts.map +1 -0
- package/dist/tools/primers.js +451 -0
- package/dist/tools/primers.js.map +1 -0
- package/dist/tools/reports.d.ts +19 -0
- package/dist/tools/reports.d.ts.map +1 -0
- package/dist/tools/reports.js +573 -0
- package/dist/tools/reports.js.map +1 -0
- package/dist/tools/source.d.ts +10 -0
- package/dist/tools/source.d.ts.map +1 -0
- package/dist/tools/source.js +101 -0
- package/dist/tools/source.js.map +1 -0
- package/dist/tools/vanilla-data.d.ts +127 -0
- package/dist/tools/vanilla-data.d.ts.map +1 -0
- package/dist/tools/vanilla-data.js +824 -0
- package/dist/tools/vanilla-data.js.map +1 -0
- package/dist/tools/vanilla.d.ts +171 -0
- package/dist/tools/vanilla.d.ts.map +1 -0
- package/dist/tools/vanilla.js +612 -0
- package/dist/tools/vanilla.js.map +1 -0
- package/dist/tools/version-diff.d.ts +113 -0
- package/dist/tools/version-diff.d.ts.map +1 -0
- package/dist/tools/version-diff.js +519 -0
- package/dist/tools/version-diff.js.map +1 -0
- package/dist/tools/version-diff.test.d.ts +2 -0
- package/dist/tools/version-diff.test.d.ts.map +1 -0
- package/dist/tools/version-diff.test.js +102 -0
- package/dist/tools/version-diff.test.js.map +1 -0
- package/dist/validate.d.ts +19 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +54 -0
- package/dist/validate.js.map +1 -0
- package/dist/validate.test.d.ts +2 -0
- package/dist/validate.test.d.ts.map +1 -0
- package/dist/validate.test.js +73 -0
- package/dist/validate.test.js.map +1 -0
- package/package.json +62 -0
- package/prisma/backends/schema.sqlite.prisma +215 -0
- package/prisma/backends/template.db +0 -0
- package/prisma/schema.prisma +303 -0
- package/scripts/backup.mjs +151 -0
- package/scripts/build-template-db.mjs +38 -0
- package/scripts/check-atm10.mjs +27 -0
- package/scripts/check-sync.mjs +13 -0
- package/scripts/create-fts-index.mjs +50 -0
- package/scripts/enable-pgvector.mjs +90 -0
- package/scripts/enable-sqlite-vec.mjs +158 -0
- package/scripts/migrate-backend.mjs +188 -0
- package/scripts/migrate-embed-provenance.mjs +80 -0
- package/scripts/migrate-metadata-source.mjs +62 -0
- package/scripts/migrate-mod-source-files.mjs +67 -0
- package/scripts/post-update.mjs +77 -0
- 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
|