fix: 修复插件包生产路径发现
This commit is contained in:
parent
1796360506
commit
1508c63e5c
@ -2,13 +2,10 @@ import { Inject, Injectable, Optional } from '@nestjs/common';
|
||||
import { existsSync, statSync } from 'node:fs';
|
||||
import { isAbsolute, relative, resolve, sep } from 'node:path';
|
||||
|
||||
const DEFAULT_BUILTIN_PACKAGE_ROOT = resolve(
|
||||
process.cwd(),
|
||||
'src',
|
||||
'modules',
|
||||
'qqbot',
|
||||
'plugins',
|
||||
);
|
||||
const DEFAULT_BUILTIN_PACKAGE_ROOT_SEGMENTS = [
|
||||
['src', 'modules', 'qqbot', 'plugins'],
|
||||
['dist', 'modules', 'qqbot', 'plugins'],
|
||||
];
|
||||
export const QQBOT_PLUGIN_PACKAGE_CONTROLLED_ROOTS = Symbol(
|
||||
'QQBOT_PLUGIN_PACKAGE_CONTROLLED_ROOTS',
|
||||
);
|
||||
@ -30,7 +27,9 @@ export class QqbotPluginPackagePathPolicyService {
|
||||
controlledRoots?: string[],
|
||||
) {
|
||||
this.controlledRoots = (
|
||||
controlledRoots?.length ? controlledRoots : [DEFAULT_BUILTIN_PACKAGE_ROOT]
|
||||
controlledRoots?.length
|
||||
? controlledRoots
|
||||
: resolveDefaultBuiltinPackageRoots()
|
||||
).map((root) => resolve(root));
|
||||
}
|
||||
|
||||
@ -58,7 +57,7 @@ export class QqbotPluginPackagePathPolicyService {
|
||||
throw new Error('Plugin entry must stay inside the package root');
|
||||
}
|
||||
|
||||
return entryFile;
|
||||
return this.resolveCompiledEntryFile(entryFile);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,4 +94,33 @@ export class QqbotPluginPackagePathPolicyService {
|
||||
isAbsolute(relation)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a manifest entry to the file Node can import in the current runtime.
|
||||
* @param entryFile - Policy-checked entry path declared by `plugin.json`.
|
||||
* @returns The declared file when it exists, otherwise the compiled `.js` sibling for TypeScript entries.
|
||||
*/
|
||||
private resolveCompiledEntryFile(entryFile: string): string {
|
||||
if (existsSync(entryFile)) return entryFile;
|
||||
|
||||
if (entryFile.endsWith('.ts')) {
|
||||
const compiledEntryFile = `${entryFile.slice(0, -3)}.js`;
|
||||
if (existsSync(compiledEntryFile)) {
|
||||
return compiledEntryFile;
|
||||
}
|
||||
}
|
||||
|
||||
return entryFile;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the default built-in package root for source development or production `dist` output.
|
||||
* @returns A single preferred controlled root so package discovery does not duplicate source and dist manifests.
|
||||
*/
|
||||
function resolveDefaultBuiltinPackageRoots(): string[] {
|
||||
const candidates = DEFAULT_BUILTIN_PACKAGE_ROOT_SEGMENTS.map((segments) =>
|
||||
resolve(process.cwd(), ...segments),
|
||||
);
|
||||
return [candidates.find((candidate) => existsSync(candidate)) || candidates[0]];
|
||||
}
|
||||
|
||||
@ -136,6 +136,74 @@ describe('QqbotPluginPackageSourceService', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('resolves TypeScript manifest entries to compiled JavaScript files in dist packages', async () => {
|
||||
const packageRoot = join(tempRoot, 'compiled-entry');
|
||||
mkdirSync(join(packageRoot, 'src'), { recursive: true });
|
||||
writeFileSync(
|
||||
join(packageRoot, 'plugin.json'),
|
||||
JSON.stringify({
|
||||
key: 'compiled-entry',
|
||||
name: 'Compiled Entry',
|
||||
version: '1.0.0',
|
||||
entry: 'src/index.ts',
|
||||
runtime: {
|
||||
workerType: 'thread',
|
||||
timeoutMs: 5000,
|
||||
memoryMb: 128,
|
||||
maxConcurrency: 1,
|
||||
},
|
||||
operations: [],
|
||||
}),
|
||||
'utf8',
|
||||
);
|
||||
writeFileSync(
|
||||
join(packageRoot, 'src', 'index.js'),
|
||||
'module.exports = { createPlugin() {} };',
|
||||
'utf8',
|
||||
);
|
||||
|
||||
const source = new QqbotPluginPackageSourceService(
|
||||
new QqbotPluginPackagePathPolicyService([tempRoot]),
|
||||
);
|
||||
|
||||
await expect(source.discoverPackages()).resolves.toEqual([
|
||||
expect.objectContaining({
|
||||
entry: 'src/index.ts',
|
||||
entryFile: join(packageRoot, 'src', 'index.js'),
|
||||
pluginKey: 'compiled-entry',
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('discovers the default built-in plugin root from production dist output', async () => {
|
||||
const previousCwd = process.cwd();
|
||||
const productionRoot = join(tempRoot, 'production-app');
|
||||
const distPluginRoot = join(
|
||||
productionRoot,
|
||||
'dist',
|
||||
'modules',
|
||||
'qqbot',
|
||||
'plugins',
|
||||
);
|
||||
mkdirSync(distPluginRoot, { recursive: true });
|
||||
|
||||
try {
|
||||
process.chdir(productionRoot);
|
||||
jest.resetModules();
|
||||
const {
|
||||
QqbotPluginPackagePathPolicyService: RuntimePathPolicyService,
|
||||
} = await import(
|
||||
'../../../../src/modules/qqbot/plugin-platform/infrastructure/integration/package/plugin-package-path-policy.service'
|
||||
);
|
||||
const pathPolicy = new RuntimePathPolicyService();
|
||||
|
||||
expect(pathPolicy.listExistingRoots()).toEqual([distPluginRoot]);
|
||||
} finally {
|
||||
process.chdir(previousCwd);
|
||||
jest.resetModules();
|
||||
}
|
||||
});
|
||||
|
||||
it('does not keep platform-side manifest transfer shims', () => {
|
||||
const source = readFileSync(
|
||||
join(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user