diff --git a/apps/web/src/index.tsx b/apps/web/src/index.tsx index 8f50163..7d420ae 100644 --- a/apps/web/src/index.tsx +++ b/apps/web/src/index.tsx @@ -77,7 +77,6 @@ function Chat() { } const rootRoute = createRootRoute({ - component: RootShell, }); @@ -99,7 +98,7 @@ const chatRoute = createRoute({ component: Chat, validateSearch: z.object({ id: z.number().optional(), - }) + }), }); const callRoute = createRoute({ diff --git a/apps/web/src/routes/app/layout.tsx b/apps/web/src/routes/app/layout.tsx index 4251d75..9666bdf 100644 --- a/apps/web/src/routes/app/layout.tsx +++ b/apps/web/src/routes/app/layout.tsx @@ -1,9 +1,7 @@ -import { useEffect, useState, type ReactNode } from "react"; -import { useNavigate } from "@tanstack/react-router"; +import { type ReactNode } from "react"; import Sidebar from "@/components/sidebar"; import Navbar from "@/components/navbar"; -import { useStorage } from "@tensamin/storage/context"; import { motion } from "framer-motion"; @@ -13,40 +11,6 @@ import { motion } from "framer-motion"; * @returns unknown. */ export default function Layout(props: { children: ReactNode }) { - const [loggedIn, setLoggedIn] = useState(null); - - const { load } = useStorage(); - - const navigate = useNavigate(); - - useEffect(() => { - let active = true; - - void load("user_id").then((userId) => { - if (!active) { - return; - } - - if (userId !== 0) { - setLoggedIn(true); - return; - } - - setLoggedIn(false); - void navigate({ - to: "/login", - }); - }); - - return () => { - active = false; - }; - }, [load, navigate]); - - if (loggedIn !== true) { - return null; - } - return ( - - {props.children} - + + + {props.children} + + ); } + +function LoginWrapper({ children }: { children: ReactNode }) { + const [loggedIn, setLoggedIn] = useState(null); + + const { load } = useStorage(); + + const navigate = useNavigate(); + const location = useLocation(); + + useEffect(() => { + let active = true; + + load("user_id").then((userId) => { + if (!active) { + return; + } + + if (userId !== 0) { + setLoggedIn(true); + return; + } + + setLoggedIn(false); + navigate({ + to: "/login", + }); + }); + + return () => { + active = false; + }; + }, [load, navigate, location.pathname]); + + if (loggedIn !== true && location.pathname !== "/login") { + return null; + } + + return children; +} diff --git a/packages/call/src/context.tsx b/packages/call/src/context.tsx index 585e44a..8f08ba8 100644 --- a/packages/call/src/context.tsx +++ b/packages/call/src/context.tsx @@ -6,7 +6,7 @@ export const context = createContext(undefined); export default function Provider(props: { children: React.ReactNode }) { const navigate = useNavigate(); - + const [state, setState] = useState<"closed" | "connecting" | "open">( "closed", ); @@ -33,14 +33,14 @@ export default function Provider(props: { children: React.ReactNode }) { // Utils function joinCall(userId: number, callId?: string) { // get/generate e2ee secret - // go into convs and find call id - // generate shared secret and decrypt enc call secret - + // go into convs and find call id + // generate shared secret and decrypt enc call secret + // check if user is already in call - + // connect to call connect("", ""); - + // navigate to call page navigate({ to: "/call", search: { userId: userId, callId: callId } }); } diff --git a/packages/chat/src/context.tsx b/packages/chat/src/context.tsx index e102ef2..c19c8ce 100644 --- a/packages/chat/src/context.tsx +++ b/packages/chat/src/context.tsx @@ -22,7 +22,9 @@ export default function Provider(props: { children: React.ReactNode }) { const { load } = useStorage(); const { send } = useSocket(); - const [liveMessagesState, setLiveMessagesState] = React.useState([]); + const [liveMessagesState, setLiveMessagesState] = React.useState< + LiveMessage[] + >([]); const [currentSharedSecret, setCurrentSharedSecret] = React.useState(""); const locationSearch = useRouterState({ diff --git a/packages/shared/src/log.tsx b/packages/shared/src/log.tsx index e202b17..e3726a0 100644 --- a/packages/shared/src/log.tsx +++ b/packages/shared/src/log.tsx @@ -26,7 +26,7 @@ export function log( blue: "\x1b[34m", }; const resetCode = "\x1b[0m"; - console.log(`${colorCodes[color]}[${logger}]${resetCode}`, ...args); + console.log(`${colorCodes[color]}${logger}${resetCode}`, ...args); } const size = 20; diff --git a/packages/ttp/src/codec.ts b/packages/ttp/src/codec.ts index bc364cf..26d5b61 100644 --- a/packages/ttp/src/codec.ts +++ b/packages/ttp/src/codec.ts @@ -11,193 +11,193 @@ const textDecoder = new TextDecoder(); type PrimitiveDataKind = "bool" | "number" | "string" | "container" | "null"; type DataKind = - | PrimitiveDataKind - | { array: PrimitiveDataKind | "container" | "null" }; + | PrimitiveDataKind + | { array: PrimitiveDataKind | "container" | "null" }; const COMMUNICATION_TYPES = [ - "error", - "error_protocol", - "error_anonymous", - "error_internal", - "error_invalid_data", - "error_invalid_user_id", - "error_invalid_omikron_id", - "error_not_found", - "error_not_authenticated", - "error_no_iota", - "error_invalid_challenge", - "error_invalid_secret", - "error_invalid_private_key", - "error_invalid_public_key", - "error_no_user_id", - "error_no_call_id", - "error_invalid_call_id", - "success", - "shorten_link", - "settings_save", - "settings_load", - "settings_list", - "message", - "message_state", - "message_send", - "message_live", - "message_other_iota", - "message_chunk", - "messages_get", - "push_notification", - "read_notification", - "get_notifications", - "change_confirm", - "confirm_receive", - "confirm_read", - "get_conversations", - "get_states", - "add_community", - "remove_community", - "get_communities", - "challenge", - "challenge_response", - "register", - "register_response", - "identification", - "identification_response", - "register_iota", - "register_iota_success", - "ping", - "pong", - "add_conversation", - "send_chat", - "client_changed", - "client_connected", - "client_disconnected", - "client_closed", - "public_key", - "private_key", - "webrtc_sdp", - "webrtc_ice", - "start_stream", - "end_stream", - "watch_stream", - "call_token", - "call_invite", - "call_disconnect_user", - "call_timeout_user", - "call_set_anonymous_joining", - "end_call", - "function", - "update", - "create_user", - "rho_update", - "user_connected", - "user_disconnected", - "iota_connected", - "iota_disconnected", - "sync_client_iota_status", - "get_user_data", - "get_iota_data", - "iota_user_data", - "change_user_data", - "change_iota_data", - "get_register", - "complete_register_user", - "complete_register_iota", - "delete_user", - "delete_iota", - "start_register", - "complete_register", + "error", + "error_protocol", + "error_anonymous", + "error_internal", + "error_invalid_data", + "error_invalid_user_id", + "error_invalid_omikron_id", + "error_not_found", + "error_not_authenticated", + "error_no_iota", + "error_invalid_challenge", + "error_invalid_secret", + "error_invalid_private_key", + "error_invalid_public_key", + "error_no_user_id", + "error_no_call_id", + "error_invalid_call_id", + "success", + "shorten_link", + "settings_save", + "settings_load", + "settings_list", + "message", + "message_state", + "message_send", + "message_live", + "message_other_iota", + "message_chunk", + "messages_get", + "push_notification", + "read_notification", + "get_notifications", + "change_confirm", + "confirm_receive", + "confirm_read", + "get_conversations", + "get_states", + "add_community", + "remove_community", + "get_communities", + "challenge", + "challenge_response", + "register", + "register_response", + "identification", + "identification_response", + "register_iota", + "register_iota_success", + "ping", + "pong", + "add_conversation", + "send_chat", + "client_changed", + "client_connected", + "client_disconnected", + "client_closed", + "public_key", + "private_key", + "webrtc_sdp", + "webrtc_ice", + "start_stream", + "end_stream", + "watch_stream", + "call_token", + "call_invite", + "call_disconnect_user", + "call_timeout_user", + "call_set_anonymous_joining", + "end_call", + "function", + "update", + "create_user", + "rho_update", + "user_connected", + "user_disconnected", + "iota_connected", + "iota_disconnected", + "sync_client_iota_status", + "get_user_data", + "get_iota_data", + "iota_user_data", + "change_user_data", + "change_iota_data", + "get_register", + "complete_register_user", + "complete_register_iota", + "delete_user", + "delete_iota", + "start_register", + "complete_register", ] as const; const DATA_TYPES = [ - "error_type", - "error_protocol", - "accepted_ids", - "uuid", - "register_id", - "link", - "settings", - "settings_name", - "chat_partner_id", - "chat_partner_name", - "iota_id", - "user_id", - "user_ids", - "iota_ids", - "user_state", - "user_states", - "user_pings", - "call_state", - "screen_share", - "private_key_hash", - "accepted", - "accepted_profiles", - "denied_profiles", - "content", - "messages", - "notifications", - "timestamp", - "get_time", - "get_variant", - "shared_secret_own", - "shared_secret_other", - "shared_secret_sign", - "shared_secret", - "call_id", - "call_token", - "untill", - "enabled", - "start_date", - "end_date", - "receiver_id", - "sender_id", - "signature", - "signed", - "message", - "message_state", - "last_ping", - "ping_iota", - "ping_clients", - "matches", - "omikron", - "offset", - "amount", - "position", - "name", - "path", - "codec", - "function", - "payload", - "result", - "interactables", - "want_to_watch", - "watcher", - "created_at", - "username", - "display", - "avatar", - "about", - "status", - "public_key", - "sub_level", - "sub_end", - "community_address", - "challenge", - "community_title", - "communities", - "rho_connections", - "user", - "online_status", - "omikron_id", - "omikron_connections", - "reset_token", - "new_token", - "call_invited", - "call_members", - "calls", - "timeout", - "has_admin", - "last_message_at", - "height", - "sent_by_self" + "error_type", + "error_protocol", + "accepted_ids", + "uuid", + "register_id", + "link", + "settings", + "settings_name", + "chat_partner_id", + "chat_partner_name", + "iota_id", + "user_id", + "user_ids", + "iota_ids", + "user_state", + "user_states", + "user_pings", + "call_state", + "screen_share", + "private_key_hash", + "accepted", + "accepted_profiles", + "denied_profiles", + "content", + "messages", + "notifications", + "timestamp", + "get_time", + "get_variant", + "shared_secret_own", + "shared_secret_other", + "shared_secret_sign", + "shared_secret", + "call_id", + "call_token", + "untill", + "enabled", + "start_date", + "end_date", + "receiver_id", + "sender_id", + "signature", + "signed", + "message", + "message_state", + "last_ping", + "ping_iota", + "ping_clients", + "matches", + "omikron", + "offset", + "amount", + "position", + "name", + "path", + "codec", + "function", + "payload", + "result", + "interactables", + "want_to_watch", + "watcher", + "created_at", + "username", + "display", + "avatar", + "about", + "status", + "public_key", + "sub_level", + "sub_end", + "community_address", + "challenge", + "community_title", + "communities", + "rho_connections", + "user", + "online_status", + "omikron_id", + "omikron_connections", + "reset_token", + "new_token", + "call_invited", + "call_members", + "calls", + "timeout", + "has_admin", + "last_message_at", + "height", + "sent_by_self", ] as const; const COMMUNICATION_TYPE_BY_NAME = createIndexMap(COMMUNICATION_TYPES); @@ -207,156 +207,156 @@ const SCALAR_NUMBER_ARRAY_DATA_TYPES = new Set(["last_ping", "ping_iota"]); const dataKindByType = new Map(); registerDataKinds("number", [ - "user_id", - "sender_id", - "register_id", - "receiver_id", - "call_id", - "amount", - "position", - "offset", - "timeout", - "iota_id", - "chat_partner_id", - "untill", - "start_date", - "end_date", - "omikron_id", - "timestamp", - "sub_level", - "sub_end", - "last_message_at", - "height" + "user_id", + "sender_id", + "register_id", + "receiver_id", + "call_id", + "amount", + "position", + "offset", + "timeout", + "iota_id", + "chat_partner_id", + "untill", + "start_date", + "end_date", + "omikron_id", + "timestamp", + "sub_level", + "sub_end", + "last_message_at", + "height", ]); registerDataKinds("string", [ - "error_type", - "username", - "display", - "avatar", - "about", - "public_key", - "message", - "content", - "path", - "codec", - "function", - "uuid", - "link", - "settings_name", - "chat_partner_name", - "user_state", - "call_state", - "private_key_hash", - "name", - "shared_secret_own", - "shared_secret_other", - "shared_secret_sign", - "shared_secret", - "message_state", - "signature", - "reset_token", - "new_token", - "call_token", - "challenge", - "online_status", + "error_type", + "username", + "display", + "avatar", + "about", + "public_key", + "message", + "content", + "path", + "codec", + "function", + "uuid", + "link", + "settings_name", + "chat_partner_name", + "user_state", + "call_state", + "private_key_hash", + "name", + "shared_secret_own", + "shared_secret_other", + "shared_secret_sign", + "shared_secret", + "message_state", + "signature", + "reset_token", + "new_token", + "call_token", + "challenge", + "online_status", ]); registerDataKinds({ array: "container" }, [ - "messages", - "communities", - "rho_connections", - "matches", - "get_conversations", - "get_communities", + "messages", + "communities", + "rho_connections", + "matches", + "get_conversations", + "get_communities", ]); registerDataKinds({ array: "number" }, [ - "notifications", - "iota_ids", - "user_ids", - "accepted_ids", - "last_ping", - "ping_iota", - "get_time", - "omikron_connections" + "notifications", + "iota_ids", + "user_ids", + "accepted_ids", + "last_ping", + "ping_iota", + "get_time", + "omikron_connections", ]); registerDataKinds("container", [ - "settings", - "user", - "payload", - "result", - "ping_clients", - "user_pings", + "settings", + "user", + "payload", + "result", + "ping_clients", + "user_pings", ]); registerDataKinds("bool", [ - "enabled", - "signed", - "accepted", - "has_admin", - "screen_share", - "sent_by_self", + "enabled", + "signed", + "accepted", + "has_admin", + "screen_share", + "sent_by_self", ]); registerDataKinds({ array: "string" }, ["user_states"]); registerDataKinds("null", [ - "error_protocol", - "accepted_profiles", - "denied_profiles", - "get_variant", - "omikron", - "interactables", - "want_to_watch", - "watcher", - "created_at", - "status", - "community_address", - "community_title", - "call_invited", - "call_members", - "calls", + "error_protocol", + "accepted_profiles", + "denied_profiles", + "get_variant", + "omikron", + "interactables", + "want_to_watch", + "watcher", + "created_at", + "status", + "community_address", + "community_title", + "call_invited", + "call_members", + "calls", ]); for (const dataType of DATA_TYPES) { - if (!dataKindByType.has(dataType)) { - throw new Error(`Missing data kind mapping for "${dataType}"`); - } + if (!dataKindByType.has(dataType)) { + throw new Error(`Missing data kind mapping for "${dataType}"`); + } } export type TypedMessage> = { - id: number; - type: string; - data: TData; + id: number; + type: string; + data: TData; }; /** * Represents non-fatal payload decoding failures for individual protocol messages. */ export class RecoverableMessageDecodeError extends Error { - readonly messageId: number; + readonly messageId: number; - readonly messageType: string; + readonly messageType: string; - readonly cause: unknown; + readonly cause: unknown; - /** - * Creates a recoverable decode error associated with a specific message. - * @param messageId Protocol message id that failed to decode. - * @param messageType Protocol message type that failed to decode. - * @param cause Original decode failure cause. - */ - constructor(messageId: number, messageType: string, cause: unknown) { - super( - `Failed to decode message payload for "${messageType}" (id=${messageId}): ${formatUnknownError(cause)}`, - ); - this.name = "RecoverableMessageDecodeError"; - this.messageId = messageId; - this.messageType = messageType; - this.cause = cause; - } + /** + * Creates a recoverable decode error associated with a specific message. + * @param messageId Protocol message id that failed to decode. + * @param messageType Protocol message type that failed to decode. + * @param cause Original decode failure cause. + */ + constructor(messageId: number, messageType: string, cause: unknown) { + super( + `Failed to decode message payload for "${messageType}" (id=${messageId}): ${formatUnknownError(cause)}`, + ); + this.name = "RecoverableMessageDecodeError"; + this.messageId = messageId; + this.messageType = messageType; + this.cause = cause; + } } /** @@ -365,19 +365,19 @@ export class RecoverableMessageDecodeError extends Error { * @returns Human-readable error description. */ function formatUnknownError(error: unknown) { - if (error instanceof Error) { - return error.message; - } + if (error instanceof Error) { + return error.message; + } - if (typeof error === "string") { - return error; - } + if (typeof error === "string") { + return error; + } - try { - return JSON.stringify(error); - } catch { - return String(error); - } + try { + return JSON.stringify(error); + } catch { + return String(error); + } } /** @@ -386,7 +386,7 @@ function formatUnknownError(error: unknown) { * @returns True when the value is a plain object. */ function isPlainObject(value: unknown): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); + return typeof value === "object" && value !== null && !Array.isArray(value); } /** @@ -395,27 +395,27 @@ function isPlainObject(value: unknown): value is Record { * @returns Encoded communication frame bytes. */ export function encodeCommunicationMessage( - message: TypedMessage>, + message: TypedMessage>, ) { - const typeIndex = parseCommunicationType(message.type); - const hasId = message.id !== 0; - const dataBuffer = encodeContainerPayload(message.data, "payload"); - const payloadLength = 2 + (hasId ? 4 : 0) + dataBuffer.byteLength; - const buffer = new Uint8Array(4 + payloadLength); + const typeIndex = parseCommunicationType(message.type); + const hasId = message.id !== 0; + const dataBuffer = encodeContainerPayload(message.data, "payload"); + const payloadLength = 2 + (hasId ? 4 : 0) + dataBuffer.byteLength; + const buffer = new Uint8Array(4 + payloadLength); - writeU32(buffer, 0, payloadLength); - buffer[4] = typeIndex; - buffer[5] = hasId ? 0b0000_0100 : 0; + writeU32(buffer, 0, payloadLength); + buffer[4] = typeIndex; + buffer[5] = hasId ? 0b0000_0100 : 0; - let offset = 6; - if (hasId) { - writeU32(buffer, offset, message.id); - offset += 4; - } + let offset = 6; + if (hasId) { + writeU32(buffer, offset, message.id); + offset += 4; + } - buffer.set(dataBuffer, offset); + buffer.set(dataBuffer, offset); - return buffer; + return buffer; } /** @@ -424,83 +424,83 @@ export function encodeCommunicationMessage( * @returns Decoded typed protocol message. */ export function decodeCommunicationMessage(frame: Uint8Array): TypedMessage { - const reader = new ByteReader(frame); - const frameLength = reader.readU32(); - if (frameLength !== frame.byteLength - 4) { - throw new Error( - `Communication frame length mismatch: expected ${frameLength}, received ${frame.byteLength - 4}`, - ); - } + const reader = new ByteReader(frame); + const frameLength = reader.readU32(); + if (frameLength !== frame.byteLength - 4) { + throw new Error( + `Communication frame length mismatch: expected ${frameLength}, received ${frame.byteLength - 4}`, + ); + } - const payloadLength = reader.readU32(); - if (payloadLength !== frameLength - 4) { - throw new Error( - `Communication payload length mismatch: expected ${payloadLength}, received ${frameLength - 4}`, - ); - } + const payloadLength = reader.readU32(); + if (payloadLength !== frameLength - 4) { + throw new Error( + `Communication payload length mismatch: expected ${payloadLength}, received ${frameLength - 4}`, + ); + } - const typeIndex = reader.readU8(); - const flags = reader.readU8(); - const hasSender = (flags & 0b0000_0001) !== 0; - const hasReceiver = (flags & 0b0000_0010) !== 0; - const hasId = (flags & 0b0000_0100) !== 0; + const typeIndex = reader.readU8(); + const flags = reader.readU8(); + const hasSender = (flags & 0b0000_0001) !== 0; + const hasReceiver = (flags & 0b0000_0010) !== 0; + const hasId = (flags & 0b0000_0100) !== 0; - const id = hasId ? reader.readU32() : 0; - if (hasSender) { - reader.readU48(); - } - if (hasReceiver) { - reader.readU48(); - } + const id = hasId ? reader.readU32() : 0; + if (hasSender) { + reader.readU48(); + } + if (hasReceiver) { + reader.readU48(); + } - const consumedHeaderBytes = - 2 + (hasId ? 4 : 0) + (hasSender ? 6 : 0) + (hasReceiver ? 6 : 0); - if (consumedHeaderBytes > payloadLength) { - throw new Error("Communication header exceeds payload length"); - } + const consumedHeaderBytes = + 2 + (hasId ? 4 : 0) + (hasSender ? 6 : 0) + (hasReceiver ? 6 : 0); + if (consumedHeaderBytes > payloadLength) { + throw new Error("Communication header exceeds payload length"); + } - const messageType = COMMUNICATION_TYPES[typeIndex] ?? "error_protocol"; + const messageType = COMMUNICATION_TYPES[typeIndex] ?? "error_protocol"; - const dataLength = payloadLength - consumedHeaderBytes; - let decodedData: Record; + const dataLength = payloadLength - consumedHeaderBytes; + let decodedData: Record; - if (dataLength === 0) { - decodedData = {}; - } else { - const dataReader = new ByteReader(reader.readBytes(dataLength)); + if (dataLength === 0) { + decodedData = {}; + } else { + const dataReader = new ByteReader(reader.readBytes(dataLength)); - try { - decodedData = decodeContainerPayload(dataReader); - } catch (error) { - if (messageType.startsWith("error")) { - return { - id, - type: messageType, - data: {}, - }; - } else { - throw new RecoverableMessageDecodeError(id, messageType, error); - } - } + try { + decodedData = decodeContainerPayload(dataReader); + } catch (error) { + if (messageType.startsWith("error")) { + return { + id, + type: messageType, + data: {}, + }; + } else { + throw new RecoverableMessageDecodeError(id, messageType, error); + } + } - if (!dataReader.isAtEnd()) { - throw new RecoverableMessageDecodeError( - id, - messageType, - new Error("Trailing bytes found after communication data payload"), - ); - } - } + if (!dataReader.isAtEnd()) { + throw new RecoverableMessageDecodeError( + id, + messageType, + new Error("Trailing bytes found after communication data payload"), + ); + } + } - if (!reader.isAtEnd()) { - throw new Error("Trailing bytes found after communication payload"); - } + if (!reader.isAtEnd()) { + throw new Error("Trailing bytes found after communication payload"); + } - return { - id, - type: messageType, - data: decodedData, - }; + return { + id, + type: messageType, + data: decodedData, + }; } /** @@ -509,13 +509,13 @@ export function decodeCommunicationMessage(frame: Uint8Array): TypedMessage { * @returns Map from normalized name to array index. */ function createIndexMap(values: readonly string[]) { - const map = new Map(); + const map = new Map(); - values.forEach((value, index) => { - map.set(normalizeName(value), index); - }); + values.forEach((value, index) => { + map.set(normalizeName(value), index); + }); - return map; + return map; } /** @@ -525,13 +525,13 @@ function createIndexMap(values: readonly string[]) { * @returns Void. */ function registerDataKinds(kind: DataKind, names: readonly string[]) { - for (const name of names) { - if (dataKindByType.has(name)) { - throw new Error(`Duplicate data kind registration for "${name}"`); - } + for (const name of names) { + if (dataKindByType.has(name)) { + throw new Error(`Duplicate data kind registration for "${name}"`); + } - dataKindByType.set(name, kind); - } + dataKindByType.set(name, kind); + } } /** @@ -540,7 +540,7 @@ function registerDataKinds(kind: DataKind, names: readonly string[]) { * @returns Normalized protocol key. */ function normalizeName(value: string) { - return value.toLowerCase().replaceAll("_", ""); + return value.toLowerCase().replaceAll("_", ""); } /** @@ -549,15 +549,15 @@ function normalizeName(value: string) { * @returns Canonical data key metadata with index and normalized name. */ function parseDataType(type: string) { - const index = DATA_TYPE_BY_NAME.get(normalizeName(type)); - if (index === undefined) { - throw new Error(`Unknown data type "${type}"`); - } + const index = DATA_TYPE_BY_NAME.get(normalizeName(type)); + if (index === undefined) { + throw new Error(`Unknown data type "${type}"`); + } - return { - index, - name: DATA_TYPES[index], - }; + return { + index, + name: DATA_TYPES[index], + }; } /** @@ -566,12 +566,12 @@ function parseDataType(type: string) { * @returns Numeric protocol type index. */ function parseCommunicationType(type: string) { - const index = COMMUNICATION_TYPE_BY_NAME.get(normalizeName(type)); - if (index === undefined) { - throw new Error(`Unknown communication type "${type}"`); - } + const index = COMMUNICATION_TYPE_BY_NAME.get(normalizeName(type)); + if (index === undefined) { + throw new Error(`Unknown communication type "${type}"`); + } - return index; + return index; } /** @@ -580,17 +580,17 @@ function parseCommunicationType(type: string) { * @returns Expected data kind definition. */ function getExpectedKind(type: string) { - const kind = dataKindByType.get(type); - if (!kind) { - throw new Error(`No data kind registered for "${type}"`); - } + const kind = dataKindByType.get(type); + if (!kind) { + throw new Error(`No data kind registered for "${type}"`); + } - return kind; + return kind; } type EncodedDataValue = { - kind: number; - payload: Uint8Array; + kind: number; + payload: Uint8Array; }; /** @@ -601,64 +601,64 @@ type EncodedDataValue = { * @returns Encoded value marker and payload bytes. */ function encodeDataValueForKind( - kind: DataKind, - value: unknown, - path: string, + kind: DataKind, + value: unknown, + path: string, ): EncodedDataValue { - if (typeof kind === "object") { - return { - kind: DATA_VALUE_KIND_ARRAY, - payload: encodeArrayPayload(kind.array, value, path), - }; - } + if (typeof kind === "object") { + return { + kind: DATA_VALUE_KIND_ARRAY, + payload: encodeArrayPayload(kind.array, value, path), + }; + } - switch (kind) { - case "bool": - if (typeof value !== "boolean") { - throw new Error(`Expected boolean at "${path}"`); - } + switch (kind) { + case "bool": + if (typeof value !== "boolean") { + throw new Error(`Expected boolean at "${path}"`); + } - return { - kind: value ? DATA_VALUE_KIND_BOOL_TRUE : DATA_VALUE_KIND_BOOL_FALSE, - payload: new Uint8Array(0), - }; + return { + kind: value ? DATA_VALUE_KIND_BOOL_TRUE : DATA_VALUE_KIND_BOOL_FALSE, + payload: new Uint8Array(0), + }; - case "number": - return { - kind: DATA_VALUE_KIND_NUMBER, - payload: encodeNumberPayload(value, path), - }; + case "number": + return { + kind: DATA_VALUE_KIND_NUMBER, + payload: encodeNumberPayload(value, path), + }; - case "string": - if (typeof value !== "string") { - throw new Error(`Expected string at "${path}"`); - } + case "string": + if (typeof value !== "string") { + throw new Error(`Expected string at "${path}"`); + } - return { - kind: DATA_VALUE_KIND_STRING, - payload: textEncoder.encode(value), - }; + return { + kind: DATA_VALUE_KIND_STRING, + payload: textEncoder.encode(value), + }; - case "container": - if (!isPlainObject(value)) { - throw new Error(`Expected object at "${path}"`); - } + case "container": + if (!isPlainObject(value)) { + throw new Error(`Expected object at "${path}"`); + } - return { - kind: DATA_VALUE_KIND_CONTAINER, - payload: encodeContainerPayload(value, path), - }; + return { + kind: DATA_VALUE_KIND_CONTAINER, + payload: encodeContainerPayload(value, path), + }; - case "null": - if (value !== null && value !== undefined) { - throw new Error(`Expected null at "${path}"`); - } + case "null": + if (value !== null && value !== undefined) { + throw new Error(`Expected null at "${path}"`); + } - return { - kind: DATA_VALUE_KIND_NULL, - payload: new Uint8Array(0), - }; - } + return { + kind: DATA_VALUE_KIND_NULL, + payload: new Uint8Array(0), + }; + } } /** @@ -668,17 +668,17 @@ function encodeDataValueForKind( * @returns Encoded i64 byte array. */ function encodeNumberPayload(value: unknown, path: string) { - if ( - typeof value !== "number" || - !Number.isFinite(value) || - !Number.isSafeInteger(value) - ) { - throw new Error(`Expected safe integer at "${path}"`); - } + if ( + typeof value !== "number" || + !Number.isFinite(value) || + !Number.isSafeInteger(value) + ) { + throw new Error(`Expected safe integer at "${path}"`); + } - const buffer = new Uint8Array(8); - writeI64(buffer, 0, value); - return buffer; + const buffer = new Uint8Array(8); + writeI64(buffer, 0, value); + return buffer; } /** @@ -689,56 +689,56 @@ function encodeNumberPayload(value: unknown, path: string) { * @returns Encoded array payload bytes. */ function encodeArrayPayload( - innerKind: PrimitiveDataKind | "container" | "null", - value: unknown, - path: string, + innerKind: PrimitiveDataKind | "container" | "null", + value: unknown, + path: string, ) { - if (!Array.isArray(value)) { - throw new Error(`Expected array at "${path}"`); - } + if (!Array.isArray(value)) { + throw new Error(`Expected array at "${path}"`); + } - if (value.length > 0xffff) { - throw new Error(`Array at "${path}" is too large for protocol encoding`); - } + if (value.length > 0xffff) { + throw new Error(`Array at "${path}" is too large for protocol encoding`); + } - const encodedItems = value.map((entry, index) => - encodeDataValueForKind(innerKind, entry, `${path}[${index}]`), - ); + const encodedItems = value.map((entry, index) => + encodeDataValueForKind(innerKind, entry, `${path}[${index}]`), + ); - let totalLength = 2; - for (const encodedItem of encodedItems) { - totalLength += 1; + let totalLength = 2; + for (const encodedItem of encodedItems) { + totalLength += 1; - if (!isBoolKindMarker(encodedItem.kind)) { - if (encodedItem.payload.byteLength > 0xffff) { - throw new Error( - `Array item at "${path}" is too large for protocol encoding`, - ); - } + if (!isBoolKindMarker(encodedItem.kind)) { + if (encodedItem.payload.byteLength > 0xffff) { + throw new Error( + `Array item at "${path}" is too large for protocol encoding`, + ); + } - totalLength += 2 + encodedItem.payload.byteLength; - } - } + totalLength += 2 + encodedItem.payload.byteLength; + } + } - const buffer = new Uint8Array(totalLength); - writeU16(buffer, 0, value.length); + const buffer = new Uint8Array(totalLength); + writeU16(buffer, 0, value.length); - let offset = 2; - for (const item of encodedItems) { - buffer[offset] = item.kind; - offset += 1; + let offset = 2; + for (const item of encodedItems) { + buffer[offset] = item.kind; + offset += 1; - if (isBoolKindMarker(item.kind)) { - continue; - } + if (isBoolKindMarker(item.kind)) { + continue; + } - writeU16(buffer, offset, item.payload.byteLength); - offset += 2; - buffer.set(item.payload, offset); - offset += item.payload.byteLength; - } + writeU16(buffer, offset, item.payload.byteLength); + offset += 2; + buffer.set(item.payload, offset); + offset += item.payload.byteLength; + } - return buffer; + return buffer; } /** @@ -748,84 +748,84 @@ function encodeArrayPayload( * @returns Encoded container payload bytes. */ function encodeContainerPayload(value: Record, path: string) { - const normalizedEntries = new Map< - string, - { index: number; value: unknown } - >(); + const normalizedEntries = new Map< + string, + { index: number; value: unknown } + >(); - for (const [rawKey, rawValue] of Object.entries(value)) { - const parsedType = parseDataType(rawKey); - normalizedEntries.set(parsedType.name, { - index: parsedType.index, - value: normalizeOutgoingValue(parsedType.name, rawValue), - }); - } + for (const [rawKey, rawValue] of Object.entries(value)) { + const parsedType = parseDataType(rawKey); + normalizedEntries.set(parsedType.name, { + index: parsedType.index, + value: normalizeOutgoingValue(parsedType.name, rawValue), + }); + } - const entries = [...normalizedEntries.entries()].sort( - ([, left], [, right]) => left.index - right.index, - ); + const entries = [...normalizedEntries.entries()].sort( + ([, left], [, right]) => left.index - right.index, + ); - if (entries.length > 0xffff) { - throw new Error( - `Container at "${path}" has too many entries for protocol encoding`, - ); - } + if (entries.length > 0xffff) { + throw new Error( + `Container at "${path}" has too many entries for protocol encoding`, + ); + } - const encodedEntries: Array<{ keyIndex: number; value: EncodedDataValue }> = - []; - let totalLength = 2; + const encodedEntries: Array<{ keyIndex: number; value: EncodedDataValue }> = + []; + let totalLength = 2; - for (const [name, entry] of entries) { - const expectedKind = getExpectedKind(name); - const pathForEntry = `${path}.${name}`; + for (const [name, entry] of entries) { + const expectedKind = getExpectedKind(name); + const pathForEntry = `${path}.${name}`; - const encodedValue = encodeDataValueForKind( - expectedKind, - entry.value, - pathForEntry, - ); + const encodedValue = encodeDataValueForKind( + expectedKind, + entry.value, + pathForEntry, + ); - if (isBoolKindMarker(encodedValue.kind)) { - totalLength += 2; - } else { - if (encodedValue.payload.byteLength > 0xffff) { - throw new Error( - `Container entry "${pathForEntry}" is too large for protocol encoding`, - ); - } + if (isBoolKindMarker(encodedValue.kind)) { + totalLength += 2; + } else { + if (encodedValue.payload.byteLength > 0xffff) { + throw new Error( + `Container entry "${pathForEntry}" is too large for protocol encoding`, + ); + } - totalLength += 4 + encodedValue.payload.byteLength; - } + totalLength += 4 + encodedValue.payload.byteLength; + } - encodedEntries.push({ - keyIndex: entry.index, - value: encodedValue, - }); - } + encodedEntries.push({ + keyIndex: entry.index, + value: encodedValue, + }); + } - const buffer = new Uint8Array(totalLength); - writeU16(buffer, 0, entries.length); + const buffer = new Uint8Array(totalLength); + writeU16(buffer, 0, entries.length); - let offset = 2; - for (const entry of encodedEntries) { - buffer[offset] = entry.value.kind; - offset += 1; + let offset = 2; + for (const entry of encodedEntries) { + buffer[offset] = entry.value.kind; + offset += 1; - if (isBoolKindMarker(entry.value.kind)) { - buffer[offset] = entry.keyIndex; - offset += 1; - continue; - } + if (isBoolKindMarker(entry.value.kind)) { + buffer[offset] = entry.keyIndex; + offset += 1; + continue; + } - writeU16(buffer, offset, entry.value.payload.byteLength); - offset += 2; - buffer[offset] = entry.keyIndex; - offset += 1; - buffer.set(entry.value.payload, offset); - offset += entry.value.payload.byteLength; - } + writeU16(buffer, offset, entry.value.payload.byteLength); + offset += 2; + buffer[offset] = entry.keyIndex; + offset += 1; + buffer.set(entry.value.payload, offset); + offset += entry.value.payload.byteLength; + } - return buffer; + return buffer; } /** @@ -835,49 +835,49 @@ function encodeContainerPayload(value: Record, path: string) { * @returns Decoded JavaScript value. */ function decodeValuePayload(marker: number, payload: Uint8Array): unknown { - const reader = new ByteReader(payload); + const reader = new ByteReader(payload); - switch (marker) { - case DATA_VALUE_KIND_BOOL_TRUE: - if (!reader.isAtEnd()) { - throw new Error("Unexpected payload for boolean true value"); - } + switch (marker) { + case DATA_VALUE_KIND_BOOL_TRUE: + if (!reader.isAtEnd()) { + throw new Error("Unexpected payload for boolean true value"); + } - return true; + return true; - case DATA_VALUE_KIND_BOOL_FALSE: - if (!reader.isAtEnd()) { - throw new Error("Unexpected payload for boolean false value"); - } + case DATA_VALUE_KIND_BOOL_FALSE: + if (!reader.isAtEnd()) { + throw new Error("Unexpected payload for boolean false value"); + } - return false; + return false; - case DATA_VALUE_KIND_NUMBER: - if (payload.byteLength !== 8) { - throw new Error(`Invalid number payload length ${payload.byteLength}`); - } + case DATA_VALUE_KIND_NUMBER: + if (payload.byteLength !== 8) { + throw new Error(`Invalid number payload length ${payload.byteLength}`); + } - return reader.readI64(); + return reader.readI64(); - case DATA_VALUE_KIND_STRING: - return textDecoder.decode(payload); + case DATA_VALUE_KIND_STRING: + return textDecoder.decode(payload); - case DATA_VALUE_KIND_ARRAY: - return decodeArrayPayload(reader); + case DATA_VALUE_KIND_ARRAY: + return decodeArrayPayload(reader); - case DATA_VALUE_KIND_CONTAINER: - return decodeContainerPayload(reader); + case DATA_VALUE_KIND_CONTAINER: + return decodeContainerPayload(reader); - case DATA_VALUE_KIND_NULL: - if (!reader.isAtEnd()) { - throw new Error("Unexpected payload for null value"); - } + case DATA_VALUE_KIND_NULL: + if (!reader.isAtEnd()) { + throw new Error("Unexpected payload for null value"); + } - return null; + return null; - default: - throw new Error(`Unknown data value marker 0x${marker.toString(16)}`); - } + default: + throw new Error(`Unknown data value marker 0x${marker.toString(16)}`); + } } /** @@ -886,23 +886,23 @@ function decodeValuePayload(marker: number, payload: Uint8Array): unknown { * @returns Decoded array values. */ function decodeArrayPayload(reader: ByteReader) { - const itemCount = reader.readU16(); - const values: unknown[] = []; + const itemCount = reader.readU16(); + const values: unknown[] = []; - for (let index = 0; index < itemCount; index += 1) { - const marker = reader.readU8(); + for (let index = 0; index < itemCount; index += 1) { + const marker = reader.readU8(); - if (isBoolKindMarker(marker)) { - values.push(marker === DATA_VALUE_KIND_BOOL_TRUE); - continue; - } + if (isBoolKindMarker(marker)) { + values.push(marker === DATA_VALUE_KIND_BOOL_TRUE); + continue; + } - const payloadLength = reader.readU16(); - const payload = reader.readBytes(payloadLength); - values.push(decodeValuePayload(marker, payload)); - } + const payloadLength = reader.readU16(); + const payload = reader.readBytes(payloadLength); + values.push(decodeValuePayload(marker, payload)); + } - return values; + return values; } /** @@ -911,36 +911,36 @@ function decodeArrayPayload(reader: ByteReader) { * @returns Decoded object payload. */ function decodeContainerPayload(reader: ByteReader) { - const entryCount = reader.readU16(); - const value: Record = {}; + const entryCount = reader.readU16(); + const value: Record = {}; - for (let index = 0; index < entryCount; index += 1) { - const marker = reader.readU8(); - const payloadLength = isBoolKindMarker(marker) ? 0 : reader.readU16(); - const keyIndex = reader.readU8(); - const payload = isBoolKindMarker(marker) - ? new Uint8Array(0) - : reader.readBytes(payloadLength); + for (let index = 0; index < entryCount; index += 1) { + const marker = reader.readU8(); + const payloadLength = isBoolKindMarker(marker) ? 0 : reader.readU16(); + const keyIndex = reader.readU8(); + const payload = isBoolKindMarker(marker) + ? new Uint8Array(0) + : reader.readBytes(payloadLength); - const key = getDataTypeNameByIndex(keyIndex); - if (!key) { - continue; - } + const key = getDataTypeNameByIndex(keyIndex); + if (!key) { + continue; + } - const expectedKind = getExpectedKind(key); - if (!isMarkerCompatibleWithKey(marker, expectedKind, key)) { - throw new Error( - `Unexpected marker 0x${marker.toString(16)} for data type "${key}"`, - ); - } + const expectedKind = getExpectedKind(key); + if (!isMarkerCompatibleWithKey(marker, expectedKind, key)) { + throw new Error( + `Unexpected marker 0x${marker.toString(16)} for data type "${key}"`, + ); + } - value[key] = normalizeIncomingValue( - key, - decodeValuePayload(marker, payload), - ); - } + value[key] = normalizeIncomingValue( + key, + decodeValuePayload(marker, payload), + ); + } - return value; + return value; } /** @@ -949,7 +949,7 @@ function decodeContainerPayload(reader: ByteReader) { * @returns Canonical protocol data key name. */ function getDataTypeNameByIndex(index: number) { - return DATA_TYPES[index]; + return DATA_TYPES[index]; } /** @@ -958,10 +958,10 @@ function getDataTypeNameByIndex(index: number) { * @returns True when marker is boolean true or false. */ function isBoolKindMarker(marker: number) { - return ( - marker === DATA_VALUE_KIND_BOOL_TRUE || - marker === DATA_VALUE_KIND_BOOL_FALSE - ); + return ( + marker === DATA_VALUE_KIND_BOOL_TRUE || + marker === DATA_VALUE_KIND_BOOL_FALSE + ); } /** @@ -971,22 +971,22 @@ function isBoolKindMarker(marker: number) { * @returns True when marker matches the expected kind. */ function isMarkerCompatibleWithKind(marker: number, kind: DataKind) { - if (typeof kind === "object") { - return marker === DATA_VALUE_KIND_ARRAY; - } + if (typeof kind === "object") { + return marker === DATA_VALUE_KIND_ARRAY; + } - switch (kind) { - case "bool": - return isBoolKindMarker(marker); - case "number": - return marker === DATA_VALUE_KIND_NUMBER; - case "string": - return marker === DATA_VALUE_KIND_STRING; - case "container": - return marker === DATA_VALUE_KIND_CONTAINER; - case "null": - return marker === DATA_VALUE_KIND_NULL; - } + switch (kind) { + case "bool": + return isBoolKindMarker(marker); + case "number": + return marker === DATA_VALUE_KIND_NUMBER; + case "string": + return marker === DATA_VALUE_KIND_STRING; + case "container": + return marker === DATA_VALUE_KIND_CONTAINER; + case "null": + return marker === DATA_VALUE_KIND_NULL; + } } /** @@ -997,18 +997,18 @@ function isMarkerCompatibleWithKind(marker: number, kind: DataKind) { * @returns True when marker is compatible for the key. */ function isMarkerCompatibleWithKey( - marker: number, - kind: DataKind, - key: string, + marker: number, + kind: DataKind, + key: string, ) { - if ( - SCALAR_NUMBER_ARRAY_DATA_TYPES.has(key) && - marker === DATA_VALUE_KIND_NUMBER - ) { - return true; - } + if ( + SCALAR_NUMBER_ARRAY_DATA_TYPES.has(key) && + marker === DATA_VALUE_KIND_NUMBER + ) { + return true; + } - return isMarkerCompatibleWithKind(marker, kind); + return isMarkerCompatibleWithKind(marker, kind); } /** @@ -1018,11 +1018,11 @@ function isMarkerCompatibleWithKey( * @returns Normalized outbound value. */ function normalizeOutgoingValue(type: string, value: unknown) { - if (SCALAR_NUMBER_ARRAY_DATA_TYPES.has(type) && typeof value === "number") { - return [value]; - } + if (SCALAR_NUMBER_ARRAY_DATA_TYPES.has(type) && typeof value === "number") { + return [value]; + } - return value; + return value; } /** @@ -1032,16 +1032,16 @@ function normalizeOutgoingValue(type: string, value: unknown) { * @returns Normalized inbound value. */ function normalizeIncomingValue(type: string, value: unknown) { - if ( - SCALAR_NUMBER_ARRAY_DATA_TYPES.has(type) && - Array.isArray(value) && - value.length === 1 && - typeof value[0] === "number" - ) { - return value[0]; - } + if ( + SCALAR_NUMBER_ARRAY_DATA_TYPES.has(type) && + Array.isArray(value) && + value.length === 1 && + typeof value[0] === "number" + ) { + return value[0]; + } - return value; + return value; } /** @@ -1052,11 +1052,11 @@ function normalizeIncomingValue(type: string, value: unknown) { * @returns Void. */ function writeU16(buffer: Uint8Array, offset: number, value: number) { - new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).setUint16( - offset, - value, - false, - ); + new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).setUint16( + offset, + value, + false, + ); } /** @@ -1067,11 +1067,11 @@ function writeU16(buffer: Uint8Array, offset: number, value: number) { * @returns Void. */ function writeU32(buffer: Uint8Array, offset: number, value: number) { - new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).setUint32( - offset, - value, - false, - ); + new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).setUint32( + offset, + value, + false, + ); } /** @@ -1082,124 +1082,124 @@ function writeU32(buffer: Uint8Array, offset: number, value: number) { * @returns Void. */ function writeI64(buffer: Uint8Array, offset: number, value: number) { - new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).setBigInt64( - offset, - BigInt(value), - false, - ); + new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).setBigInt64( + offset, + BigInt(value), + false, + ); } /** * Provides sequential big-endian reads over protocol byte buffers. */ class ByteReader { - private readonly view: DataView; + private readonly view: DataView; - private offset = 0; + private offset = 0; - private readonly bytes: Uint8Array; + private readonly bytes: Uint8Array; - /** - * Creates a byte reader over an immutable Uint8Array view. - * @param bytes Source bytes to read from. - */ - constructor(bytes: Uint8Array) { - this.bytes = bytes; - this.view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); - } + /** + * Creates a byte reader over an immutable Uint8Array view. + * @param bytes Source bytes to read from. + */ + constructor(bytes: Uint8Array) { + this.bytes = bytes; + this.view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); + } - /** - * Reads one unsigned byte. - * @returns Unsigned 8-bit integer. - */ - readU8() { - this.ensureAvailable(1); - const value = this.view.getUint8(this.offset); - this.offset += 1; - return value; - } + /** + * Reads one unsigned byte. + * @returns Unsigned 8-bit integer. + */ + readU8() { + this.ensureAvailable(1); + const value = this.view.getUint8(this.offset); + this.offset += 1; + return value; + } - /** - * Reads two bytes as big-endian unsigned 16-bit integer. - * @returns Unsigned 16-bit integer. - */ - readU16() { - this.ensureAvailable(2); - const value = this.view.getUint16(this.offset, false); - this.offset += 2; - return value; - } + /** + * Reads two bytes as big-endian unsigned 16-bit integer. + * @returns Unsigned 16-bit integer. + */ + readU16() { + this.ensureAvailable(2); + const value = this.view.getUint16(this.offset, false); + this.offset += 2; + return value; + } - /** - * Reads four bytes as big-endian unsigned 32-bit integer. - * @returns Unsigned 32-bit integer. - */ - readU32() { - this.ensureAvailable(4); - const value = this.view.getUint32(this.offset, false); - this.offset += 4; - return value; - } + /** + * Reads four bytes as big-endian unsigned 32-bit integer. + * @returns Unsigned 32-bit integer. + */ + readU32() { + this.ensureAvailable(4); + const value = this.view.getUint32(this.offset, false); + this.offset += 4; + return value; + } - /** - * Reads eight bytes as big-endian signed 64-bit integer. - * @returns Safe integer representation of the decoded value. - */ - readI64() { - this.ensureAvailable(8); - const value = this.view.getBigInt64(this.offset, false); - this.offset += 8; + /** + * Reads eight bytes as big-endian signed 64-bit integer. + * @returns Safe integer representation of the decoded value. + */ + readI64() { + this.ensureAvailable(8); + const value = this.view.getBigInt64(this.offset, false); + this.offset += 8; - const numberValue = Number(value); - if (!Number.isSafeInteger(numberValue)) { - throw new Error( - `Decoded number ${value.toString()} exceeds JS safe integer range`, - ); - } + const numberValue = Number(value); + if (!Number.isSafeInteger(numberValue)) { + throw new Error( + `Decoded number ${value.toString()} exceeds JS safe integer range`, + ); + } - return numberValue; - } + return numberValue; + } - /** - * Reads six bytes as a big-endian unsigned 48-bit integer. - * @returns Unsigned 48-bit integer represented as number. - */ - readU48() { - this.ensureAvailable(6); - const upper = this.view.getUint16(this.offset, false); - const lower = this.view.getUint32(this.offset + 2, false); - this.offset += 6; - return upper * 2 ** 32 + lower; - } + /** + * Reads six bytes as a big-endian unsigned 48-bit integer. + * @returns Unsigned 48-bit integer represented as number. + */ + readU48() { + this.ensureAvailable(6); + const upper = this.view.getUint16(this.offset, false); + const lower = this.view.getUint32(this.offset + 2, false); + this.offset += 6; + return upper * 2 ** 32 + lower; + } - /** - * Reads a byte slice of the requested length. - * @param length Number of bytes to read. - * @returns View over the requested bytes. - */ - readBytes(length: number) { - this.ensureAvailable(length); - const value = this.bytes.subarray(this.offset, this.offset + length); - this.offset += length; - return value; - } + /** + * Reads a byte slice of the requested length. + * @param length Number of bytes to read. + * @returns View over the requested bytes. + */ + readBytes(length: number) { + this.ensureAvailable(length); + const value = this.bytes.subarray(this.offset, this.offset + length); + this.offset += length; + return value; + } - /** - * Indicates whether all bytes have been consumed. - * @returns True when reader offset is at buffer end. - */ - isAtEnd() { - return this.offset === this.bytes.byteLength; - } + /** + * Indicates whether all bytes have been consumed. + * @returns True when reader offset is at buffer end. + */ + isAtEnd() { + return this.offset === this.bytes.byteLength; + } - /** - * Ensures that at least a specific number of bytes can still be read. - * @param length Required available byte count. - * @returns Void. - */ - private ensureAvailable(length: number) { - if (this.offset + length > this.bytes.byteLength) { - throw new Error("Unexpected end of protocol buffer"); - } - } + /** + * Ensures that at least a specific number of bytes can still be read. + * @param length Required available byte count. + * @returns Void. + */ + private ensureAvailable(length: number) { + if (this.offset + length > this.bytes.byteLength) { + throw new Error("Unexpected end of protocol buffer"); + } + } } diff --git a/packages/ttp/src/core.test.ts b/packages/ttp/src/core.test.ts index 2582213..dab9548 100644 --- a/packages/ttp/src/core.test.ts +++ b/packages/ttp/src/core.test.ts @@ -1,8 +1,5 @@ import { describe, it, expect } from "bun:test"; -import { - createTransportClient, - type SchemaMap, -} from "./core"; +import { createTransportClient, type SchemaMap } from "./core"; import { decodeCommunicationMessage, encodeCommunicationMessage, diff --git a/packages/ttp/src/core.ts b/packages/ttp/src/core.ts index e32dbac..d6a4838 100644 --- a/packages/ttp/src/core.ts +++ b/packages/ttp/src/core.ts @@ -199,7 +199,7 @@ export function createTransportClient( */ const handleIncomingMessage = (message: TypedMessage) => { if (message.type !== "pong") { - log(2, "Socket", "blue", "Received:", message.type, message.data, { + log(2, "ttp", "blue", "Received:", message.type, message.data, { id: message.id, }); } @@ -233,7 +233,7 @@ export function createTransportClient( log( 0, - "Socket", + "ttp", "red", `Response validation failed for "${message.type}"`, result.error, @@ -254,7 +254,7 @@ export function createTransportClient( if (!result.success) { log( 0, - "Socket", + "ttp", "red", `Push-event validation failed for "${message.type}"`, result.error, @@ -282,7 +282,7 @@ export function createTransportClient( const handleRecoverableDecodeFailure = ( error: RecoverableMessageDecodeError, ) => { - log(1, "Socket", "yellow", "Recoverable message decode failure", { + log(1, "ttp", "yellow", "Recoverable message decode failure", { id: error.messageId, type: error.messageType, error: error.message, @@ -359,13 +359,7 @@ export function createTransportClient( shouldDiscardFrames, ); } catch (error) { - log( - 0, - "Socket", - "red", - "Incoming transport stream failed", - error, - ); + log(0, "ttp", "red", "Incoming transport stream failed", error); handleConnectionFailure(connection, error); } })(); @@ -387,7 +381,7 @@ export function createTransportClient( ); } } catch (error) { - log(0, "Socket", "red", "Incoming stream accept loop failed", error); + log(0, "ttp", "red", "Incoming stream accept loop failed", error); handleConnectionFailure(connection, error); } finally { connection.streamReader?.releaseLock(); @@ -456,11 +450,11 @@ export function createTransportClient( return; } - log(1, "Socket", "green", "Connected"); + log(1, "ttp", "green", "Connected"); setReadyState(READY_STATE.OPEN); startIncomingLoop(connection); } catch (error) { - log(0, "Socket", "red", "WebTransport connection failed", error); + log(0, "ttp", "red", "WebTransport connection failed", error); handleConnectionFailure(connection, error); throw error; } @@ -494,7 +488,7 @@ export function createTransportClient( try { await writeCloseFrame(connection.transport); } catch (error) { - log(1, "Socket", "yellow", "Failed to send close sentinel", error); + log(1, "ttp", "yellow", "Failed to send close sentinel", error); } try { @@ -544,7 +538,7 @@ export function createTransportClient( if (!result.success) { log( 0, - "Socket", + "ttp", "red", `Request validation failed for "${type}"`, result.error, @@ -569,7 +563,7 @@ export function createTransportClient( } if (type !== "ping") { - log(2, "Socket", "purple", "Sent:", type, payload, { id: options.id }); + log(2, "ttp", "purple", "Sent:", type, payload, { id: options.id }); } const expectsResponse = !options?.noResponse; @@ -704,10 +698,7 @@ function logBinaryMessage( return; } - console.log( - `[Socket] ${direction} binary message (${payload.byteLength} bytes)`, - payload, - ); + log(3, "ttp", "yellow", `${direction} ${payload.byteLength} bytes:`, payload); } /** diff --git a/packages/ui/src/cmp/avatar.tsx b/packages/ui/src/cmp/avatar.tsx index e585f7d..8b30cbb 100644 --- a/packages/ui/src/cmp/avatar.tsx +++ b/packages/ui/src/cmp/avatar.tsx @@ -1,14 +1,14 @@ -import * as React from "react" -import { Avatar as AvatarPrimitive } from "radix-ui" +import * as React from "react"; +import { Avatar as AvatarPrimitive } from "radix-ui"; -import { cn } from "../lib/utils" +import { cn } from "../lib/utils"; function Avatar({ className, size = "default", ...props }: React.ComponentProps & { - size?: "default" | "sm" | "lg" + size?: "default" | "sm" | "lg"; }) { return ( - ) + ); } function AvatarImage({ @@ -32,11 +32,11 @@ function AvatarImage({ data-slot="avatar-image" className={cn( "aspect-square size-full rounded-full object-cover", - className + className, )} {...props} /> - ) + ); } function AvatarFallback({ @@ -48,11 +48,11 @@ function AvatarFallback({ data-slot="avatar-fallback" className={cn( "flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs", - className + className, )} {...props} /> - ) + ); } function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) { @@ -64,11 +64,11 @@ function AvatarBadge({ className, ...props }: React.ComponentProps<"span">) { "group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden", "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2", "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2", - className + className, )} {...props} /> - ) + ); } function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) { @@ -77,11 +77,11 @@ function AvatarGroup({ className, ...props }: React.ComponentProps<"div">) { data-slot="avatar-group" className={cn( "group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background", - className + className, )} {...props} /> - ) + ); } function AvatarGroupCount({ @@ -93,11 +93,11 @@ function AvatarGroupCount({ data-slot="avatar-group-count" className={cn( "relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3", - className + className, )} {...props} /> - ) + ); } export { @@ -107,4 +107,4 @@ export { AvatarGroup, AvatarGroupCount, AvatarBadge, -} +}; diff --git a/packages/ui/src/cmp/button.tsx b/packages/ui/src/cmp/button.tsx index 57240b1..437a3e4 100644 --- a/packages/ui/src/cmp/button.tsx +++ b/packages/ui/src/cmp/button.tsx @@ -1,8 +1,8 @@ -import * as React from "react" -import { cva, type VariantProps } from "class-variance-authority" -import { Slot } from "radix-ui" +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; +import { Slot } from "radix-ui"; -import { cn } from "../lib/utils" +import { cn } from "../lib/utils"; const buttonVariants = cva( "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", @@ -38,8 +38,8 @@ const buttonVariants = cva( variant: "default", size: "default", }, - } -) + }, +); function Button({ className, @@ -49,9 +49,9 @@ function Button({ ...props }: React.ComponentProps<"button"> & VariantProps & { - asChild?: boolean + asChild?: boolean; }) { - const Comp = asChild ? Slot.Root : "button" + const Comp = asChild ? Slot.Root : "button"; return ( - ) + ); } -export { Button, buttonVariants } +export { Button, buttonVariants }; diff --git a/packages/ui/src/cmp/card.tsx b/packages/ui/src/cmp/card.tsx index 4e5020e..85e5ec7 100644 --- a/packages/ui/src/cmp/card.tsx +++ b/packages/ui/src/cmp/card.tsx @@ -1,6 +1,6 @@ -import * as React from "react" +import * as React from "react"; -import { cn } from "../lib/utils" +import { cn } from "../lib/utils"; function Card({ className, @@ -13,11 +13,11 @@ function Card({ data-size={size} className={cn( "group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl", - className + className, )} {...props} /> - ) + ); } function CardHeader({ className, ...props }: React.ComponentProps<"div">) { @@ -26,11 +26,11 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) { data-slot="card-header" className={cn( "group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3", - className + className, )} {...props} /> - ) + ); } function CardTitle({ className, ...props }: React.ComponentProps<"div">) { @@ -39,11 +39,11 @@ function CardTitle({ className, ...props }: React.ComponentProps<"div">) { data-slot="card-title" className={cn( "text-base leading-snug font-medium group-data-[size=sm]/card:text-sm", - className + className, )} {...props} /> - ) + ); } function CardDescription({ className, ...props }: React.ComponentProps<"div">) { @@ -53,7 +53,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) { className={cn("text-sm text-muted-foreground", className)} {...props} /> - ) + ); } function CardAction({ className, ...props }: React.ComponentProps<"div">) { @@ -62,11 +62,11 @@ function CardAction({ className, ...props }: React.ComponentProps<"div">) { data-slot="card-action" className={cn( "col-start-2 row-span-2 row-start-1 self-start justify-self-end", - className + className, )} {...props} /> - ) + ); } function CardContent({ className, ...props }: React.ComponentProps<"div">) { @@ -76,7 +76,7 @@ function CardContent({ className, ...props }: React.ComponentProps<"div">) { className={cn("px-4 group-data-[size=sm]/card:px-3", className)} {...props} /> - ) + ); } function CardFooter({ className, ...props }: React.ComponentProps<"div">) { @@ -85,11 +85,11 @@ function CardFooter({ className, ...props }: React.ComponentProps<"div">) { data-slot="card-footer" className={cn( "flex items-center rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/card:p-3", - className + className, )} {...props} /> - ) + ); } export { @@ -100,4 +100,4 @@ export { CardAction, CardDescription, CardContent, -} +}; diff --git a/packages/ui/src/cmp/checkbox.tsx b/packages/ui/src/cmp/checkbox.tsx index 508a63e..97707c6 100644 --- a/packages/ui/src/cmp/checkbox.tsx +++ b/packages/ui/src/cmp/checkbox.tsx @@ -1,10 +1,10 @@ -"use client" +"use client"; -import * as React from "react" -import { Checkbox as CheckboxPrimitive } from "radix-ui" +import * as React from "react"; +import { Checkbox as CheckboxPrimitive } from "radix-ui"; -import { cn } from "../lib/utils" -import { CheckIcon } from "lucide-react" +import { cn } from "../lib/utils"; +import { CheckIcon } from "lucide-react"; function Checkbox({ className, @@ -15,7 +15,7 @@ function Checkbox({ data-slot="checkbox" className={cn( "peer relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input transition-colors outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary", - className + className, )} {...props} > @@ -23,11 +23,10 @@ function Checkbox({ data-slot="checkbox-indicator" className="grid place-content-center text-current transition-none [&>svg]:size-3.5" > - + - ) + ); } -export { Checkbox } +export { Checkbox }; diff --git a/packages/ui/src/cmp/context-menu.tsx b/packages/ui/src/cmp/context-menu.tsx index 3aebeec..3602a4b 100644 --- a/packages/ui/src/cmp/context-menu.tsx +++ b/packages/ui/src/cmp/context-menu.tsx @@ -1,13 +1,13 @@ -import * as React from "react" -import { ContextMenu as ContextMenuPrimitive } from "radix-ui" +import * as React from "react"; +import { ContextMenu as ContextMenuPrimitive } from "radix-ui"; -import { cn } from "../lib/utils" -import { ChevronRightIcon, CheckIcon } from "lucide-react" +import { cn } from "../lib/utils"; +import { ChevronRightIcon, CheckIcon } from "lucide-react"; function ContextMenu({ ...props }: React.ComponentProps) { - return + return ; } function ContextMenuTrigger({ @@ -20,7 +20,7 @@ function ContextMenuTrigger({ className={cn("select-none", className)} {...props} /> - ) + ); } function ContextMenuGroup({ @@ -28,7 +28,7 @@ function ContextMenuGroup({ }: React.ComponentProps) { return ( - ) + ); } function ContextMenuPortal({ @@ -36,13 +36,13 @@ function ContextMenuPortal({ }: React.ComponentProps) { return ( - ) + ); } function ContextMenuSub({ ...props }: React.ComponentProps) { - return + return ; } function ContextMenuRadioGroup({ @@ -53,24 +53,27 @@ function ContextMenuRadioGroup({ data-slot="context-menu-radio-group" {...props} /> - ) + ); } function ContextMenuContent({ className, ...props }: React.ComponentProps & { - side?: "top" | "right" | "bottom" | "left" + side?: "top" | "right" | "bottom" | "left"; }) { return ( - ) + ); } function ContextMenuItem({ @@ -79,8 +82,8 @@ function ContextMenuItem({ variant = "default", ...props }: React.ComponentProps & { - inset?: boolean - variant?: "default" | "destructive" + inset?: boolean; + variant?: "default" | "destructive"; }) { return ( - ) + ); } function ContextMenuSubTrigger({ @@ -102,7 +105,7 @@ function ContextMenuSubTrigger({ children, ...props }: React.ComponentProps & { - inset?: boolean + inset?: boolean; }) { return ( {children} - ) + ); } function ContextMenuSubContent({ @@ -127,10 +130,13 @@ function ContextMenuSubContent({ return ( - ) + ); } function ContextMenuCheckboxItem({ @@ -140,7 +146,7 @@ function ContextMenuCheckboxItem({ inset, ...props }: React.ComponentProps & { - inset?: boolean + inset?: boolean; }) { return ( - + {children} - ) + ); } function ContextMenuRadioItem({ @@ -170,7 +175,7 @@ function ContextMenuRadioItem({ inset, ...props }: React.ComponentProps & { - inset?: boolean + inset?: boolean; }) { return ( - + {children} - ) + ); } function ContextMenuLabel({ @@ -198,7 +202,7 @@ function ContextMenuLabel({ inset, ...props }: React.ComponentProps & { - inset?: boolean + inset?: boolean; }) { return ( - ) + ); } function ContextMenuSeparator({ @@ -223,7 +227,7 @@ function ContextMenuSeparator({ className={cn("-mx-1 my-1 h-px bg-border", className)} {...props} /> - ) + ); } function ContextMenuShortcut({ @@ -235,11 +239,11 @@ function ContextMenuShortcut({ data-slot="context-menu-shortcut" className={cn( "ml-auto text-xs tracking-widest text-muted-foreground group-focus/context-menu-item:text-accent-foreground", - className + className, )} {...props} /> - ) + ); } export { @@ -258,4 +262,4 @@ export { ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuRadioGroup, -} +}; diff --git a/packages/ui/src/cmp/dialog.tsx b/packages/ui/src/cmp/dialog.tsx index 1a1fda9..5e3dd8f 100644 --- a/packages/ui/src/cmp/dialog.tsx +++ b/packages/ui/src/cmp/dialog.tsx @@ -1,34 +1,34 @@ -"use client" +"use client"; -import * as React from "react" -import { Dialog as DialogPrimitive } from "radix-ui" +import * as React from "react"; +import { Dialog as DialogPrimitive } from "radix-ui"; -import { cn } from "../lib/utils" -import { Button } from "./button" -import { XIcon } from "lucide-react" +import { cn } from "../lib/utils"; +import { Button } from "./button"; +import { XIcon } from "lucide-react"; function Dialog({ ...props }: React.ComponentProps) { - return + return ; } function DialogTrigger({ ...props }: React.ComponentProps) { - return + return ; } function DialogPortal({ ...props }: React.ComponentProps) { - return + return ; } function DialogClose({ ...props }: React.ComponentProps) { - return + return ; } function DialogOverlay({ @@ -40,11 +40,11 @@ function DialogOverlay({ data-slot="dialog-overlay" className={cn( "fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0", - className + className, )} {...props} /> - ) + ); } function DialogContent({ @@ -53,7 +53,7 @@ function DialogContent({ showCloseButton = true, ...props }: React.ComponentProps & { - showCloseButton?: boolean + showCloseButton?: boolean; }) { return ( @@ -62,7 +62,7 @@ function DialogContent({ data-slot="dialog-content" className={cn( "fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", - className + className, )} {...props} > @@ -74,15 +74,14 @@ function DialogContent({ className="absolute top-2 right-2" size="icon-sm" > - + Close )} - ) + ); } function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { @@ -92,7 +91,7 @@ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { className={cn("flex flex-col gap-2", className)} {...props} /> - ) + ); } function DialogFooter({ @@ -101,14 +100,14 @@ function DialogFooter({ children, ...props }: React.ComponentProps<"div"> & { - showCloseButton?: boolean + showCloseButton?: boolean; }) { return (
@@ -119,7 +118,7 @@ function DialogFooter({ )}
- ) + ); } function DialogTitle({ @@ -129,13 +128,10 @@ function DialogTitle({ return ( - ) + ); } function DialogDescription({ @@ -147,11 +143,11 @@ function DialogDescription({ data-slot="dialog-description" className={cn( "text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground", - className + className, )} {...props} /> - ) + ); } export { @@ -165,4 +161,4 @@ export { DialogPortal, DialogTitle, DialogTrigger, -} +}; diff --git a/packages/ui/src/cmp/input.tsx b/packages/ui/src/cmp/input.tsx index 098b3ca..535ea3b 100644 --- a/packages/ui/src/cmp/input.tsx +++ b/packages/ui/src/cmp/input.tsx @@ -1,6 +1,6 @@ -import * as React from "react" +import * as React from "react"; -import { cn } from "../lib/utils" +import { cn } from "../lib/utils"; function Input({ className, type, ...props }: React.ComponentProps<"input">) { return ( @@ -9,11 +9,11 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) { data-slot="input" className={cn( "h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40", - className + className, )} {...props} /> - ) + ); } -export { Input } +export { Input }; diff --git a/packages/ui/src/cmp/label.tsx b/packages/ui/src/cmp/label.tsx index db0eaee..1f63e01 100644 --- a/packages/ui/src/cmp/label.tsx +++ b/packages/ui/src/cmp/label.tsx @@ -1,9 +1,9 @@ -"use client" +"use client"; -import * as React from "react" -import { Label as LabelPrimitive } from "radix-ui" +import * as React from "react"; +import { Label as LabelPrimitive } from "radix-ui"; -import { cn } from "../lib/utils" +import { cn } from "../lib/utils"; function Label({ className, @@ -14,11 +14,11 @@ function Label({ data-slot="label" className={cn( "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", - className + className, )} {...props} /> - ) + ); } -export { Label } +export { Label }; diff --git a/packages/ui/src/cmp/select.tsx b/packages/ui/src/cmp/select.tsx index eeb4e02..db947b3 100644 --- a/packages/ui/src/cmp/select.tsx +++ b/packages/ui/src/cmp/select.tsx @@ -1,13 +1,13 @@ -import * as React from "react" -import { Select as SelectPrimitive } from "radix-ui" +import * as React from "react"; +import { Select as SelectPrimitive } from "radix-ui"; -import { cn } from "../lib/utils" -import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react" +import { cn } from "../lib/utils"; +import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"; function Select({ ...props }: React.ComponentProps) { - return + return ; } function SelectGroup({ @@ -20,13 +20,13 @@ function SelectGroup({ className={cn("scroll-my-1 p-1", className)} {...props} /> - ) + ); } function SelectValue({ ...props }: React.ComponentProps) { - return + return ; } function SelectTrigger({ @@ -35,7 +35,7 @@ function SelectTrigger({ children, ...props }: React.ComponentProps & { - size?: "sm" | "default" + size?: "sm" | "default"; }) { return ( @@ -52,7 +52,7 @@ function SelectTrigger({ - ) + ); } function SelectContent({ @@ -67,7 +67,12 @@ function SelectContent({ {children} @@ -85,7 +90,7 @@ function SelectContent({ - ) + ); } function SelectLabel({ @@ -98,7 +103,7 @@ function SelectLabel({ className={cn("px-1.5 py-1 text-xs text-muted-foreground", className)} {...props} /> - ) + ); } function SelectItem({ @@ -111,7 +116,7 @@ function SelectItem({ data-slot="select-item" className={cn( "relative flex w-full cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2", - className + className, )} {...props} > @@ -122,7 +127,7 @@ function SelectItem({ {children} - ) + ); } function SelectSeparator({ @@ -135,7 +140,7 @@ function SelectSeparator({ className={cn("pointer-events-none -mx-1 my-1 h-px bg-border", className)} {...props} /> - ) + ); } function SelectScrollUpButton({ @@ -147,14 +152,13 @@ function SelectScrollUpButton({ data-slot="select-scroll-up-button" className={cn( "z-10 flex cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4", - className + className, )} {...props} > - + - ) + ); } function SelectScrollDownButton({ @@ -166,14 +170,13 @@ function SelectScrollDownButton({ data-slot="select-scroll-down-button" className={cn( "z-10 flex cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4", - className + className, )} {...props} > - + - ) + ); } export { @@ -187,4 +190,4 @@ export { SelectSeparator, SelectTrigger, SelectValue, -} +}; diff --git a/packages/ui/src/cmp/skeleton.tsx b/packages/ui/src/cmp/skeleton.tsx index 67837b3..99f46eb 100644 --- a/packages/ui/src/cmp/skeleton.tsx +++ b/packages/ui/src/cmp/skeleton.tsx @@ -1,4 +1,4 @@ -import { cn } from "../lib/utils" +import { cn } from "../lib/utils"; function Skeleton({ className, ...props }: React.ComponentProps<"div">) { return ( @@ -7,7 +7,7 @@ function Skeleton({ className, ...props }: React.ComponentProps<"div">) { className={cn("animate-pulse rounded-md bg-muted", className)} {...props} /> - ) + ); } -export { Skeleton } +export { Skeleton }; diff --git a/packages/ui/src/cmp/sonner.tsx b/packages/ui/src/cmp/sonner.tsx index 9280ee5..7cbe96b 100644 --- a/packages/ui/src/cmp/sonner.tsx +++ b/packages/ui/src/cmp/sonner.tsx @@ -1,32 +1,28 @@ -"use client" +"use client"; -import { useTheme } from "next-themes" -import { Toaster as Sonner, type ToasterProps } from "sonner" -import { CircleCheckIcon, InfoIcon, TriangleAlertIcon, OctagonXIcon, Loader2Icon } from "lucide-react" +import { useTheme } from "next-themes"; +import { Toaster as Sonner, type ToasterProps } from "sonner"; +import { + CircleCheckIcon, + InfoIcon, + TriangleAlertIcon, + OctagonXIcon, + Loader2Icon, +} from "lucide-react"; const Toaster = ({ ...props }: ToasterProps) => { - const { theme = "system" } = useTheme() + const { theme = "system" } = useTheme(); return ( - ), - info: ( - - ), - warning: ( - - ), - error: ( - - ), - loading: ( - - ), + success: , + info: , + warning: , + error: , + loading: , }} style={ { @@ -43,7 +39,7 @@ const Toaster = ({ ...props }: ToasterProps) => { }} {...props} /> - ) -} + ); +}; -export { Toaster } +export { Toaster }; diff --git a/packages/ui/src/cmp/tooltip.tsx b/packages/ui/src/cmp/tooltip.tsx index 3c79ef9..7cd7fbb 100644 --- a/packages/ui/src/cmp/tooltip.tsx +++ b/packages/ui/src/cmp/tooltip.tsx @@ -1,7 +1,7 @@ -import * as React from "react" -import { Tooltip as TooltipPrimitive } from "radix-ui" +import * as React from "react"; +import { Tooltip as TooltipPrimitive } from "radix-ui"; -import { cn } from "../lib/utils" +import { cn } from "../lib/utils"; function TooltipProvider({ delayDuration = 0, @@ -13,19 +13,19 @@ function TooltipProvider({ delayDuration={delayDuration} {...props} /> - ) + ); } function Tooltip({ ...props }: React.ComponentProps) { - return + return ; } function TooltipTrigger({ ...props }: React.ComponentProps) { - return + return ; } function TooltipContent({ @@ -41,7 +41,7 @@ function TooltipContent({ sideOffset={sideOffset} className={cn( "z-50 inline-flex w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", - className + className, )} {...props} > @@ -49,7 +49,7 @@ function TooltipContent({ - ) + ); } -export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } +export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };