evOo-local/packages/adapters/src/connector-safety.ts
cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

41 lines
1.5 KiB
TypeScript

import { redactSecrets } from "@rakazo/core";
export function combineSignals(...signals: Array<AbortSignal | undefined>): AbortSignal {
return AbortSignal.any(signals.filter((signal): signal is AbortSignal => Boolean(signal)));
}
export function sanitizeConnectorError(error: unknown, secrets: string[] = []): string {
const message = error instanceof Error ? error.message : String(error);
return redactSecrets(
message
.replace(/Bearer\s+\S+/gi, "Bearer [redacted]")
.replace(/trg_(?:live|test)_[A-Za-z0-9_-]+/g, "[redacted]"),
secrets,
).slice(0, 2_000);
}
export function redactConnectorPayload(value: unknown, secrets: string[]): unknown {
if (secrets.length === 0) return value;
try {
return redactPayloadValue(JSON.parse(JSON.stringify(value)), secrets);
} catch {
return { ok: true };
}
}
function redactPayloadValue(value: unknown, secrets: string[]): unknown {
if (typeof value === "string") return redactSecrets(value, secrets);
if (Array.isArray(value)) return value.map((item) => redactPayloadValue(item, secrets));
if (value === null || typeof value === "number" || typeof value === "boolean") {
const serialized = String(value);
return redactSecrets(serialized, secrets) === serialized ? value : "[redacted]";
}
if (typeof value !== "object") return value;
return Object.fromEntries(
Object.entries(value).map(([key, item]) => [
redactSecrets(key, secrets),
redactPayloadValue(item, secrets),
]),
);
}