mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-18 08:31:49 -06:00
58a538767c
* fix(security): centralize provider diagnostic redaction * fix(workers): redact finishing diagnostics * fix(security): fail closed on malformed diagnostics * fix(security): redact media wrapper diagnostics * fix(security): normalize diagnostic field redaction * fix(security): redact diagnostic media URIs * fix(ai): preserve diagnostic compatibility in error projection * refactor(ai): simplify diagnostic error handling * fix(security): redact credential query diagnostics * fix(security): redact diagnostic media arrays * fix(security): redact diagnostic credential headers * test: align shared expectations with current runtime contracts * test(ui): align managed media and picker expectations * fix(security): redact plural media diagnostics * fix(ai): preserve bracketed provider errors * fix(security): cover generic diagnostic credentials * fix(security): redact prefixed diagnostic JSON * fix(security): redact embedded diagnostic JSON * test(agents): align cache trace media redaction * fix(security): redact cookie diagnostics * refactor(ai): isolate diagnostic host policy * refactor(ai): narrow diagnostic helper exports * fix(security): bound diagnostic descriptor reads * fix(security): bound diagnostic graph traversal
73 lines
2.1 KiB
TypeScript
73 lines
2.1 KiB
TypeScript
type JsonOpeningDelimiter = "{" | "[";
|
|
|
|
type BalancedJsonFragment = {
|
|
json: string;
|
|
startIndex: number;
|
|
endIndex: number;
|
|
};
|
|
|
|
function isJsonOpeningDelimiter(
|
|
char: string | undefined,
|
|
openers: readonly JsonOpeningDelimiter[],
|
|
): char is JsonOpeningDelimiter {
|
|
return (char === "{" || char === "[") && openers.includes(char);
|
|
}
|
|
|
|
/** Extracts the first balanced JSON object/array from text. */
|
|
export function extractBalancedJsonPrefix(
|
|
raw: string,
|
|
opts: { openers?: readonly JsonOpeningDelimiter[] } = {},
|
|
): BalancedJsonFragment | null {
|
|
const openers = opts.openers ?? (["{", "["] as const);
|
|
let start = 0;
|
|
while (start < raw.length && !isJsonOpeningDelimiter(raw[start], openers)) {
|
|
start += 1;
|
|
}
|
|
const stack: JsonOpeningDelimiter[] = [];
|
|
let inString = false;
|
|
let escaped = false;
|
|
for (let index = start; index < raw.length; index += 1) {
|
|
const char = raw[index];
|
|
if (inString) {
|
|
if (escaped) {
|
|
escaped = false;
|
|
} else if (char === "\\") {
|
|
escaped = true;
|
|
} else if (char === '"') {
|
|
inString = false;
|
|
}
|
|
} else if (char === '"') {
|
|
inString = true;
|
|
} else if (isJsonOpeningDelimiter(char, openers)) {
|
|
stack.push(char);
|
|
} else if (stack.length > 0 && char === (stack.at(-1) === "{" ? "}" : "]")) {
|
|
stack.pop();
|
|
if (stack.length === 0) {
|
|
return { json: raw.slice(start, index + 1), startIndex: start, endIndex: index };
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/** Extracts every balanced JSON object/array fragment from arbitrary text. */
|
|
export function extractBalancedJsonFragments(
|
|
raw: string,
|
|
opts: { openers?: readonly JsonOpeningDelimiter[] } = {},
|
|
): BalancedJsonFragment[] {
|
|
const fragments: BalancedJsonFragment[] = [];
|
|
for (let offset = 0; offset < raw.length;) {
|
|
const fragment = extractBalancedJsonPrefix(raw.slice(offset), opts);
|
|
if (!fragment) {
|
|
break;
|
|
}
|
|
fragments.push({
|
|
json: fragment.json,
|
|
startIndex: offset + fragment.startIndex,
|
|
endIndex: offset + fragment.endIndex,
|
|
});
|
|
offset += fragment.endIndex + 1;
|
|
}
|
|
return fragments;
|
|
}
|