perf(runtime): reduce startup import overhead in logging and schema validation

This commit is contained in:
Peter Steinberger
2026-03-02 18:20:51 +00:00
parent 41c8734afd
commit 82f01d6081
2 changed files with 36 additions and 9 deletions

View File

@@ -1,6 +1,5 @@
import { Chalk } from "chalk"; import { Chalk } from "chalk";
import type { Logger as TsLogger } from "tslog"; import type { Logger as TsLogger } from "tslog";
import { CHAT_CHANNEL_ORDER } from "../channels/registry.js";
import { isVerbose } from "../globals.js"; import { isVerbose } from "../globals.js";
import { defaultRuntime, type RuntimeEnv } from "../runtime.js"; import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
import { clearActiveProgressLine } from "../terminal/progress-line.js"; import { clearActiveProgressLine } from "../terminal/progress-line.js";
@@ -94,7 +93,17 @@ const SUBSYSTEM_COLOR_OVERRIDES: Record<string, (typeof SUBSYSTEM_COLORS)[number
}; };
const SUBSYSTEM_PREFIXES_TO_DROP = ["gateway", "channels", "providers"] as const; const SUBSYSTEM_PREFIXES_TO_DROP = ["gateway", "channels", "providers"] as const;
const SUBSYSTEM_MAX_SEGMENTS = 2; const SUBSYSTEM_MAX_SEGMENTS = 2;
const CHANNEL_SUBSYSTEM_PREFIXES = new Set<string>(CHAT_CHANNEL_ORDER); // Keep local to avoid importing channel registry into hot logging paths.
const CHANNEL_SUBSYSTEM_PREFIXES = new Set<string>([
"telegram",
"whatsapp",
"discord",
"irc",
"googlechat",
"slack",
"signal",
"imessage",
]);
function pickSubsystemColor(color: ChalkInstance, subsystem: string): ChalkInstance { function pickSubsystemColor(color: ChalkInstance, subsystem: string): ChalkInstance {
const override = SUBSYSTEM_COLOR_OVERRIDES[subsystem]; const override = SUBSYSTEM_COLOR_OVERRIDES[subsystem];

View File

@@ -1,10 +1,28 @@
import AjvPkg, { type ErrorObject, type ValidateFunction } from "ajv"; import { createRequire } from "node:module";
import type { ErrorObject, ValidateFunction } from "ajv";
const ajv = new (AjvPkg as unknown as new (opts?: object) => import("ajv").default)({ const require = createRequire(import.meta.url);
allErrors: true, type AjvLike = {
strict: false, compile: (schema: Record<string, unknown>) => ValidateFunction;
removeAdditional: false, };
}); let ajvSingleton: AjvLike | null = null;
function getAjv(): AjvLike {
if (ajvSingleton) {
return ajvSingleton;
}
const ajvModule = require("ajv") as { default?: new (opts?: object) => AjvLike };
const AjvCtor =
typeof ajvModule.default === "function"
? ajvModule.default
: (ajvModule as unknown as new (opts?: object) => AjvLike);
ajvSingleton = new AjvCtor({
allErrors: true,
strict: false,
removeAdditional: false,
});
return ajvSingleton;
}
type CachedValidator = { type CachedValidator = {
validate: ValidateFunction; validate: ValidateFunction;
@@ -31,7 +49,7 @@ export function validateJsonSchemaValue(params: {
}): { ok: true } | { ok: false; errors: string[] } { }): { ok: true } | { ok: false; errors: string[] } {
let cached = schemaCache.get(params.cacheKey); let cached = schemaCache.get(params.cacheKey);
if (!cached || cached.schema !== params.schema) { if (!cached || cached.schema !== params.schema) {
const validate = ajv.compile(params.schema); const validate = getAjv().compile(params.schema);
cached = { validate, schema: params.schema }; cached = { validate, schema: params.schema };
schemaCache.set(params.cacheKey, cached); schemaCache.set(params.cacheKey, cached);
} }