feat: integrate XSLT Tools with toolbox portal

This commit is contained in:
2026-07-20 18:16:18 +02:00
parent 3193cc395c
commit 8f8a59e76c
36 changed files with 1737 additions and 243 deletions

View File

@@ -0,0 +1,65 @@
import type { TransformRequest, TransformResult } from './transformTypes';
export const TRANSFORM_LIMITS = {
maxXmlBytes: 5 * 1024 * 1024,
maxXsltBytes: 2 * 1024 * 1024,
maxOutputBytes: 10 * 1024 * 1024,
timeoutMs: 20_000,
} as const;
function utf8Bytes(value: string): number {
return new TextEncoder().encode(value).byteLength;
}
export function assertTransformInputWithinLimits(
request: TransformRequest
): void {
const xmlBytes = utf8Bytes(request.xmlText);
if (xmlBytes > TRANSFORM_LIMITS.maxXmlBytes) {
throw new Error(
`XML input exceeds the ${TRANSFORM_LIMITS.maxXmlBytes}-byte execution limit.`
);
}
const xsltBytes = utf8Bytes(request.xsltText);
if (xsltBytes > TRANSFORM_LIMITS.maxXsltBytes) {
throw new Error(
`XSLT stylesheet exceeds the ${TRANSFORM_LIMITS.maxXsltBytes}-byte execution limit.`
);
}
}
export function assertTransformOutputWithinLimits(
result: TransformResult
): void {
if (utf8Bytes(result.output) > TRANSFORM_LIMITS.maxOutputBytes) {
throw new Error(
`Transformation output exceeds the ${TRANSFORM_LIMITS.maxOutputBytes}-byte execution limit.`
);
}
}
export async function withTransformationTimeout<T>(
operation: () => Promise<T>,
timeoutMs: number = TRANSFORM_LIMITS.timeoutMs
): Promise<T> {
let timer: number | undefined;
try {
return await Promise.race([
Promise.resolve().then(operation),
new Promise<never>((_resolve, reject) => {
timer = window.setTimeout(
() =>
reject(
new Error(
`Transformation exceeded the ${timeoutMs}-millisecond execution limit.`
)
),
timeoutMs
);
}),
]);
} finally {
if (timer !== undefined) window.clearTimeout(timer);
}
}