Giter VIP home page Giter VIP logo

evolu's Introduction

Evolu

React Hooks library for local-first apps with end-to-end encrypted backup and sync using SQLite and CRDT.

Evolu is designed for privacy, ease of use, and no vendor lock-in.

  • The official SQLite Wasm in all browsers (React Native and Electron soon)
  • E2E encrypted sync and backup with CRDT (merging changes without conflicts)
  • Free Evolu server for testing (paid production-ready soon, or you can run your own)
  • Typed database schema with branded types (NonEmptyString1000, PositiveInt, etc.)
  • Reactive queries
  • Real-time experience via revalidation on focus and network recovery
  • Schema evolving via filterMap ad-hoc migration
  • No signup/login, no email collection, only Bitcoin-like mnemonic (12 words)
  • React Suspense (soon)

Local-first apps

Local-first apps allow users to own their data. Evolu stores data in the user's device(s), so Evolu apps can work offline and without a specific server. How is it different from keeping files on disk? Files are not the right abstraction for apps and are complicated to synchronize among devices. That's why client-server architecture rules the world. But as with everything, it has trade-offs.

The trade-offs of the client-server architecture

Client-server architecture provides us with easy backup and synchronization, but all that depends on the ability of a server to fulfill its promises. Internet is offline, companies go bankrupt, users are banned, and errors occur. All those things happen all the time, and then what? Right, that's why the world needs local-first apps. But until now, writing local-first apps has been challenging because of the lack of libraries and design patterns. That's why I created Evolu.

Requirements

  • TypeScript 4.7 or newer
  • The strict flag enabled in your tsconfig.json file
  • The exactOptionalPropertyTypes flag enabled in your tsconfig.json file
{
  // ...
  "compilerOptions": {
    // ...
    "strict": true,
    "exactOptionalPropertyTypes": true
  }
}

Getting Started

npm install evolu @effect/schema

The complete Next.js example is here.

Define Data

To start using Evolu, define schemas for your database and export React Hooks.

import * as S from "@effect/schema";
import * as E from "evolu";

const TodoId = E.id("Todo");
type TodoId = S.Infer<typeof TodoId>;

const TodoTable = S.struct({
  id: TodoId,
  title: E.NonEmptyString1000,
  isCompleted: E.SqliteBoolean,
});
type TodoTable = S.Infer<typeof TodoTable>;

const Database = S.struct({
  todo: TodoTable,
});

export const {
  useQuery,
  useMutation,
  useOwner,
  useOwnerActions,
  useEvoluError,
} = E.createHooks(Database);

Validate Data

Learn more about Schema.

import * as S from "@effect/schema";
import * as E from "evolu";

S.decode(E.String1000)(title);

Mutate Data

Mutation API is designed for local-first apps to ensure changes are always merged without conflicts.

const { create, update } = useMutation();

create("todo", { title, isCompleted: false });
update("todo", { id, isCompleted: true });

Query Data

Evolu uses type-safe TypeScript SQL query builder kysely, so autocompletion works out-of-the-box.

const { rows } = useQuery(
  (db) => db.selectFrom("todo").select(["id", "title"]).orderBy("updatedAt"),
  // (row) => row
  ({ title, ...rest }) => title && { title, ...rest }
);

Protect Data

Evolu encrypts data with Mnemonic, a safe autogenerated password based on bip39.

const owner = useOwner();

alert(owner.mnemonic);

Delete Data

Leave no traces on a device.

const ownerActions = useOwnerActions();

if (confirm("Are you sure? It will delete all your local data."))
  ownerActions.reset();

Restore Data

Restore data elsewhere. Encrypted data can only be restored with a Mnemonic.

const ownerActions = useOwnerActions();

ownerActions.restore(mnemonic).then((either) => {
  if (either._tag === "Left") alert(JSON.stringify(either.left, null, 2));
});

Handle Errors

Evolu useQuery and useMutation never fail, it's the advantage of local first apps, but Evolu, in rare cases, can.

const evoluError = useEvoluError();

useEffect(() => {
  // eslint-disable-next-line no-console
  if (evoluError) console.log(evoluError);
}, [evoluError]);

And that's all. Minimal API is the key to a great developer experience.

Privacy

Evolu uses end-to-end encryption and generates strong and safe passwords for you. Evolu sync and backup server see only timestamps.

Trade-offs

“There are no solutions. There are only trade-offs.” ― Thomas Sowell

Evolu is not P2P. For reliable syncing and backup, there needs to be a server. Evolu server is very minimal, and everyone can run their own. While it's theoretically possible to have P2P Evolu, I have yet to see a reliable solution. It's not only a technical problem; it's an economic problem. Someone has to be paid to keep your data safe. Evolu provides a free server for testing. Soon we will provide a paid server for production usage.

All table columns except for ID are nullable by default. It's not a bug; it's a feature. Local-first data are meant to last forever, but schemas evolve. This design decision was inspired by GraphQL nullability and versioning. Evolu provides a handy filterMap helper for queries.

Evolu has no support for CRDT transactions because CRDT transactions are still in the research phase. There are a few proposals, but nothing is usable yet. Instead of a half-baked solution, I made a design decision not to implement them. Fortunately, it's not a show-stopper.

Community

The Evolu community is on GitHub Discussions, where you can ask questions and voice ideas.

To chat with other community members, you can join the Evolu Discord.

Twitter URL

FAQ

Is Evolu ready for production?

It should be. The CRDT message format is stable.

What is the SQLite database size limit?

Evolu uses OPFS in Chrome and LocalStorage in Firefox and Safari. The size limit of OPFS is 256 MB (LocalStorage is 5 MB).

How can I check the current database filesize?

Use OPFS Explorer Chrome DevTools extension.

Contributing

Evolu monorepo uses pnpm.

Install the dependencies with:

pnpm install

Build Evolu monorepo:

pnpm build

Start developing and watch for code changes:

pnpm dev

Describe changes for release log:

pnpm changeset

evolu's People

Contributors

steida avatar github-actions[bot] avatar harrywebdev avatar atgctg avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.