Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

What is VoidMerge?

Void Merge is the next-generation, developer oriented web services platform.

  • Forever open-source design eliminates big-tech vendor lock-in.
  • Conflict-free data replication makes clustering a breeze.
  • Built from the start for state of the art real-time P2P apps and post-quantum security.
  • Managed hosting for turnkey security and reliability.

The vm Utility

Install the vm command-line utility to work with VoidMerge.

  • vm serve runs a VoidMerge server instance.
  • The other commands let you administrate a running server instance.

Installing the vm Utility

Option 1: Install from crates.io

  1. First, Get Rust (https://rustup.rs/).
  2. Second, Install the vm utility with cargo:
cargo install voidmerge --bin vm

Use this command like other local commands:

vm --help

Option 2: Use a docker image

docker pull ghcr.io/voidmerge/voidmerge-vm:latest

Use this command through docker:

docker run -it ghcr.io/voidmerge/voidmerge-vm:latest vm --help

Note: if you're running 'vm serve' in docker, you'll likely need to add additional options to the command to bind a volume and expose the port of the server.

Quick Start

Clone the Template Repository

git clone https://github.com/voidmerge/voidmerge-template.git

# then go into the directory
cd voidmerge-template

Install Dependencies

npm install

Run the VM Server (Using Docker):

npm run start-docker

Open a browser:

http://127.0.0.1:8080/test/

No Docker? Install the "vm" Cli Tool.

https://rustup.rs/

cargo install voidmerge

Run the VM Server (Using Native CLI):

npm start

Open a browser:

http://127.0.0.1:8080/test/

Functions

Functions represent the main request/response type of a Void Merge service.

RequestFn type API Docs

// Import the voidmerge-code library to gain access to types.
import * as VM from "@voidmerge/voidmerge-code"

// The "VoidMergeHandler" is the main entry point to void merge logic.
VM.defineVoidMergeHandler(async (req) => {
  // If this is a "Function" type request, send back a "Hello World!" response.
  if (req instanceof VM.RequestFn) {
    return new VM.ResponseFnOk({
      // Set the http status code to 200.
      status: 200,

      // Send back "Hello World!" text.
      body: new TextEncoder().encode("Hello World!"),

      // Set the content type to "text/plain".
      headers: {
        "content-type": "text/plain",
      },
    });
  }

  // Output an error if the request is a type we don't handle.
  throw new Error(`Unhandled Request ${JSON.stringify(req)}`);
})

Object Store

A Void Merge service has access to an object store.

Put data into the store.

objPut API Docs

const { meta } = await VM.objPut({
    meta: VM.ObjMeta.fromParts({ appPath: "test-path" }),
    data: new TextEncoder().encode("test-data"),
});

Get data from the store.

objGet API Docs

const { data } = await VM.objGet({
    meta: VM.ObjMeta.fromParts({ appPath: "test-path" }),
});

List data from the store.

objList API Docs

const { metaList } = await VM.objList({
    appPathPrefix: "test-",
    createdGt: 0,
    limit: 50,
});

Object Store Validation

When data is put into the object store, either from a call in a function or cron handler, or when it is synced from a peer node in a cluster, Void Merge provides an opportunity to validate the data, and reject it if needed.

RequestObjCheck type API Docs

import * as VM from "@voidmerge/voidmerge-code";

VM.defineVoidMergeHandler(async (req) => {
  if (req instanceof VM.RequestObjCheck) {
    const data = new TextDecoder().decode(req.data);
    if (data === "hello") {
      return new VM.ResponseObjCheckOk();
    } else {
      throw new Error(`invalid data: ${data}`);
    }
  }
}

Cron

Void Merge web services provide a method for periodic maintenance tasks.

First, we have to tell void merge how often to run this task.

ResponseCodeConfigOk type API Docs

import * as VM from "@voidmerge/voidmerge-code";

VM.defineVoidMergeHandler(async (req) => {
  const reqType = req.type;

  if (req instanceof VM.RequestCodeConfig) {
    // Run cron every 10 seconds.
    return new VM.ResponseCodeConfigOk({ cronIntervalSecs: 10 });
  }
}

Now we need to actually do something when a cron request is triggered.

import * as VM from "@voidmerge/voidmerge-code";

VM.defineVoidMergeHandler(async (req) => {
  const reqType = req.type;

  if (req instanceof VM.RequestCodeConfig) {
    // Run cron every 10 seconds.
    return new VM.ResponseCodeConfigOk({ cronIntervalSecs: 10 });
  } else if (req instanceof VM.RequestCron) {
    // Write a new unique entry every cron run.
    await VM.objPut({
      meta: VM.ObjMeta.fromParts({ appPath: Date.now().toString() }),
      data: new TextEncoder().encode(Date.now().toString()),
    });

    return new VM.ResponseCronOk();
  }
}

Messaging

A Void Merge service provides the ability to send messages to connected clients and can be set up so clients can message each other.

Create a new messaging channel for a client.

msgNew API Docs

const { msgId } = await VM.msgNew();

MsgListener API Docs

// In the client code:

import * as VM from "@voidmerge/voidmerge-client"

const listener = await VM.MsgListener.connect({
    msgId,
    ...
});

List open messaging channels.

msgList API Docs

const { msgIdList } = await VM.msgList();

Send a message over an open channel.

msgSend API Docs

await VM.msgSend({
    msg: new TextEncoder().encode("hello"),
    msgId,
});