@adhisang/minecraft-modding-mcp 4.2.1 → 6.0.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 (144) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +5 -4
  3. package/dist/access-transformer-parser.d.ts +2 -1
  4. package/dist/access-transformer-parser.js +10 -1
  5. package/dist/access-widener-parser.d.ts +1 -0
  6. package/dist/access-widener-parser.js +6 -3
  7. package/dist/build-suggested-call.js +31 -10
  8. package/dist/cache-registry.d.ts +8 -0
  9. package/dist/cache-registry.js +50 -32
  10. package/dist/config.d.ts +1 -0
  11. package/dist/config.js +4 -0
  12. package/dist/decompiler/vineflower.js +8 -2
  13. package/dist/entry-tools/analyze-mod-service.d.ts +24 -24
  14. package/dist/entry-tools/analyze-mod-service.js +2 -1
  15. package/dist/entry-tools/analyze-symbol-service.d.ts +57 -22
  16. package/dist/entry-tools/analyze-symbol-service.js +139 -34
  17. package/dist/entry-tools/batch-class-members-service.d.ts +3 -1
  18. package/dist/entry-tools/batch-class-members-service.js +6 -6
  19. package/dist/entry-tools/batch-class-source-service.d.ts +3 -1
  20. package/dist/entry-tools/batch-class-source-service.js +5 -6
  21. package/dist/entry-tools/batch-mappings-service.d.ts +3 -1
  22. package/dist/entry-tools/batch-mappings-service.js +4 -5
  23. package/dist/entry-tools/batch-symbol-exists-service.d.ts +3 -1
  24. package/dist/entry-tools/batch-symbol-exists-service.js +4 -5
  25. package/dist/entry-tools/compare-minecraft-service.d.ts +10 -10
  26. package/dist/entry-tools/compare-minecraft-service.js +1 -1
  27. package/dist/entry-tools/entry-tool-schema.d.ts +1 -1
  28. package/dist/entry-tools/inspect-minecraft/handlers/artifact.js +1 -3
  29. package/dist/entry-tools/inspect-minecraft/handlers/class-members.js +4 -3
  30. package/dist/entry-tools/inspect-minecraft/handlers/class-overview.js +0 -5
  31. package/dist/entry-tools/inspect-minecraft/handlers/class-source.js +0 -1
  32. package/dist/entry-tools/inspect-minecraft/handlers/file.js +26 -2
  33. package/dist/entry-tools/inspect-minecraft/handlers/list-files.js +0 -1
  34. package/dist/entry-tools/inspect-minecraft/handlers/search.d.ts +8 -0
  35. package/dist/entry-tools/inspect-minecraft/handlers/search.js +13 -2
  36. package/dist/entry-tools/inspect-minecraft/handlers/versions.d.ts +1 -1
  37. package/dist/entry-tools/inspect-minecraft/handlers/versions.js +3 -2
  38. package/dist/entry-tools/inspect-minecraft/internal.d.ts +90 -89
  39. package/dist/entry-tools/inspect-minecraft/internal.js +32 -14
  40. package/dist/entry-tools/inspect-minecraft-service.d.ts +218 -218
  41. package/dist/entry-tools/inspect-minecraft-service.js +1 -1
  42. package/dist/entry-tools/manage-cache-service.d.ts +4 -4
  43. package/dist/entry-tools/response-contract.d.ts +3 -1
  44. package/dist/entry-tools/response-contract.js +3 -2
  45. package/dist/entry-tools/validate-project/cases/mixin.js +2 -1
  46. package/dist/entry-tools/validate-project/cases/project-summary.js +5 -3
  47. package/dist/entry-tools/validate-project-service.d.ts +42 -36
  48. package/dist/entry-tools/validate-project-service.js +3 -1
  49. package/dist/entry-tools/verify-mixin-target-service.d.ts +30 -0
  50. package/dist/entry-tools/verify-mixin-target-service.js +120 -29
  51. package/dist/error-mapping.d.ts +51 -0
  52. package/dist/error-mapping.js +157 -2
  53. package/dist/index.js +147 -76
  54. package/dist/java-process.js +1 -1
  55. package/dist/json-rpc-framing.d.ts +4 -0
  56. package/dist/json-rpc-framing.js +23 -1
  57. package/dist/mapping/internal-types.d.ts +24 -0
  58. package/dist/mapping/loaders/tiny-maven.js +46 -20
  59. package/dist/mapping/lookup.d.ts +13 -2
  60. package/dist/mapping/lookup.js +60 -2
  61. package/dist/mapping/types.d.ts +6 -0
  62. package/dist/mapping-service.d.ts +26 -2
  63. package/dist/mapping-service.js +212 -55
  64. package/dist/mcp-helpers.d.ts +1 -0
  65. package/dist/mcp-helpers.js +25 -3
  66. package/dist/minecraft-explorer-service.js +24 -11
  67. package/dist/mixin/access-validators.js +33 -1
  68. package/dist/mixin/annotation-validators.js +73 -9
  69. package/dist/mixin/parsed-validator.js +3 -2
  70. package/dist/mixin-parser.js +119 -7
  71. package/dist/mod-decompile-service.d.ts +2 -0
  72. package/dist/mod-decompile-service.js +21 -3
  73. package/dist/mod-remap-service.d.ts +20 -1
  74. package/dist/mod-remap-service.js +101 -45
  75. package/dist/mojang-tiny-mapping-service.js +5 -2
  76. package/dist/nbt/java-nbt-codec.js +46 -16
  77. package/dist/nbt/json-patch.js +51 -12
  78. package/dist/nbt/typed-json.d.ts +1 -0
  79. package/dist/nbt/typed-json.js +12 -2
  80. package/dist/nbt/types.d.ts +2 -2
  81. package/dist/observability.d.ts +6 -0
  82. package/dist/observability.js +10 -0
  83. package/dist/page-cursor.d.ts +17 -0
  84. package/dist/page-cursor.js +0 -0
  85. package/dist/path-converter.js +10 -3
  86. package/dist/registry-service.d.ts +2 -0
  87. package/dist/registry-service.js +41 -2
  88. package/dist/repo-downloader.js +4 -3
  89. package/dist/resources.js +45 -9
  90. package/dist/response-utils.d.ts +29 -4
  91. package/dist/response-utils.js +95 -5
  92. package/dist/source/access-validate.js +12 -2
  93. package/dist/source/artifact-resolver.js +2 -2
  94. package/dist/source/class-source/members-builder.d.ts +44 -1
  95. package/dist/source/class-source/members-builder.js +51 -4
  96. package/dist/source/class-source/snippet-builder.d.ts +13 -0
  97. package/dist/source/class-source/snippet-builder.js +54 -4
  98. package/dist/source/class-source-helpers.d.ts +4 -4
  99. package/dist/source/class-source-helpers.js +77 -20
  100. package/dist/source/class-source.d.ts +19 -0
  101. package/dist/source/class-source.js +144 -40
  102. package/dist/source/file-access.js +3 -2
  103. package/dist/source/indexer.js +29 -9
  104. package/dist/source/lifecycle/mapping-helpers.js +28 -3
  105. package/dist/source/lifecycle/runtime-check.js +20 -6
  106. package/dist/source/search.d.ts +1 -1
  107. package/dist/source/search.js +117 -30
  108. package/dist/source/validate-mixin/pipeline/resolve.js +23 -3
  109. package/dist/source/validate-mixin.d.ts +2 -1
  110. package/dist/source/validate-mixin.js +45 -4
  111. package/dist/source/workspace-target.js +17 -10
  112. package/dist/source-jar-reader.d.ts +54 -1
  113. package/dist/source-jar-reader.js +121 -10
  114. package/dist/source-resolver.js +2 -2
  115. package/dist/source-service.d.ts +28 -7
  116. package/dist/source-service.js +9 -1
  117. package/dist/stdio-supervisor.d.ts +2 -2
  118. package/dist/stdio-supervisor.js +29 -9
  119. package/dist/storage/db.js +24 -1
  120. package/dist/storage/files-repo.d.ts +15 -0
  121. package/dist/storage/files-repo.js +67 -37
  122. package/dist/storage/symbols-repo.d.ts +15 -0
  123. package/dist/storage/symbols-repo.js +53 -19
  124. package/dist/symbols/symbol-extractor.js +35 -6
  125. package/dist/text-truncate.d.ts +7 -0
  126. package/dist/text-truncate.js +21 -0
  127. package/dist/tiny-remapper-resolver.js +10 -0
  128. package/dist/tool-contract-manifest.js +2 -2
  129. package/dist/tool-execution-gate.js +12 -1
  130. package/dist/tool-guidance.d.ts +6 -2
  131. package/dist/tool-guidance.js +63 -13
  132. package/dist/tool-schemas.d.ts +561 -496
  133. package/dist/tool-schemas.js +175 -139
  134. package/dist/types.d.ts +1 -0
  135. package/dist/version-diff-service.js +5 -0
  136. package/dist/version-service.d.ts +3 -0
  137. package/dist/version-service.js +18 -2
  138. package/dist/warning-details.d.ts +30 -0
  139. package/dist/warning-details.js +80 -0
  140. package/dist/workspace-mapping-service.js +9 -0
  141. package/docs/README-ja.md +2 -2
  142. package/docs/examples.md +26 -2
  143. package/docs/tool-reference.md +22 -17
  144. package/package.json +1 -1
@@ -20,6 +20,18 @@ export type DirectionIndex = {
20
20
  simple: Map<string, Set<string>>;
21
21
  records: Map<string, MappingSymbolRecord>;
22
22
  };
23
+ /**
24
+ * O(1) exact-lookup index over a single target namespace's records, used by
25
+ * existence checks. `byKey` is keyed by `kind|owner|name` (owner empty for
26
+ * classes, which key on their FQCN symbol); `classBySimpleName` resolves the
27
+ * auto-class short-name path. Values are arrays so callers can still tell a
28
+ * unique match (resolved) from multiple (ambiguous).
29
+ */
30
+ export type ExactRecordIndex = {
31
+ byKey: Map<string, MappingSymbolRecord[]>;
32
+ classBySimpleName: Map<string, MappingSymbolRecord[]>;
33
+ membersByOwner: Map<string, MappingSymbolRecord[]>;
34
+ };
23
35
  export type MappingLookupSource = "loom-cache" | "maven" | "mojang-client-mappings";
24
36
  export type PairRecord = {
25
37
  index: DirectionIndex;
@@ -50,5 +62,17 @@ export type LoadedGraph = {
50
62
  adjacency: Map<import("../types.js").SourceMapping, import("../types.js").SourceMapping[]>;
51
63
  pathCache: Map<PairKey, import("../types.js").SourceMapping[] | undefined>;
52
64
  recordsByTarget: Map<import("../types.js").SourceMapping, MappingSymbolRecord[]>;
65
+ /**
66
+ * Graph-scoped, lazily-built exact-lookup indexes keyed by target namespace.
67
+ * Populated on first existence check for a namespace; dies with graph eviction.
68
+ */
69
+ exactRecordIndex: Map<import("../types.js").SourceMapping, ExactRecordIndex>;
70
+ /**
71
+ * Graph-scoped cache of class-to-class descriptor projections, keyed by
72
+ * `path.join(">") + NUL + internalName`. Value is the projected internal name,
73
+ * or `null` to memoize an unmapped/ambiguous class. Shared across all member
74
+ * lookups on this graph; dies with graph eviction.
75
+ */
76
+ classProjectionCache: Map<string, string | null>;
53
77
  warnings: string[];
54
78
  };
@@ -53,36 +53,62 @@ export async function loadTinyPairsFromMaven(deps, version) {
53
53
  const warnings = [];
54
54
  const merged = new Map();
55
55
  const repos = deps.config.sourceRepos;
56
- const intermediaryUrls = [];
57
- const yarnUrls = [];
56
+ const attemptedUrls = [];
58
57
  const repoBases = repos.map((repo) => repo.replace(/\/+$/, ""));
59
58
  const yarnCoordinatesByRepo = await Promise.all(repoBases.map(async (base) => ({
60
59
  base,
61
60
  yarnCoordinates: await fetchYarnCoordinates(deps.fetchFn, base, version)
62
61
  })));
62
+ const tryUrls = async (urls) => {
63
+ for (const url of urls) {
64
+ attemptedUrls.push(url);
65
+ try {
66
+ const downloaded = await downloadToCache(url, defaultDownloadPath(deps.config.cacheDir, url), {
67
+ fetchFn: deps.fetchFn,
68
+ retries: deps.config.fetchRetries,
69
+ timeoutMs: deps.config.fetchTimeoutMs
70
+ });
71
+ if (!downloaded.ok || !downloaded.path) {
72
+ continue;
73
+ }
74
+ const parsed = await parseTinyFromJar(downloaded.path);
75
+ if (parsed.size > 0) {
76
+ return parsed;
77
+ }
78
+ }
79
+ catch {
80
+ // try the next candidate URL
81
+ }
82
+ }
83
+ return undefined;
84
+ };
85
+ let intermediaryParsed;
86
+ let yarnParsed;
63
87
  for (const { base, yarnCoordinates } of yarnCoordinatesByRepo) {
64
- intermediaryUrls.push(`${base}/net/fabricmc/intermediary/${version}/intermediary-${version}-v2.jar`, `${base}/net/fabricmc/intermediary/${version}/intermediary-${version}.jar`);
88
+ if (!intermediaryParsed) {
89
+ intermediaryParsed = await tryUrls([
90
+ `${base}/net/fabricmc/intermediary/${version}/intermediary-${version}-v2.jar`,
91
+ `${base}/net/fabricmc/intermediary/${version}/intermediary-${version}.jar`
92
+ ]);
93
+ }
65
94
  for (const coordinate of yarnCoordinates) {
66
- yarnUrls.push(`${base}/net/fabricmc/yarn/${coordinate}/yarn-${coordinate}-v2.jar`, `${base}/net/fabricmc/yarn/${coordinate}/yarn-${coordinate}.jar`);
95
+ if (yarnParsed) {
96
+ break;
97
+ }
98
+ yarnParsed = await tryUrls([
99
+ `${base}/net/fabricmc/yarn/${coordinate}/yarn-${coordinate}-v2.jar`,
100
+ `${base}/net/fabricmc/yarn/${coordinate}/yarn-${coordinate}.jar`
101
+ ]);
67
102
  }
68
- }
69
- const allUrls = [...intermediaryUrls, ...yarnUrls];
70
- const parsedResults = await Promise.allSettled(allUrls.map(async (url) => {
71
- const downloaded = await downloadToCache(url, defaultDownloadPath(deps.config.cacheDir, url), {
72
- fetchFn: deps.fetchFn,
73
- retries: deps.config.fetchRetries,
74
- timeoutMs: deps.config.fetchTimeoutMs
75
- });
76
- if (!downloaded.ok || !downloaded.path) {
77
- return undefined;
103
+ if (intermediaryParsed && yarnParsed) {
104
+ break;
78
105
  }
79
- return parseTinyFromJar(downloaded.path);
80
- }));
81
- for (const result of parsedResults) {
82
- if (result.status !== "fulfilled" || !result.value) {
106
+ }
107
+ for (const parsed of [intermediaryParsed, yarnParsed]) {
108
+ if (!parsed) {
83
109
  continue;
84
110
  }
85
- for (const [key, index] of result.value.entries()) {
111
+ for (const [key, index] of parsed.entries()) {
86
112
  const existing = merged.get(key);
87
113
  if (!existing) {
88
114
  merged.set(key, index);
@@ -98,7 +124,7 @@ export async function loadTinyPairsFromMaven(deps, version) {
98
124
  return {
99
125
  pairs: merged,
100
126
  warnings,
101
- mappingArtifact: allUrls[0] ?? "maven:none"
127
+ mappingArtifact: attemptedUrls[0] ?? "maven:none"
102
128
  };
103
129
  }
104
130
  //# sourceMappingURL=tiny-maven.js.map
@@ -1,5 +1,5 @@
1
1
  import type { MappingSourcePriority, SourceMapping } from "../types.js";
2
- import type { CandidateAccumulator, DirectionIndex, LoadedGraph, MappingLookupSource, MappingSymbolRecord, MatchRankKey, PairKey, PairRecord } from "./internal-types.js";
2
+ import type { CandidateAccumulator, DirectionIndex, ExactRecordIndex, LoadedGraph, MappingLookupSource, MappingSymbolRecord, MatchRankKey, PairKey, PairRecord } from "./internal-types.js";
3
3
  import { MAX_CANDIDATES } from "./internal-types.js";
4
4
  import type { ClassApiMatrixKind, DescriptorProjection, MappingLookupCandidate, ResolutionCandidate, SymbolQueryInput, SymbolReference } from "./types.js";
5
5
  export type { DescriptorProjection };
@@ -37,10 +37,21 @@ export declare function normalizeDescriptorHint(descriptorHint: string | undefin
37
37
  export declare function applyDisambiguationHints(candidates: MappingLookupCandidate[], disambiguation: {
38
38
  ownerHint?: string;
39
39
  descriptorHint?: string;
40
- } | undefined): MappingLookupCandidate[];
40
+ } | undefined, warnings?: string[]): MappingLookupCandidate[];
41
41
  export declare function projectLookupCandidateDescriptor(candidate: MappingLookupCandidate, sourceDescriptor: string, targetDescriptor: string | undefined): MappingLookupCandidate;
42
42
  export declare function effectiveLoomSearchProjectPath(projectPath: string | undefined): string | undefined;
43
43
  export declare function collectTargetRecords(graph: LoadedGraph, targetMapping: SourceMapping): MappingSymbolRecord[];
44
+ /**
45
+ * Lazily build (and memoize on the graph) an O(1) exact-lookup index for a
46
+ * target namespace. Classes key on their FQCN symbol (owner left empty) and are
47
+ * additionally indexed by simple name for the auto-class short-name path;
48
+ * fields/methods key on `kind|owner|name`.
49
+ */
50
+ export declare function collectExactRecordIndex(graph: LoadedGraph, targetMapping: SourceMapping): ExactRecordIndex;
51
+ export declare function lookupExactClassBySymbol(index: ExactRecordIndex, symbol: string): MappingSymbolRecord[];
52
+ export declare function lookupExactMembersByOwner(index: ExactRecordIndex, owner: string): MappingSymbolRecord[];
53
+ export declare function lookupExactClassBySimpleName(index: ExactRecordIndex, name: string): MappingSymbolRecord[];
54
+ export declare function lookupExactMembers(index: ExactRecordIndex, kind: "field" | "method", owner: string, name: string): MappingSymbolRecord[];
44
55
  export declare function normalizeIncludedKinds(inputKinds: ClassApiMatrixKind[] | undefined): Set<ClassApiMatrixKind>;
45
56
  export declare function inferAmbiguityReasons(candidates: ResolutionCandidate[], usedMojangClientMappings: boolean): string[];
46
57
  export declare function clampCandidateLimit(limit: number | undefined): number;
@@ -376,7 +376,7 @@ export function normalizeDescriptorHint(descriptorHint) {
376
376
  const normalized = descriptorHint?.trim();
377
377
  return normalized || undefined;
378
378
  }
379
- export function applyDisambiguationHints(candidates, disambiguation) {
379
+ export function applyDisambiguationHints(candidates, disambiguation, warnings) {
380
380
  if (!disambiguation || candidates.length <= 1) {
381
381
  return candidates;
382
382
  }
@@ -400,6 +400,12 @@ export function applyDisambiguationHints(candidates, disambiguation) {
400
400
  if (descriptorMatched.length > 0) {
401
401
  filtered = descriptorMatched;
402
402
  }
403
+ else {
404
+ // Candidate descriptors are projected toward the target namespace, so a hint
405
+ // written in another namespace silently matches nothing. Surface that instead
406
+ // of leaving the ambiguity unexplained.
407
+ warnings?.push(`descriptorHint "${descriptorHint}" matched none of the ${filtered.length} candidate descriptor(s); it may be in a different mapping namespace. Hint ignored.`);
408
+ }
403
409
  }
404
410
  return filtered;
405
411
  }
@@ -423,7 +429,59 @@ export function effectiveLoomSearchProjectPath(projectPath) {
423
429
  return normalizeOptionalProjectPath(projectPath) ?? normalizeOptionalProjectPath(process.cwd());
424
430
  }
425
431
  export function collectTargetRecords(graph, targetMapping) {
426
- return [...(graph.recordsByTarget.get(targetMapping) ?? [])];
432
+ return graph.recordsByTarget.get(targetMapping) ?? [];
433
+ }
434
+ function exactRecordKey(kind, owner, name) {
435
+ return `${kind}|${owner}|${name}`;
436
+ }
437
+ /**
438
+ * Lazily build (and memoize on the graph) an O(1) exact-lookup index for a
439
+ * target namespace. Classes key on their FQCN symbol (owner left empty) and are
440
+ * additionally indexed by simple name for the auto-class short-name path;
441
+ * fields/methods key on `kind|owner|name`.
442
+ */
443
+ export function collectExactRecordIndex(graph, targetMapping) {
444
+ const cached = graph.exactRecordIndex.get(targetMapping);
445
+ if (cached) {
446
+ return cached;
447
+ }
448
+ const byKey = new Map();
449
+ const classBySimpleName = new Map();
450
+ const membersByOwner = new Map();
451
+ const push = (map, key, record) => {
452
+ const bucket = map.get(key);
453
+ if (bucket) {
454
+ bucket.push(record);
455
+ }
456
+ else {
457
+ map.set(key, [record]);
458
+ }
459
+ };
460
+ for (const record of collectTargetRecords(graph, targetMapping)) {
461
+ if (record.kind === "class") {
462
+ push(byKey, exactRecordKey("class", "", record.symbol), record);
463
+ push(classBySimpleName, record.name, record);
464
+ }
465
+ else {
466
+ push(byKey, exactRecordKey(record.kind, record.owner ?? "", record.name), record);
467
+ push(membersByOwner, record.owner ?? "", record);
468
+ }
469
+ }
470
+ const index = { byKey, classBySimpleName, membersByOwner };
471
+ graph.exactRecordIndex.set(targetMapping, index);
472
+ return index;
473
+ }
474
+ export function lookupExactClassBySymbol(index, symbol) {
475
+ return index.byKey.get(exactRecordKey("class", "", symbol)) ?? [];
476
+ }
477
+ export function lookupExactMembersByOwner(index, owner) {
478
+ return index.membersByOwner.get(owner) ?? [];
479
+ }
480
+ export function lookupExactClassBySimpleName(index, name) {
481
+ return index.classBySimpleName.get(name) ?? [];
482
+ }
483
+ export function lookupExactMembers(index, kind, owner, name) {
484
+ return index.byKey.get(exactRecordKey(kind, owner, name)) ?? [];
427
485
  }
428
486
  export function normalizeIncludedKinds(inputKinds) {
429
487
  const normalized = new Set();
@@ -55,6 +55,7 @@ export type FindMappingInput = {
55
55
  name: string;
56
56
  owner?: string;
57
57
  descriptor?: string;
58
+ nameMode?: "fqcn" | "auto";
58
59
  signatureMode?: "exact" | "name-only";
59
60
  sourceMapping: SourceMapping;
60
61
  targetMapping: SourceMapping;
@@ -103,6 +104,7 @@ export type ClassApiMatrixInput = {
103
104
  gradleUserHome?: string;
104
105
  includeKinds?: ClassApiMatrixKind[];
105
106
  maxRows?: number;
107
+ cursor?: string;
106
108
  };
107
109
  export type ClassApiMatrixEntry = {
108
110
  symbol: string;
@@ -127,6 +129,10 @@ export type ClassApiMatrixOutput = {
127
129
  rows: ClassApiMatrixRow[];
128
130
  rowCount: number;
129
131
  rowsTruncated?: boolean;
132
+ /** Continuation cursor when more rows remain; pass back as cursor for the next page. */
133
+ nextCursor?: string;
134
+ /** True when a provided cursor was malformed or belonged to a different query and was ignored. */
135
+ cursorIgnored?: boolean;
130
136
  warnings: string[];
131
137
  ambiguousRowCount?: number;
132
138
  };
@@ -14,11 +14,21 @@ export declare class MappingService {
14
14
  private static readonly RESOLUTION_CACHE_TTL_MS;
15
15
  private resolutionCacheHits;
16
16
  private resolutionCacheMisses;
17
+ private classProjectionComputes;
18
+ private apiMatrixRowMaps;
17
19
  get resolutionCacheStats(): {
18
20
  hits: number;
19
21
  misses: number;
20
22
  size: number;
21
23
  };
24
+ /** Test seam: counts genuine class-projection computes (cache misses). */
25
+ get classProjectionStats(): {
26
+ computes: number;
27
+ };
28
+ /** Test seam: counts genuine per-row cross-namespace path walks in getClassApiMatrix. */
29
+ get apiMatrixStats(): {
30
+ rowMaps: number;
31
+ };
22
32
  constructor(config: Config, versionService?: VersionMappingsResolver, fetchFn?: typeof fetch);
23
33
  findMapping(input: FindMappingInput): Promise<FindMappingOutput>;
24
34
  ensureMappingAvailable(input: EnsureMappingAvailableInput): Promise<EnsureMappingAvailableOutput>;
@@ -60,13 +70,27 @@ export declare class MappingService {
60
70
  private buildResolutionCacheKey;
61
71
  private trimResolutionCache;
62
72
  }
73
+ export type ResolvedTinyMapping = {
74
+ path: string;
75
+ coordinate?: string;
76
+ };
63
77
  /**
64
78
  * Resolve and cache a Tiny v2 mapping file for the given Minecraft version.
65
79
  *
80
+ * Intermediary is version-keyed (immutable per release). Yarn is coordinate-keyed:
81
+ * Fabric publishes incrementing yarn builds for the same MC version, so the tiny
82
+ * is cached at `mappings/yarn/${coordinate}.tiny` and the newest coordinate is
83
+ * re-checked once per {@link YARN_METADATA_TTL_MS}. The resolved yarn coordinate
84
+ * is returned so callers can key their own caches on the actual mappings used.
85
+ *
66
86
  * @param version - Minecraft version (e.g. "1.20.4")
67
87
  * @param mapping - "intermediary" or "yarn"
68
88
  * @param cacheDir - The application cache directory
69
89
  * @param fetchFn - Optional fetch implementation for testing
70
- * @returns Path to the extracted Tiny v2 file
90
+ * @param options - forceRefresh bypasses the yarn metadata TTL; now overrides the clock (testing)
91
+ * @returns The extracted Tiny v2 path and, for yarn, the resolved build coordinate
71
92
  */
72
- export declare function resolveTinyMappingFile(version: string, mapping: "intermediary" | "yarn", cacheDir: string, fetchFn?: typeof fetch): Promise<string>;
93
+ export declare function resolveTinyMappingFile(version: string, mapping: "intermediary" | "yarn", cacheDir: string, fetchFn?: typeof fetch, options?: {
94
+ forceRefresh?: boolean;
95
+ now?: () => number;
96
+ }): Promise<ResolvedTinyMapping>;