fix: share plugin runtime helpers

Consolidate shared plugin runtime MIME/schema helpers, preserve canonical runtime behavior, and guard QQBot STT fetches.
This commit is contained in:
Peter Steinberger
2026-05-08 00:28:43 +01:00
committed by GitHub
parent f3c9203631
commit 6a4069dead
127 changed files with 789 additions and 829 deletions

View File

@@ -146,6 +146,36 @@ describe("schema validator", () => {
expectValidationIssue(result, "<root>");
});
it("can isolate caller schemas that reuse the same $id with different shapes", () => {
const first = validateJsonSchemaValue({
cacheKey: "schema-validator.test.same-id.uncached",
schema: {
$id: "https://example.test/shared-schema",
type: "object",
properties: { foo: { type: "string" } },
required: ["foo"],
additionalProperties: false,
},
value: { foo: "ok" },
cache: false,
});
expect(first.ok).toBe(true);
const second = validateJsonSchemaValue({
cacheKey: "schema-validator.test.same-id.uncached",
schema: {
$id: "https://example.test/shared-schema",
type: "object",
properties: { bar: { type: "number" } },
required: ["bar"],
additionalProperties: false,
},
value: { bar: 1 },
cache: false,
});
expect(second.ok).toBe(true);
});
it.each([
{
title: "includes allowed values in enum validation errors",

View File

@@ -20,11 +20,7 @@ type AjvLike = {
};
const ajvSingletons = new Map<"default" | "defaults", AjvLike>();
function getAjv(mode: "default" | "defaults"): AjvLike {
const cached = ajvSingletons.get(mode);
if (cached) {
return cached;
}
function createAjv(mode: "default" | "defaults"): AjvLike {
const ajvModule = require("ajv") as { default?: new (opts?: object) => AjvLike };
const AjvCtor =
typeof ajvModule.default === "function"
@@ -44,6 +40,15 @@ function getAjv(mode: "default" | "defaults"): AjvLike {
return URL.canParse(value);
},
});
return instance;
}
function getAjv(mode: "default" | "defaults"): AjvLike {
const cached = ajvSingletons.get(mode);
if (cached) {
return cached;
}
const instance = createAjv(mode);
ajvSingletons.set(mode, instance);
return instance;
}
@@ -197,7 +202,24 @@ export function validateJsonSchemaValue(params: {
cacheKey: string;
value: unknown;
applyDefaults?: boolean;
cache?: boolean;
}): { ok: true; value: unknown } | { ok: false; errors: JsonSchemaValidationError[] } {
const useCache = params.cache !== false;
if (!useCache) {
const validate = createAjv(params.applyDefaults ? "defaults" : "default").compile(
params.schema,
);
const value =
params.applyDefaults && schemaHasDefaults(params.schema)
? cloneValidationValue(params.value)
: params.value;
const ok = validate(value);
if (ok) {
return { ok: true, value };
}
return { ok: false, errors: formatAjvErrors(validate.errors) };
}
const cacheKey = params.applyDefaults ? `${params.cacheKey}::defaults` : params.cacheKey;
let cached = schemaCache.get(cacheKey);
const schemaFingerprint =