createDocFromSnapshot = (originDoc, snapshot, newDoc = new Doc()) => {
  if (originDoc.gc) {
    // we should not try to restore a GC-ed document, because some of the restored items might have their content deleted
    throw new Error('originDoc must not be garbage collected');
  }

  const {
    sv,
    ds
  } = snapshot;
  const encoder = new UpdateEncoderV2();
  originDoc.transact(transaction => {
    let size = 0;
    sv.forEach(clock => {
      if (clock > 0) {
        size++;
      }
    });
    encoding.writeVarUint(encoder.restEncoder, size); // splitting the structs before writing them to the encoder

    for (const [client, clock] of sv) {
      if (clock === 0) {
        continue;
      }

      if (clock < getState(originDoc.store, client)) {
        getItemCleanStart(transaction, createID(client, clock));
      }

      const structs = originDoc.store.clients.get(client) || [];
      const lastStructIndex = findIndexSS(structs, clock - 1); // write # encoded structs

      encoding.writeVarUint(encoder.restEncoder, lastStructIndex + 1);
      encoder.writeClient(client); // first clock written is 0

      encoding.writeVarUint(encoder.restEncoder, 0);

      for (let i = 0; i <= lastStructIndex; i++) {
        structs[i].write(encoder, 0);
      }
    }

    writeDeleteSet(encoder, ds);
  });
  applyUpdateV2(newDoc, encoder.toUint8Array(), 'snapshot');
  return newDoc;
}
@param {Doc} originDoc
@param {Snapshot} snapshot
@param {Doc} [newDoc] Optionally, you may define the Yjs document that receives the data from originDoc
@return {Doc}