mutate.ts

Overview

The mutate.ts file provides a core utility function internalMutate designed to update and revalidate cached data in an advanced caching and data fetching system, such as SWR (stale-while-revalidate). It supports optimistic updates, rollback on errors, and flexible mutation strategies, including synchronous or asynchronous updates, key filtering for batch mutations, and custom mutation logic.

This function is responsible for managing mutation lifecycles including:

internalMutate is a foundational building block that interacts deeply with the caching layer, global mutation state, and event system to maintain consistency and reliability of cached data.


Detailed Explanations

Types


Function: internalMutate

async function internalMutate<Data>(
  cache: Cache,
  _key: KeyFilter | Arguments,
  _data?: Data | Promise<Data | undefined> | MutatorCallback<Data>,
  _opts?: boolean | MutatorOptions<Data>
): Promise<Data | undefined | Array<Data | undefined>>

Purpose

Mutates the cached data for a given cache key or multiple keys filtered by a KeyFilter. It updates cache entries optimistically or synchronously/asynchronously with the provided data or mutation callback, then optionally revalidates the cache entry.

Parameters

Parameter

Type

Description

cache

Cache

The cache instance where data is stored and mutated.

_key

`KeyFilter \

Arguments`

_data

`Data \

Promise<Data

_opts

`boolean \

MutatorOptions` (optional)

Return Value

Usage Examples

// 1. Simple mutation with new data and default options
await internalMutate(cache, ['user', 1], { name: 'Alice' });

// 2. Mutation with optimistic update and rollback on error
await internalMutate(
  cache,
  ['user', 1],
  async (currentData) => {
    // Perform async update (e.g. API call)
    const updatedData = await fetchUpdate();
    return updatedData;
  },
  {
    optimisticData: { name: 'Loading...' },
    rollbackOnError: true,
  }
);

// 3. Batch mutation for all keys matching a filter
await internalMutate(
  cache,
  (key) => Array.isArray(key) && key[0] === 'user',
  { active: false }
);

Implementation Details

Key Features


Workflow (Mutate By Key)

  1. Serialize the key.

  2. Obtain cache getter/setter helpers.

  3. Retrieve global mutation and event state.

  4. If no new data provided, trigger revalidation only.

  5. Otherwise, prepare mutation:

    • Record mutation start timestamp.

    • Apply optimistic data if provided.

    • If _data is a function, call it with current committed data.

    • Await promise if _data is async.

    • Check mutation timestamp to avoid race condition updates.

    • On error, optionally rollback and restore committed data.

    • Populate cache with mutation result if enabled.

  6. Update mutation end timestamp.

  7. Trigger revalidation and broadcast updates.

  8. Return mutation result or throw error.


Interaction with Other System Parts


Mermaid Diagram: Function Flowchart

flowchart TD
    A[internalMutate Entry] --> B{Is _key a function?}
    B -- Yes --> C[Filter cache keys using _key]
    C --> D[For each matched key: mutateByKey]
    D --> E[Return Promise.all of results]
    B -- No --> F[mutateByKey(_key)]

    F --> G[Serialize key]
    G --> H{Is key valid?}
    H -- No --> I[Return undefined]
    H -- Yes --> J[Get cache getter/setter]
    J --> K{Is _data provided?}
    K -- No --> L[Start revalidation only]
    L --> M[Return revalidated data]
    K -- Yes --> N[Prepare mutation state]
    N --> O{Is optimisticData set?}
    O -- Yes --> P[Apply optimistic data update]
    O -- No --> Q[Continue]
    P --> Q
    Q --> R{Is _data a function?}
    R -- Yes --> S[Call _data with committed data]
    R -- No --> T[Use _data as is]
    S --> U{Is _data promise-like?}
    T --> U
    U -- Yes --> V[Await _data promise]
    U -- No --> W[Continue]
    V --> X{Mutation timestamp valid?}
    W --> X
    X -- No --> Y[Return data without cache update]
    X -- Yes --> Z{Is error and rollbackOnError?}
    Z -- Yes --> AA[Rollback to committed data]
    Z -- No --> AB[Update cache with data]
    AA --> AB
    AB --> AC[Update mutation end timestamp]
    AC --> AD[Start revalidation and broadcast]
    AD --> AE{Is error and throwOnError?}
    AE -- Yes --> AF[Throw error]
    AE -- No --> AG[Return data]
    Y --> AG

Summary

mutate.ts implements a robust, flexible mutation mechanism for a caching/data fetching system. It provides fine-grained control over cache updates, supports optimistic UI patterns, handles async updates safely, and ensures data consistency through revalidation and error rollback strategies. This file is a critical component that interacts with cache, global mutation state, and event systems to maintain a smooth and reliable data mutation workflow.


If you need documentation for additional files or further elaborations on integration points, please let me know!