Releases: tinyplex/tinybase
v5.0.3
This includes a final tiny breaking change for v5 (before the working week starts!)
In the WsServer API, the PathIdsListener and ClientIdsListener types are now given the changing path Id or client Id directly, rather than needing to call the clumsy getIdChanges callback.
v5.0.2
This release includes a few minor improvements to the ui-react module hooks, including:
- ensuring the callbacks are stable references when
GetId
-typed functions are used - allowing the
useDel*
hooks to useGetId
-typed functions in order to delete specific tables, rows, cells, or values based on the event parameter
Thanks to @cpojer for identifying these improvements.
v5.0.1
v5.0.0
We're excited to announce this major release for TinyBase! It includes important data synchronization functionality and a range of other improvements.
In Summary
- The new MergeableStore type wraps your data as a Conflict-Free Replicated Data Type (CRDT).
- The new Synchronizer framework keeps multiple instances of data in sync across different media.
- An improved module folder structure removes common packaging and bundling issues.
- The TinyBase Inspector is now in its own standalone ui-react-inspector module.
- TinyBase now supports only Expo SQLite v14 (SDK 51) and above.
There are also some small breaking changes that may affect you (but which should easy to fix if they do).
Let's look at the major functionality in more detail!
The New MergeableStore Type
A key part of TinyBase v5.0 is the new mergeable-store module, which contains a subtype of Store - called MergeableStore - that can be merged with another with deterministic results. The implementation uses an encoded hybrid logical clock (HLC) to timestamp the changes made so that they can be cleanly merged.
The getMergeableContent method on a MergeableStore is used to get the state of a store that can be merged into another. The applyMergeableChanges method will let you apply that to (another) store. The merge method is a convenience function to bidirectionally merge two stores together:
import {createMergeableStore} from 'tinybase';
const localStore1 = createMergeableStore();
const localStore2 = createMergeableStore();
localStore1.setCell('pets', 'fido', 'species', 'dog');
localStore2.setCell('pets', 'felix', 'species', 'cat');
localStore1.merge(localStore2);
console.log(localStore1.getContent());
// -> [{pets: {felix: {species: 'cat'}, fido: {species: 'dog'}}}, {}]
console.log(localStore2.getContent());
// -> [{pets: {felix: {species: 'cat'}, fido: {species: 'dog'}}}, {}]
Please read the new Using A MergeableStore guide for more details of how to use this important new API.
A MergeableStore can be persisted locally, just like a regular Store into file, local and session storage, and simple SQLite environments such as Expo and SQLite3. These allow you to save the state of a MergeableStore locally before it has had the chance to be synchronized online, for example.
Which leads us onto the next important feature in v5.0, allowing you to synchronize stores between systems...
The New Synchronizer Framework
The v5.0 release also introduces the new concept of synchronization. Synchronizer objects implement a negotiation protocol that allows multiple MergeableStore objects to be merged together. This can be across a network, using WebSockets, for example:
import {WebSocketServer, WebSocket} from 'ws';
import {createWsServer} from 'tinybase/synchronizers/synchronizer-ws-server';
import {createWsSynchronizer} from 'tinybase/synchronizers/synchronizer-ws-client';
// On a server machine:
const server = createWsServer(new WebSocketServer({port: 8043}));
// On the first client machine:
const store1 = createMergeableStore();
const synchronizer1 = await createWsSynchronizer(
store1,
new WebSocket('ws://localhost:8043'),
);
await synchronizer1.startSync();
store1.setCell('pets', 'fido', 'legs', 4);
// On the second client machine:
const store2 = createMergeableStore();
const synchronizer2 = await createWsSynchronizer(
store2,
new WebSocket('ws://localhost:8043'),
);
await synchronizer2.startSync();
store2.setCell('pets', 'felix', 'price', 5);
// ...
console.log(store1.getTables());
// -> {pets: {felix: {price: 5}, fido: {legs: 4}}}
console.log(store2.getTables());
// -> {pets: {felix: {price: 5}, fido: {legs: 4}}}
synchronizer1.destroy();
synchronizer2.destroy();
server.destroy();
This release includes three types of Synchronizer:
- The WsSynchronizer uses WebSockets to communicate between different systems as shown above.
- The BroadcastChannelSynchronizer uses the browser's BroadcastChannel API to communicate between different tabs and workers.
- The LocalSynchronizer demonstrates synchronization in memory on a single local system.
Notice that the WsSynchronizer assumes that there exists a server that can forward requests to other WsSynchronizer systems. This can be created using the createWsServer function that takes a WebSocketServer as also shown above.
Please read the new Using A Synchronizer guide for more details of how to synchronize your data.
Improved Module Folder Structure
We have previously found issues with legacy bundlers and other tools that didn't fully support the new exports field in the module's package.
To mitigate that, the TinyBase distribution now has a top-level folder structure that fully echoes the import paths, including signifiers for JavaScript versions, schema support, minification and so on.
Please read the comprehensive Importing TinyBase guide for more details of how to construct the correct import paths in v5.0.
Breaking Changes in v5.0
Module File Structure
If you previously had /lib/ in your import paths, you should remove it. You also do not have to explicitly specify whether you need the cjs version of TinyBase - if you are using a require rather than an import, you will get it automatically.
The non-minified version of the code is now default and you need to be explicit with you want minified code. Previously you would add /debug to the import path to get non-minified code, but now you add /min to the import path to get minified code.
Expo SQLite Persister
Previously the persister-expo-sqlite module supported expo-sqlite v13 and the persister-expo-sqlite-next module supported their modern 'next' package. In v5.0, the persister-expo-sqlite module only supports v14 and later, and the persister-expo-sqlite-next module has been removed.
The TinyBase Inspector
Previously, the React-based inspector (then known as StoreInspector) resided in the debug version of the ui-react-dom module. It now lives in its own ui-react-inspector module (so that it can be used against non-debug code) and has been renamed to Inspector.
Please update your imports and rename the component when used, accordingly. See the API documentation for details, or the demo, for example.
API Changes
The following changes have been made to the existing TinyBase API for consistency. These are less common parts of the API but should straightforward to correct if you are using them.
In the type definitions:
v4.8.17
Updates peer dependencies.
v4.8.15
Updates peer dependencies and fixes some documentation issues.
v4.8.14
This dials back the React version for peer dependencies so that TinyBase installs cleanly with the Expo create-expo-app tool.
v4.8.13
Updates peer dependencies.
v4.8.12
Updates peer dependencies.
v4.8.11
Updates peer dependencies.