Getting Started
Installation

Installation

Krmx provides reference implementations of its protocol. These have been written in TypeScript. The server implementation for a NodeJS backend server and two client implementations. One client for a NodeJS client and one client for a React frontend.

Almost everyone has access to a browser. Since, WebSockets are supported by all major web browsers nowadays, it makes sense for the reference implementation of the client to be browser-based. The client reference implementations have been written in TypeScript as that is the recommended language for the web. For type reusability and consistency with the clients, the server has also been written in TypeScript.

NodeJS Installation

These steps help you to add Krmx to an already existing NodeJS TypeScript backend server and a TypeScript React frontend. If you start from scratch, you can follow the demo from scratch.

You can also start by learning more about Krmx.

Server

In your NodeJS server, install the @krmx/server package using npm or yarn.

npm install @krmx/server
 
# or use yarn
yarn add @krmx/server

Then, you can create a simple server using the following setup. The api level documentation can be found on the type definitions.

Example Server Code
// in server.ts
import { createServer, Props } from '@krmx/server';
 
const props: Props = { /* configure here */ }
const server = createServer(props);
 
server.on('authenticate', (username, isNewUser, reject) => {
  if (isNewUser && server.getUsers().length > 4) {
    reject('server is full');
  }
});
 
server.on('message', (username, message) => {
  console.debug(`[debug] [krmx] ${username} sent ${message.type}`);
});
 
const port = 8082;
server.listen(port);

Then run npx ts-node server.ts to start your server, the Krmx server will start listening on port 8082 and clients will be able to connect using ws://localhost:8082 on your local machine.

More information about the Krmx server.

Client in React

In your React project, install the @krmx/client-react package using npm or yarn.

npm install @krmx/client-react
 
# or use yarn
yarn add @krmx/client-react

Then, you can create a simple React component that serves as a client using the following setup.

Example Client Code
// in components/krmx-example-client.tsx
"use client";
import { useEffect, useState } from 'react';
import { createClient, createStore } from '@krmx/client-react';
 
// Create the client
export const { client, useClient } = createClient();
 
// Create an example store for messages received from the server
let id = 0;
export const useMessages = createStore(
  client,
  /* the initial internal state */
  [] as { id: number, message: string }[],
  /* a reducer handling state changes based on incoming messages */
  (state, message) => {
    id += 1;
    return [...state, { id, message: message.type }].slice(-10);
  },
  /* a mapper that can map the internal state to a different format */
  s => s
);
 
// The example client component that you can use in your React app to connect to a Krmx server
export function KrmxExampleClient({ serverUrl }: { serverUrl: string }) {
  // Use the Krmx client and the example message store in this component
  const { status, username, users } = useClient();
  const messages = useMessages();
 
  // Keep track of failures
  const [failure, setFailure] = useState<string | null>(null);
  useEffect(() => { setFailure(null); }, [status]);
 
  // When the server url changes, disconnect the client from the server
  useEffect(() => {
    if (client.getStatus() !== 'initializing' && client.getStatus() !== 'closed') {
      client.disconnect(true)
        .catch((e: Error) => console.error('error disconnecting', e.message));
    }
 
    // And... disconnect from the server when the component unmounts
    return () => {
      if (client.getStatus() !== 'initializing' && client.getStatus() !== 'closed') {
        client.disconnect(true)
          .catch((e: Error) => console.error('error disconnecting', e.message));
      }
    };
  }, [serverUrl]);
 
  // Your logic for when you're not (yet) connected to the server goes here
  if (status === 'initializing' || status === 'connecting' || status === 'closing' || status === 'closed') {
    return <>
      <h2>Status: {status}</h2>
      <p>No connection to the server...</p>
      <button onClick={() => {
        client.connect(serverUrl)
          .catch((e: Error) => setFailure(e.message));
      }}>
        Connect to {serverUrl}.
      </button>
    </>;
  }
 
  // Your logic for when your connection is not (yet) linked to a user goes here
  if (status === 'connected' || status === 'linking' || status === 'unlinking') {
    return (
      <div>
        <h2>Status: {status}</h2>
        <button onClick={() => {
          client.link('simon-' + Math.random().toString(36).slice(2, 6), 'no-auth')
            .catch((e: Error) => setFailure(e.message))
        }}>
          Link!
        </button>
        {failure && <p>Rejected: {failure}</p>}
        <button onClick={() => {
          client.disconnect()
            .catch((e: Error) => setFailure(e.message));
        }}>
          Disconnect!
        </button>
      </div>
    );
  }
 
  // Your logic for when you're ready to go goes here
  return (
    <div>
      <h2>Status: {status}</h2>
      <p>Welcome, <strong>{username}</strong>!</p>
      <button onClick={() => client.send({ type: 'custom/hello' })}>
        Send custom/hello
      </button>
      <button onClick={() => client.unlink().catch((e: Error) => setFailure(e.message))}>
        Unlink
      </button>
      <button onClick={() => client.leave().catch((e: Error) => setFailure(e.message))}>
        Leave
      </button>
      <h2>Users</h2>
      <ul>
        {users.map(({ username: otherUsername, isLinked }) => (
          <li key={otherUsername}>
            {isLinked ? '🟢' : '🔴'} {otherUsername}
          </li>),
        )}
      </ul>
      <ul>
        {messages.map(({ id, message }) => <li
          key={id}
        >{message}</li>)}
      </ul>
    </div>
  );
}

Then you can use the KrmxExampleClient component in your React app to connect to a Krmx server.

// in App.tsx
import { KrmxExampleClient } from '@/components/krmx-example-client';
 
export default function App() {
  return (<>
    {/* ... */}
    <KrmxExampleClient serverUrl="ws://localhost:8082" />
    {/* ... */}
  </>);
}

More information about the Krmx React client.

Support for other Programming Languages

Currently, Krmx has only been implemented in TypeScript. However, the Krmx protocol is language agnostic. If you decide to build your own Krmx compatible implementation for example using GoLang or Rust, then feel free to add that as a reference implementation to this repository by opening a pull request (opens in a new tab).