0.0.13 • Published 7 years ago

@wessberg/syncdb-client v0.0.13

Weekly downloads
1
License
MIT
Repository
-
Last release
7 years ago

SyncDBClient NPM version

The client part of the offline-first, observable, decoupled, peer-to-peer distributed database SyncDB.

Installation

Simply do: npm install @wessberg/syncdb-client.

What is it

This is the client-part of the Offline-First, observable, decoupled Peer-To-Peer Distributed database SyncDB. It uses a central server to propagate messages around between clients, but it has no centralized data store. This means that the data in the network at all times reflects the contents of the local databases of the peers, and thus provides fully decentralized storage.

Disclaimer

It is still very early days for the synchronization flow between the clients and the server. It doesn't tackle failure resilience or scenarios where a peer simply doesn't reply. For now, use this library with caution.

Where does it work?

Anywhere! You just pass in the WebSocket and URL implementation to use. So, yes, this also works in the browser.

Usage

To support all WebSocket and URL implementations, it takes the implementations to use as a constructor argument:

const webSocketImplementation = WebSocket;
const urlImplementation = URL;
const client = new SyncDBClient({url: "localhost:8000", webSocketImplementation, urlImplementation});
await client.listen();
// The client is listening to the central server and is ready to send/receive messages!

SyncDBClient will automatically add 'ws://' or 'ws://' in front of the URL, depending on what you give as a URL. Writing a URL that starts with 'https://' will rewrite the URL to connect to a secure WebSocket (wss://) and so on. It is designed to be as flexible as possible to work with.

When you listen to the central server, you can send/receive messages from it. It will send you a message when it wants you to accept or reject a push request or to ask you for some data for another peer:

Pull example

// Request to pull the newest data:
const response = await client.pull();

// This data will come from another peer in the network. It may be rejected if no other peer has data.
if (response.status === SyncDBPullResponseStatusKind.ACCEPTED) {
	doSomethingWithTheNewData(response.value);
}

Push example

// Request to push some data:
const response = await client.push({
  changeDate: new Date(),
  storeName: "foo",
  key: 1,
  value: {bar: "baz"}
});

// If the push request was rejected, for example if the data has been invalidated by another request, it's probably a good idea to cancel the local transaction to rollback the local changes and maybe pull some fresh content from the central server.
if (response.status === SyncDBPushResponseStatusKind.REJECTED) {
	abortAndRollbackLocalChanges();
}

Validating push and pull requests from other peers

It's the role of any client to use the onPull() and onPush() hooks to validate incoming requests to pull/push data to/from the database. Here's how to use them:

// Hooking on to incoming push requests:
client.onPush(pushRequest => {
	// Validate the request here. You can return a Promise if it requires asynchronous work. In this example, the client decides to reject the push request.
	return {
		status: SyncDBPushResponseStatusKind.REJECTED,
		reason: SyncDBPushResponseRejectKind.UNAUTHORIZED
	}
});

// Hooking on to incoming pull requests
client.onPull(async pullRequest => {
	// Check if you have the data in your local database and return it if it exists
	const value = await fetchMissingDataFromDatabase(pullRequest);
	return {
		status: SyncDBPullResponseStatusKind.ACCEPTED, value
	}
});

Receiving change notifications

You can use the onChange() hook to be notified when the contents of the database changes from any of the remote peers. This is also a very useful way to observe a local database for changes and respond to them in real-time, for example if multiple tabs are open.

client.onChange(async change => {
	await updateLocalDatabase(change);
});

Changelog:

v0.0.13:

  • Bumped dependencies.

v0.0.12:

  • BREAKING: Constructor now takes a "URL" string rather than separate hosts and ports. This also means that you can pass in an optional path you want to connect to. It also takes a URL constructor to support more environments.

v0.0.11:

  • Bumped dependencies.

v0.0.10:

  • Forgot to build in the previous version.

v0.0.9:

v0.0.8:

  • Refactoring.

v0.0.7:

  • Refactoring. Documentation.

v0.0.6:

  • Bumped dependency on the common module. Updated type signatures.

v0.0.5:

  • Updated interface declaration for 'push' and 'pull' methods to reflect implementation.

v0.0.3:

  • Bumped dependency on the common module. Updated type signatures.

v0.0.2:

  • Fixed an issue in the client adapter where on() hooks would return a MessageEvent rather than the actual data for browser clients.

v0.0.1:

  • First release.