📣The September 27th release is out!Read the release notes

    An astronaut, on the moon, stands over a table covered in security badges.

    Triplit 0.5.0

    TLDR

    Triplit 0.5.0 brings new quality of life improvements to queries and sessions. We explain the breaking changes and how to migrate.

    Queries now return an array of objects

    You asked, we listened! One of the original design decisions of Triplit was to return query result as a JavaScript Map of ids and entities. While this was useful due to limitations of our query engine at the time, those limitations no longer exist. This, paired with the feedback we've gotten that most of our developers prefer arrays to Maps, have led us to change the return type of queries. This should result in cleaner, more idiomatic code when working with rendering frameworks, and generally be familiar to more developers.

    Migrating your code

    Once you've update to @triplit/client@0.5.0 and the corresponding framework, you'll need to update your code to work with the new query return type. Here's an example of how you might update your code:

    import { useQuery } from '@triplit/react';
    import { client } from './client';
    
    // before
    function Blog() {
      const { results } = useQuery(client, client.query('posts'));
      const posts = Array.from(query.entries());
      return (
        <div>
          {posts.map(([id, post]) => (
            <div key={id}>{post.title}</div>
          ))}
        </div>
      );
    }
    
    // after
    function Blog() {
      const { results } = useQuery(client, client.query('allPosts'));
      return (
        <div>
          {results.map((post) => (
            <div key={post.id}>{post.title}</div>
          ))}
        </div>
      );
    }
    

    Luckily, both the Map and Array classes support the .entries() and .values() methods, so much of your existing code should work as is. One thing to note is that Array.entries() will return a tuple of [index, entity], while Map.entries() will return a tuple of [entityId, entity], so you may want to update your destructuring accordingly and your components such that they're using stable keys.

    New client.reset() method for managing user data and sessions

    We're introducing some changes and clarification for how to use the various TriplitClient methods to manage authentication sessions and user data. The new client.reset() is designed to be used when a user signs out of your application. It will clear the current user data and reset the metadata that Triplit uses to manage their syncing session with the user. The existing client.clear() now has a more narrow use: it should be used when the user's cache should be cleared, but the user is still signed in.

    In adding this new method, we've also made changes to client.updateOptions() and client.updateToken(). Previously, these methods would cause the client to restart the sync session with the server. Now, they no longer have that side effect. Instead, they will update the client's metadata and token, respectively, and disconnect the client from the server. Developers will need to call client.connect() to reestablish the connection once the token has changed.

    Here's the new pattern for signing users in and out:

    import { TriplitClient } from '@triplit/client';
    import { schema } from './schema';
    
    const client = new TriplitClient({
      storage: 'indexeddb',
      schema,
    });
    
    // call when you sign in
    function onSignIn(token) {
      client.updateToken(token);
      client.connect();
    }
    
    // call when you sign out
    async function onSignOut() {
      client.disconnect();
      client.updateToken(undefined);
      await client.reset();
    }
    

    Migrating your code

    If you're using client.clear() to sign out a user, you should update your code to use client.reset() instead. Here's an example of how you might update your code:

    import { TriplitClient } from '@triplit/client';
    import { schema } from './schema';
    import { auth } from './auth-provider';
    
    const client = new TriplitClient({
      storage: 'indexeddb',
      schema,
    });
    
    // before
    async function clearCacheAndSignOut() {
      client.disconnect();
      await auth.signOut();
      client.updateToken(undefined);
      await client.clear();
    }
    
    // after
    async function clearCacheAndSignOut() {
      client.disconnect();
      await auth.signOut();
      client.updateToken(undefined);
      await client.reset();
    }
    

    If you were using client.updateOptions() or client.updateToken() to update the client's token and initiate a new connection, you should now explicitly add , you should update your code to use the new methods. Here's an example of how you might update your code:

    // before
    async function signIn(credentials) {
      const token = await auth.signIn(credentials);
      token && client.updateToken(token);
    }
    
    // after
    async function signIn(credentials) {
      const token = await auth.signIn(credentials);
      if (token) {
        client.updateToken(token);
        client.connect();
      }
    }
    

    For more information on using these methods with specific Auth providers, check out our guides in the docs.

    Other deprecations in 0.5.0

    • Removed the client.query(collection).entityId(id) method. You should use client.query(collection).id(id) method instead.
    • Removed the server option from the TriplitClient and HttpClient constructors. Use the serverUrl option instead.
    • Removed the client.remote property and RemoteClient class. You should use client.http property and HttpClient class instead.
    • Removed the migrations API for updating your schema. Refer to the schema updating documentation for more information.

    Additional improvements

    • Fixed an issue where the @triplit/tanstack integration would return stale query results.
    • Added a ClientComlinkWrapper to the @triplit/client package to make it easier to use Triplit in your existing Web Worker code.