Triplit Release Notes 3/22/2024

Logging and debug mode

Added a built-in logger to the Triplit client and database. You can now set the log level for a TriplitClient like so:

import { TriplitClient } from '@triplit/client';

const client = new TriplitClient({
  logLevel: 'debug', // or 'info', 'warn', 'error'
});

When you set the log level to debug, you will see detailed logs in the browser console, including the request and response payloads for all network requests, and the parameters for various database queries and mutations.

When the TriplitClient is in debug mode, it will also accumulate logs in memory, which can be accessed via the TriplitClient.logs property. For example:

const logs = client.logs; // an array of log objects

// copy the logs to the clipboard when in the browser console
copy(JSON.stringify(logs));

// or save the logs to a file when in Node.js
import fs from 'fs';
fs.writeFileSync('logs.json', JSON.stringify(logs));

Read more about logging in the documentation.

subscribeWithExpand and useInfiniteQuery

Added a new subscribeWithExpand method to the TriplitClient class, which allows you to subscribe to a paginated query (i.e. one with a limit set) and use the fetchMore function to load more items. This is useful for implementing infinite scrolling in your app. Here's an example using the useInfiniteQuery hook from @triplit/react:

import { useInfiniteQuery } from '@triplit/react';

const client = new TriplitClient();

function App() {
  const { results, fetchingMore, hasMore, loadMore } = useInfiniteQuery(
    client,
    client.query('todos').limit(10).orderBy('created_at', 'DESC')
  );

  return (
    <div>
      {results.entries().map((item) => (
        <div>{item.text}</div>
      ))}
      {fetchingMore && <div>Loading more...</div>}
      {hasMore && <button onClick={loadMore}>Load more</button>}
    </div>
  );
}

Read more about the subscribeWithExpand here or the React wrapper here.

Validating the safety of schema changes

As we transition to a more declarative schema definition, we have added new safety checks to the database to prevent accidentally data loss or corruption. When you make a schema change that could result in data loss, the database will now alert you to the specific changes that are unsafe, and not apply the new schema.

For example, if you have a simple schema like this:

import { Schema as S } from '@triplit/db';

export const schema = {
  todos: {
    schema: S.Schema({
      id: S.String({ nullable: false, default: S.Default.uuid() }),
      text: S.Text(),
      completed: S.Boolean({ default: false }),
    }),
  },
};

And a client using some persistent storage provider like 'indexeddb':

const client = new TriplitClient({
  schema,
  storage: 'indexeddb',
});

And you try to change the schema to this:

export const schema = {
  todos: {
    schema: S.Schema({
      id: S.String({ nullable: false, default: S.Default.uuid() }),
      text: S.Text(),
      completed: S.Boolean({ default: false }),
      dueDate: S.Date(), // just added
    }),
  },
};

On startup, your client will throw a warning like this:

The DB received an updated schema.

It may be backwards incompatible with existing data.

Please resolve the following issues: {
  todos: {
    dueDate: {
      issue: 'added a non-optional attribute',
      violatesExistingData: false
    },
  }
}

If your database already has data in it that doesn't have a dueDate attribute, the database will refuse to apply the new schema, and you will need to resolve the issue before the new schema can be applied.