mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-04 04:41:36 +00:00
* refactor(normalization): consolidate string helpers * refactor(normalization): consolidate agent ids * refactor(paths): consolidate user path resolution * refactor(gateway): preserve transcript helper facade * fix(normalization): align helper build aliases * fix(memory): keep helper import line neutral * chore(plugin-sdk): align consolidated helper surface * refactor(normalization): reuse lowercase string helper * refactor(normalization): reuse record guard * refactor(normalization): share surrogate boundary helper * refactor(agents): share token estimate constant * refactor(memory): distinguish standalone helper contracts * refactor(normalization): share error cause formatter * refactor(config): distinguish eligibility predicates * refactor(plugins): share registry state symbol * refactor(cli): reuse outbound dependency adapter * refactor(cron): distinguish positive duration parser * fix(gateway): keep transcript helper private * fix(paths): preserve public helper status * refactor(channels): reuse registry normalizer * refactor(agents): reuse agent core runtime facade * refactor(auth): reuse locked profile upsert * refactor(records): distinguish trap-safe guard * refactor(migrations): distinguish sync directory helper * test(plugins): drop stale duration alias expectations * fix(channels): remove stale registry import * chore(plugin-sdk): refresh helper API baseline * fix(memory): keep renamed helpers private * fix(plugins): keep registry state key private * fix(plugin-sdk): tighten wildcard surface budget * chore(plugin-sdk): refresh rebased helper API baseline
77 lines
1.8 KiB
TypeScript
77 lines
1.8 KiB
TypeScript
/** Defensive object guard for values that may have hostile traps. */
|
|
export function isRecordWithoutThrowing(value: unknown): value is Record<string, unknown> {
|
|
try {
|
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/** Read one property from a record-like value without letting traps escape. */
|
|
export function readRecordValue(value: unknown, key: string): unknown {
|
|
if (!isRecordWithoutThrowing(value)) {
|
|
return undefined;
|
|
}
|
|
try {
|
|
return value[key];
|
|
} catch {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
/** Copy array entries defensively from values that may throw on length/index access. */
|
|
export function copyArrayEntries(value: unknown): unknown[] {
|
|
let isArray: boolean;
|
|
try {
|
|
isArray = Array.isArray(value);
|
|
} catch {
|
|
return [];
|
|
}
|
|
if (!isArray) {
|
|
return [];
|
|
}
|
|
|
|
const arrayValue = value as readonly unknown[];
|
|
let length: number;
|
|
try {
|
|
length = arrayValue.length;
|
|
} catch {
|
|
return [];
|
|
}
|
|
|
|
const entries: unknown[] = [];
|
|
for (let index = 0; index < length; index += 1) {
|
|
try {
|
|
entries.push(arrayValue[index]);
|
|
} catch {
|
|
continue;
|
|
}
|
|
}
|
|
return entries;
|
|
}
|
|
|
|
/** Copy record entries whose values are also record-shaped. */
|
|
export function copyRecordEntries<T>(value: unknown): Array<[string, T]> {
|
|
if (!isRecordWithoutThrowing(value)) {
|
|
return [];
|
|
}
|
|
|
|
let keys: string[];
|
|
try {
|
|
keys = Object.keys(value);
|
|
} catch {
|
|
return [];
|
|
}
|
|
|
|
const entries: Array<[string, T]> = [];
|
|
for (const key of keys) {
|
|
const entry = readRecordValue(value, key);
|
|
// Callers use this for nested config maps; non-object leaves are ignored so
|
|
// later code does not need repeated record guards.
|
|
if (isRecordWithoutThrowing(entry)) {
|
|
entries.push([key, entry as T]);
|
|
}
|
|
}
|
|
return entries;
|
|
}
|