offline-sync
    TypeScript icon, indicating that this package has built-in type declarations

    1.4.1 • Public • Published

    offline-sync

    Differential Synchronization based method with offline mode implemented, using diffsyncpatch to merge json objects.

    Prerequisites

    Typescript project or a support of es2017 is required.

    Installation

    $ npm install --save offline-sync
    const offlineSync = require('offline-sync');

    Client usage

    Options

    // Id among which state is synchronized between clients
    let roomId = 'shared_document';
     
    // Store for saving data in offline mode
    let store = new offlineSync.LocalStorageStore('local_storage_key');
     
    // On significant state conflicts this function is called to let user manually perform merge
    let onUserMerge = (clientState, serverState) => {
      // show screen similiar to git's diffviewers
      // This can consist of 3 richText editors, like Quill
      let [leftEditor, middleEditor, rightEditor, submitButton] = showMergeScreen();
     
      leftEditor.setContents(clientState);
      leftEditor.editor.disable(); // make read-only
     
      // This is where the merging happens
      middleEditor.setContents(serverState);
     
      rightEditor.setContents(serverState);
      rightEditor.editor.disable(); // make read-only
     
      // Wait for submit click
      let mergeSubmit = new Promise((resolve, reject) => {
        submitButton.addEventListener('click', event => {
          // On click take a snapshot of edited content
          let mergedState = middleEditor.getContents();
          resolve(mergedState);
        }, {once: true});
      });
     
      return mergeSubmit;
    };
     
    // https://github.com/benjamine/jsondiffpatch#options
    // Optional: defaults to empty object
    let jsondiffpatchOptions = {};
     
    // Url on which commands will be syncrhonized (eg. http://server.com/state/synchronization/join)
    // Optional: defaults to empty string
    let endpointUrl = 'state/synchronization';

    Example

    let client = new offlineSync.Client(roomId, store, onUserMerge, jsondiffpatchOptions, endpointUrl);
     
    try {
      let document = await client.initialize();
     
      // change the document JSON object any way you want
      ...
      // After some document changes:
      await client.sync();
      updateView(document);
      ...
      // document will now be synchronized between client and server
      // this synchronization is guaranteed, even after packets get dropped or connection lost for some time,
      // the sync will recover
      await client.sync();
      updateView(document);
      ...
      // To fetch the server changes also use sync
      await client.sync();
      updateView(document);
      ...
      // Await is needed to wait for syncing to finish, multiple syncs cannot run in parallel
      client.sync(); // runs
      client.sync(); // prints to console that syncing is already in progress
     
    } catch(error) {
      console.error(error);
    }

    Store interface

    To implement your own client side store interface has to be met:

    /**
     * Interface for client side data persistence. Can use localstorage, sessionstorage, indexDb, cookies
     * or just in memory, if offline mode is not needed.
     */
    interface LocalStore {
     
      /**
       * Data are present on the browser
       */
      hasData(): boolean;
     
      /**
       * Clears data so that next time hasData retuns false
       */
      clearData(): void;
     
      /**
       * Get the client data
       */
      getData(): Document | null;
     
      /**
       * Store the client data
       */
      storeData(data: Document): void;
     
    }

    The structure of Document can change in time, however it is guaranteed to be of object type.

    Server Usage

    Options

    // Data adapter for storing data on the server, some database adapter is expected here
    let adapter = new offlineSync.InMemoryDataAdapter();
     
    // https://github.com/benjamine/jsondiffpatch#options
    // Optional: defaults to empty object
    let jsondiffpatchOptions = {};
     
    // Url on which commands will be syncrhonized (eg. http://server.com/state/synchronization/join)
    // Optional: defaults to empty string
    let endpointUrl = '/state/synchronization';

    Example

    let server = new offlineSync.Server(adapter, jsondiffpatchOptions, endpointUrl);
    // List of endpoints and their handlers that you can use in any http server implementation
    let endpoints = server.generatedEndpoints();
     
    endpoints.forEach(endpoint => {
      // Example usage with Express
      app.post(endpoint.url, async (request, response) => {
        try {
          // request.body has to be JSON
          let result = await endpoint.process(request.body);
          response.json(result);
     
        } catch (error) {
          // this will eventually be handled by your error handling middleware
          next(error);
        }
      });
    });

    Data Adapter Interface

    To implement a way server side data is stored, create a class using this interface:

    /**
     * Interface for communicating with persistence layer, saving entities of type Document and State
     * Server side provides no caching, so if you require it, please implement it here.
     */
    interface DataAdapter {
     
        /**
         * Server side of document is present
         */
        hasData(sessionId: string): boolean;
     
        /**
         * Get the server side of document
         */
        getData(sessionId: string): Document | null;
     
        /**
         * Store the server side of document
         */
        storeData(sessionId: string, document: Document): void;
     
     
        /**
         * Document synchronized across clients with id exists
         */
        hasRoom(roomId: string): boolean;
     
        /**
         * Get document synchronized across clients by id
         */
        getRoom(roomId: string): object |null;
     
        /**
         * Store Document synchronized across clients
         */
        storeRoom(roomId: string, room: object): void;
     
        /**
         * Optional implementation of getting unique id using database.
         * Default implementation generates a UUID v4
         */
        generateSessionId?(): string;
     
    }

    Install

    npm i offline-sync

    DownloadsWeekly Downloads

    0

    Version

    1.4.1

    License

    MIT

    Unpacked Size

    74.4 kB

    Total Files

    50

    Last publish

    Collaborators

    • simonkocurek