@adhisang/minecraft-modding-mcp 1.2.1 → 2.1.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 (51) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +184 -64
  3. package/dist/cli.js +31 -4
  4. package/dist/compat-stdio-transport.d.ts +2 -7
  5. package/dist/compat-stdio-transport.js +12 -154
  6. package/dist/index.js +537 -202
  7. package/dist/json-rpc-framing.d.ts +22 -0
  8. package/dist/json-rpc-framing.js +168 -0
  9. package/dist/mapping-pipeline-service.d.ts +1 -1
  10. package/dist/mapping-pipeline-service.js +13 -5
  11. package/dist/mapping-service.d.ts +12 -4
  12. package/dist/mapping-service.js +222 -105
  13. package/dist/mcp-helpers.d.ts +10 -2
  14. package/dist/mcp-helpers.js +59 -5
  15. package/dist/minecraft-explorer-service.d.ts +1 -2
  16. package/dist/minecraft-explorer-service.js +120 -24
  17. package/dist/mixin-validator.d.ts +24 -2
  18. package/dist/mixin-validator.js +228 -103
  19. package/dist/mod-decompile-service.d.ts +5 -0
  20. package/dist/mod-decompile-service.js +40 -5
  21. package/dist/mod-remap-service.js +142 -30
  22. package/dist/mojang-tiny-mapping-service.js +26 -26
  23. package/dist/path-resolver.js +41 -4
  24. package/dist/registry-service.d.ts +10 -1
  25. package/dist/registry-service.js +154 -22
  26. package/dist/resources.js +7 -7
  27. package/dist/search-hit-accumulator.d.ts +0 -3
  28. package/dist/search-hit-accumulator.js +27 -6
  29. package/dist/source-jar-reader.js +16 -2
  30. package/dist/source-resolver.d.ts +1 -0
  31. package/dist/source-resolver.js +93 -2
  32. package/dist/source-service.d.ts +76 -47
  33. package/dist/source-service.js +1344 -763
  34. package/dist/stdio-supervisor.d.ts +46 -0
  35. package/dist/stdio-supervisor.js +349 -0
  36. package/dist/storage/files-repo.d.ts +3 -0
  37. package/dist/storage/files-repo.js +66 -1
  38. package/dist/storage/migrations.d.ts +1 -1
  39. package/dist/storage/migrations.js +6 -2
  40. package/dist/storage/schema.d.ts +1 -0
  41. package/dist/storage/schema.js +7 -0
  42. package/dist/symbols/symbol-extractor.js +6 -4
  43. package/dist/tool-execution-gate.d.ts +15 -0
  44. package/dist/tool-execution-gate.js +58 -0
  45. package/dist/tool-input.d.ts +6 -0
  46. package/dist/tool-input.js +64 -0
  47. package/dist/types.d.ts +1 -1
  48. package/dist/version-diff-service.js +10 -5
  49. package/dist/version-service.js +7 -2
  50. package/dist/workspace-mapping-service.js +12 -0
  51. package/package.json +4 -1
@@ -1,19 +1,20 @@
1
1
  import { createHash } from "node:crypto";
2
- import { existsSync, mkdirSync, statSync, rmSync } from "node:fs";
2
+ import { copyFileSync, existsSync, mkdirSync, rmSync, statSync } from "node:fs";
3
3
  import { dirname, join } from "node:path";
4
4
  import { tmpdir } from "node:os";
5
- import { createError, ERROR_CODES } from "./errors.js";
5
+ import { createError, ERROR_CODES, isAppError } from "./errors.js";
6
6
  import { log } from "./logger.js";
7
7
  import { resolveTinyMappingFile } from "./mapping-service.js";
8
8
  import { resolveMojangTinyFile } from "./mojang-tiny-mapping-service.js";
9
9
  import { analyzeModJar } from "./mod-analyzer.js";
10
10
  import { normalizePathForHost } from "./path-converter.js";
11
+ import { listJarEntries, readJarEntryAsBuffer } from "./source-jar-reader.js";
11
12
  import { remapJar } from "./tiny-remapper-service.js";
12
13
  import { resolveTinyRemapperJar } from "./tiny-remapper-resolver.js";
13
14
  function normalizeTargetNamespace(target) {
14
15
  return target === "yarn" ? "yarn" : "mojang";
15
16
  }
16
- function sourceNamespaceForLoader(loader) {
17
+ function defaultSourceNamespaceForLoader(loader) {
17
18
  if (loader === "fabric" || loader === "quilt") {
18
19
  return "intermediary";
19
20
  }
@@ -35,6 +36,81 @@ function extractMinecraftVersion(dependencies) {
35
36
  const match = mcDep.versionRange.match(/(\d+\.\d+(?:\.\d+)?)/);
36
37
  return match?.[1];
37
38
  }
39
+ function countMatches(input, pattern) {
40
+ const flags = pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`;
41
+ const globalPattern = new RegExp(pattern.source, flags);
42
+ let count = 0;
43
+ while (globalPattern.exec(input)) {
44
+ count += 1;
45
+ }
46
+ return count;
47
+ }
48
+ async function detectFabricLikeInputNamespace(inputJar) {
49
+ const warnings = [];
50
+ const classEntries = (await listJarEntries(inputJar))
51
+ .filter((entry) => entry.endsWith(".class"))
52
+ .slice(0, 24);
53
+ if (classEntries.length === 0) {
54
+ warnings.push("Could not inspect class entries to detect input mapping; assuming intermediary.");
55
+ return {
56
+ fromNamespace: "intermediary",
57
+ warnings
58
+ };
59
+ }
60
+ let mojangScore = 0;
61
+ let intermediaryScore = 0;
62
+ for (const entry of classEntries) {
63
+ let text = "";
64
+ try {
65
+ text = (await readJarEntryAsBuffer(inputJar, entry)).toString("latin1");
66
+ }
67
+ catch {
68
+ continue;
69
+ }
70
+ mojangScore += countMatches(text, /net\/minecraft\/(?:advancements|client|commands|core|data|gametest|nbt|network|recipe|resources|server|sounds|stats|tags|util|world)\//g) * 3;
71
+ intermediaryScore += countMatches(text, /net\/minecraft\/class_\d+/g) * 3;
72
+ intermediaryScore += countMatches(text, /\b(?:method|field)_\d+\b/g);
73
+ }
74
+ if (mojangScore > intermediaryScore && mojangScore > 0) {
75
+ return {
76
+ fromNamespace: "mojang",
77
+ warnings
78
+ };
79
+ }
80
+ if (intermediaryScore > mojangScore && intermediaryScore > 0) {
81
+ return {
82
+ fromNamespace: "intermediary",
83
+ warnings
84
+ };
85
+ }
86
+ warnings.push("Could not confidently detect whether the input jar uses intermediary or mojang names; assuming intermediary.");
87
+ return {
88
+ fromNamespace: "intermediary",
89
+ warnings
90
+ };
91
+ }
92
+ async function detectInputNamespaceForLoader(inputJar, loader) {
93
+ if (loader === "fabric" || loader === "quilt") {
94
+ return detectFabricLikeInputNamespace(inputJar);
95
+ }
96
+ return {
97
+ fromNamespace: defaultSourceNamespaceForLoader(loader),
98
+ warnings: []
99
+ };
100
+ }
101
+ function resolveOutputJarPath(input, normalizedInput, modId, modVersion) {
102
+ const defaultOutputName = `${modId ?? "mod"}-${modVersion ?? "0"}-${input.targetMapping}.jar`;
103
+ return input.outputJar
104
+ ? normalizePathForHost(input.outputJar, undefined, "outputJar")
105
+ : join(dirname(normalizedInput), defaultOutputName);
106
+ }
107
+ function copyJarToDestination(sourceJar, destinationJar) {
108
+ if (sourceJar === destinationJar) {
109
+ return;
110
+ }
111
+ mkdirSync(dirname(destinationJar), { recursive: true });
112
+ copyFileSync(sourceJar, destinationJar);
113
+ }
38
114
  function buildCacheKey(inputJar, fromNamespace, targetNamespace, mcVersion) {
39
115
  const stat = statSync(inputJar, { throwIfNoEntry: false });
40
116
  const signature = stat ? `${stat.mtimeMs}:${stat.size}` : "unknown";
@@ -71,7 +147,9 @@ export async function remapModJar(input, config) {
71
147
  details: { inputJar: normalizedInput }
72
148
  });
73
149
  }
74
- const fromNamespace = sourceNamespaceForLoader(analysis.loader);
150
+ const namespaceDetection = await detectInputNamespaceForLoader(normalizedInput, analysis.loader);
151
+ warnings.push(...namespaceDetection.warnings);
152
+ const fromNamespace = namespaceDetection.fromNamespace;
75
153
  // 3. Determine MC version
76
154
  const mcVersion = input.mcVersion ?? extractMinecraftVersion(analysis.dependencies);
77
155
  if (!mcVersion) {
@@ -85,21 +163,32 @@ export async function remapModJar(input, config) {
85
163
  }
86
164
  });
87
165
  }
166
+ const outputJar = resolveOutputJarPath(input, normalizedInput, analysis.modId, analysis.modVersion);
88
167
  // 4. Check cache after mapping context is known
89
168
  const cacheKey = buildCacheKey(normalizedInput, fromNamespace, resolvedTargetNamespace, mcVersion);
90
169
  const cacheDir = join(config.cacheDir, "remapped-mods");
91
170
  mkdirSync(cacheDir, { recursive: true });
92
171
  const cachedOutput = join(cacheDir, `${cacheKey}.jar`);
93
172
  if (existsSync(cachedOutput)) {
94
- const outputJar = input.outputJar
95
- ? normalizePathForHost(input.outputJar, undefined, "outputJar")
173
+ const cacheHitOutputJar = input.outputJar
174
+ ? outputJar
96
175
  : cachedOutput;
97
- if (outputJar !== cachedOutput) {
98
- const { copyFileSync } = await import("node:fs");
99
- mkdirSync(dirname(outputJar), { recursive: true });
100
- copyFileSync(cachedOutput, outputJar);
101
- }
102
- log("info", "remap.cache-hit", { inputJar: normalizedInput, outputJar });
176
+ copyJarToDestination(cachedOutput, cacheHitOutputJar);
177
+ log("info", "remap.cache-hit", { inputJar: normalizedInput, outputJar: cacheHitOutputJar });
178
+ return {
179
+ outputJar: cacheHitOutputJar,
180
+ mcVersion,
181
+ fromMapping: fromNamespace,
182
+ targetMapping: input.targetMapping,
183
+ resolvedTargetNamespace,
184
+ durationMs: Date.now() - startedAt,
185
+ warnings: [...warnings, "Result served from cache."]
186
+ };
187
+ }
188
+ if (fromNamespace === resolvedTargetNamespace) {
189
+ copyJarToDestination(normalizedInput, outputJar);
190
+ copyJarToDestination(normalizedInput, cachedOutput);
191
+ warnings.push(`Input JAR already uses ${fromNamespace} names; output is a copy of the input JAR.`);
103
192
  return {
104
193
  outputJar,
105
194
  mcVersion,
@@ -107,9 +196,23 @@ export async function remapModJar(input, config) {
107
196
  targetMapping: input.targetMapping,
108
197
  resolvedTargetNamespace,
109
198
  durationMs: Date.now() - startedAt,
110
- warnings: ["Result served from cache."]
199
+ warnings
111
200
  };
112
201
  }
202
+ if (fromNamespace === "mojang" && resolvedTargetNamespace === "yarn") {
203
+ throw createError({
204
+ code: ERROR_CODES.REMAP_FAILED,
205
+ message: "Mojang-mapped Fabric/Quilt input jars cannot be remapped to yarn with the available mapping files.",
206
+ details: {
207
+ inputJar: normalizedInput,
208
+ mcVersion,
209
+ fromMapping: fromNamespace,
210
+ targetMapping: input.targetMapping,
211
+ resolvedTargetNamespace,
212
+ nextAction: 'Use targetMapping="mojang" for Mojang-mapped inputs, or rebuild the mod against intermediary mappings before requesting yarn output.'
213
+ }
214
+ });
215
+ }
113
216
  // 5. Resolve tiny-remapper
114
217
  const tinyRemapperJar = await resolveTinyRemapperJar(config.cacheDir, config.tinyRemapperJarPath);
115
218
  // 6. Resolve mapping file and remap
@@ -125,30 +228,39 @@ export async function remapModJar(input, config) {
125
228
  toNamespace = "mojang";
126
229
  warnings.push(...mojangTiny.warnings);
127
230
  }
128
- // 7. Determine output path
129
- const modId = analysis.modId ?? "mod";
130
- const modVersion = analysis.modVersion ?? "0";
131
- const defaultOutputName = `${modId}-${modVersion}-${input.targetMapping}.jar`;
132
- const outputJar = input.outputJar
133
- ? normalizePathForHost(input.outputJar, undefined, "outputJar")
134
- : join(dirname(normalizedInput), defaultOutputName);
135
231
  mkdirSync(dirname(outputJar), { recursive: true });
136
232
  // 8. Use temporary directory for intermediate work
137
233
  const tempDir = join(tmpdir(), `mcp-remap-${cacheKey.slice(0, 12)}`);
138
234
  mkdirSync(tempDir, { recursive: true });
139
235
  try {
140
236
  const tempOutput = join(tempDir, "remapped.jar");
141
- await remapJar(tinyRemapperJar, {
142
- inputJar: normalizedInput,
143
- outputJar: tempOutput,
144
- mappingsFile,
145
- fromNamespace,
146
- toNamespace,
147
- timeoutMs: config.remapTimeoutMs,
148
- maxMemoryMb: config.remapMaxMemoryMb
149
- });
237
+ try {
238
+ await remapJar(tinyRemapperJar, {
239
+ inputJar: normalizedInput,
240
+ outputJar: tempOutput,
241
+ mappingsFile,
242
+ fromNamespace,
243
+ toNamespace,
244
+ timeoutMs: config.remapTimeoutMs,
245
+ maxMemoryMb: config.remapMaxMemoryMb
246
+ });
247
+ }
248
+ catch (caughtError) {
249
+ if (isAppError(caughtError)) {
250
+ throw createError({
251
+ code: caughtError.code,
252
+ message: caughtError.message,
253
+ details: {
254
+ ...(caughtError.details ?? {}),
255
+ fromMapping: fromNamespace,
256
+ targetMapping: input.targetMapping,
257
+ resolvedTargetNamespace
258
+ }
259
+ });
260
+ }
261
+ throw caughtError;
262
+ }
150
263
  // Copy to final destination and cache
151
- const { copyFileSync } = await import("node:fs");
152
264
  copyFileSync(tempOutput, outputJar);
153
265
  if (outputJar !== cachedOutput) {
154
266
  mkdirSync(dirname(cachedOutput), { recursive: true });
@@ -30,13 +30,13 @@ function parseProguardMappings(text) {
30
30
  const classMatch = /^(.+?)\s+->\s+(.+):$/.exec(line);
31
31
  if (classMatch) {
32
32
  const mojangFqn = normalizeFqn(classMatch[1] ?? "");
33
- const officialInternal = normalizeInternalName(classMatch[2] ?? "");
34
- if (!mojangFqn || !officialInternal) {
33
+ const obfuscatedInternal = normalizeInternalName(classMatch[2] ?? "");
34
+ if (!mojangFqn || !obfuscatedInternal) {
35
35
  currentClass = undefined;
36
36
  continue;
37
37
  }
38
38
  currentClass = mojangFqn;
39
- classes.push({ mojangFqn, officialInternal });
39
+ classes.push({ mojangFqn, obfuscatedInternal });
40
40
  continue;
41
41
  }
42
42
  if (!currentClass) {
@@ -47,14 +47,14 @@ function parseProguardMappings(text) {
47
47
  continue;
48
48
  }
49
49
  const leftRaw = stripLineInfo(line.slice(0, arrowIndex));
50
- const officialName = line.slice(arrowIndex + 4).trim();
51
- if (!leftRaw || !officialName) {
50
+ const obfuscatedName = line.slice(arrowIndex + 4).trim();
51
+ if (!leftRaw || !obfuscatedName) {
52
52
  continue;
53
53
  }
54
54
  members.push({
55
55
  ownerMojangFqn: currentClass,
56
56
  leftSignature: leftRaw,
57
- officialName
57
+ obfuscatedName
58
58
  });
59
59
  }
60
60
  return { classes, members };
@@ -164,8 +164,8 @@ function normalizeMemberMappings(rawMappings, classMap, warnings) {
164
164
  const seen = new Set();
165
165
  for (const mapping of rawMappings) {
166
166
  for (const member of mapping.members) {
167
- const ownerOfficial = classMap.get(normalizeFqn(member.ownerMojangFqn));
168
- if (!ownerOfficial) {
167
+ const ownerObfuscated = classMap.get(normalizeFqn(member.ownerMojangFqn));
168
+ if (!ownerObfuscated) {
169
169
  warnings.push(`Skipping member mapping for "${member.ownerMojangFqn}" because class mapping is missing.`);
170
170
  continue;
171
171
  }
@@ -183,7 +183,7 @@ function normalizeMemberMappings(rawMappings, classMap, warnings) {
183
183
  record = {
184
184
  kind: "m",
185
185
  descriptor,
186
- officialName: member.officialName,
186
+ obfuscatedName: member.obfuscatedName,
187
187
  mojangName
188
188
  };
189
189
  }
@@ -203,19 +203,19 @@ function normalizeMemberMappings(rawMappings, classMap, warnings) {
203
203
  record = {
204
204
  kind: "f",
205
205
  descriptor,
206
- officialName: member.officialName,
206
+ obfuscatedName: member.obfuscatedName,
207
207
  mojangName
208
208
  };
209
209
  }
210
- const dedupeKey = `${ownerOfficial}|${record.kind}|${record.officialName}|` +
210
+ const dedupeKey = `${ownerObfuscated}|${record.kind}|${record.obfuscatedName}|` +
211
211
  `${record.mojangName}|${record.descriptor}`;
212
212
  if (seen.has(dedupeKey)) {
213
213
  continue;
214
214
  }
215
215
  seen.add(dedupeKey);
216
- const list = membersByOwner.get(ownerOfficial) ?? [];
216
+ const list = membersByOwner.get(ownerObfuscated) ?? [];
217
217
  list.push(record);
218
- membersByOwner.set(ownerOfficial, list);
218
+ membersByOwner.set(ownerObfuscated, list);
219
219
  }
220
220
  }
221
221
  return membersByOwner;
@@ -225,38 +225,38 @@ function mergeClasses(rawMappings, warnings) {
225
225
  for (const mapping of rawMappings) {
226
226
  for (const clazz of mapping.classes) {
227
227
  const mojang = normalizeFqn(clazz.mojangFqn);
228
- const official = normalizeInternalName(clazz.officialInternal);
228
+ const obfuscated = normalizeInternalName(clazz.obfuscatedInternal);
229
229
  const existing = classMap.get(mojang);
230
- if (existing && existing !== official) {
231
- warnings.push(`Conflicting class mapping for "${mojang}" (${existing} vs ${official}); keeping first.`);
230
+ if (existing && existing !== obfuscated) {
231
+ warnings.push(`Conflicting class mapping for "${mojang}" (${existing} vs ${obfuscated}); keeping first.`);
232
232
  continue;
233
233
  }
234
- classMap.set(mojang, official);
234
+ classMap.set(mojang, obfuscated);
235
235
  }
236
236
  }
237
237
  return classMap;
238
238
  }
239
239
  function renderTinyV2(classMap, membersByOwner) {
240
240
  const classEntries = [...classMap.entries()]
241
- .map(([mojangFqn, officialInternal]) => ({
242
- officialInternal,
241
+ .map(([mojangFqn, obfuscatedInternal]) => ({
242
+ obfuscatedInternal,
243
243
  mojangInternal: mojangFqn.replace(/\./g, "/")
244
244
  }))
245
- .sort((left, right) => left.officialInternal.localeCompare(right.officialInternal));
246
- const lines = ["tiny\t2\t0\tofficial\tmojang"];
245
+ .sort((left, right) => left.obfuscatedInternal.localeCompare(right.obfuscatedInternal));
246
+ const lines = ["tiny\t2\t0\tobfuscated\tmojang"];
247
247
  for (const entry of classEntries) {
248
- lines.push(`c\t${entry.officialInternal}\t${entry.mojangInternal}`);
249
- const members = [...(membersByOwner.get(entry.officialInternal) ?? [])].sort((left, right) => {
248
+ lines.push(`c\t${entry.obfuscatedInternal}\t${entry.mojangInternal}`);
249
+ const members = [...(membersByOwner.get(entry.obfuscatedInternal) ?? [])].sort((left, right) => {
250
250
  if (left.kind !== right.kind) {
251
251
  return left.kind.localeCompare(right.kind);
252
252
  }
253
- if (left.officialName !== right.officialName) {
254
- return left.officialName.localeCompare(right.officialName);
253
+ if (left.obfuscatedName !== right.obfuscatedName) {
254
+ return left.obfuscatedName.localeCompare(right.obfuscatedName);
255
255
  }
256
256
  return left.descriptor.localeCompare(right.descriptor);
257
257
  });
258
258
  for (const member of members) {
259
- lines.push(`\t${member.kind}\t${member.descriptor}\t${member.officialName}\t${member.mojangName}`);
259
+ lines.push(`\t${member.kind}\t${member.descriptor}\t${member.obfuscatedName}\t${member.mojangName}`);
260
260
  }
261
261
  }
262
262
  return `${lines.join("\n")}\n`;
@@ -2,12 +2,35 @@ import { realpathSync, statSync } from "node:fs";
2
2
  import { extname, resolve } from "node:path";
3
3
  import { createHash } from "node:crypto";
4
4
  import { normalizePathForHost } from "./path-converter.js";
5
- import { createError, ERROR_CODES } from "./errors.js";
5
+ import { createError, ERROR_CODES, isAppError } from "./errors.js";
6
6
  const INVALID_ENTRY = /(^|\/|\\)\.\.(\/|\\|$)/;
7
7
  export function normalizeJarPath(jarPath) {
8
8
  const normalizedInput = normalizePathForHost(jarPath, undefined, "jarPath");
9
9
  const absolute = resolve(normalizedInput);
10
- const stats = statSync(absolute);
10
+ let stats;
11
+ try {
12
+ stats = statSync(absolute, { throwIfNoEntry: false });
13
+ }
14
+ catch (cause) {
15
+ if (isAppError(cause)) {
16
+ throw cause;
17
+ }
18
+ throw createError({
19
+ code: ERROR_CODES.JAR_NOT_FOUND,
20
+ message: `Could not access jar "${normalizedInput}".`,
21
+ details: {
22
+ jarPath: normalizedInput,
23
+ reason: cause instanceof Error ? cause.message : String(cause)
24
+ }
25
+ });
26
+ }
27
+ if (!stats) {
28
+ throw createError({
29
+ code: ERROR_CODES.JAR_NOT_FOUND,
30
+ message: `Jar not found: "${normalizedInput}".`,
31
+ details: { jarPath: normalizedInput }
32
+ });
33
+ }
11
34
  if (!stats.isFile()) {
12
35
  throw createError({
13
36
  code: ERROR_CODES.JAR_NOT_FOUND,
@@ -22,8 +45,22 @@ export function normalizeJarPath(jarPath) {
22
45
  details: { jarPath: normalizedInput }
23
46
  });
24
47
  }
25
- const resolved = realpathSync(absolute);
26
- return resolved;
48
+ try {
49
+ return realpathSync(absolute);
50
+ }
51
+ catch (cause) {
52
+ if (isAppError(cause)) {
53
+ throw cause;
54
+ }
55
+ throw createError({
56
+ code: ERROR_CODES.JAR_NOT_FOUND,
57
+ message: `Could not resolve jar "${normalizedInput}".`,
58
+ details: {
59
+ jarPath: normalizedInput,
60
+ reason: cause instanceof Error ? cause.message : String(cause)
61
+ }
62
+ });
63
+ }
27
64
  }
28
65
  export function resolveJarPathWithSymlinkCheck(jarPath) {
29
66
  const resolvedPath = normalizeJarPath(jarPath);
@@ -3,6 +3,8 @@ import type { Config } from "./types.js";
3
3
  export type GetRegistryDataInput = {
4
4
  version: string;
5
5
  registry?: string;
6
+ includeData?: boolean;
7
+ maxEntriesPerRegistry?: number;
6
8
  };
7
9
  export type RegistryEntry = {
8
10
  protocol_id: number;
@@ -15,8 +17,11 @@ export type GetRegistryDataOutput = {
15
17
  version: string;
16
18
  registry?: string;
17
19
  registries?: string[];
18
- data: Record<string, RegistryData> | RegistryData;
20
+ data?: Record<string, RegistryData> | RegistryData;
19
21
  entryCount: number;
22
+ returnedEntryCount?: number;
23
+ registryEntryCounts?: Record<string, number>;
24
+ dataTruncated?: boolean;
20
25
  warnings: string[];
21
26
  };
22
27
  export declare class RegistryService {
@@ -26,4 +31,8 @@ export declare class RegistryService {
26
31
  constructor(config: Config, versionService: VersionService);
27
32
  getRegistryData(input: GetRegistryDataInput): Promise<GetRegistryDataOutput>;
28
33
  private loadRegistries;
34
+ private loadExistingRegistries;
35
+ private readRegistryFileOrThrow;
36
+ private isInvalidRegistrySnapshot;
37
+ private cacheRegistries;
29
38
  }