import { existsSync, readdirSync, readFileSync } from "node:fs" ;
import path from "node:path" ;
import { fileURLToPath } from "node:url" ;
import { describe, expect, it } from "vitest" ;
import { bundledPluginFile } from "../../../test/helpers/bundled-plugin-paths.js" ;
const thisFilePath = fileURLToPath(import .meta.url);
const thisDir = path.dirname(thisFilePath);
const repoRoot = path.resolve(thisDir, "../../.." );
const loadConfigPattern = /\b(?:loadConfig|config\.loadConfig)\s*\(/;
function toPosix(relativePath: string): string {
return relativePath.split(path.sep).join("/" );
}
function readRepoFile(relativePath: string): string {
const absolute = path.join(repoRoot, relativePath);
return readFileSync(absolute, "utf8" );
}
function listCoreOutboundEntryFiles(): string[] {
const outboundDir = path.join(repoRoot, "src/channels/plugins/outbound" );
return readdirSync(outboundDir)
.filter((name) => name.endsWith(".ts" ) && !name.endsWith(".test.ts" ))
.map((name) => toPosix(path.join("src/channels/plugins/outbound" , name)))
.toSorted();
}
function listExtensionFiles(): {
adapterEntrypoints: string[];
inlineChannelEntrypoints: string[];
} {
const extensionsRoot = path.join(repoRoot, "extensions" );
const adapterEntrypoints: string[] = [];
const inlineChannelEntrypoints: string[] = [];
for (const entry of readdirSync(extensionsRoot, { withFileTypes: true })) {
if (!entry.isDirectory()) {
continue ;
}
const srcDir = path.join(extensionsRoot, entry.name, "src" );
const outboundPath = path.join(srcDir, "outbound.ts" );
if (existsSync(outboundPath)) {
adapterEntrypoints.push(toPosix(path.join("extensions" , entry.name, "src/outbound.ts" )));
}
const channelPath = path.join(srcDir, "channel.ts" );
if (!existsSync(channelPath)) {
continue ;
}
const source = readFileSync(channelPath, "utf8" );
if (/\boutbound\s*:\s*\{/.test(source)) {
inlineChannelEntrypoints.push(toPosix(path.join("extensions" , entry.name, "src/channel.ts" )));
}
}
return {
adapterEntrypoints: adapterEntrypoints.toSorted(),
inlineChannelEntrypoints: inlineChannelEntrypoints.toSorted(),
};
}
function listHighRiskRuntimeCfgFiles(): string[] {
return [
bundledPluginFile("telegram" , "src/action-runtime.ts" ),
bundledPluginFile("discord" , "src/monitor/reply-delivery.ts" ),
bundledPluginFile("discord" , "src/monitor/thread-bindings.discord-api.ts" ),
bundledPluginFile("discord" , "src/monitor/thread-bindings.manager.ts" ),
];
}
function extractOutboundBlock(source: string, file: string): string {
const outboundKeyIndex = source.indexOf("outbound:" );
expect(outboundKeyIndex, `${file} should define outbound:`).toBeGreaterThanOrEqual(0 );
const braceStart = source.indexOf("{" , outboundKeyIndex);
expect(braceStart, `${file} should define outbound object`).toBeGreaterThanOrEqual(0 );
let depth = 0 ;
let state: "code" | "single" | "double" | "template" | "lineComment" | "blockComment" = "code" ;
for (let i = braceStart; i < source.length; i += 1 ) {
const current = source[i];
const next = source[i + 1 ];
if (state === "lineComment" ) {
if (current === "\n" ) {
state = "code" ;
}
continue ;
}
if (state === "blockComment" ) {
if (current === "*" && next === "/" ) {
state = "code" ;
i += 1 ;
}
continue ;
}
if (state === "single" ) {
if (current === "\\" && next) {
i += 1 ;
continue ;
}
if (current === "'" ) {
state = "code" ;
}
continue ;
}
if (state === "double" ) {
if (current === "\\" && next) {
i += 1 ;
continue ;
}
if (current === '"' ) {
state = "code" ;
}
continue ;
}
if (state === "template" ) {
if (current === "\\" && next) {
i += 1 ;
continue ;
}
if (current === "`" ) {
state = "code" ;
}
continue ;
}
if (current === "/" && next === "/" ) {
state = "lineComment" ;
i += 1 ;
continue ;
}
if (current === "/" && next === "*" ) {
state = "blockComment" ;
i += 1 ;
continue ;
}
if (current === "'" ) {
state = "single" ;
continue ;
}
if (current === '"' ) {
state = "double" ;
continue ;
}
if (current === "`" ) {
state = "template" ;
continue ;
}
if (current === "{" ) {
depth += 1 ;
continue ;
}
if (current === "}" ) {
depth -= 1 ;
if (depth === 0 ) {
return source.slice(braceStart, i + 1 );
}
}
}
throw new Error(`Unable to parse outbound block in ${file}`);
}
describe("outbound cfg-threading guard" , () => {
it("keeps outbound adapter entrypoints free of loadConfig calls" , () => {
const coreAdapterFiles = listCoreOutboundEntryFiles();
const extensionAdapterFiles = listExtensionFiles().adapterEntrypoints;
const adapterFiles = [...coreAdapterFiles, ...extensionAdapterFiles];
for (const file of adapterFiles) {
const source = readRepoFile(file);
expect(source, `${file} must not call loadConfig in outbound entrypoint`).not.toMatch(
loadConfigPattern,
);
}
});
it("keeps inline channel outbound blocks free of loadConfig calls" , () => {
const inlineFiles = listExtensionFiles().inlineChannelEntrypoints;
for (const file of inlineFiles) {
const source = readRepoFile(file);
const outboundBlock = extractOutboundBlock(source, file);
expect(outboundBlock, `${file} outbound block must not call loadConfig`).not.toMatch(
loadConfigPattern,
);
}
});
it("keeps high-risk runtime delivery paths free of loadConfig calls" , () => {
const runtimeFiles = listHighRiskRuntimeCfgFiles();
for (const file of runtimeFiles) {
const source = readRepoFile(file);
expect(source, `${file} must not call loadConfig`).not.toMatch(loadConfigPattern);
}
});
});
Messung V0.5 in Prozent C=100 H=90 G=95
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland