When responding to requests with cached entries, while being fast, it
comes with a tradeoff that users may end up seeing stale data.

The `workbox-broadcast-update` package provides a standard way of notifying
[Window Clients](https://developer.mozilla.org/docs/Web/API/Clients)
that a cached response has been updated. This is most commonly used along with
the [`StaleWhileRevalidate` strategy](https://developer.chrome.com/docs/workbox/modules/workbox-strategies#stale-while-revalidate).

Whenever the "revalidate" step of that strategy retrieves a response from the
network that differs from what was previously cached, this module will send a
message (via
[`postMessage()`](https://developer.mozilla.org/docs/Web/API/Worker/postMessage))
to all Window Clients within scope of the current service worker.

Window Clients can listen for updates and take appropriate action, like
automatically displaying a message to the user letting them know that updates
are available.

## How are updates determined?

Certain headers of the cached and new
[`Response`](https://developer.mozilla.org/docs/Web/API/Response)
objects are compared, and if any of the headers have different values,
it's considered an update.

By default, the `Content-Length`, `ETag`, and `Last-Modified` headers are
compared.

Workbox uses header values instead of a byte-for-byte comparison of
response bodies to be more efficient, in particular for potentially
large responses

> [!WARNING]
> **Warning:** Because Workbox needs to be able to read the header values, [opaque responses](https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses), whose headers are not accessible, will never trigger update messages.

## Using Broadcast Update

The library is intended to be used along with the `StaleWhileRevalidate`
caching strategy, since that strategy involves returning a cached
response immediately, but also provides a mechanism for updating the
cache asynchronously.

> [!NOTE]
> **Note:** The `BroadcastUpdatePlugin` can't be used to broadcast information about `workbox-precaching`'s updates. `BroadcastUpdatePlugin` detects when a previously cached URL has been overwritten with new contents. `workbox-precaching` creates cache entries with URLs that uniquely correspond to the contents, so it will never overwrite existing cache entries.

To broadcast updates, you just need to add a `broadcastUpdate.BroadcastUpdatePlugin` to your
strategy options.

    import {registerRoute} from 'workbox-routing';
    import {StaleWhileRevalidate} from 'workbox-strategies';
    import {BroadcastUpdatePlugin} from 'workbox-broadcast-update';

    registerRoute(
      ({url}) => url.pathname.startsWith('/api/'),
      new StaleWhileRevalidate({
        plugins: [new BroadcastUpdatePlugin()],
      })
    );

In your web app, before the [`DOMContentLoaded`](https://developer.mozilla.org/docs/Web/API/Window/DOMContentLoaded_event)
event fires, you can listen for these events like so:

    navigator.serviceWorker.addEventListener('message', async event => {
      // Optional: ensure the message came from workbox-broadcast-update
      if (event.data.meta === 'workbox-broadcast-update') {
        const {cacheName, updatedURL} = event.data.payload;

        // Do something with cacheName and updatedURL.
        // For example, get the cached content and update
        // the content on the page.
        const cache = await caches.open(cacheName);
        const updatedResponse = await cache.match(updatedURL);
        const updatedText = await updatedResponse.text();
      }
    });

> [!NOTE]
> **Note:** Make sure to add the `message` event listener before the `DOMContentLoaded` event, as browsers will [queue
> messages](https://developer.mozilla.org/docs/Web/API/ServiceWorkerContainer/startMessages#Explanation) received early in the page load (before your JavaScript code has had a chance to run) up until (but not after) the `DOMContentLoaded` event.

### Message format

When a `message` event listener is invoked in your web app, the
`event.data` property will have the following format:

    {
      type: 'CACHE_UPDATED',
      meta: 'workbox-broadcast-update',
      // The two payload values vary depending on the actual update:
      payload: {
        cacheName: 'the-cache-name',
        updatedURL: 'https://example.com/'
      }
    }

> [!NOTE]
> **Note:** This message format adheres to the [Flux standard action
> format](https://github.com/acdlite/flux-standard-action#introduction), though it is not tied in any way to the Flux framework.

### Customize Headers to Check

You can customize the headers to check by setting the `headersToCheck`
property.

    import {registerRoute} from 'workbox-routing';
    import {StaleWhileRevalidate} from 'workbox-strategies';
    import {BroadcastUpdatePlugin} from 'workbox-broadcast-update';

    registerRoute(
      ({url}) => url.pathname.startsWith('/api/'),
      new StaleWhileRevalidate({
        plugins: [
          new BroadcastUpdatePlugin({
            headersToCheck: ['X-My-Custom-Header'],
          }),
        ],
      })
    );

## Advanced Usage

While most developers will use `workbox-broadcast-update` as a plugin
of a particular strategy as shown above, it's possible to use the underlying
logic in service worker code.

    import {BroadcastCacheUpdate} from 'workbox-broadcast-update';

    const broadcastUpdate = new BroadcastCacheUpdate({
      headersToCheck: ['X-My-Custom-Header'],
    });

    const cacheName = 'api-cache';
    const request = new Request('https://example.com/api');

    const cache = await caches.open(cacheName);
    const oldResponse = await cache.match(request);
    const newResponse = await fetch(request);

    broadcastUpdate.notifyIfUpdated({
      cacheName,
      oldResponse,
      newResponse,
      request,
    );

<br />

## Types

### BroadcastCacheUpdate

Uses the `postMessage()` API to inform any open windows/tabs when a cached
response has been updated.

For efficiency's sake, the underlying response bodies are not compared;
only specific response headers are checked.

#### Properties

- constructor void

  Construct a BroadcastCacheUpdate instance with a specific `channelName` to
  broadcast messages on


  The `constructor` function looks like:

  ```typescript
  (options?: BroadcastCacheUpdateOptions) => {...}
  ```

  <br />

  - options [BroadcastCacheUpdateOptions](https://developer.chrome.com/docs/workbox/modules/workbox-broadcast-update#type-BroadcastCacheUpdateOptions) optional
  - returns[BroadcastCacheUpdate](https://developer.chrome.com/docs/workbox/modules/workbox-broadcast-update#type-BroadcastCacheUpdate)
- notifyIfUpdated void

  Compares two [Responses](https://developer.mozilla.org/en-US/docs/Web/API/Response)
  and sends a message (via `postMessage()`) to all window clients if the
  responses differ. Neither of the Responses can be
  [opaque](https://developer.chrome.com/docs/workbox/caching-resources-during-runtime/#opaque-responses).

  The message that's posted has the following format (where `payload` can
  be customized via the `generatePayload` option the instance is created
  with):

      {
        type: 'CACHE_UPDATED',
        meta: 'workbox-broadcast-update',
        payload: {
          cacheName: 'the-cache-name',
          updatedURL: 'https://example.com/'
        }
      }


  The `notifyIfUpdated` function looks like:

  ```typescript
  (options: CacheDidUpdateCallbackParam) => {...}
  ```

  <br />

  - options [CacheDidUpdateCallbackParam](https://developer.chrome.com/docs/workbox/workbox-core/#type-CacheDidUpdateCallbackParam)
  - returnsPromise\<void\>

    Resolves once the update is sent.

### BroadcastCacheUpdateOptions

#### Properties

- headersToCheck string\[\] optional
- notifyAllClients boolean optional
- generatePayload void optional


  The `generatePayload` function looks like:

  ```typescript
  (options: CacheDidUpdateCallbackParam) => {...}
  ```

  <br />

  - options [CacheDidUpdateCallbackParam](https://developer.chrome.com/docs/workbox/workbox-core/#type-CacheDidUpdateCallbackParam)
  - returnsRecord\<stringany\>

### BroadcastUpdatePlugin

This plugin will automatically broadcast a message whenever a cached response
is updated.

#### Properties

- constructor void

  Construct a `workbox-broadcast-update.BroadcastUpdate` instance with
  the passed options and calls its `notifyIfUpdated` method whenever the
  plugin's `cacheDidUpdate` callback is invoked.


  The `constructor` function looks like:

  ```typescript
  (options?: BroadcastCacheUpdateOptions) => {...}
  ```

  <br />

  - options [BroadcastCacheUpdateOptions](https://developer.chrome.com/docs/workbox/modules/workbox-broadcast-update#type-BroadcastCacheUpdateOptions) optional
  - returns[BroadcastUpdatePlugin](https://developer.chrome.com/docs/workbox/modules/workbox-broadcast-update#type-BroadcastUpdatePlugin)

## Methods

### responsesAreSame()

```typescript
workbox-broadcast-update.responsesAreSame(
  firstResponse: Response,
  secondResponse: Response,
  headersToCheck: string[],
): boolean
```

Given two `Response's`, compares several header values to see if they are
the same or not.

#### Parameters

- firstResponse Response
- secondResponse Response
- headersToCheck string\[\]

#### Returns

- boolean

<br />