Skip to content

Commit 96c103d

Browse files
elrrrrrrrclaude
andcommitted
fix(utils): resolve modules from caller paths instead of package context
Use import.meta.resolve(specifier, parentUrl) with each caller-provided path to avoid relying on package manager hoisting behavior. Falls back to resolving from the current module context only after all provided paths have been exhausted. Also remove stale @ts-expect-error comments in tegg mcp-proxy and controller plugins where content-type and koa-compose now ship types. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 5badc83 commit 96c103d

3 files changed

Lines changed: 37 additions & 16 deletions

File tree

packages/utils/src/import.ts

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -343,20 +343,44 @@ export function importResolve(filepath: string, options?: ImportResolveOptions):
343343
});
344344
} else {
345345
if (supportImportMetaResolve) {
346-
try {
347-
moduleFilePath = import.meta.resolve(filepath);
348-
} catch (err) {
349-
debug('[importResolve:error] import.meta.resolve %o => %o, options: %o', filepath, err, options);
350-
throw new ImportResolveError(filepath, paths, err as Error);
351-
}
352-
if (moduleFilePath.startsWith('file://')) {
353-
// resolve will return file:// URL on Linux and MacOS expect on Windows
354-
moduleFilePath = fileURLToPath(moduleFilePath);
346+
// Try resolving from each provided path using import.meta.resolve with parent URL.
347+
// This avoids relying on the package manager hoisting modules to a shared location.
348+
let lastErr: Error | undefined;
349+
for (const p of paths) {
350+
try {
351+
const parentUrl = pathToFileURL(path.join(p, 'index.js')).toString();
352+
let resolved = import.meta.resolve(filepath, parentUrl);
353+
if (resolved.startsWith('file://')) {
354+
resolved = fileURLToPath(resolved);
355+
}
356+
const stat = fs.statSync(resolved, { throwIfNoEntry: false });
357+
if (stat?.isFile()) {
358+
moduleFilePath = resolved;
359+
debug('[importResolve:importMetaResolveFromPaths] %o => %o', filepath, moduleFilePath);
360+
break;
361+
}
362+
} catch (err) {
363+
lastErr = err as Error;
364+
debug('[importResolve:importMetaResolveFromPaths:error] path %o, %o => %o', p, filepath, err);
365+
}
355366
}
356-
debug('[importResolve] import.meta.resolve %o => %o', filepath, moduleFilePath);
357-
const stat = fs.statSync(moduleFilePath, { throwIfNoEntry: false });
358-
if (!stat?.isFile()) {
359-
throw new TypeError(`Cannot find module ${filepath}, because ${moduleFilePath} does not exists`);
367+
// Fall back to resolving from this module's context
368+
if (!moduleFilePath) {
369+
try {
370+
moduleFilePath = import.meta.resolve(filepath);
371+
} catch (err) {
372+
debug('[importResolve:error] import.meta.resolve %o => %o, options: %o', filepath, err, options);
373+
throw new ImportResolveError(filepath, paths, (err ?? lastErr) as Error);
374+
}
375+
if (moduleFilePath.startsWith('file://')) {
376+
// resolve will return file:// URL on Linux and MacOS expect on Windows
377+
moduleFilePath = fileURLToPath(moduleFilePath);
378+
}
379+
debug('[importResolve] import.meta.resolve %o => %o', filepath, moduleFilePath);
380+
const stat = fs.statSync(moduleFilePath, { throwIfNoEntry: false });
381+
if (!stat?.isFile()) {
382+
throw new TypeError(`Cannot find module ${filepath}, because ${moduleFilePath} does not exists`);
383+
}
360384
}
361385
} else {
362386
moduleFilePath = getRequire().resolve(filepath);

tegg/plugin/controller/src/lib/impl/mcp/MCPControllerRegister.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import { isInitializeRequest, isJSONRPCRequest } from '@modelcontextprotocol/sdk
2323
import type { JSONRPCMessage, MessageExtraInfo } from '@modelcontextprotocol/sdk/types.js';
2424
// @ts-expect-error await-event is not typed
2525
import awaitEvent from 'await-event';
26-
// @ts-expect-error content-type is not typed
2726
import contentType from 'content-type';
2827
import type { Application, Context, Router } from 'egg';
2928
import compose from 'koa-compose';

tegg/plugin/mcp-proxy/src/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,10 @@ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/
1313
import awaitEvent from 'await-event';
1414
// @ts-expect-error cluster-client is not typed
1515
import { APIClientBase } from 'cluster-client';
16-
// @ts-expect-error content-type is not typed
1716
import contentType from 'content-type';
1817
import type { Application, Context } from 'egg';
1918
import type { EggLogger } from 'egg';
2019
import { EventSourceParserStream } from 'eventsource-parser/stream';
21-
// @ts-expect-error koa-compose is not typed
2220
import compose from 'koa-compose';
2321
import getRawBody from 'raw-body';
2422

0 commit comments

Comments
 (0)