blob: 203e5a24d7637b3302d77b5d97ea59f911fa40db [file]
import { invalidProtocolFrame } from './errors.js';
export function requireRecord(value: unknown, label: string): Record<string, unknown> {
if (!value || typeof value !== 'object' || Array.isArray(value)) {
throw invalidProtocolFrame(`Invalid ${label}`);
}
return value as Record<string, unknown>;
}
export function requireExactRecord(
value: unknown,
label: string,
keys: readonly string[],
): Record<string, unknown> {
const record = requireRecord(value, label);
assertExactKeys(record, label, keys);
return record;
}
export function assertExactKeys(
record: Record<string, unknown>,
label: string,
keys: readonly string[],
): void {
const allowed = new Set(keys);
if (Object.keys(record).some((key) => !allowed.has(key))) {
throw invalidProtocolFrame(`Unknown ${label} field`);
}
if (
Object.keys(record).length !== keys.length ||
keys.some((key) => !Object.hasOwn(record, key))
) {
throw invalidProtocolFrame(`Invalid ${label} fields`);
}
}
export function requireString(value: unknown, label: string, maxLength: number): string {
if (typeof value !== 'string' || value.length === 0 || value.length > maxLength) {
throw invalidProtocolFrame(`Invalid ${label}`);
}
return value;
}
export function requireId(value: unknown, label: string): string {
return requireString(value, label, 128);
}
export function requireEntityId(value: unknown, label: string): string {
const id = requireId(value, label);
if (!/^[A-Za-z0-9_-]{1,128}$/.test(id)) throw invalidProtocolFrame(`Invalid ${label}`);
return id;
}
export function requireCount(value: unknown, label: string): number {
if (!Number.isSafeInteger(value) || (value as number) < 0) {
throw invalidProtocolFrame(`Invalid ${label}`);
}
return value as number;
}