@kitn.ai/chat
Version:
Framework-agnostic, Shadow-DOM web components for building AI chat interfaces — works in React, Vue, Angular, Svelte, or plain HTML. Authored in SolidJS.
31 lines (28 loc) • 1.69 kB
text/typescript
export function assertOrigin(actual: string, expected: string): boolean {
return typeof actual === 'string' && actual.length > 0 && actual === expected;
}
/** Fail-closed precondition (H-F): the iframe must be cross-origin to the host so
* `allow-same-origin` can't reach host DOM, and `src` must be on the provider origin. */
export function assertCrossOrigin(src: string, providerOrigin: string, hostOrigin: string): void {
const srcOrigin = new URL(src).origin;
if (providerOrigin === hostOrigin) throw new Error('[kc-remote] providerOrigin must be cross-origin to the host');
if (srcOrigin === hostOrigin) throw new Error('[kc-remote] src must not be same-origin as the host');
if (srcOrigin !== providerOrigin) throw new Error('[kc-remote] src origin must equal providerOrigin');
}
/** Field-positive log redaction (H-H/H-P): keep structural keys, redact secrets +
* unknown leaf values by default. nonce + authToken are always redacted. */
const SAFE_KEYS = new Set(['protocol', 'version', 'dir', 'kind', 'mode', 'locale', 'edge', 'code', 'acceptedVersion', 'supportedVersions', 'cardId', 'type', 'id', 'height', 'target']);
const ALWAYS_REDACT = new Set(['authToken', 'nonce']);
export function redactFrame(value: unknown): unknown {
if (Array.isArray(value)) return value.map(redactFrame);
if (value && typeof value === 'object') {
const out: Record<string, unknown> = {};
for (const [k, v] of Object.entries(value)) {
if (ALWAYS_REDACT.has(k)) out[k] = '[redacted]';
else if (typeof v === 'object' && v !== null) out[k] = redactFrame(v);
else out[k] = SAFE_KEYS.has(k) ? v : '[redacted]';
}
return out;
}
return value;
}