JSPM

@hardingjam/svelte-socket

0.0.7
    • ESM via JSPM
    • ES Module Entrypoint
    • Export Map
    • Keywords
    • License
    • Repository URL
    • TypeScript Types
    • README
    • Created
    • Published
    • Downloads 9
    • Score
      100M100P100Q76900F

    Package Exports

    • @hardingjam/svelte-socket

    Readme

    svelte-socket

    WebSocket wrapper for Svelte 5 using runes.

    Overview

    This library provides:

    • SvelteSocket - WebSocket wrapper class with reactive state properties (connectionStatus, sentMessages, receivedMessages)
    • SocketProvider - Context provider component that instantiates SvelteSocket and makes it available to child components
    • Debugger - UI panel component showing connection status, sent messages, and received messages
    • useSocket() - Hook to access socket instance from context

    Features

    • Constructor accepts configuration object with URL and optional callbacks (onMessage, onOpen, onClose, onError)
    • Optional debug logging via debug flag
    • Auto-reconnection with configurable delay and max attempts
    • Reactive message history (sent and received)
    • All state properties use Svelte 5 $state runes
    • TypeScript support

    Installation

    npm install svelte-socket

    Usage

    In parent components including +page.svelte or +layout.svelte...

    <script>
        import { SvelteSocket } from 'svelte-socket';
    
        // Callbacks can be added on construction...
        const socket = new SvelteSocket({
            url: 'ws://localhost:8080',
            onOpen: () => console.log('Hello, server!')
        });
        const isConnected = $derived(socket.connectionStatus === WebSocket.OPEN);
    
        // ...or later using addEventListener
        socket.addEventListener('message', (event) => {
            console.log(event.data);
        });
    
        socket.sendMessage('text');
    </script>
    
    <SocketProvider {svelteSocket}>
        {@render children()}
    </SocketProvider>

    In any child component...

    <script>
        import { useSocket } from 'svelte-socket';
        let { children } = $props();
        const socket = useSocket()
        let isConnected = $derived(socket.connectionStatus === WebSocket.OPEN);
        let receivedMessages = $derived(socket.receivedMessages)
    </script>
    
    <p>{isConnected}</p>
    {#each receivedMessages as msg, i}
        <p>{msg.origin}<p>
    {/each}
    

    API

    SvelteSocket

    Constructor

    new SvelteSocket(options: SocketConstructorArgs)

    Options:

    Property Type Required Description
    url string Yes WebSocket server URL
    onMessage (event: MessageEvent) => void No Called when message received
    onOpen (event: Event) => void No Called when connection opens
    onClose (event: CloseEvent) => void No Called when connection closes
    onError (event: Event) => void No Called on error
    debug boolean No Enable console logging (default: false)
    reconnectOptions ReconnectOptions No Auto-reconnection config
    maxMessageHistory number No Max messages to keep in history (default: 50). Set to 0 for unlimited

    ReconnectOptions:

    Property Type Description
    enabled boolean Enable auto-reconnection
    delay number Milliseconds before reconnect attempt
    maxAttempts number Maximum reconnection attempts

    Example:

    const socket = new SvelteSocket({
        url: 'ws://localhost:8080',
        debug: true,
        maxMessageHistory: 100, // Keep last 100 messages (default: 50)
        reconnectOptions: {
            enabled: true,
            delay: 1000,
            maxAttempts: 5
        },
        onMessage: (event) => console.log(event.data),
        onOpen: () => console.log('connected'),
        onClose: () => console.log('disconnected')
    });

    Properties

    Property Type Description
    connectionStatus WebSocket['readyState'] Connection state: 0 (CONNECTING), 1 (OPEN), 2 (CLOSING), 3 (CLOSED)
    sentMessages Array<{message: string | ArrayBuffer | Blob | ArrayBufferView, timestamp: number}> Sent message history (newest first, via unshift). Auto-trimmed to maxMessageHistory
    receivedMessages Array<{message: MessageEvent}> Received message history (newest first, via unshift). Auto-trimmed to maxMessageHistory
    maxMessageHistory number Maximum number of messages to keep in history (default: 50, readonly)

    Example:

    <script>
        const socket = new SvelteSocket({ url: 'ws://localhost:8080' });
    
        const connectionStatus = $derived(socket.connectionStatus);
        const sentMessages = $derived(socket.sentMessages);
        const receivedMessages = $derived(socket.receivedMessages);
    </script>
    
    {#if connectionStatus === WebSocket.OPEN}
        <p>Open</p>
    {:else if connectionStatus === WebSocket.CONNECTING}
        <p>Connecting</p>
    {:else}
        <p>Closed</p>
    {/if}
    
    <p>{sentMessages.length} sent</p>
    <p>{receivedMessages.length} received</p>
    
    {#each receivedMessages as { message }}
        <div>{message.data}</div>
    {/each}

    Methods

    addEventListener(event, callback)
    addEventListener(
        event: 'message' | 'close' | 'open' | 'error',
        callback: (event: MessageEvent | CloseEvent | Event) => void
    ): void

    Adds event listener to WebSocket. The callback type is automatically inferred based on the event type:

    • 'message'(event: MessageEvent) => void
    • 'close'(event: CloseEvent) => void
    • 'open'(event: Event) => void
    • 'error'(event: Event) => void

    Throws if socket not connected.

    socket.addEventListener('message', (event) => {
        console.log(event.data); // event is typed as MessageEvent
    });
    removeEventListener(event, callback)
    removeEventListener(
        event: 'message' | 'close' | 'open' | 'error',
        callback: (event: MessageEvent | CloseEvent | Event) => void
    ): void

    Removes event listener. Callback types match addEventListener.

    const handler = (event) => console.log(event.data);
    socket.addEventListener('message', handler);
    socket.removeEventListener('message', handler);
    sendMessage(message)
    sendMessage(message: string | ArrayBuffer | Blob | ArrayBufferView): void

    Sends a text or binary message through the WebSocket. Supports strings, ArrayBuffer, Blob, TypedArray, and DataView. Stores in sentMessages array. Throws if not connected or not in OPEN state.

    Example:

    // Send text
    socket.sendMessage('Hello, server!');
    socket.sendMessage(JSON.stringify({ type: 'ping' }));
    
    // Send binary data
    const buffer = new Uint8Array([1, 2, 3, 4]);
    socket.sendMessage(buffer);
    clearSentMessages()
    clearSentMessages(): void

    Clears sentMessages array.

    socket.clearSentMessages();
    clearReceivedMessages()
    clearReceivedMessages(): void

    Clears receivedMessages array.

    socket.clearReceivedMessages();
    removeSocket()
    removeSocket(): void

    Closes WebSocket connection. Clears message history. Prevents reconnection.

    socket.removeSocket();

    SocketProvider

    Context provider component that makes a socket instance available to child components.

    Props:

    Property Type Required Description
    url string Yes* WebSocket server URL (automatically creates socket)
    svelteSocket SvelteSocket Yes* Pre-configured SvelteSocket instance
    children Snippet No Child components

    *At least one of url or svelteSocket must be provided. If both are provided, svelteSocket takes precedence.

    Basic Usage:

    The simplest way to use the provider is to pass a url, which automatically creates a SvelteSocket for you:

    <script>
        import { SocketProvider } from 'svelte-socket';
    
        let { children } = $props();
    </script>
    
    <SocketProvider url="ws://localhost:8080">
        {@render children()}
    </SocketProvider>

    Custom Socket Configuration:

    You can also create your own SvelteSocket with custom callbacks and options, then pass it to the provider:

    <script>
        import { SocketProvider, SvelteSocket } from 'svelte-socket';
    
        let { children } = $props();
    
        const svelteSocket = new SvelteSocket({
            url: 'ws://localhost:8080',
            debug: true,
            reconnectOptions: {
                enabled: true,
                delay: 1000,
                maxAttempts: 5
            },
            onMessage: (event) => {
                console.log('Received:', event.data);
            },
            onOpen: () => {
                console.log('Connected!');
            }
        });
    </script>
    
    <SocketProvider {svelteSocket}>
        {@render children()}
    </SocketProvider>

    useSocket()

    useSocket(): SvelteSocket

    Returns socket instance from context.

    Throws if not used within SocketProvider.

    Example:

    <script>
        import { useSocket } from 'svelte-socket';
    
        const socket = useSocket();
    </script>

    Debugger

    Debug UI component. Shows connection status, sent messages, received messages.

    Props:

    Property Type Required
    socket SvelteSocket Yes

    Example:

    <script>
        import { SvelteSocket, Debugger } from 'svelte-socket';
    
        const socket = new SvelteSocket({ url: 'ws://localhost:8080' });
    </script>
    
    <Debugger {socket} />

    Displays:

    • Connection state (CONNECTING/OPEN/CLOSING/CLOSED)
    • Message counts (sent/received)
    • Sent message history with timestamps
    • Received message history with data

    Styling Requirements:

    This component requires Tailwind CSS. You must configure Tailwind to scan the package files:

    Tailwind v4:

    /* app.css */
    @import 'tailwindcss';
    @source '../node_modules/@hardingjam/svelte-socket/dist/**/*.svelte';

    Tailwind v3:

    // tailwind.config.js
    export default {
        content: [
            './src/**/*.{html,js,svelte,ts}',
            './node_modules/@hardingjam/svelte-socket/dist/**/*.svelte'
        ]
        // ... rest of config
    };

    Context Functions

    setSocket(socket)

    setSocket(socket: SvelteSocket): void

    Sets socket in Svelte context. Used by SocketProvider.

    getSocketContext()

    getSocketContext(): SvelteSocket

    Gets socket from context. Throws if not found.

    Examples

    Basic

    <script>
        import { SvelteSocket } from 'svelte-socket';
    
        const socket = new SvelteSocket({ url: 'ws://localhost:8080' });
    
        socket.addEventListener('message', (event) => {
            console.log(event.data);
        });
    
        function send() {
            socket.sendMessage('test');
        }
    </script>
    
    <button onclick={send}>Send</button>

    Auto-reconnect

    <script>
        import { SvelteSocket } from 'svelte-socket';
    
        const socket = new SvelteSocket({
            url: 'ws://localhost:8080',
            debug: true,
            reconnectOptions: {
                enabled: true,
                delay: 1000,
                maxAttempts: 5
            }
        });
    </script>

    JSON Messages

    <script>
        import { SvelteSocket } from 'svelte-socket';
    
        const socket = new SvelteSocket({ url: 'ws://localhost:8080' });
    
        socket.addEventListener('message', (event) => {
            const data = JSON.parse(event.data);
    
            if (data.type === 'ping') {
                socket.sendMessage(JSON.stringify({ type: 'pong' }));
            }
        });
    </script>

    Message History

    <script>
        import { SvelteSocket } from 'svelte-socket';
    
        const socket = new SvelteSocket({ url: 'ws://localhost:8080' });
        const sentMessages = $derived(socket.sentMessages);
        const receivedMessages = $derived(socket.receivedMessages);
    
        let input = $state('');
    
        function send() {
            if (input) {
                socket.sendMessage(input);
                input = '';
            }
        }
    </script>
    
    <input bind:value={input} />
    <button onclick={send}>Send</button>
    
    <h3>Sent ({sentMessages.length})</h3>
    {#each sentMessages as { message, timestamp }}
        <div>
            {new Date(timestamp).toLocaleTimeString()}: {message}
        </div>
    {/each}
    
    <h3>Received ({receivedMessages.length})</h3>
    {#each receivedMessages as { message }}
        <div>{message.data}</div>
    {/each}
    
    <button onclick={() => socket.clearSentMessages()}>Clear</button>

    With Provider

    <!-- +layout.svelte -->
    <script>
        import { SocketProvider } from 'svelte-socket';
    
        let { children } = $props();
    </script>
    
    <SocketProvider url="ws://localhost:8080">
        {@render children()}
    </SocketProvider>
    
    <!-- +page.svelte -->
    <script>
        import { useSocket } from 'svelte-socket';
    
        const socket = useSocket();
    
        socket.addEventListener('message', (event) => {
            console.log(event.data);
        });
    </script>

    TouchDesigner Integration

    Broadcast to all connected clients:

    # TouchDesigner Text DAT
    def broadcast():
        webServer = op('webserver1')
        clients = webServer.clients
    
        for client in clients:
            webServer.webSocketSendText(client, "message")
    
        print(f"Sent to {len(clients)} clients")

    Requirements

    • Svelte 5.0+
    • WebSocket support

    License

    MIT