# service-worker

Observes `navigator.serviceWorker` and optionally relays its events — zero app JS required.


```html
<div>
  <service-worker></service-worker>
</div>
```


## Features

- **Observation only** Reports on an existing Service Worker; never registers one
- **Support detection** `is-supported` reflects API availability
- **Ready state** `is-ready` reflects once an active worker controls the page
- **Event relay** `relay-events` forwards `message` / `messageerror` / `controllerchange` as plain DOM events
- **Bindable state** `.provision` is `{ isSupported, isReady, hasController, scope }` — kept current on connect, `ready`, and every `controllerchange`; read it from Quark with `prop("provision")`

## Installation


`@excom/service-worker` v0.1.4

```bash
pnpm add @excom/service-worker
```

```bash
npm install @excom/service-worker
```

```bash
yarn add @excom/service-worker
```

### Import

```ts
import "@excom/service-worker";
```



## Usage

This element only *observes* an already-registered Service Worker — it does not call `navigator.serviceWorker.register(...)` itself. Register your Service Worker separately (in app code, or your build tool), then drop this element anywhere to expose its state as attributes and, optionally, relay its events.

```html
<event-handler listen-for="message" fire-event="sw-message-received">
  <service-worker relay-events="message"></service-worker>
</event-handler>
```

Relayed events (`message`, `messageerror`, `controllerchange`) are dispatched with their original names — they are **not** prefixed with `service-worker-`.

### API Reference


#### Attributes

| Name | Surface | Type | Default | Values | Description |
| --- | --- | --- | --- | --- | --- |
| `relay-events` | option | `tokenlist` |  | `"message"` \| `"messageerror"` \| `"controllerchange"` | Space-separated `navigator.serviceWorker` events to relay onto this element. Bare attribute (no value) relays all three. Event names are relayed as-is — not prefixed with the tag. |
| `is-ready` | state | `boolean` |  |  | `navigator.serviceWorker.ready` has resolved — an active worker is controlling the page. |
| `is-supported` | state | `boolean` |  |  | The Service Worker API is available (`'serviceWorker' in navigator`). |

#### Provision

| Name | Type | Description |
| --- | --- | --- |
| `provision` | `ServiceWorkerProvision` (`{ isSupported: boolean; isReady: boolean; hasController: boolean; scope: string \| null; }`) | `{ isSupported, isReady, hasController, scope }` — set on connect, when `ready` resolves (`scope` comes from the registration), and on every `controllerchange`. Not reflected as an attribute. |

#### Fires

| Name | Type | Description |
| --- | --- | --- |
| `message` | `ServiceWorkerMessageEvent` (`CustomEvent & { type: "message"; detail: unknown; bubbles: true; cancelable: true; composed: true }`) | Relayed verbatim from `navigator.serviceWorker`'s `message` event when `message` is included in `relay-events`. Not tag-prefixed. `event.detail` is `event.data` from the original message. |
| `messageerror` | `ServiceWorkerMessageErrorEvent` (`CustomEvent & { type: "messageerror"; detail: unknown; bubbles: true; cancelable: true; composed: true }`) | Relayed verbatim from `navigator.serviceWorker`'s `messageerror` event when `messageerror` is included in `relay-events`. Not tag-prefixed. |
| `controllerchange` | `ServiceWorkerControllerChangeEvent` (`CustomEvent & { type: "controllerchange"; detail: void; bubbles: true; cancelable: true; composed: true }`) | Relayed verbatim from `navigator.serviceWorker`'s `controllerchange` event when `controllerchange` is included in `relay-events`. Not tag-prefixed. |



### Examples

#### Support / mount / ready state

`is-supported`, `is-mounted` (reflected by default), and `is-ready` are all plain attributes — style or branch on them with CSS. `is-ready` needs an app-registered Service Worker to ever resolve, and this docs site registers one, so it is set here.


```html
<div>
  <service-worker></service-worker>
</div>
```


#### Relay messages from your Service Worker

Relaying `message` / `messageerror` / `controllerchange` requires a Service Worker that your app has already registered and that is actively posting messages — this is not runnable in this docs site, but works like so once wired up:

```html
<service-worker relay-events="message"></service-worker>
<script>
  document
    .querySelector("service-worker")
    .addEventListener("message", (e) => console.log(e.detail));
</script>
```

## Release notes

### 0.1.1 (2026-09-23)

- Ship only dist (and declared extras) in the npm tarball; drop build logs, tests and sources
