mirror of
https://github.com/morluto/rea.git
synced 2026-10-28 10:25:42 +00:00
fix(javascript): bound primitive string growth and repeated evaluation
This commit is contained in:
1 parent
770d2f60aa
commit
4a1837d9d5
10 files changed
+298
-25
No files matched your search
@@ -3,16 +3,71 @@ import type {
|
||||
JavaScriptSemanticValue,
|
||||
} from "./javascriptSemanticValueTypes.js";
|
||||
|
||||
/** Maximum distinct alternatives retained in one normalized primitive value. */
|
||||
export const SEMANTIC_PRIMITIVE_CANDIDATE_LIMIT = 256;
|
||||
/** Maximum active expression nesting during inert semantic evaluation. */
|
||||
export const SEMANTIC_EXPRESSION_DEPTH_LIMIT = 256;
|
||||
/** Bound normalized strings and transient keys independently of transport limits. */
|
||||
export const SEMANTIC_PRIMITIVE_JSON_BYTES_LIMIT = 1_048_576;
|
||||
|
||||
const RESOURCE_LIMIT_REASON: Record<JavaScriptSemanticResourceLimit, string> = {
|
||||
"primitive-candidates":
|
||||
"Primitive candidate budget exceeded (maximum 256 alternatives).",
|
||||
"primitive-bytes":
|
||||
"Primitive string-byte budget exceeded (maximum 1048576 estimated JSON bytes).",
|
||||
"expression-depth":
|
||||
"Semantic expression depth budget exceeded (maximum 256 nested expressions).",
|
||||
};
|
||||
|
||||
/** Check UTF-16 length against worst-case JSON escaping without flattening. */
|
||||
const jsonStringBytesFromLength = (codeUnits: number): number =>
|
||||
codeUnits * 6 + 2;
|
||||
|
||||
/** Bound string payload before JSON key serialization or candidate creation. */
|
||||
export const exceedsSemanticPrimitiveStringByteBudget = (
|
||||
strings: Iterable<string>,
|
||||
): boolean => {
|
||||
let total = 0;
|
||||
for (const value of strings) {
|
||||
total += jsonStringBytesFromLength(value.length);
|
||||
if (total > SEMANTIC_PRIMITIVE_JSON_BYTES_LIMIT) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/** Bound all outputs of a primitive addition before concatenating any. */
|
||||
export const exceedsSemanticPrimitiveAdditionByteBudget = (
|
||||
left: readonly (string | number | boolean | null)[],
|
||||
right: readonly (string | number | boolean | null)[],
|
||||
): boolean => {
|
||||
let total = 0;
|
||||
for (const leftValue of left) {
|
||||
for (const rightValue of right) {
|
||||
if (typeof leftValue !== "string" && typeof rightValue !== "string")
|
||||
continue;
|
||||
const length = String(leftValue).length + String(rightValue).length;
|
||||
total += jsonStringBytesFromLength(length);
|
||||
if (total > SEMANTIC_PRIMITIVE_JSON_BYTES_LIMIT) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/** Bound template interpolation outputs before creating concatenated strings. */
|
||||
export const exceedsSemanticTemplateByteBudget = (
|
||||
prefixes: readonly string[],
|
||||
suffixes: readonly string[],
|
||||
): boolean => {
|
||||
let total = 0;
|
||||
for (const prefix of prefixes) {
|
||||
for (const suffix of suffixes) {
|
||||
total += jsonStringBytesFromLength(prefix.length + suffix.length);
|
||||
if (total > SEMANTIC_PRIMITIVE_JSON_BYTES_LIMIT) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/** Make an explicit unknown value tagged with the semantic resource bound. */
|
||||
export const semanticResourceLimitUnknown = (
|
||||
resourceLimit: JavaScriptSemanticResourceLimit,
|
||||
|
||||
Reference in new issue
Block a user