From 82f01d6081c6675475fc92ef2b60782ddcb44203 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 2 Mar 2026 18:20:51 +0000 Subject: [PATCH] perf(runtime): reduce startup import overhead in logging and schema validation --- src/logging/subsystem.ts | 13 +++++++++++-- src/plugins/schema-validator.ts | 32 +++++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/logging/subsystem.ts b/src/logging/subsystem.ts index 32fe853f0..ab73bc0b3 100644 --- a/src/logging/subsystem.ts +++ b/src/logging/subsystem.ts @@ -1,6 +1,5 @@ import { Chalk } from "chalk"; import type { Logger as TsLogger } from "tslog"; -import { CHAT_CHANNEL_ORDER } from "../channels/registry.js"; import { isVerbose } from "../globals.js"; import { defaultRuntime, type RuntimeEnv } from "../runtime.js"; import { clearActiveProgressLine } from "../terminal/progress-line.js"; @@ -94,7 +93,17 @@ const SUBSYSTEM_COLOR_OVERRIDES: Record(CHAT_CHANNEL_ORDER); +// Keep local to avoid importing channel registry into hot logging paths. +const CHANNEL_SUBSYSTEM_PREFIXES = new Set([ + "telegram", + "whatsapp", + "discord", + "irc", + "googlechat", + "slack", + "signal", + "imessage", +]); function pickSubsystemColor(color: ChalkInstance, subsystem: string): ChalkInstance { const override = SUBSYSTEM_COLOR_OVERRIDES[subsystem]; diff --git a/src/plugins/schema-validator.ts b/src/plugins/schema-validator.ts index 1244dfc76..19af4d63c 100644 --- a/src/plugins/schema-validator.ts +++ b/src/plugins/schema-validator.ts @@ -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)({ - allErrors: true, - strict: false, - removeAdditional: false, -}); +const require = createRequire(import.meta.url); +type AjvLike = { + compile: (schema: Record) => ValidateFunction; +}; +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 = { validate: ValidateFunction; @@ -31,7 +49,7 @@ export function validateJsonSchemaValue(params: { }): { ok: true } | { ok: false; errors: string[] } { let cached = schemaCache.get(params.cacheKey); if (!cached || cached.schema !== params.schema) { - const validate = ajv.compile(params.schema); + const validate = getAjv().compile(params.schema); cached = { validate, schema: params.schema }; schemaCache.set(params.cacheKey, cached); }