bun-ws-router
Version:
Lightweight client/server WebSocket router for Bun with type-safe Zod/Valibot validation.
53 lines • 2.03 kB
JavaScript
// SPDX-FileCopyrightText: 2025-present Kriasoft
// SPDX-License-Identifier: MIT
import { RESERVED_META_KEYS } from "./constants.js";
/**
* Validates that extended meta schema does not define reserved keys.
*
* This check occurs in messageSchema() factory to fail fast at design time.
*
* @throws {Error} If meta schema contains reserved keys
*/
export function validateMetaSchema(meta) {
if (!meta)
return;
const reservedInMeta = Object.keys(meta).filter((k) => RESERVED_META_KEYS.has(k));
if (reservedInMeta.length > 0) {
throw new Error(`Reserved meta keys not allowed in schema: ${reservedInMeta.join(", ")}. ` +
`Reserved keys: ${Array.from(RESERVED_META_KEYS).join(", ")}`);
}
}
/**
* Normalizes inbound message before validation (security boundary).
*
* MUST be called before schema validation to:
* - Strip reserved server-only keys (prevents spoofing)
* - Ensure meta exists (allows optional client meta)
*
* Mutates in place for performance (hot path, every message).
* O(k) complexity where k = RESERVED_META_KEYS.size (currently 2).
*
* @param raw - Raw parsed message from client
* @returns Normalized message (same reference, mutated in place)
*/
export function normalizeInboundMessage(raw) {
if (!raw || typeof raw !== "object") {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return raw; // Will fail validation
}
const msg = raw;
// Ensure meta exists (default to empty object)
if (!msg.meta || typeof msg.meta !== "object" || Array.isArray(msg.meta)) {
msg.meta = {};
}
// Strip reserved server-only keys (security: client cannot set these)
const meta = msg.meta;
RESERVED_META_KEYS.forEach((key) => {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete meta[key];
});
// O(k) where k = RESERVED_META_KEYS.size (currently 2)
// Faster than iterating all meta keys: O(n)
return msg;
}
//# sourceMappingURL=normalize.js.map