Title: Service Workers Nightly
Status: ED
ED: https://w3c.github.io/ServiceWorker/
TR: https://www.w3.org/TR/service-workers/
Shortname: service-workers
Level:
Editor: Alex Russell, Google, slightlyoff@chromium.org
Editor: Jungkee Song, Samsung Electronics, jungkee.song@samsung.com
Editor: Jake Archibald, Google, jakearchibald@chromium.org
Editor: Marijn Kruisselbrink, Google, mek@chromium.org
Repository: w3c/ServiceWorker
Group: webplatform
Status Text: This is a living document addressing new features including foreign fetch, header-based installation, navigation preload, etc. Readers need to be aware that this specification may include unstable features. Service Workers 1 is a version that is advancing toward a W3C Recommendation.
Abstract: This specification describes a method that enables applications to take advantage of persistent background processing, including hooks to enable bootstrapping of web applications while offline.
Abstract:
Abstract: The core of this system is an event-driven Web Worker, which responds to events dispatched from documents and other sources. A system for managing installation, versions, and upgrades is provided.
Abstract:
Abstract: The service worker is a generic entry point for event-driven background processing in the Web Platform that is extensible by other specifications.
Markup Shorthands: css no, markdown yes
spec: push; urlPrefix: https://w3c.github.io/push-api/
    type: event
        text: push; url: h-the-push-event

spec: ecma-262; urlPrefix: http://tc39.github.io/ecma262/
    type: dfn
        text: Assert; url: sec-algorithm-conventions
        text: [[Call]]; url: sec-ecmascript-function-objects-call-thisargument-argumentslist
        text: promise; url: sec-promise-objects
        text: DetachArrayBuffer; url: sec-detacharraybuffer
        url: sec-list-and-record-specification-type
            text: List
            text: Record
        text: map objects; url: sec-map-objects
        text: InitializeHostDefinedRealm; url: sec-initializehostdefinedrealm
        text: execution context; url: sec-execution-contexts

spec: page-visibility; urlPrefix: https://www.w3.org/TR/page-visibility/
    type: enum; text: VisibilityState; url: VisibilityState
    type: attribute; text: visibilityState; for: Document; url: dom-document-visibilitystate

spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/
    type: attribute
        urlPrefix: comms.html
            text: origin; for: MessageEvent; url: dom-messageevent-origin
            text: source; for: MessageEvent; url: dom-messageevent-source
            text: ports; for: MessageEvent; url: dom-messageevent-ports
            text: data; for: MessageEvent; url: dom-messageevent-data
    type: dfn
        urlPrefix: browsers.html
            text: ancestor origins list; for: Location; url: concept-location-ancestor-origins-list
        urlPrefix: syntax.html
            text: delay the load event; for: document; url: delay-the-load-event

spec: fetch; urlPrefix: https://fetch.spec.whatwg.org/
    type: dfn
        text: response; for: Response; url: concept-response-response
        text: request; for: Request; url: concept-request-request
        text: HTTP fetch; for: /; url: concept-http-fetch

spec: rfc5988; urlPrefix: https://tools.ietf.org/html/rfc5988
    type: dfn
        text: context IRI; url: section-5.2
        text: target attribute; url: section-5.4
        text: target attributes; url: section-5.4
        text: target IRI; url: section-5.1

spec: rfc7230; urlPrefix: https://tools.ietf.org/html/rfc7230
    type: dfn
        text: field-value; for: http; url: section-3.2

spec: rfc7231; urlPrefix: https://tools.ietf.org/html/rfc7231
    type: dfn
        text: Vary; url: section-7.1.4

spec: webappsec-referrer-policy; urlPrefix: https://w3c.github.io/webappsec-referrer-policy/
    type: dfn
        text: Parse a referrer policy from a Referrer-Policy header; url: parse-referrer-policy-from-header
{
  "unsanctioned-tracking": {
    "href": "https://www.w3.org/2001/tag/doc/unsanctioned-tracking/",
    "title": "Unsanctioned Web Tracking",
    "date": "17 July 2015",
    "status": "Finding of the W3C TAG",
    "publisher": "W3C TAG"
  }
}

Motivations

*This section is non-normative.* Web Applications traditionally assume that the network is reachable. This assumption pervades the platform. HTML documents are loaded over HTTP and traditionally fetch all of their sub-resources via subsequent HTTP requests. This places web content at a disadvantage versus other technology stacks. The [=/service worker=] is designed first to redress this balance by providing a Web Worker context, which can be started by a runtime when navigations are about to occur. This event-driven worker is registered against an origin and a path (or pattern), meaning it can be consulted when navigations occur to that location. Events that correspond to network requests are dispatched to the worker and the responses generated by the worker may override default network stack behavior. This puts the [=/service worker=], conceptually, between the network and a document renderer, allowing the [=/service worker=] to provide content for documents, even while offline. Web developers familiar with previous attempts to solve the offline problem have reported a deficit of flexibility in those solutions. As a result, the [=/service worker=] is highly procedural, providing a maximum of flexibility at the price of additional complexity for developers. Part of this complexity arises from the need to keep [=/service workers=] responsive in the face of a single-threaded execution model. As a result, APIs exposed by [=/service workers=] are almost entirely asynchronous, a pattern familiar in other JavaScript contexts but accentuated here by the need to avoid blocking document and resource loading. Developers using the HTML5 Application Cache have also reported that several attributes of the design contribute to unrecoverable errors. A key design principle of the [=/service worker=] is that errors should *always* be recoverable. Many details of the update process of [=/service workers=] are designed to avoid these hazards. [=/Service workers=] are started and kept alive by their relationship to events, not documents. This design borrows heavily from developer and vendor experience with Shared Workers and Chrome Background Pages. A key lesson from these systems is the necessity to time-limit the execution of background processing contexts, both to conserve resources and to ensure that background context loss and restart is top-of-mind for developers. As a result, [=/service workers=] bear more than a passing resemblance to Chrome Event Pages, the successor to Background Pages. [=/Service workers=] may be started by user agents *without an attached document* and may be killed by the user agent at nearly any time. Conceptually, [=/service workers=] can be thought of as Shared Workers that can start, process events, and die without ever handling messages from documents. Developers are advised to keep in mind that [=/service workers=] may be started and killed many times a second. [=/Service workers=] are generic, event-driven, time-limited script contexts that run at an origin. These properties make them natural endpoints for a range of runtime services that may outlive the context of a particular document, e.g. handling push notifications, background data synchronization, responding to resource requests from other origins, or receiving centralized updates to expensive-to-calculate data (e.g., geolocation or gyroscope).

Model

Service Worker

A service worker is a type of web worker. A [=/service worker=] executes in the registering [=/service worker client=]'s [=/origin=]. A [=/service worker=] has an associated state, which is one of *parsed*, *installing*, *installed*, *activating*, *activated*, and *redundant*. It is initially *parsed*. A [=/service worker=] has an associated script url (a [=/URL=]). A [=/service worker=] has an associated type which is either "classic" or "module". Unless stated otherwise, it is "classic". A [=/service worker=] has an associated containing service worker registration (a [=/service worker registration=]), which contains itself. A [=/service worker=] has an associated id (an opaque string), which uniquely identifies itself during the lifetime of its containing service worker registration. A [=/service worker=] has an associated global object (a {{ServiceWorkerGlobalScope}} object or null). A [=/service worker=] is dispatched a set of lifecycle events, {{install!!event}} and {{activate!!event}}, and functional events including {{fetch!!event}}. A [=/service worker=] has an associated script resource (a script), which represents its own script resource. It is initially set to null. A script resource has an associated has ever been evaluated flag. It is initially unset. A script resource has an associated HTTPS state (an HTTPS state value). It is initially "none". A script resource has an associated referrer policy (a [=/referrer policy=]). It is initially the empty string. A [=/service worker=] has an associated script resource map which is an ordered map where the keys are [=/URLs=] and the values are [=/responses=]. A [=/service worker=] has an associated skip waiting flag. Unless stated otherwise it is unset. A [=/service worker=] has an associated imported scripts updated flag. It is initially unset. A [=/service worker=] has an associated set of event types to handle (a [=ordered set|set=]) whose [=item=] is an event listener's event type. It is initially an empty set. A [=/service worker=] has an associated set of extended events (a [=ordered set|set=]) whose [=item=] is an {{ExtendableEvent}}. It is initially an empty set. A [=/service worker=] has an associated list of foreign fetch scopes whose element type is a [=/URL=]. It is initially empty. A [=/service worker=] has an associated list of foreign fetch origins whose element type is a [=/URL=]. It is initially empty.

Lifetime

The lifetime of a [=/service worker=] is tied to the execution lifetime of events and not references held by [=/service worker clients=] to the {{ServiceWorker}} object. A user agent *may* terminate [=/service workers=] at any time it: * Has no event to handle. * Detects abnormal operation: such as infinite loops and tasks exceeding imposed time limits (if any) while handling the events.

Service Worker Registration

A service worker registration is a tuple of a [=service worker registration/scope url=] and a set of [=/service workers=], an installing worker, a waiting worker, and an active worker. A user agent *may* enable many [=/service worker registrations=] at a single origin so long as the [=service worker registration/scope url=] of the [=/service worker registration=] differs. A [=/service worker registration=] of an identical [=service worker registration/scope url=] when one already exists in the user agent causes the existing [=/service worker registration=] to be replaced. A [=/service worker registration=] has an associated scope url (a [=/URL=]). A [=/service worker registration=] has an associated installing worker (a [=/service worker=] or null) whose [=service worker/state=] is *installing*. It is initially set to null. A [=/service worker registration=] has an associated waiting worker (a [=/service worker=] or null) whose [=service worker/state=] is *installed*. It is initially set to null. A [=/service worker registration=] has an associated active worker (a [=/service worker=] or null) whose [=service worker/state=] is either *activating* or *activated*. It is initially set to null. A [=/service worker registration=] has an associated last update check time. It is initially set to null. A [=/service worker registration=] has an associated use cache (a boolean). It is initially set to false. A [=/service worker registration=] has an associated uninstalling flag. It is initially unset. A [=/service worker registration=] has one or more task queues that back up the tasks from its active worker's event loop's corresponding [=/task queues=]. (The target task sources for this back up operation are the handle fetch task source and the handle functional event task source.) The user agent dumps the active worker's tasks to the [=/service worker registration=]'s [=service worker registration/task queues=] when the active worker is terminated and re-queues those tasks to the active worker's event loop's corresponding [=/task queues=] when the active worker spins off. Unlike the [=/task queues=] owned by event loops, the [=/service worker registration=]'s [=service worker registration/task queues=] are not processed by any event loops in and of itself. A [=/service worker registration=] has an associated {{NavigationPreloadManager}} object. A [=/service worker registration=] has an associated navigation preload enabled flag. It is initially unset. A [=/service worker registration=] has an associated navigation preload header value, which is a [=byte sequence=]. It is initially set to \`true\`.

Lifetime

A user agent *must* persistently keep a list of registered [=/service worker registrations=] unless otherwise they are explicitly unregistered. A user agent has a scope to registration map that stores the entries of the tuple of [=/service worker registration=]'s [=service worker registration/scope url=] and the corresponding [=/service worker registration=]. The lifetime of [=/service worker registrations=] is beyond that of the {{ServiceWorkerRegistration}} objects which represent them within the lifetime of their corresponding [=/service worker clients=].

Service Worker Client

A service worker client is an [=environment=]. A [=/service worker client=] has an algorithm defined as the origin that returns the [=/service worker client=]'s [=environment settings object/origin=] if the [=/service worker client=] is an [=environment settings object=], and the [=/service worker client=]'s creation URL's [=url/origin=] otherwise. A window client is a [=/service worker client=] whose [=environment settings object/global object=] is a {{Window}} object. A dedicated worker client is a [=/service worker client=] whose [=environment settings object/global object=] is a {{DedicatedWorkerGlobalScope}} object. A shared worker client is a [=/service worker client=] whose [=environment settings object/global object=] is a {{SharedWorkerGlobalScope}} object. A worker client is either a dedicated worker client or a shared worker client.

Selection and Use

A [=/service worker client=] independently selects and uses a [=/service worker registration=] for its own loading and its subresources. The selection of a [=/service worker registration=], upon a non-subresource request, is a process of either matching a [=/service worker registration=] from scope to registration map or inheriting an existing [=/service worker registration=] from its parent or owner context depending on the request's [=request/url=]. When the request's [=request/url=] is not local, a [=/service worker client=] matches a [=/service worker registration=] from scope to registration map. That is, the [=/service worker client=] attempts to consult a [=/service worker registration=] whose [=service worker registration/scope url=] matches its creation URL. When the request's [=request/url=] is local, if the [=/service worker client=]'s responsible browsing context is a nested browsing context or the [=/service worker client=] is a worker client, the [=/service worker client=] inherits the [=/service worker registration=] from its parent browsing context's environment or one of the worker's Documents' environment, respectively, if it exists. If the selection was successful, the selected [=/service worker registration=]'s active worker starts to control the [=/service worker client=]. Otherwise, the flow returns to [=/fetch=] where it falls back to the default behavior. When a [=/service worker client=] is controlled by an active worker, it is considered that the [=/service worker client=] is using the active worker's containing service worker registration.

Task Sources

The following additional task sources are used by [=/service workers=]. : The handle fetch task source :: This task source is used for dispatching {{fetch!!event}} events to [=/service workers=]. : The handle functional event task source :: This task source is used for features that dispatch other functional events, e.g. {{push!!event}} events, to [=/service workers=]. Note: A user agent may use a separate task source for each functional event type in order to avoid a head-of-line blocking phenomenon for certain functional events.

User Agent Shutdown

A user agent *must* maintain the state of its stored [=/service worker registrations=] across restarts with the following rules: * An installing worker does not persist but is discarded. If the installing worker was the only [=/service worker=] for the [=/service worker registration=], the [=/service worker registration=] is discarded. * A waiting worker promotes to an active worker. To attain this, the user agent *must* invoke Handle User Agent Shutdown when it terminates.

Client Context

Bootstrapping with a service worker:
      // scope defaults to the path the script sits in
      // "/" in this example
      navigator.serviceWorker.register("/serviceworker.js").then(registration => {
        console.log("success!");
        if (registration.installing) {
          registration.installing.postMessage("Howdy from your installing page.");
        }
      }, err => {
        console.error("Installing the worker failed!", err);
      });
    

{{ServiceWorker}}

      [SecureContext, Exposed=(Window,Worker)]
      interface ServiceWorker : EventTarget {
        readonly attribute USVString scriptURL;
        readonly attribute ServiceWorkerState state;
        void postMessage(any message, optional sequence<object> transfer = []);

        // event
        attribute EventHandler onstatechange;
      };
      ServiceWorker implements AbstractWorker;

      enum ServiceWorkerState {
        "installing",
        "installed",
        "activating",
        "activated",
        "redundant"
      };
    
A {{ServiceWorker}} object represents a [=/service worker=]. Each {{ServiceWorker}} object is associated with a [=/service worker=]. Multiple separate objects implementing the {{ServiceWorker}} interface across documents and workers can all be associated with the same [=/service worker=] simultaneously. A {{ServiceWorker}} object has an associated {{ServiceWorkerState}} object which is itself associated with [=/service worker=]'s state.

{{ServiceWorker/scriptURL}}

The scriptURL attribute *must* return the [=/service worker=]'s serialized [=service worker/script url=].
For example, consider a document created by a navigation to https://example.com/app.html which matches via the following registration call which has been previously executed:
          // Script on the page https://example.com/app.html
          navigator.serviceWorker.register("/service_worker.js");
        
The value of navigator.serviceWorker.controller.scriptURL will be "https://example.com/service_worker.js".

{{ServiceWorker/state}}

The state attribute *must* return the value (in {{ServiceWorkerState}} enumeration) to which it was last set.

{{ServiceWorker/postMessage(message, transfer)}}

The postMessage(|message|, |transfer|) method *must* run these steps: 1. If the {{ServiceWorker/state}} attribute value of the context object is {{"redundant"}}, throw an "{{InvalidStateError}}" exception and abort these steps. 1. Let |serviceWorker| be the [=/service worker=] represented by the context object. 1. Invoke Run Service Worker algorithm with |serviceWorker| as the argument. 1. Let |destination| be the {{ServiceWorkerGlobalScope}} object associated with |serviceWorker|. 1. Let |targetRealm| be |destination|'s [=global object/Realm=]. 1. Let |incumbentSettings| be the incumbent settings object, and |incumbentGlobal| its [=environment settings object/global object=]. 1. Let |cloneRecord| be StructuredCloneWithTransfer(|message|, |transfer|, |targetRealm|). If this throws an exception, rethrow that exception and abort these steps. 1. Let |clonedMessage| be |cloneRecord|.\[[Clone]]. 1. Let |newPorts| be a new [=frozen array type|frozen array=] consisting of all {{MessagePort}} objects in |cloneRecord|.\[[TransferList]], if any, maintaining their relative order. 1. Queue a task that runs the following steps: 1. Create an event |e| that uses the {{ExtendableMessageEvent}} interface, with the event type {{message!!event}}, which does not bubble and is not cancelable. 1. Let the {{ExtendableMessageEvent/data}} attribute of |e| be initialized to |clonedMessage|. 1. Let the {{ExtendableMessageEvent/origin}} attribute of |e| be initialized to the Unicode serialization of |incumbentSettings|'s [=environment settings object/origin=]. 1. If |incumbentGlobal| is a {{ServiceWorkerGlobalScope}} object, let the {{ExtendableMessageEvent/source}} attribute of |e| be initialized to a new {{ServiceWorker}} object that represents |incumbentGlobal|'s [=ServiceWorkerGlobalScope/service worker=]. 1. Else if |incumbentGlobal| is a {{Window}} object, let the {{ExtendableMessageEvent/source}} attribute of |e| be initialized to a new {{WindowClient}} object that represents |incumbentGlobal|'s [=/environment settings object=]. 1. Else, let it be initialized to a new {{Client}} object that represents the worker associated with |incumbentGlobal|. 1. Let the {{ExtendableMessageEvent/ports}} attribute of |e| be initialized to |newPorts|. 1. Dispatch |e| at |destination|. 1. Invoke [=Update Service Worker Extended Events Set=] with |serviceWorker| and |e|. The task *must* use the DOM manipulation task source.

Event handler

The following is the event handler (and its corresponding event handler event type) that *must* be supported, as event handler IDL attributes, by all objects implementing {{ServiceWorker}} interface:
event handler event handler event type
onstatechange {{ServiceWorker/statechange}}

{{ServiceWorkerRegistration}}

      [SecureContext, Exposed=(Window,Worker)]
      interface ServiceWorkerRegistration : EventTarget {
        readonly attribute ServiceWorker? installing;
        readonly attribute ServiceWorker? waiting;
        readonly attribute ServiceWorker? active;
        readonly attribute NavigationPreloadManager navigationPreload;

        readonly attribute USVString scope;
        readonly attribute boolean useCache;

        [NewObject] Promise<void> update();
        [NewObject] Promise<boolean> unregister();

        // event
        attribute EventHandler onupdatefound;
      };
    
A {{ServiceWorkerRegistration}} object represents a [=/service worker registration=]. Each {{ServiceWorkerRegistration}} object is associated with a service worker registration (a [=/service worker registration=]). Multiple separate objects implementing the {{ServiceWorkerRegistration}} interface across documents and workers can all be associated with the same [=/service worker registration=] simultaneously.
installing attribute *must* return the value to which it was last set. Note: The {{ServiceWorker}} objects returned from this attribute getter that represent the same [=/service worker=] are the same objects.
waiting attribute *must* return the value to which it was last set. Note: The {{ServiceWorker}} objects returned from this attribute getter that represent the same [=/service worker=] are the same objects.
active attribute *must* return the value to which it was last set. Note: The {{ServiceWorker}} objects returned from this attribute getter that represent the same [=/service worker=] are the same objects.

{{ServiceWorkerRegistration/navigationPreload}}

The navigationPreload attribute *must* return [=ServiceWorkerRegistration/service worker registration=]'s {{NavigationPreloadManager}} object.

{{ServiceWorkerRegistration/scope}}

The scope attribute *must* return [=ServiceWorkerRegistration/service worker registration=]'s serialized [=service worker registration/scope url=].
In the example in [[#service-worker-url]], the value of registration.scope, obtained from navigator.serviceWorker.ready.then(registration => console.log(registration.scope)) for example, will be "https://example.com/".

{{ServiceWorkerRegistration/useCache}}

The useCache attribute *must* return [=ServiceWorkerRegistration/service worker registration=]'s [=service worker registration/use cache=].

{{ServiceWorkerRegistration/update()}}

update() method *must* run these steps: 1. Let |p| be a promise. 1. Let |registration| be the [=ServiceWorkerRegistration/service worker registration=]. 1. Let |newestWorker| be the result of running Get Newest Worker algorithm passing |registration| as its argument. 1. If |newestWorker| is null, reject |p| with an "{{InvalidStateError}}" exception and abort these steps. 1. If the context object's relevant settings object's [=environment settings object/global object=] |globalObject| is a {{ServiceWorkerGlobalScope}} object, and |globalObject|'s associated [=ServiceWorkerGlobalScope/service worker=]'s state is *installing*, reject |p| with an "{{InvalidStateError}}" exception and abort these steps. 1. Let |job| be the result of running Create Job with *update*, |registration|'s [=service worker registration/scope url=], |newestWorker|'s [=service worker/script url=], |p|, and the context object's relevant settings object. 1. Set |job|'s worker type to |newestWorker|'s [=service worker/type=]. 1. Invoke Schedule Job with |job|. 1. Return |p|.
Note: The {{ServiceWorkerRegistration/unregister()}} method unregisters the [=/service worker registration=]. It is important to note that the currently controlled [=/service worker client=]'s active service worker's containing service worker registration is effective until all the [=/service worker clients=] (including itself) using this [=/service worker registration=] unload. That is, the {{ServiceWorkerRegistration/unregister()}} method only affects subsequent navigations. unregister() method *must* run these steps: 1. Let |p| be a promise. 1. Let |job| be the result of running Create Job with *unregister*, the [=service worker registration/scope url=] of the [=ServiceWorkerRegistration/service worker registration=], null, |p|, and the context object's relevant settings object. 1. Invoke Schedule Job with |job|. 1. Return |p|.

Event handler

The following is the event handler (and its corresponding event handler event type) that *must* be supported, as event handler IDL attributes, by all objects implementing {{ServiceWorkerRegistration}} interface:
event handler event handler event type
onupdatefound {{updatefound!!event}}
      partial interface Navigator {
        [SecureContext, SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
      };

      partial interface WorkerNavigator {
        [SecureContext, SameObject] readonly attribute ServiceWorkerContainer serviceWorker;
      };
    
The serviceWorker attribute *must* return the {{ServiceWorkerContainer}} object that is associated with the context object.

{{ServiceWorkerContainer}}

      [SecureContext, Exposed=(Window,Worker)]
      interface ServiceWorkerContainer : EventTarget {
        readonly attribute ServiceWorker? controller;
        readonly attribute Promise<ServiceWorkerRegistration> ready;

        [NewObject] Promise<ServiceWorkerRegistration> register(USVString scriptURL, optional RegistrationOptions options);

        [NewObject] Promise<any> getRegistration(optional USVString clientURL = "");
        [NewObject] Promise<sequence<ServiceWorkerRegistration>> getRegistrations();

        void startMessages();


        // events
        attribute EventHandler oncontrollerchange;
        attribute EventHandler onmessage; // event.source of message events is ServiceWorker object
      };
    
      dictionary RegistrationOptions {
        USVString scope;
        WorkerType type = "classic";
        boolean useCache = false;
      };
    
The user agent *must* create a {{ServiceWorkerContainer}} object when a {{Navigator}} object or a {{WorkerNavigator}} object is created and associate it with that object. A {{ServiceWorkerContainer}} provides capabilities to register, unregister, and update the [=/service worker registrations=], and provides access to the state of the [=/service worker registrations=] and their associated [=/service workers=]. A {{ServiceWorkerContainer}} has an associated service worker client, which is a [=/service worker client=] whose [=environment settings object/global object=] is associated with the {{Navigator}} object or the {{WorkerNavigator}} object that the {{ServiceWorkerContainer}} is retrieved from. A {{ServiceWorkerContainer}} object has an associated ready promise (a promise). It is initially set to a new promise. A {{ServiceWorkerContainer}} object has a task source called the client message queue, initially empty. A [=ServiceWorkerContainer/client message queue=] can be enabled or disabled, and is initially disabled. When a {{ServiceWorkerContainer}} object's [=ServiceWorkerContainer/client message queue=] is enabled, the event loop *must* use it as one of its task sources. When the {{ServiceWorkerContainer}} object's relevant global object is a {{Window}} object, all tasks queued on its [=ServiceWorkerContainer/client message queue=] *must* be associated with its relevant settings object's responsible document.
controller attribute *must* run these steps: 1. Let |client| be the context object's [=ServiceWorkerContainer/service worker client=]. 1. Return the {{ServiceWorker}} object that represents |client|'s active service worker. Note: {{ServiceWorkerContainer/controller|navigator.serviceWorker.controller}} returns null if the request is a force refresh (shift+refresh). The {{ServiceWorker}} objects returned from this attribute getter that represent the same [=/service worker=] are the same objects.
ready attribute *must* run these steps: 1. If the context object's [=ServiceWorkerContainer/ready promise=] is settled, return the context object's [=ServiceWorkerContainer/ready promise=]. 1. Let |client| be the context object's [=ServiceWorkerContainer/service worker client=]. 1. Let |registration| be null. 1. Let |clientURL| be |client|'s creation URL. 1. Run the following substeps in parallel: 1. *CheckRegistration*: If the result of running Match Service Worker Registration algorithm with |clientURL| as its argument is not null, then: 1. Set |registration| to the result value. 1. Else: 1. Wait until scope to registration map has a new entry. 1. Jump to the step labeled *CheckRegistration*. 1. If |registration|'s active worker is null, wait until |registration|'s active worker changes. Note: Implementers should consider this condition is met when the corresponding registration request gets to the step 6 of Activate algorithm. 1. Resolve context object's [=ServiceWorkerContainer/ready promise=] with the {{ServiceWorkerRegistration}} object which represents |registration|. 1. Return context object's [=ServiceWorkerContainer/ready promise=]. Note: When the {{ServiceWorkerContainer/ready}} attribute is accessed, the returned promise will never reject. Instead, it waits until the promise resolves with a [=/service worker registration=] that has an active worker.
Note: The {{ServiceWorkerContainer/register(scriptURL, options)}} method creates or updates a [=/service worker registration=] for the given [=service worker registration/scope url=]. If successful, a [=/service worker registration=] ties the provided |scriptURL| to a [=service worker registration/scope url=], which is subsequently used for navigation matching. register(|scriptURL|, |options|) method *must* run these steps: 1. Let |p| be a promise. 1. Let |client| be the context object's [=ServiceWorkerContainer/service worker client=]. 1. Let |scriptURL| be the result of parsing |scriptURL| with the context object's relevant settings object's API base URL. 1. Let |scopeURL| be null. 1. If |options|.{{RegistrationOptions/scope}} is present, set |scopeURL| to the result of parsing |options|.{{RegistrationOptions/scope}} with the context object's relevant settings object's API base URL. 1. Invoke [=Start Register=] with |scopeURL|, |scriptURL|, |p|, |client|, |client|'s creation URL, |options|.{{RegistrationOptions/type}}, and |options|.{{RegistrationOptions/useCache}}. 1. Return |p|.
getRegistration(|clientURL|) method *must* run these steps: 1. Let |client| be the context object's [=ServiceWorkerContainer/service worker client=]. 1. Let |clientURL| be the result of parsing |clientURL| with the context object's relevant settings object's API base URL. 1. If |clientURL| is failure, return a promise rejected with a TypeError. 1. If the [=environment settings object/origin=] of |clientURL| is not |client|'s [=environment settings object/origin=], return a |promise| rejected with a "{{SecurityError}}" exception. 1. Let |promise| be a new promise. 1. Run the following substeps in parallel: 1. Let |registration| be the result of running Match Service Worker Registration algorithm with |clientURL| as its argument. 1. If |registration| is not null, then: 1. Resolve |promise| with the {{ServiceWorkerRegistration}} object which represents |registration|. 1. Else: 1. Resolve |promise| with undefined. 1. Return |promise|.
getRegistrations() method *must* run these steps: 1. Let |client| be the context object's [=ServiceWorkerContainer/service worker client=]. 1. Let |promise| be a new promise. 1. Run the following substeps in parallel: 1. Let |array| be an empty array. 1. [=map/For each=] |key| → |value| of scope to registration map: 1. If the [=url/origin=] of the result of parsing |key| is the same as |client|'s [=environment settings object/origin=], and |value|'s uninstalling flag is unset, add the {{ServiceWorkerRegistration}} object associated with |value| to the |array|. 1. Resolve |promise| with |array|. 1. Return |promise|.
startMessages() method *must* enable the context object's [=ServiceWorkerContainer/client message queue=] if it is not enabled.

Event handlers

The following are the event handlers (and their corresponding event handler event types) that *must* be supported, as event handler IDL attributes, by all objects implementing the {{ServiceWorkerContainer}} interface:
event handler event handler event type
oncontrollerchange {{ServiceWorkerContainer/controllerchange!!event}}
onmessage {{ServiceWorkerContainer/message!!event}}
The first time the context object's {{ServiceWorkerContainer/onmessage}} IDL attribute is set, its [=ServiceWorkerContainer/client message queue=] *must* be enabled.

Events

The following event is dispatched on {{ServiceWorker}} object:
Event name Interface Dispatched when…
statechange {{Event}} The {{ServiceWorker/state}} attribute of the {{ServiceWorker}} object is changed.
The following event is dispatched on {{ServiceWorkerRegistration}} object:
Event name Interface Dispatched when…
updatefound {{Event}} The [=ServiceWorkerRegistration/service worker registration=]'s installing worker changes. (See step 8 of the Install algorithm.)
The following events are dispatched on {{ServiceWorkerContainer}} object:
Event name Interface Dispatched when…
controllerchange {{Event}} The [=ServiceWorkerContainer/service worker client=]'s active service worker changes. (See step 9.2 of the Activate algorithm. The skip waiting flag of a [=/service worker=] causes activation of the [=/service worker registration=] to occur while [=/service worker clients=] are using the [=/service worker registration=], {{ServiceWorkerContainer/controller|navigator.serviceWorker.controller}} immediately reflects the active worker as the [=/service worker=] that controls the [=/service worker client=].)
      [SecureContext, Exposed=(Window,Worker)]
      interface NavigationPreloadManager {
        Promise<void> enable();
        Promise<void> disable();
        Promise<void> setHeaderValue(ByteString value);
        Promise<NavigationPreloadState> getState();
      };

      dictionary NavigationPreloadState {
        boolean enabled = false;
        ByteString headerValue;
      };
    
The enable() method, when invoked, *must* return a new [=promise=] |promise| and run the following steps [=in parallel=]: 1. Let |registration| be the [=context object=]'s associated [=/service worker registration=]. 1. If |registration|'s [=active worker=] is null, [=reject=] |promise| with an "{{InvalidStateError}}" exception, and abort these steps. 1. Set |registration|'s [=navigation preload enabled flag=]. 1. [=Resolve=] |promise| with undefined.
The disable() method, when invoked, *must* return a new [=promise=] |promise| and run the following steps [=in parallel=]: 1. Let |registration| be the [=context object=]'s associated [=/service worker registration=]. 1. If |registration|'s [=active worker=] is null, [=reject=] |promise| with an "{{InvalidStateError}}" exception, and abort these steps. 1. Unset |registration|'s [=navigation preload enabled flag=]. 1. [=Resolve=] |promise| with undefined.
The setHeaderValue(|value|) method, when invoked, *must* return [=a new promise=] |promise| and run the following steps [=in parallel=]: 1. Let |registration| be the [=context object=]'s associated [=/service worker registration=]. 1. If |registration|'s [=active worker=] is null, [=reject=] |promise| with an "{{InvalidStateError}}" exception, and abort these steps. 1. Set |registration|'s [=navigation preload header value=] to |value|. 1. [=Resolve=] |promise| with undefined.
The getState() method, when invoked, *must* return [=a new promise=] |promise| and run the following steps [=in parallel=]: 1. Let |registration| be the [=context object=]'s associated [=/service worker registration=]. 1. Let |state| be a new {{NavigationPreloadState}} dictionary. 1. If |registration|'s [=navigation preload enabled flag=] is set, set |state|'s {{NavigationPreloadState/enabled}} dictionary member to true. 1. Set |state|'s {{NavigationPreloadState/headerValue}} dictionary member to the |registration|'s [=navigation preload header value=]. 1. [=Resolve=] |promise| with |state|.

Execution Context

Serving Cached Resources:
      // caching.js
      self.addEventListener("install", event => {
        event.waitUntil(
          // Open a cache of resources.
          caches.open("shell-v1").then(cache => {
            // Begins the process of fetching them.
            // The coast is only clear when all the resources are ready.
            return cache.addAll([
              "/app.html",
              "/assets/v1/base.css",
              "/assets/v1/app.js",
              "/assets/v1/logo.png",
              "/assets/v1/intro_video.webm"
            ]);
          })
        );
      });

      self.addEventListener("fetch", event => {
        // No "fetch" events are dispatched to the service worker until it
        // successfully installs and activates.

        // All operations on caches are async, including matching URLs, so we use
        // promises heavily. e.respondWith() even takes promises to enable this:
        event.respondWith(
          caches.match(e.request).then(response => {
            return response || fetch(e.request);
          }).catch(() => {
            return caches.match("/fallback.html");
          })
        );
      });
    

{{ServiceWorkerGlobalScope}}

      [Global=(Worker,ServiceWorker), Exposed=ServiceWorker]
      interface ServiceWorkerGlobalScope : WorkerGlobalScope {
        [SameObject] readonly attribute Clients clients;
        [SameObject] readonly attribute ServiceWorkerRegistration registration;

        [NewObject] Promise<void> skipWaiting();

        attribute EventHandler oninstall;
        attribute EventHandler onactivate;
        attribute EventHandler onfetch;
        attribute EventHandler onforeignfetch;

        // event
        attribute EventHandler onmessage; // event.source of the message events is Client object
      };
    
A {{ServiceWorkerGlobalScope}} object represents the global execution context of a [=/service worker=]. A {{ServiceWorkerGlobalScope}} object has an associated service worker (a [=/service worker=]). A {{ServiceWorkerGlobalScope}} object has an associated force bypass cache for importscripts flag. It is initially unset. Note: {{ServiceWorkerGlobalScope}} object provides generic, event-driven, time-limited script execution contexts that run at an origin. Once successfully registered, a [=/service worker=] is started, kept alive and killed by their relationship to events, not [=/service worker clients=]. Any type of synchronous requests must not be initiated inside of a [=/service worker=].

{{ServiceWorkerGlobalScope/clients}}

clients attribute *must* return the {{Clients}} object that is associated with the context object.

{{ServiceWorkerGlobalScope/registration}}

The registration attribute *must* return the {{ServiceWorkerRegistration}} object that represents the [=ServiceWorkerGlobalScope/service worker=]'s containing service worker registration.

{{ServiceWorkerGlobalScope/skipWaiting()}}

Note: The {{ServiceWorkerGlobalScope/skipWaiting()}} method allows this [=/service worker=] to progress from the [=service worker/registration=]'s waiting position to active even while [=/service worker clients=] are using the [=service worker/registration=]. skipWaiting() method *must* run these steps: 1. Let |promise| be a new promise. 1. Run the following substeps in parallel: 1. Set [=ServiceWorkerGlobalScope/service worker=]'s skip waiting flag. 1. Invoke [=Try Activate=] with [=ServiceWorkerGlobalScope/service worker=]'s [=containing service worker registration=]. 1. Resolve |promise| with undefined. 1. Return |promise|.

Event handlers

The following are the event handlers (and their corresponding event handler event types) that *must* be supported, as event handler IDL attributes, by all objects implementing the {{ServiceWorkerGlobalScope}} interface:
event handler event handler event type
oninstall {{install!!event}}
onactivate {{activate!!event}}
onfetch {{fetch!!event}}
onforeignfetch {{foreignfetch!!event}}
onmessage {{message!!event}}

{{Client}}

      [Exposed=ServiceWorker]
      interface Client {
        readonly attribute USVString url;
        readonly attribute DOMString id;
        readonly attribute ClientType type;
        readonly attribute boolean reserved;
        void postMessage(any message, optional sequence<object> transfer = []);
      };

      [Exposed=ServiceWorker]
      interface WindowClient : Client {
        readonly attribute VisibilityState visibilityState;
        readonly attribute boolean focused;
        [SameObject] readonly attribute FrozenArray<USVString> ancestorOrigins;
        [NewObject] Promise<WindowClient> focus();
        [NewObject] Promise<WindowClient> navigate(USVString url);
      };
    
A {{Client}} object has an associated service worker client (a [=/service worker client=]). A {{Client}} object has an associated reserved state, which is either true or false. A {{WindowClient}} object has an associated visibility state, which is one of {{Document/visibilityState}} attribute value. A {{WindowClient}} object has an associated focus state, which is either true or false (initially false). A {{WindowClient}} object has an associated ancestor origins array.

{{Client/url}}

The url attribute *must* return the context object's associated [=Client/service worker client=]'s serialized creation URL.

{{Client/id}}

The id attribute *must* return its associated [=Client/service worker client=]'s [=environment/id=].

{{Client/type}}

The type attribute *must* run these steps: 1. Let |client| be [=context object=]'s [=Client/service worker client=]. 1. If |client| is an [=environment settings object=], then: 1. If |client| is a [=window client=], return {{ClientType/"window"}}. 1. Else if |client| is a [=dedicated worker client=], return {{ClientType/"worker"}}. 1. Else if |client| is a [=shared worker client=], return {{ClientType/"sharedworker"}}. 1. Else: 1. Return {{ClientType/"window"}}.

{{Client/reserved}}

The reserved attribute *must* return the context object's associated [=Client/reserved state=].

{{Client/postMessage(message, transfer)}}

The postMessage(|message|, |transfer|) method *must* run these steps: 1. Let |sourceSettings| be the context object's relevant settings object. 1. Let |destination| be the {{ServiceWorkerContainer}} object whose [=ServiceWorkerContainer/service worker client=] is the context object's [=Client/service worker client=]. 1. If |destination| is null, throw an "{{InvalidStateError}}" exception. 1. Let |targetRealm| be |destination|'s relevant Realm. 1. Let |cloneRecord| be StructuredCloneWithTransfer(|message|, |transfer|, |targetRealm|). If this throws an exception, rethrow that exception and abort these steps. 1. Let |clonedMessage| be |cloneRecord|.\[[Clone]]. 1. Let |newPorts| be a new [=frozen array type|frozen array=] consisting of all {{MessagePort}} objects in |cloneRecord|.\[[TransferList]], if any, maintaining their relative order. 1. Add a task that runs the following steps to |destination|'s [=ServiceWorkerContainer/client message queue=]: 1. Create an event |e| that uses the {{MessageEvent}} interface, with the event type {{Window/message!!event}}, which does not bubble and is not cancelable. 1. Let the data attribute of |e| be initialized to |clonedMessage|. 1. Let the origin attribute of |e| be initialized to the Unicode serialization of |sourceSettings|'s [=environment settings object/origin=]. 1. Let the source attribute of |e| be initialized to a {{ServiceWorker}} object, which represents the [=ServiceWorkerGlobalScope/service worker=] associated with |sourceSettings|'s [=environment settings object/global object=]. 1. Let the ports attribute of |e| be initialized to |newPorts|. 1. Dispatch |e| at |destination|.

{{WindowClient/visibilityState}}

The visibilityState attribute *must* return the context object's visibility state.

{{WindowClient/focused}}

The focused attribute *must* return the context object's focus state.

{{WindowClient/ancestorOrigins}}

The ancestorOrigins attribute *must* return the context object's associated [=WindowClient/ancestor origins array=].

{{WindowClient/focus()}}

The focus() method *must* run these steps: 1. If this algorithm is not triggered by user activation, return a promise rejected with an "{{InvalidAccessError}}" exception. 1. Let |promise| be a new promise. 1. Run these substeps in parallel: 1. Let |browsingContext| be the context object's associated [=Client/service worker client=]'s [=environment settings object/global object=]'s [=/browsing context=]. 1. Let |visibilityState| be null. 1. Let |focusState| be false. 1. Let |ancestorOriginsList| be the empty list. 1. Queue a task |task| to run the following substeps on the context object's associated [=Client/service worker client=]'s responsible event loop using the user interaction task source: 1. Run the focusing steps with |browsingContext|. 1. Set |visibilityState| to |browsingContext|'s active document's {{Document/visibilityState}} attribute value. 1. Set |focusState| to the result of running the has focus steps with |browsingContext|'s active document as the argument. 1. Set |ancestorOriginsList| to |browsingContext|'s active document's relevant global object's {{Location}} object's [=Location/ancestor origins list=]'s associated list. 1. Wait for |task| to have executed. 1. Let |windowClient| be the result of running Create Window Client algorithm with the context object's associated [=Client/service worker client=], |visibilityState|, |focusState|, and |ancestorOriginsList| as the arguments. 1. If |windowClient|'s focus state is true, resolve |promise| with |windowClient|. 1. Else, reject |promise| with a TypeError. 1. Return |promise|.

{{WindowClient/navigate(url)}}

The navigate() method *must* run these steps: 1. Let |url| be the result of parsing |url| with the context object's relevant settings object's API base URL. 1. If |url| is failure, return a promise rejected with a TypeError. 1. If |url| is about:blank, return a promise rejected with a TypeError. 1. If the context object's associated [=Client/service worker client=]'s active service worker is not the context object's relevant global object's [=ServiceWorkerGlobalScope/service worker=], return a promise rejected with a TypeError. 1. Let |promise| be a new promise. 1. Run these substeps in parallel: 1. Let |browsingContext| be the context object's associated [=Client/service worker client=]'s [=environment settings object/global object=]'s [=/browsing context=]. 1. If |browsingContext| has discarded its {{Document}}, reject |promise| with a TypeError and abort these steps. 1. Let |navigateFailed| to false. 1. Let |visibilityState| be null. 1. Let |focusState| be false. 1. Let |ancestorOriginsList| be the empty list. 1. Queue a task |task| to run the following substeps on the context object's associated [=Client/service worker client=]'s responsible event loop using the user interaction task source: 1. *HandleNavigate*: Navigate |browsingContext| to |url| with exceptions enabled. The source browsing context must be |browsingContext|. 1. If the algorithm steps invoked in the step labeled *HandleNavigate* throws an exception, set |navigateFailed| to true. 1. Set |visibilityState| to |browsingContext|'s active document's {{Document/visibilityState}} attribute value. 1. Set |focusState| to the result of running the has focus steps with |browsingContext|'s active document as the argument. 1. Set |ancestorOriginsList| to |browsingContext|'s active document's relevant global object's {{Location}} object's [=Location/ancestor origins list=]'s associated list. 1. Wait for |task| to have executed (including its asynchronous steps). 1. If |navigateFailed| is true, reject |promise| with a TypeError and abort these steps. 1. If |browsingContext|'s {{Window}} object's environment settings object's creation URL's [=url/origin=] is not the same as the [=ServiceWorkerGlobalScope/service worker=]'s [=environment settings object/origin=], then: 1. Resolve |promise| with null. 1. Abort these steps. 1. Let |windowClient| be the result of running Create Window Client algorithm with |browsingContext|'s {{Window}} object's environment settings object, |visibilityState|, |focusState|, and |ancestorOriginsList| as the arguments. 1. Resolve |promise| with |windowClient|. 1. Return |promise|.

{{Clients}}

      [Exposed=ServiceWorker]
      interface Clients {
        // The objects returned will be new instances every time
        [NewObject] Promise<any> get(DOMString id);
        [NewObject] Promise<sequence<Client>> matchAll(optional ClientQueryOptions options);
        [NewObject] Promise<WindowClient?> openWindow(USVString url);
        [NewObject] Promise<void> claim();
      };
    
      dictionary ClientQueryOptions {
        boolean includeUncontrolled = false;
        boolean includeReserved = false;
        ClientType type = "window";
      };
    
      enum ClientType {
        "window",
        "worker",
        "sharedworker",
        "all"
      };
    
The user agent *must* create a {{Clients}} object when a {{ServiceWorkerGlobalScope}} object is created and associate it with that object.

{{Clients/get(id)}}

The get(|id|) method *must* run these steps: 1. Let |promise| be a new promise. 1. Run these substeps in parallel: 1. For each [=/service worker client=] |client| whose [=service worker client/origin=] is the same as the associated [=ServiceWorkerGlobalScope/service worker=]'s [=environment settings object/origin=]: 1. If |client|'s [=environment/id=] is not |id|, continue to the next iteration of the loop. 1. If |client| is an [=environment settings object=], then: 1. If |client| is not a secure context, reject |promise| with a "{{SecurityError}}" exception and abort these steps. 1. Else: 1. If |client|’s creation URL is not a potentially trustworthy URL, reject |promise| with a "{{SecurityError}}" exception and abort these steps. 1. If |client| is an [=environment settings object=] and is not a [=window client=], then: 1. Let |clientObject| be the result of running Create Client algorithm with |client| as the argument. 1. Resolve |promise| with |clientObject| and abort these steps. 1. Else: 1. Let |browsingContext| be null. 1. Let |visibilityState| be null. 1. Let |focusState| be false. 1. Let |ancestorOriginsList| be the empty list. 1. If |client| is an [=environment settings object=], set |browsingContext| to |client|'s [=environment settings object/global object=]'s [=/browsing context=]. 1. Else, set |browsingContext| to |client|’s [=environment/target browsing context=]. 1. Queue a task |task| to run the following substeps on |browsingContext|'s event loop using the user interaction task source: 1. Set |visibilityState| to |browsingContext|'s active document's {{Document/visibilityState}} attribute value. 1. Set |focusState| to the result of running the has focus steps with |browsingContext|'s active document as the argument. 1. If |client| is a window client, set |ancestorOriginsList| to |browsingContext|'s active document's relevant global object's {{Location}} object's [=Location/ancestor origins list=]'s associated list. 1. Wait for |task| to have executed. 1. Let |windowClient| be the result of running Create Window Client algorithm with |client|, |visibilityState|, |focusState|, and |ancestorOriginsList| as the arguments. 1. Resolve |promise| with |windowClient| and abort these steps. 1. Resolve |promise| with undefined. 1. Return |promise|.

{{Clients/matchAll(options)}}

The matchAll(|options|) method *must* run these steps: 1. Let |promise| be a new promise. 1. Run these substeps in parallel: 1. Let |targetClients| be an empty array. 1. For each [=/service worker client=] |client| whose [=service worker client/origin=] is the same as the associated [=ServiceWorkerGlobalScope/service worker=]'s [=environment settings object/origin=]: 1. If |client| is an [=environment settings object=], then: 1. If |client| is not a secure context, continue to the next iteration of the loop. 1. Else: 1. If |client|’s creation URL is not a potentially trustworthy URL, continue to the next iteration of the loop. 1. If |options|.{{ClientQueryOptions/includeUncontrolled}} is false, then: 1. If |client|'s active service worker is not the associated [=ServiceWorkerGlobalScope/service worker=], continue to the next iteration of the loop. 1. If |options|.{{ClientQueryOptions/includeReserved}} is false, then: 1. If |client|'s [=environment/execution ready flag=] is unset, continue to the next iteration of the loop. 1. Add |client| to |targetClients|. 1. Let |matchedClients| be an empty array. 1. For each [=/service worker client=] |client| in |targetClients|: 1. If |options|.{{ClientQueryOptions/type}} is {{ClientType/"window"}} or {{ClientType/"all"}}, and |client| is not an [=environment settings object=] or is a [=window client=], then: 1. Let |browsingContext| be null. 1. Let |isClientEnumerable| be true. 1. Let |visibilityState| be the empty string. 1. Let |focusState| be false. 1. Let |ancestorOriginsList| be the empty list. 1. If |client| is an [=environment settings object=], set |browsingContext| to |client|'s [=environment settings object/global object=]'s [=/browsing context=]. 1. Else, set |browsingContext| to |client|’s [=environment/target browsing context=]. 1. Queue a task |task| to run the following substeps on |browsingContext|'s event loop using the user interaction task source: 1. If |browsingContext| has been discarded, set |isClientEnumerable| to false and abort these steps. 1. If |client| is a window client and |client|'s responsible document is not |browsingContext|'s active document, set |isClientEnumerable| to false and abort these steps. 1. Set |visibilityState| to |browsingContext|'s active document's {{Document/visibilityState}} attribute value. 1. Set |focusState| to the result of running the has focus steps with |browsingContext|'s active document as the argument. 1. It |client| is a window client, set |ancestorOriginsList| to |browsingContext|'s active document's relevant global object's {{Location}} object's [=Location/ancestor origins list=]'s associated list. 1. Wait for |task| to have executed. Note: Wait is a blocking wait, but implementers may run the iterations in parallel as long as the state is not broken. 1. If |isClientEnumerable| is true, then: 1. Let |windowClient| be the result of running Create Window Client algorithm with |client|, |visibilityState|, |focusState|, and |ancestorOriginsList| as the arguments. 1. Add |windowClient| to |matchedClients|. 1. Else if |options|.{{ClientQueryOptions/type}} is {{ClientType/"worker"}} or {{ClientType/"all"}} and |client| is a [=dedicated worker client=], or |options|.{{ClientQueryOptions/type}} is {{ClientType/"sharedworker"}} or {{ClientType/"all"}} and |client| is a [=shared worker client=], then: 1. Let |clientObject| be the result of running Create Client algorithm with |client| as the argument. 1. Add |clientObject| to |matchedClients|. 1. Sort |matchedClients| such that: * {{WindowClient}} objects are always placed before {{Client}} objects whose associated [=Client/service worker clients=] are worker clients. * {{WindowClient}} objects that have been focused are placed first sorted in the most recently focused order, and {{WindowClient}} objects that have never been focused are placed next sorted in their [=Client/service worker clients=]' creation order. * {{Client}} objects whose associated [=Client/service worker clients=] are worker clients are placed next sorted in their [=Client/service worker clients=]' creation order. 1. Resolve |promise| with |matchedClients|. 1. Return |promise|.

{{Clients/openWindow(url)}}

The openWindow(|url|) method *must* run these steps: 1. Let |url| be the result of parsing |url| with the context object's relevant settings object's API base URL. 1. If |url| is failure, return a promise rejected with a TypeError. 1. If |url| is about:blank, return a promise rejected with a TypeError. 1. If this algorithm is not triggered by user activation, return a promise rejected with an "{{InvalidAccessError}}" exception. 1. Let |promise| be a new promise. 1. Run these substeps in parallel: 1. Let |newContext| be a new top-level browsing context. 1. Let |openWindowFailed| to false. 1. Let |visibilityState| be null. 1. Let |focusState| be false. 1. Let |ancestorOriginsList| be the empty list. 1. Queue a task |task| to run the following substeps on |newContext|'s {{Window}} object's environment settings object's responsible event loop using the user interaction task source: 1. *HandleNavigate*: Navigate |newContext| to |url| with exceptions enabled and replacement enabled. 1. If the algorithm steps invoked in the step labeled *HandleNavigate* throws an exception, set |openWindowFailed| to true. 1. Set |visibilityState| to |newContext|'s active document's {{Document/visibilityState}} attribute value. 1. Set |focusState| to the result of running the has focus steps with |newContext|'s active document as the argument. 1. Set |ancestorOriginsList| to |newContext|'s active document's relevant global object's {{Location}} object's [=Location/ancestor origins list=]'s associated list. 1. Wait for |task| to have executed (including its asynchronous steps). 1. If |openWindowFailed| is true, reject |promise| with a TypeError and abort these steps. 1. If |newContext|'s {{Window}} object's environment settings object's creation URL's [=environment settings object/origin=] is not the same as the [=ServiceWorkerGlobalScope/service worker=]'s [=environment settings object/origin=], then: 1. Resolve |promise| with null. 1. Abort these steps. 1. Let |client| be the result of running Create Window Client algorithm with |newContext|'s {{Window}} object's environment settings object, |visibilityState|, |focusState|, and |ancestorOriginsList| as the arguments. 1. Resolve |promise| with |client|. 1. Return |promise|.

{{Clients/claim()}}

The claim() method *must* run these steps: 1. If the [=ServiceWorkerGlobalScope/service worker=] is not an active worker, return a promise rejected with an "{{InvalidStateError}}" exception. 1. Let |promise| be a new promise. 1. Run the following substeps in parallel: 1. For each [=/service worker client=] |client| whose [=service worker client/origin=] is the same as the [=ServiceWorkerGlobalScope/service worker=]'s [=environment settings object/origin=]: 1. If |client| is an [=environment settings object=], then: 1. If |client| is not a secure context, continue to the next iteration of the loop. 1. Else: 1. If |client|’s creation URL is not a potentially trustworthy URL, continue to the next iteration of the loop. 1. Let |registration| be the result of running Match Service Worker Registration algorithm passing |client|'s creation URL as the argument. 1. If |registration| is not the [=ServiceWorkerGlobalScope/service worker=]'s containing service worker registration, continue to the next iteration of the loop. 1. If |client|'s active service worker is not the [=ServiceWorkerGlobalScope/service worker=], then: 1. Invoke Handle Service Worker Client Unload with |client| as the argument. 1. Set |client|'s active service worker to [=ServiceWorkerGlobalScope/service worker=]. 1. Invoke Notify Controller Change algorithm with |client| as the argument. 1. Resolve |promise| with undefined. 1. Return |promise|.

{{ExtendableEvent}}

      [Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
      interface ExtendableEvent : Event {
        void waitUntil(Promise<any> f);
      };
    
      dictionary ExtendableEventInit : EventInit {
        // Defined for the forward compatibility across the derived events
      };
    
An {{ExtendableEvent}} object has an associated extend lifetime promises (an array of promises). It is initially an empty array. An {{ExtendableEvent}} object has an associated pending promises count (the number of pending promises in the [=ExtendableEvent/extend lifetime promises=]). It is initially set to zero. [=/Service workers=] have two lifecycle events, {{install!!event}} and {{activate!!event}}. [=/Service workers=] use the {{ExtendableEvent}} interface for {{activate!!event}} event and {{install!!event}} event. Service worker extensions that define event handlers *may* also use or extend the {{ExtendableEvent}} interface.

{{ExtendableEvent/waitUntil()|event.waitUntil(f)}}

{{ExtendableEvent/waitUntil()}} method extends the lifetime of the event. waitUntil(|f|) method *must* run these steps: 1. If the [=ExtendableEvent/pending promises count=] is zero and the [=dispatch flag=] is unset, then: 1. Throw an "{{InvalidStateError}}" exception. 1. Abort these steps. Note: If no lifetime extension promise has been added in the task that called the event handlers), calling {{ExtendableEvent/waitUntil()}} in subsequent asynchronous tasks will throw. 1. Add |f| to the [=ExtendableEvent/extend lifetime promises=]. 1. Increment the [=ExtendableEvent/pending promises count=] by one. Note: The [=ExtendableEvent/pending promises count=] is incremented even if the given promise has already been settled. The corresponding count decrement is done in the microtask queued by the reaction to the promise. 1. Upon [=upon fulfillment|fulfillment=] or [=upon rejection|rejection=] of |f|, [=queue a microtask=] to run these substeps: 1. Decrement the [=ExtendableEvent/pending promises count=] by one. 1. Let |registration| be the [=context object=]'s [=relevant global object=]'s associated [=ServiceWorkerGlobalScope/service worker=]'s [=containing service worker registration=]. 1. If |registration|'s [=uninstalling flag=] is set, invoke [=Try Clear Registration=] with |registration|. 1. If |registration| is not null, invoke [=Try Activate=] with |registration|. The user agent *should not* terminate the [=/service worker=] associated with |event|'s relevant settings object's [=environment settings object/global object=] when |event|'s [=dispatch flag=] is set or |event|'s [=ExtendableEvent/pending promises count=] is not zero. However, the user agent *may* impose a time limit to this lifetime extension.
[=/Service workers=] and extensions that define event handlers *may* define their own behaviors, allowing the [=ExtendableEvent/extend lifetime promises=] to suggest operation length, and the rejected state of any of the promise in [=ExtendableEvent/extend lifetime promises=] to suggest operation failure. [=/Service workers=] define the following behaviors for install event and activate event, respectively: * Adding a promise |f| to the event's extend lifetime promises delays treating the installing worker as *installed* (i.e. a waiting worker) until all the promises in the extend lifetime promises resolve successfully. (See step 11.3.1 of Install algorithm.) If |f| rejects, the installation fails. This is primarily used to ensure that a [=/service worker=] is not considered *installed* (i.e. a waiting worker) until all of the core caches it depends on are populated. * Adding a promise to the event's extend lifetime promises delays treating the active worker as *activated* until all the promises in the extend lifetime promises settle. (See step 12.3 of Activate algorithm.) This is primarily used to ensure that any functional events are not dispatched to the {{ServiceWorkerGlobalScope}} object that represents the [=/service worker=] until it upgrades database schemas and deletes the outdated cache entries.

{{InstallEvent}}

      [Constructor(DOMString type, optional ExtendableEventInit eventInitDict), Exposed=ServiceWorker]
      interface InstallEvent : ExtendableEvent {
        void registerForeignFetch(ForeignFetchOptions options);
      };

      dictionary ForeignFetchOptions {
        required sequence<USVString> scopes;
        required sequence<USVString> origins;
      };
    

{{InstallEvent/registerForeignFetch(options)|event.registerForeignFetch(options)}}

{{InstallEvent/registerForeignFetch(options)}} registers this service worker to handle foreign fetches from certain origins for certain sub scopes. registerForeignFetch(|options|) method *must* run these steps: 1. If the dispatch flag is unset, then: 1. Throw an "{{InvalidStateError}}" exception. 1. Abort these steps. 1. If |options|.{{ForeignFetchOptions/origins}} is empty throw a TypeError and abort these steps. 1. Let |originURLs| be an empty list of [=/URLs=]. 1. If the value of |options|.{{ForeignFetchOptions/origins}} is not a single string equal to a single U+002A ASTERISK character (*): 1. For each |origin| in |options|.origins: 1. If the value of |origin| is not an absolute-URL string, throw a TypeError and abort these steps. 1. Add the result of parsing |origin| to |originURLs|. 1. If |options|.{{ForeignFetchOptions/scopes}} is empty throw a TypeError and abort these steps. 1. Let |scopeString| be the context object's relevant global object's [=ServiceWorkerGlobalScope/service worker=]'s containing service worker registration's [=service worker registration/scope url=], serialized. 1. Let |subScopeURLs| be an empty list of [=/URLs=]. 1. For each |subScope| in |options|.{{ForeignFetchOptions/scopes}}: 1. Let |subScopeURL| be the result of parsing |subScope| with context object's relevant settings object's API base URL. 1. If |subScopeURL| is failure, throw a TypeError and abort these steps. 1. Let |subScopeString| be the serialized |subScopeURL|. 1. If |subScopeString| does not start with |scopeString|, throw a TypeError and abort these steps. 1. Add |subScopeURL| to |subScopeURLs|. 1. Set this [=/service worker=]'s list of foreign fetch scopes to |subScopeURLs|. 1. Set this [=/service worker=]'s list of foreign fetch origins to |originURLs|.

{{FetchEvent}}

      [Constructor(DOMString type, FetchEventInit eventInitDict), Exposed=ServiceWorker]
      interface FetchEvent : ExtendableEvent {
        [SameObject] readonly attribute Request request;
        readonly attribute Promise<any> preloadResponse;
        readonly attribute DOMString clientId;
        readonly attribute DOMString reservedClientId;
        readonly attribute DOMString targetClientId;

        void respondWith(Promise<Response> r);
      };
    
      dictionary FetchEventInit : ExtendableEventInit {
        required Request request;
        required Promise<any> preloadResponse;
        DOMString clientId = "";
        DOMString reservedClientId = "";
        DOMString targetClientId = "";
      };
    
[=/Service workers=] have an essential functional event {{fetch!!event}}. For {{fetch!!event}} event, [=/service workers=] use the {{FetchEvent}} interface which extends the {{ExtendableEvent}} interface. Each event using {{FetchEvent}} interface has an associated potential response (a [=/response=]), initially set to null, and the following associated flags that are initially unset: * wait to respond flag * respond-with entered flag * respond-with error flag

{{FetchEvent/request|event.request}}

request attribute *must* return the value it was initialized to.

{{FetchEvent/preloadResponse|event.preloadResponse}}

preloadResponse attribute *must* return the value it was initialized to.

{{FetchEvent/clientId|event.clientId}}

clientId attribute *must* return the value it was initialized to. When an event is created the attribute *must* be initialized to the empty string.

{{FetchEvent/reservedClientId|event.reservedClientId}}

reservedClientId attribute *must* return the value it was initialized to. When an event is created the attribute *must* be initialized to the empty string.

{{FetchEvent/targetClientId|event.targetClientId}}

targetClientId attribute *must* return the value it was initialized to. When an event is created the attribute *must* be initialized to the empty string.

{{FetchEvent/respondWith(r)|event.respondWith(r)}}

Note: Developers can set the argument |r| with either a promise that resolves with a {{Response}} object or a {{Response}} object (which is automatically cast to a promise). Otherwise, a network error is returned to [=/Fetch=]. Renderer-side security checks about tainting for cross-origin content are tied to the types of filtered responses defined in [=/Fetch=]. respondWith(|r|) method *must* run these steps: 1. If the dispatch flag is unset, then: 1. Throw an "{{InvalidStateError}}" exception. 1. Abort these steps. 1. If the [=FetchEvent/respond-with entered flag=] is set, then: 1. Throw an "{{InvalidStateError}}" exception. 1. Abort these steps. 1. Add |r| to the extend lifetime promises. 1. Increment the [=ExtendableEvent/pending promises count=] by one. Note: The [=ExtendableEvent/pending promises count=] is incremented even if the given promise has already been settled. The corresponding count decrement is done in the microtask queued by the reaction to the promise. 1. Upon [=upon fulfillment|fulfillment=] or [=upon rejection|rejection=] of |r|, [=queue a microtask=] to run these substeps: 1. Decrement the [=ExtendableEvent/pending promises count=] by one. 1. Let |registration| be the [=context object=]'s [=relevant global object=]'s associated [=ServiceWorkerGlobalScope/service worker=]'s [=containing service worker registration=]. 1. If |registration|'s [=uninstalling flag=] is set, invoke [=Try Clear Registration=] with |registration|. 1. If |registration| is not null, invoke [=Try Activate=] with |registration|. Note: {{FetchEvent/respondWith(r)|event.respondWith(r)}} extends the lifetime of the event by default as if {{ExtendableEvent/waitUntil()|event.waitUntil(r)}} is called. 1. Set the stop propagation flag and stop immediate propagation flag. 1. Set the [=FetchEvent/respond-with entered flag=]. 1. Set the [=FetchEvent/wait to respond flag=]. 1. Let |targetRealm| be the relevant Realm of the context object. 1. Run the following substeps in parallel: 1. Wait until |r| settles. 1. If |r| rejected, then: 1. Set the [=FetchEvent/respond-with error flag=]. 1. If |r| resolved with |response|, then: 1. If |response| is a {{Response}} object, then: 1. If |response| is [=Body/disturbed=] or [=Body/locked=], then: 1. Set the [=FetchEvent/respond-with error flag=]. 1. Else: 1. Let |bytes| be an empty byte sequence. 1. Let |end-of-body| be false. 1. Let |done| be false. 1. Let |potentialResponse| be a copy of |response|'s associated [=Response/response=], except for its [=response/body=]. 1. If |response|'s [=response/body=] is non-null, run these substeps: 1. Let |reader| be the result of getting a reader from |response|'s [=response/body=]'s stream. 1. Let |strategy| be an object created in |targetRealm|. The user agent may choose any object. 1. Let |pull| be an action that runs these subsubsteps: 1. Let |promise| be the result of reading a chunk from |response|'s [=response/body=]'s stream with |reader|. 1. When |promise| is fulfilled with an object whose done property is false and whose value property is a Uint8Array object, append the bytes represented by the value property to |bytes| and perform ! DetachArrayBuffer with the ArrayBuffer object wrapped by the value property. 1. When |promise| is fulfilled with an object whose done property is true, set |end-of-body| to true. 1. When |promise| is fulfilled with a value that matches with neither of the above patterns, or |promise| is rejected, [=ReadableStream/error=] |newStream| with a TypeError. 1. Let |cancel| be an action that [=ReadableStream/cancels=] |response|'s [=response/body=]'s stream with |reader|. 1. Let |newStream| be the result of [=ReadableStream/construct a ReadableStream object=] with |strategy|, |pull| and |cancel| in |targetRealm|. 1. Set |potentialResponse|'s [=response/body=] to a new [=/body=] whose stream is |newStream|. 1. Run these subsubsteps repeatedly in parallel while |done| is false: 1. If |newStream| is errored, then set |done| to true. 1. Otherwise, if |bytes| is empty and |end-of-body| is true, then [=ReadableStream/close=] |newStream| and set |done| to true. 1. Otherwise, if |bytes| is not empty, run these subsubsubsteps: 1. Let |chunk| be a subsequence of |bytes| starting from the beginning of |bytes|. 1. Remove |chunk| from |bytes|. 1. Let |buffer| be an ArrayBuffer object created in |targetRealm| and containing |chunk|. 1. [=ReadableStream/Enqueue=] a Uint8Array object created in |targetRealm| and wrapping |buffer| to |newStream|. Note: These substeps are meant to produce the observable equivalent of "piping" |response|'s [=response/body=]'s stream into |potentialResponse|. 1. Set the [=FetchEvent/potential response=] to |potentialResponse|. 1. Else: 1. Set the [=FetchEvent/respond-with error flag=]. Note: If the [=FetchEvent/respond-with error flag=] is set, a network error is returned to [=/Fetch=] through Handle Fetch algorithm. (See the step 21.1.) Otherwise, the value |response| is returned to [=/Fetch=] through Handle Fetch algorithm. (See the step 22.1.) 1. Unset the [=FetchEvent/wait to respond flag=].

{{ForeignFetchEvent}}

      [Constructor(DOMString type, ForeignFetchEventInit eventInitDict), Exposed=ServiceWorker]
      interface ForeignFetchEvent : ExtendableEvent {
        [SameObject] readonly attribute Request request;
        readonly attribute USVString origin;

        void respondWith(Promise<ForeignFetchResponse> r);
      };

      dictionary ForeignFetchEventInit : ExtendableEventInit {
        required Request request;
        USVString origin = "null";
      };

      dictionary ForeignFetchResponse {
        required Response response;
        USVString origin;
        sequence<ByteString> headers;
      };
    
[=/Service workers=] have a functional event {{foreignfetch!!event}}. For {{foreignfetch!!event}} events, [=/service workers=] use the {{ForeignFetchEvent}} interface which extends the {{ExtendableEvent}} interface. Each event using {{ForeignFetchEvent}} interface has an associated potential response (a [=/response=]), initially set to null, an associated origin (a {{USVString}} or null), initially set to null, an associated list of exposed headers (whose element type is a byte string), initially set to an empty list, and the following associated flags that are initially unset: * wait to respond flag * respond-with entered flag * respond-with error flag

{{ForeignFetchEvent/request|event.request}}

The request attribute *must* return the value it was initialized to.

{{ForeignFetchEvent/origin|event.origin}}

The origin attribute *must* return the value it was initialized to.

{{ForeignFetchEvent/respondWith(r)|event.respondWith(r)}}

Note: Developers can set the argument |r| with either a promise that resolves with a {{Response}} object or a {{Response}} object (which is automatically cast to a promise). Otherwise, a network error is returned to [=/Fetch=]. Renderer-side security checks about tainting for cross-origin content are tied to the types of filtered responses defined in [=/Fetch=]. respondWith(|r|) method *must* run these steps:
1. If the dispatch flag is unset, then: 1. Throw an "{{InvalidStateError}}" exception. 1. Abort these steps. 1. If the [=ForeignFetchEvent/respond-with entered flag=] is set, then: 1. Throw an "{{InvalidStateError}}" exception. 1. Abort these steps. 1. Add |r| to the extend lifetime promises. 1. Increment the [=ExtendableEvent/pending promises count=] by one. Note: The [=ExtendableEvent/pending promises count=] is incremented even if the given promise has already been settled. The corresponding count decrement is done in the microtask queued by the reaction to the promise. 1. Upon [=upon fulfillment|fulfillment=] or [=upon rejection|rejection=] of |r|, [=queue a microtask=] to run these substeps: 1. Decrement the [=ExtendableEvent/pending promises count=] by one. 1. Let |registration| be the [=context object=]'s [=relevant global object=]'s associated [=ServiceWorkerGlobalScope/service worker=]'s [=containing service worker registration=]. 1. If |registration|'s [=uninstalling flag=] is set, invoke [=Try Clear Registration=] with |registration|. 1. If |registration| is not null, invoke [=Try Activate=] with |registration|. Note: {{ForeignFetchEvent/respondWith(r)|event.respondWith(r)}} extends the lifetime of the event by default as if {{ExtendableEvent/waitUntil()|event.waitUntil(r)}} is called. 1. Set the stop propagation flag and stop immediate propagation flag. 1. Set the [=ForeignFetchEvent/respond-with entered flag=]. 1. Set the [=ForeignFetchEvent/wait to respond flag=]. 1. Let |targetRealm| be the relevant Realm of the context object. 1. Run the following substeps in parallel: 1. Wait until |r| settles. 1. If |r| rejected, then: 1. Set the [=ForeignFetchEvent/respond-with error flag=]. 1. If |r| resolved with |response|, then: 1. If |response| is a {{ForeignFetchResponse}}, then: 1. Set the [=ForeignFetchEvent/origin=] to |response|.{{ForeignFetchResponse/origin}}. 1. Set the list of exposed headers to |response|.{{ForeignFetchResponse/headers}}. 1. If |response|.{{ForeignFetchResponse/response}} is [=Body/disturbed=] or [=Body/locked=], then: 1. Set the [=ForeignFetchEvent/respond-with error flag=]. 1. Else: 1. Let |bytes| be an empty byte sequence. 1. Let |end-of-body| be false. 1. Let |done| be false. 1. Let |potentialResponse| be a copy of |response|.{{ForeignFetchResponse/response}}'s associated [=/response=], except for its [=response/body=]. 1. If |response|.{{ForeignFetchResponse/response}}'s body is non-null, run these substeps: 1. Let |reader| be the result of getting a reader from |response|.{{ForeignFetchResponse/response}}'s [=response/body=]'s stream. 1. Let |strategy| be an object created in |targetRealm|. The user agent may choose any object. 1. Let |pull| be an action that runs these subsubsteps: 1. Let |promise| be the result of reading a chunk from |response|.{{ForeignFetchResponse/response}}'s [=response/body=]'s stream with |reader|. 1. When |promise| is fulfilled with an object whose done property is false and whose value property is a Uint8Array object, append the bytes represented by the value property to |bytes| and perform ! DetachArrayBuffer with the ArrayBuffer object wrapped by the value property. 1. When |promise| is fulfilled with an object whose done property is true, set |end-of-body| to true. 1. When |promise| is fulfilled with a value that matches with neither of the above patterns, or |promise| is rejected, [=ReadableStream/error=] |newStream| with a TypeError. 1. Let |cancel| be an action that [=ReadableStream/cancels=] |response|.{{ForeignFetchResponse/response}}'s [=response/body=]'s stream with |reader|. 1. Let |newStream| be the result of [=ReadableStream/construct a ReadableStream object=] with |strategy|, |pull| and |cancel| in |targetRealm|. 1. Set |potentialResponse|'s [=response/body=] to a new [=/body=] whose stream is |newStream|. 1. Run these subsubsteps repeatedly in parallel while |done| is false: 1. If |newStream| is errored, then set |done| to true. 1. Otherwise, if |bytes| is empty and |end-of-body| is true, then [=ReadableStream/close=] |newStream| and set |done| to true. 1. Otherwise, if |bytes| is not empty, run these subsubsubsteps: 1. Let |chunk| be a subsequence of |bytes| starting from the beginning of |bytes|. 1. Remove |chunk| from |bytes|. 1. Let |buffer| be an ArrayBuffer object created in |targetRealm| and containing |chunk|. 1. [=ReadableStream/Enqueue=] a Uint8Array object created in |targetRealm| and wrapping |buffer| to |newStream|. 1. Set the [=ForeignFetchEvent/potential response=] to |potentialResponse|. 1. Else: 1. Set the [=ForeignFetchEvent/respond-with error flag=]. Note: If the [=ForeignFetchEvent/respond-with error flag=] is set, a network error is returned to [=/Fetch=] through [=Handle Foreign Fetch=] algorithm. (See the step 19.1.) Otherwise, a filtered version of |response| is returned to [=/Fetch=] through [=Handle Foreign Fetch=] algorithm. (See the step 20.1.) 1. Unset the [=ForeignFetchEvent/wait to respond flag=].

{{ExtendableMessageEvent}}

      [Constructor(DOMString type, optional ExtendableMessageEventInit eventInitDict), Exposed=ServiceWorker]
      interface ExtendableMessageEvent : ExtendableEvent {
        readonly attribute any data;
        readonly attribute USVString origin;
        readonly attribute DOMString lastEventId;
        [SameObject] readonly attribute (Client or ServiceWorker or MessagePort)? source;
        readonly attribute FrozenArray<MessagePort> ports;
      };
    
      dictionary ExtendableMessageEventInit : ExtendableEventInit {
        any data = null;
        USVString origin = "";
        DOMString lastEventId = "";
        (Client or ServiceWorker or MessagePort)? source = null;
        sequence<MessagePort> ports = [];
      };
    
[=/Service workers=] define the extendable {{message!!event}} event to allow extending the lifetime of the event. For the {{message!!event}} event, [=/service workers=] use the {{ExtendableMessageEvent}} interface which extends the {{ExtendableEvent}} interface.

{{ExtendableMessageEvent/data|event.data}}

The data attribute *must* return the value it was initialized to. When the object is created, this attribute *must* be initialized to null. It represents the message being sent.

{{ExtendableMessageEvent/origin|event.origin}}

The origin attribute *must* return the value it was initialized to. When the object is created, this attribute *must* be initialized to the empty string. It represents the [=environment settings object/origin=] of the [=/service worker client=] that sent the message.

{{ExtendableMessageEvent/lastEventId|event.lastEventId}}

The lastEventId attribute *must* return the value it was initialized to. When the object is created, this attribute *must* be initialized to the empty string.

{{ExtendableMessageEvent/source|event.source}}

The source attribute *must* return the value it was initialized to. When the object is created, this attribute *must* be initialized to null. It represents the {{Client}} object from which the message is sent.

{{ExtendableMessageEvent/ports|event.ports}}

The ports attribute *must* return the value it was initialized to. When the object is created, this attribute *must* be initialized to the empty array. It represents the {{MessagePort}} array being sent.

Events

The following events are dispatched on {{ServiceWorkerGlobalScope}} object:
Event name Interface Dispatched when…
install {{InstallEvent}} [Lifecycle event] The [=ServiceWorkerGlobalScope/service worker=]'s containing service worker registration's installing worker changes. (See step 11.2 of the Install algorithm.)
activate {{ExtendableEvent}} [Lifecycle event] The [=ServiceWorkerGlobalScope/service worker=]'s containing service worker registration's active worker changes. (See step 12.2 of the Activate algorithm.)
fetch {{FetchEvent}} [Functional event] The [=/http fetch=] invokes Handle Fetch with |request|. As a result of performing Handle Fetch, the [=ServiceWorkerGlobalScope/service worker=] returns a [=/response=] to the [=/http fetch=]. The [=/response=], represented by a {{Response}} object, can be retrieved from a {{Cache}} object or directly from network using {{WindowOrWorkerGlobalScope/fetch(input, init)|self.fetch(input, init)}} method. (A custom {{Response}} object can be another option.)
foreignfetch {{FetchEvent}} [Functional event] The [=/http fetch=] invokes [=Handle Foreign Fetch=] with |request|. As a result of performing [=Handle Foreign Fetch=], the [=ServiceWorkerGlobalScope/service worker=] returns a [=/response=] to the [=/http fetch=]. The [=/response=], represented by a {{Response}} object, can be retrieved from a {{Cache}} object or directly from network using {{WindowOrWorkerGlobalScope/fetch(input, init)|self.fetch(input, init)}} method. (A custom {{Response}} object can be another option.)
message {{ExtendableMessageEvent}} When it receives a message.
A [=/service worker registration=] and its [=service worker registration/scope url=] are created by a serviceworker link, which is declared using a "serviceworker" `Link` header or a <{link}> element whose <{link/rel}> attribute contains the keyword "<{link/rel/serviceworker}>".
A serviceworker link can be declared using a `Link` header [[!RFC5988]] with "`serviceworker`" as the value of the "`rel`" parameter and a [=service worker/script url=] as the target IRI, and the following optional target attributes: : `scope` :: Value: A [=service worker registration/scope url=]. : `workertype` :: Value: A [=job/worker type=]. : `updateviacache` :: Value: An [=service worker registration/update via cache mode=]. The "`anchor`" parameter must not be specified.
        Link: <sw.js>; rel="serviceworker"; scope="/"; workertype="module"; updateviacache="all"
      
When a user agent that supports [[!RFC5988]] processes a Link header that contains a serviceworker link, the user agent *should* run these steps: 1. If the Link header has an "anchor" parameter, abort these steps. 1. Let |contextURL| be the result of parsing the context IRI of the Link header. 1. If the result of running potentially trustworthy origin with the [=environment settings object/origin=] of |contextURL| is Not Trusted, abort these steps. 1. Let |request| be the [=/request=] for which this header was received in the response. 1. If |request|'s [=request/client=] is not a secure context, abort these steps. 1. Let |scriptURL| be the result of parsing the target IRI of the Link header. 1. Let |scopeURL| be null. 1. If the "scope" target attribute of the Link header is present, set |scopeURL| to the result of parsing the "scope" target attribute with |scriptURL|. 1. Let |workerType| be the "workertype" target attribute of the Link header, or "classic" if no such attribute is present. 1. If |workerType| is not a valid {{WorkerType}} value, abort these steps. 1. Let |useCache| be true if the Link header has a target attribute named "usecache", otherwise false. 1. Invoke [=Start Register=] with |scopeURL|, |scriptURL|, a new promise, null, |contextURL|, |workerType|, and |useCache|.
When a serviceworker link's <{link}> element is inserted into a document, or a serviceworker link is created on a <{link}> element that is already in a document tree, or the <{link/href}> or <{link/scope}> attributes of the <{link}> element of a serviceworker link is changed, the user agent *should* run these steps: 1. If the <{link/href}> attribute is the empty string, abort these steps. 1. Let |client| be the document's [=ServiceWorkerContainer/service worker client=]. 1. If |client| is not a secure context, queue a task to fire an event named error at the <{link}> element, and abort these steps. 1. Let |scriptURL| be the result of parsing the <{link/href}> attribute with the <{link}> element's node document's document base URL. 1. Let |scopeURL| be null. 1. If the <{link/scope}> attribute is present, set |scopeURL| to the result of parsing the <{link/scope}> attribute with the <{link}> element's node document's document base URL. 1. Let |workerType| be the state of the <{link/workertype}> attribute. 1. Let |useCache| be true if the <{link}> element has a <{link/usecache}> attribute, otherwise false. 1. Let |promise| be a new promise. 1. Invoke [=Start Register=] with |scopeURL|, |scriptURL|, |promise|, |client|, |client|'s creation URL, |workerType|, and |useCache|. 1. Run the following substeps in parallel: 1. Wait until |promise| settles. 1. If |promise| rejected, queue a task to fire an event named error at the <{link}> element. 1. If |promise| resolved, queue a task to fire an event named load at the <{link}> element. The serviceworker link element *must not* [=document/delay the load event=] of the element's node document.
A resource being loaded with the following response header:
        Link: </js/sw.js>; rel="serviceworker"; scope="/"
      
has more or less the same effect as a document being loaded in a secure context with the following link element:
        <link rel="serviceworker" href="/js/sw.js" scope="/">
      
which is more or less equivalent to the page containing javascript code like:
        navigator.serviceworker.register("/js/sw.js", { scope: "/" });
      

Caches

To allow authors to fully manage their content caches for offline use, the {{Window}} and the {{WorkerGlobalScope}} provide the asynchronous caching methods that open and manipulate {{Cache}} objects. An [=environment settings object/origin=] can have multiple, named {{Cache}} objects, whose contents are entirely under the control of scripts. Caches are not shared across [=/origins=], and they are completely isolated from the browser's HTTP cache.

Constructs

A fetching record is a Record {\[[key]], \[[value]]} where \[[key]] is a {{Request}} and \[[value]] is a {{Response}}. A fetching record has an associated incumbent record (a fetching record). It is initially set to null. A request to response map is a List of fetching records. A name to cache map is an ordered map where the keys are strings that represents a name of the {{Cache}} object, and the values are {{Cache}} objects. Each [=/origin=] has an associated name to cache map.

Understanding Cache Lifetimes

The {{Cache}} instances are not part of the browser's HTTP cache. The {{Cache}} objects are exactly what authors have to manage themselves. The {{Cache}} objects do not get updated unless authors explicitly request them to be. The {{Cache}} objects do not expire unless authors delete the entries. The {{Cache}} objects do not disappear just because the [=/service worker=] script is updated. That is, caches are not updated automatically. Updates must be manually managed. This implies that authors should version their caches by name and make sure to use the caches only from the version of the [=/service worker=] that can safely operate on.

{{WindowOrWorkerGlobalScope/caches|self.caches}}

      partial interface WindowOrWorkerGlobalScope {
        [SecureContext, SameObject] readonly attribute CacheStorage caches;
      };
    

{{WindowOrWorkerGlobalScope/caches}}

caches attribute *must* return this object's associated {{CacheStorage}} object.

{{Cache}}

      [SecureContext, Exposed=(Window,Worker)]
      interface Cache {
        [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options);
        [NewObject] Promise<sequence<Response>> matchAll(optional RequestInfo request, optional CacheQueryOptions options);
        [NewObject] Promise<void> add(RequestInfo request);
        [NewObject] Promise<void> addAll(sequence<RequestInfo> requests);
        [NewObject] Promise<void> put(RequestInfo request, Response response);
        [NewObject] Promise<boolean> delete(RequestInfo request, optional CacheQueryOptions options);
        [NewObject] Promise<sequence<Request>> keys(optional RequestInfo request, optional CacheQueryOptions options);
      };
    
      dictionary CacheQueryOptions {
        boolean ignoreSearch = false;
        boolean ignoreMethod = false;
        boolean ignoreVary = false;
        DOMString cacheName;
      };
    
      dictionary CacheBatchOperation {
        DOMString type;
        Request request;
        Response response;
        CacheQueryOptions options;
      };
    
A {{Cache}} object represents a request to response map. Multiple separate objects implementing the {{Cache}} interface across documents and workers can all be associated with the same request to response map simultaneously. {{Cache}} objects are always enumerable via {{WindowOrWorkerGlobalScope/caches|self.caches}} in insertion order (per ECMAScript 6 Map objects).

{{Cache/match(request, options)}}

match(|request|, |options|) method *must* run these steps: 1. Let |promise| be a new promise. 1. Run these substeps in parallel: 1. Let |p| be the result of running the algorithm specified in {{Cache/matchAll(request, options)}} method with |request| and |options| as the arguments. 1. Wait until |p| settles. 1. If |p| rejects with an exception, then: 1. Reject |promise| with that exception. 1. Else if |p| resolves with an array, |responseArray|, then: 1. If |responseArray| is an empty array, then: 1. Resolve |promise| with undefined. 1. Else: 1. Resolve |promise| with the first element of |responseArray|. 1. Return |promise|.

{{Cache/matchAll(request, options)}}

matchAll(|request|, |options|) method *must* run these steps: 1. Let |r| be null. 1. If the optional argument |request| is not omitted, then: 1. If |request| is a {{Request}} object, then: 1. Set |r| to |request|'s [=Request/request=]. 1. If |r|'s [=request/method=] is not \`GET\` and |options|.ignoreMethod is false, return a promise resolved with an empty array. 1. Else if |request| is a string, then: 1. Set |r| to the associated [=Request/request=] of the result of invoking the initial value of {{Request}} as constructor with |request| as its argument. If this throws an exception, return a promise rejected with that exception. 1. Let |promise| be a new promise. 1. Run these substeps in parallel: 1. Let |responseArray| be an empty array. 1. If the optional argument |request| is omitted, then: 1. For each fetching record |entry| of its request to response map, in key insertion order: 1. Add a copy of |entry|.\[[value]] to |responseArray|. 1. Resolve |promise| with |responseArray|. 1. Abort these steps. 1. Else: 1. Let |entries| be the result of running Query Cache algorithm passing a {{Request}} object associated with |r| and |options| as the arguments. 1. For each |entry| of |entries|: 1. Let |response| be null. 1. If the incumbent record |incumbentRecord| of the corresponding fetching record in request to response map is not null, set |response| to a copy of |incumbentRecord|.\[[value]]. 1. Else, set |response| to a copy of |entry|[1]. 1. Add |response| to |responseArray|. 1. Resolve |promise| with |responseArray|. 1. Return |promise|.

{{Cache/add(request)}}

add(|request|) method *must* run these steps: 1. Let |requests| be an array containing only |request|. 1. Set |responseArrayPromise| to the result of running the algorithm specified in {{Cache/addAll(requests)}} passing |requests| as the argument. 1. Return the result of transforming |responseArrayPromise| with a fulfillment handler that returns undefined.

{{Cache/addAll(requests)}}

addAll(|requests|) method *must* run these steps: 1. Let |responsePromiseArray| be an empty array. 1. Let |requestArray| be an empty array. 1. For each |request| whose type is {{Request}} in |requests|: 1. Let |r| be |request|'s [=Request/request=]. 1. If |r|'s [=request/url=]'s [=url/scheme=] is not one of "http" and "https", or |r|'s [=request/method=] is not \`GET\`, return a promise rejected with a TypeError. 1. For each |request| in |requests|: 1. Let |r| be the associated [=Request/request=] of the result of invoking the initial value of {{Request}} as constructor with |request| as its argument. If this throws an exception, return a promise rejected with that exception. 1. If |r|'s [=request/url=]'s [=url/scheme=] is not one of "http" and "https", then: 1. [=fetch/Terminate=] all the ongoing fetches initiated by |requests| with reason *fatal*. 1. Break the loop. 1. If |r|'s [=request/client=]'s [=environment settings object/global object=] is a {{ServiceWorkerGlobalScope}} object, set |request|'s [=service-workers mode=] to "`foreign`". 1. Set |r|'s [=request/initiator=] to "fetch" and [=request/destination=] to "subresource". 1. Add a {{Request}} object associated with |r| to |requestArray|. 1. Let |responsePromise| be a new promise. 1. Run the following substeps in parallel: * [=/Fetch=] |r|. * To process response for |response|, run these substeps: 1. If |response|'s [=response/type=] is "error", or |response|'s [=response/status=] is not an ok status, reject |responsePromise| with a TypeError. 1. Else if |response|'s [=response/header list=] contains a header [=header/named=] \`Vary\`, then: 1. Let |varyHeaders| be the array containing the elements corresponding to the [=http/field-values=] of the Vary header. 1. Let |matchAsterisk| be false. 1. For each |f| in |varyHeaders|: 1. If |f| matches "*", set |matchAsterisk| to true and break the loop. 1. If |matchAsterisk| is true, reject |responsePromise| with a TypeError. 1. Else, resolve |responsePromise| with a new {{Response}} object associated with |response| and a new {{Headers}} object whose guard is "immutable". 1. Else, resolve |responsePromise| with a new {{Response}} object associated with |response| and a new {{Headers}} object whose guard is "immutable". Note: This step ensures that the promise for this fetch resolves as soon as the response's headers become available. * To process response end-of-body for |response|, do nothing. * To process response done for |response|, do nothing. 1. Add |responsePromise| to |responsePromiseArray|. 1. Let |p| be waiting for all of |responsePromiseArray|. 1. Return the result of transforming |p| with a fulfillment handler that, when called with argument |responseArray|, performs the following substeps in parallel: 1. Let |operations| be an empty array. 1. For each |response| in |responseArray| with the index |index|: 1. Let |o| be an empty object representing a {{CacheBatchOperation}} dictionary. 1. Set the {{CacheBatchOperation/type}} dictionary member of |o| to "put". 1. Set the {{CacheBatchOperation/request}} dictionary member of |o| to |requestArray|[|index|]. 1. Set the {{CacheBatchOperation/response}} dictionary member of |o| to |response|. 1. Add |o| to |operations|. 1. Let |resultPromise| be the result of running Batch Cache Operations algorithm passing |operations| as the argument. 1. Return the result of transforming |resultPromise| with a fulfillment handler that, when called with argument |responses|, performs the following substeps in parallel: 1. Let |responseBodyPromiseArray| be an empty array. 1. For each |response| in |responses|: 1. Let |responseBodyPromise| be a new promise. 1. Run the following substeps in parallel: 1. Wait for either end-of-file to have been pushed to |response|'s associated [=Response/response=] |r|'s [=response/body=] or for |r| to have a [=response/termination reason=]. 1. If |r| had a [=response/termination reason=], then: 1. If the incumbent record |incumbentRecord| of the corresponding fetching record |fetchingRecord| in request to response map is not null, then: 1. Set |fetchingRecord| in request to response map to the copy of |incumbentRecord|. 1. Else: 1. Delete |fetchingRecord| from request to response map. 1. Reject |responseBodyPromise| with a TypeError. 1. Else: 1. Set the incumbent record of the corresponding fetching record |fetchingRecord| in request to response map to the copy of |fetchingRecord|. 1. Let |invalidRecords| be the result of running Query Cache algorithm passing |fetchingRecord|.\[[key]] as the argument. 1. For each |invalidRecord| in |invalidRecords|: 1. If |invalidRecord| is not |fetchingRecord|, delete it from request to response map. 1. Resolve |responseBodyPromise| with |response|. 1. Add |responseBodyPromise| to |responseBodyPromiseArray|. 1. Let |q| be waiting for all of |responseBodyPromiseArray|. 1. Return the result of transforming |q| with a fulfillment handler that returns undefined.

{{Cache/put(request, response)}}

put(|request|, |response|) method *must* run these steps: 1. Let |r| be null. 1. If |request| is a {{Request}} object, then: 1. Set |r| to |request|'s [=Request/request=]. 1. If |r|'s [=request/url=]'s [=url/scheme=] is not one of "http" and "https", or |r|'s [=request/method=] is not \`GET\`, return a promise rejected with a TypeError. 1. Else if |request| is a string, then: 1. Set |r| to the associated [=Request/request=] of the result of invoking the initial value of {{Request}} as constructor with |request| as its argument. If this throws an exception, return a promise rejected with that exception. 1. If |r|'s [=request/url=]'s [=url/scheme=] is not one of "http" and "https", return a promise rejected with a TypeError. 1. If |response|'s associated [=Response/response=]'s [=response/header list=] contains a header [=header/named=] \`Vary\`, then: 1. Let |varyHeaders| be the array containing the elements corresponding to the [=http/field-values=] of the Vary header. 1. For each |f| in |varyHeaders|: 1. If |f| matches "*", return a promise rejected with a TypeError. 1. If |response| is [=Body/disturbed=] or [=Body/locked=], return a promise rejected with a TypeError. 1. Let |newResponse| be a new {{Response}} object associated with |response|'s associated [=/response=] and a new {{Headers}} object whose guard is |response|'s {{Headers}}' guard. 1. If |response|'s body is non-null, run these substeps: 1. Let |dummyStream| be an empty {{ReadableStream}} object. 1. Set |response|'s [=response/body=] to a new [=/body=] whose stream is |dummyStream|. 1. Let |reader| be the result of getting a reader from |dummyStream|. 1. Read all bytes from |dummyStream| with |reader|. 1. Let |operations| be an empty array. 1. Let |o| be an empty object representing a {{CacheBatchOperation}} dictionary. 1. Set the {{CacheBatchOperation/type}} dictionary member of |o| to "put". 1. Set the {{CacheBatchOperation/request}} dictionary member of |o| to a {{Request}} object associated with |r|. 1. Set the {{CacheBatchOperation/response}} dictionary member of |o| to |newResponse|. 1. Add |o| to |operations|. 1. Let |resultPromise| be the result of running Batch Cache Operations passing |operations| as the argument. 1. Return the result of transforming |resultPromise| with a fulfillment handler that, when called with argument |responses|, performs the following substeps in parallel: 1. Wait for either end-of-file to have been pushed to |responses|[0]'s associated [=Response/response=] |r|'s [=response/body=] or for |r| to have a [=response/termination reason=]. 1. If |r| had a [=response/termination reason=], then: 1. If the incumbent record |incumbentRecord| of the corresponding fetching record |fetchingRecord| in request to response map is not null, then: 1. Set |fetchingRecord| in request to response map to the copy of |incumbentRecord|. 1. Else: 1. Delete |fetchingRecord| from request to response map. 1. Throw a TypeError. 1. Else: 1. Set the incumbent record of the corresponding fetching record |fetchingRecord| in request to response map to the copy of |fetchingRecord|. 1. Let |invalidRecords| be the result of running Query Cache algorithm passing |fetchingRecord|.\[[key]] as the argument. 1. For each |invalidRecord| in |invalidRecords|: 1. If |invalidRecord| is not |fetchingRecord|, delete it from request to response map. 1. Return undefined.

{{Cache/delete(request, options)}}

delete(|request|, |options|) method *must* run these steps: 1. Let |r| be null. 1. If |request| is a {{Request}} object, then: 1. Set |r| to |request|'s [=Request/request=]. 1. If |r|'s [=request/method=] is not \`GET\` and |options|.ignoreMethod is false, return a promise resolved with false. 1. Else if |request| is a string, then: 1. Set |r| to the associated [=Request/request=] of the result of invoking the initial value of {{Request}} as constructor with |request| as its argument. If this throws an exception, return a promise rejected with that exception. 1. Let |operations| be an empty array. 1. Let |o| be an empty object representing a {{CacheBatchOperation}} dictionary. 1. Set the {{CacheBatchOperation/type}} dictionary member of |o| to "delete". 1. Set the {{CacheBatchOperation/request}} dictionary member of |o| to a {{Request}} object associated with |r|. 1. Set the {{CacheBatchOperation/options}} dictionary member of |o| to |options|. 1. Add |o| to |operations|. 1. Let |resultPromise| be the result of running Batch Cache Operations passing |operations| as the argument. 1. Return the result of transforming |resultPromise| with a fulfillment handler, when called with argument |responseArray|, performs the following substeps in parallel: 1. If |responseArray| is not null, return true. 1. Else, return false.

{{Cache/keys(request, options)}}

keys(|request|, |options|) method *must* run these steps: 1. Let |promise| be a new promise. 1. Run these substeps in parallel: 1. Let |resultArray| be an empty array. 1. If the optional argument |request| is omitted, then: 1. For each fetching record |entry| of its request to response map, in key insertion order: 1. Add |entry|.\[[key]] to |resultArray|. 1. Else: 1. Let |r| be null. 1. If |request| is a {{Request}} object, then: 1. Set |r| to |request|'s [=Request/request=]. 1. If |r|'s [=request/method=] is not \`GET\` and |options|.ignoreMethod is false, resolve |promise| with an empty array. 1. Else if |request| is a string, then: 1. Set |r| to the associated [=Request/request=] of the result of invoking the initial value of {{Request}} as constructor with |request| as its argument. If this throws an exception, return a promise rejected with that exception. 1. Let |requestResponseArray| be the result of running Query Cache algorithm passing a {{Request}} object that represents |r| and |options| as the arguments. 1. For each |requestResponse| in |requestResponseArray|: 1. Add |requestResponse|[0] to |resultArray|. 1. Resolve |promise| with |resultArray|. 1. Return |promise|.

{{CacheStorage}}

      [SecureContext, Exposed=(Window,Worker)]
      interface CacheStorage {
        [NewObject] Promise<any> match(RequestInfo request, optional CacheQueryOptions options);
        [NewObject] Promise<boolean> has(DOMString cacheName);
        [NewObject] Promise<Cache> open(DOMString cacheName);
        [NewObject] Promise<boolean> delete(DOMString cacheName);
        [NewObject] Promise<sequence<DOMString>> keys();
      };
    
Note: {{CacheStorage}} interface is designed to largely conform to ECMAScript 6 Map objects but entirely async, and with additional convenience methods. The methods, clear, forEach, entries and values, are intentionally excluded from the scope of the first version resorting to the ongoing discussion about the async iteration by TC39. The user agent *must* create a {{CacheStorage}} object when a {{Window}} object or a {{WorkerGlobalScope}} object is created and associate it with that global object. A {{CacheStorage}} object represents a name to cache map of its associated [=CacheStorage/global object=]'s environment settings object's [=environment settings object/origin=]. Multiple separate objects implementing the {{CacheStorage}} interface across documents and workers can all be associated with the same name to cache map simultaneously.

{{CacheStorage/match(request, options)}}

match(|request|, |options|) method *must* run these steps: 1. If |options|.{{CacheQueryOptions/cacheName}} is present, then: 1. Return a new promise |p| and run the following substeps in parallel: 1. [=map/For each=] |cacheName| → |cache| of name to cache map: 1. If |options|.{{CacheQueryOptions/cacheName}} matches |cacheName|, then: 1. Resolve |p| with the result of running the algorithm specified in {{Cache/match(request, options)}} method of {{Cache}} interface with |request| and |options| as the arguments (providing |cache| as thisArgument to the \[[Call]] internal method of {{Cache/match(request, options)}}.) 1. Abort these steps. 1. Resolve |p| with undefined. 1. Else: 1. Let |p| be a promise resolved with undefined. 1. [=map/For each=] cacheName → |cache| of name to cache map: 1. Set |p| to the result of transforming itself with a fulfillment handler that, when called with argument |v|, performs the following substeps in parallel: 1. If |v| is not undefined, return |v|. 1. Return the result of running the algorithm specified in {{Cache/match(request, options)}} method of {{Cache}} interface with |request| and |options| as the arguments (providing |cache|] as thisArgument to the \[[Call]] internal method of {{Cache/match(request, options)}}.) 1. Return |p|.

{{CacheStorage/has(cacheName)}}

has(|cacheName|) method *must* run these steps: 1. Return a promise resolved with the result of running the following substeps: 1. [=map/For each=] |key| → value of name to cache map: 1. If |cacheName| matches |key|, then: 1. Return true. 1. Return false.

{{CacheStorage/open(cacheName)}}

open(|cacheName|) method *must* run these steps: 1. Let |p| be a new promise. 1. Run the following substeps: 1. [=map/For each=] |key| → |value| of name to cache map: 1. If |cacheName| matches |key|, then: 1. Resolve |p| with a new {{Cache}} object which is a copy of |value|. 1. Abort these steps. 1. Let |cache| be a new {{Cache}} object. 1. [=map/Set=] name to cache map[|cacheName|] to |cache|. If this cache write operation failed due to exceeding the granted quota limit, reject |p| with a "{{QuotaExceededError}}" exception and abort these steps. 1. Resolve |p| with |cache|. 1. Return |p|.

{{CacheStorage/delete(cacheName)}}

delete(|cacheName|) method *must* run these steps: 1. Let |p| be the result of running the algorithm specified in {{CacheStorage/has(cacheName)}} method with |cacheName| as the argument. 1. Return the result of transforming |p| with a fulfillment handler that, when called with argument |cacheExists|, performs the following substeps in parallel: 1. If |cacheExists| is true, then: 1. Delete a Record {\[[key]], \[[value]]} entry from its name to cache map where |cacheName| matches entry.\[[key]]. 1. Return true. 1. Abort these steps. Note: After this step, the existing DOM objects (i.e. the currently referenced Cache, Request, and Response objects) should remain functional. 1. Else: 1. Return false.

{{CacheStorage/keys()}}

keys() method *must* run these steps: Note: The promise returned from this method resolves with the sequence of keys, cache names in DOMString, in insertion order. 1. Let |cacheKeys| be the result of [=map/get the keys|getting the keys=] of name to cache map. 1. Return |cacheKeys|.

Security Considerations

Secure Context

[=/Service workers=] *must* execute in secure contexts. [=/Service worker clients=] *must* also be secure contexts to register a [=/service worker registration=], to get access to the [=/service worker registrations=] and the [=/service workers=], to do messaging with the [=/service workers=], and to be manipulated by the [=/service workers=]. This effectively means that [=/service workers=] and their [=/service worker clients=] *should* be hosted over HTTPS. A user agent *may* allow localhost, 127.0.0.0/8, and ::1/128 for development purpose. (Note that they may still be secure contexts.) The primary reason for this restriction is to protect users from the risks associated with insecure contexts.

Content Security Policy

Whenever a user agent invokes Run Service Worker algorithm with a [=/service worker=] |serviceWorker|: * If |serviceWorker|'s script resource was delivered with a Content-Security-Policy HTTP header containing the value |policy|, the user agent *must* enforce |policy| for |serviceWorker|. * If |serviceWorker|'s script resource was delivered with a Content-Security-Policy-Report-Only HTTP header containing the value |policy|, the user agent *must* monitor |policy| for |serviceWorker|. The primary reason for this restriction is to mitigate a broad class of content injection vulnerabilities, such as cross-site scripting (XSS).

Origin Relativity

Origin restriction

*This section is non-normative.* A [=/service worker=] executes in the registering [=/service worker client=]'s [=environment settings object/origin=]. One of the advanced concerns that major applications would encounter is whether they can be hosted from a CDN. By definition, these are servers in other places, often on other [=/origins=]. Therefore, [=/service workers=] cannot be hosted on CDNs. But they can include resources via importScripts(). The reason for this restriction is that [=/service workers=] create the opportunity for a bad actor to turn a bad day into a bad eternity.

{{WorkerGlobalScope/importScripts(urls)}}

When the importScripts(|urls|) method is called on a {{ServiceWorkerGlobalScope}} object, the user agent *must* import scripts into worker global scope, given this {{ServiceWorkerGlobalScope}} object and |urls|, and with the following steps to [=fetching scripts/perform the fetch=] given the [=/request=] |request|: 1. Let |serviceWorker| be |request|'s [=request/client=]'s [=environment settings object/global object=]'s [=ServiceWorkerGlobalScope/service worker=]. 1. If |serviceWorker|'s imported scripts updated flag is unset, then: 1. Let |registration| be |serviceWorker|'s [=containing service worker registration=]. 1. Set |request|'s [=service-workers mode=] to "`foreign`". 1. Set |request|'s [=request/cache mode=] to "no-cache" if any of the following are true: * |registration|'s [=service worker registration/use cache=] is false. * The [=current global object=]'s [=force bypass cache for importscripts flag=] is set. * |registration|'s [=last update check time=] is not null and the time difference in seconds calculated by the current time minus |registration|’s [=last update check time=] is greater than 86400. 1. Let |response| be the result of fetching |request|. 1. If |response|’s cache state is not "local", set |registration|’s [=service worker registration/last update check time=] to the current time. 1. [=Extract a MIME type=] from the |response|'s [=unsafe response=]'s [=response/header list=]. If this MIME type (ignoring parameters) is not a [=JavaScript MIME type=], return a [=network error=]. 1. If |response|'s unsafe response's [=response/type=] is not "error", and |response|'s [=response/status=] is an ok status, then: 1. [=map/Set=] script resource map[|request|'s [=request/url=]] to |response|. 1. Return |response|. 1. Else: 1. If script resource map[|url|] [=map/exists=], return script resource map[|url|]. 1. Else, return a network error.

Cross-Origin Resources and CORS

*This section is non-normative.* Applications tend to cache items that come from a CDN or other [=environment settings object/origin=]. It is possible to request many of them directly using <script>, <img>, <video> and <link> elements. It would be hugely limiting if this sort of runtime collaboration broke when offline. Similarly, it is possible to [=/fetch=] many sorts of off-[=environment settings object/origin=] resources when appropriate CORS headers are set. [=/Service workers=] enable this by allowing {{Cache|Caches}} to [=/fetch=] and cache off-origin items. Some restrictions apply, however. First, unlike same-origin resources which are managed in the {{Cache}} as {{Response}} objects whose corresponding [=Response/responses=] are basic filtered response, the objects stored are {{Response}} objects whose corresponding [=Response/responses=] are either CORS filtered responses or opaque filtered responses. They can be passed to {{FetchEvent/respondWith(r)|event.respondWith(r)}} method in the same manner as the {{Response}} objects whose corresponding [=Response/responses=] are basic filtered responses, but cannot be meaningfully created programmatically. These limitations are necessary to preserve the security invariants of the platform. Allowing {{Cache|Caches}} to store them allows applications to avoid re-architecting in most cases.

Implementer Concerns

*This section is non-normative.* The implementers are encouraged to note: * Plug-ins should not load via [=/service workers=]. As plug-ins may get their security origins from their own urls, the embedding [=/service worker=] cannot handle it. For this reason, the Handle Fetch algorithm makes the potential-navigation-or-subresource request (whose context is either <embed> or <object>) immediately fallback to the network without dispatching {{fetch!!event}} event. * Some of the legacy networking stack code may need to be carefully audited to understand the ramifications of interactions with [=/service workers=].

Privacy

[=/Service workers=] introduce new persistent storage features including scope to registration map (for [=/service worker registrations=] and their [=/service workers=]), request to response map and name to cache map (for caches), and script resource map (for script resources). In order to protect users from any potential unsanctioned tracking threat, these persistent storages *should* be cleared when users intend to clear them and *should* maintain and interoperate with existing user controls e.g. purging all existing persistent storages.

Extensibility

[=/Service workers=] are extensible from other specifications.

Define API bound to Service Worker Registration

Specifications *may* define an API tied to a [=/service worker registration=] by using partial interface definition to the {{ServiceWorkerRegistration}} interface where it *may* define the specification specific attributes and methods:
      partial interface ServiceWorkerRegistration {
        // e.g. define an API namespace
        readonly attribute APISpaceType APISpace;
        // e.g. define a method
        Promise<T> methodName(/* list of arguments */);
      };
    

Define Functional Event

Specifications *may* define a functional event by extending {{ExtendableEvent}} interface:
      // e.g. define FunctionalEvent interface
      interface FunctionalEvent : ExtendableEvent {
        // add a functional event's own attributes and methods
      };
    

Define Event Handler

Specifications *may* define an event handler attribute for the corresponding functional event using partial interface definition to the {{ServiceWorkerGlobalScope}} interface:
      partial interface ServiceWorkerGlobalScope {
        attribute EventHandler onfunctionalevent;
      };
    

Request Functional Event Dispatch

To request a functional event dispatch to a [=/service worker=], specifications *may* invoke Handle Functional Event algorithm with its [=/service worker registration=] registration and the algorithm |callbackSteps| as the arguments. Specifications *may* define an algorithm |callbackSteps| where the corresponding functional event can be created and fired with specification specific objects. The algorithm is passed globalObject (a {{ServiceWorkerGlobalScope}} object) at which it *may* fire its functional events. This algorithm is called on a task queued by Handle Functional Event algorithm. Note: See an example hook defined in Notifications API.

Appendix A: Algorithms

The following definitions are the user agent's internal data structures used throughout the specification. A scope to registration map is an ordered map where the keys are [=service worker registration/scope urls=] and the values are [=/service worker registrations=]. A job is an abstraction of one of register, update, and unregister request for a [=/service worker registration=].
A job has a job type, which is one of *register*, *update*, and *unregister*. A job has a scope url (a [=/URL=]). A job has a script url (a [=/URL=]). A job has a worker type ("classic" or "module"). A job has a use cache (a boolean). A job has a client (a [=/service worker client=]). It is initially null. A job has a referrer (a [=/URL=] or null). A job has a job promise (a promise). It is initially null. A job has a list of equivalent jobs (a list of jobs). It is initially the empty list. A job has a force bypass cache flag. It is initially unset.
Two jobs are equivalent when their job type is the same and: * For *register* and *update* jobs, both their [=job/scope url=] and the [=job/script url=] are the same. * For *unregister* jobs, their [=job/scope url=] is the same. A job queue is a thread safe queue used to synchronize the set of concurrent jobs. The job queue contains jobs as its elements. The job queue *should* satisfy the general properties of FIFO queue. A user agent *must* maintain a separate job queue for each [=/service worker registration=] keyed by its [=service worker registration/scope url=]. A job queue is initially empty. Unless stated otherwise, the job queue referenced from the algorithm steps is a job queue for the job's [=job/scope url=].

Create Job

: Input :: |jobType|, a job type :: |scopeURL|, a [=/URL=] :: |scriptURL|, a [=/URL=] :: |promise|, a promise :: |client|, a [=/service worker client=] : Output :: |job|, a job 1. Let |job| be a new job. 1. Set |job|'s [=job/job type=] to |jobType|. 1. Set |job|'s [=job/scope url=] to |scopeURL|. 1. Set |job|'s [=job/script url=] to |scriptURL|. 1. Set |job|'s [=job/job promise=] to |promise|. 1. Set |job|'s [=job/client=] to |client|. 1. If |client| is not null, set |job|'s [=job/referrer=] to |client|'s creation URL. 1. Return |job|.

Schedule Job

: Input :: |job|, a job : Output :: none 1. If the job queue is empty, then: 1. Push |job| to the job queue and invoke Run Job. 1. Else: 1. Let |lastJob| be the element at the back of the job queue. 1. If |job| is equivalent to |lastJob| and |lastJob|'s [=job/job promise=] has not settled, append |job| to |lastJob|'s list of equivalent jobs. 1. Else, push |job| to the job queue.

Run Job

: Input :: none : Output :: none 1. Assert: the job queue is not empty. 1. Queue a task to run these steps: 1. Let |job| be the element in the front of the job queue. 1. If |job|'s job type is *register*, run Register with |job| in parallel. 1. Else if |job|'s job type is *update*, run Update with |job| in parallel. Note: For a register job and an update job, the user agent delays queuing a task for running the job until after the document initiated the job has been dispatched {{Document/DOMContentLoaded}} event. 1. Else if |job|'s job type is *unregister*, run Unregister with |job| in parallel.

Finish Job

: Input :: |job|, a job : Output :: none 1. Assert: the top element in the job queue is |job|. 1. Pop the top element from the job queue. 1. If the job queue is not empty, invoke Run Job with the top element of the job queue.

Resolve Job Promise

: Input :: |job|, a job :: |value|, any : Output :: none 1. If |job|'s [=job/client=] is not null, queue a task to resolve |job|'s [=job/job promise=] with |value| on |job|'s [=job/client=]'s responsible event loop using the DOM manipulation task source as the task source. 1. For each |equivalentJob| in |job|'s list of equivalent jobs: 1. If |equivalentJob|'s [=job/client=] is not null, queue a task to resolve |equivalentJob|'s [=job/job promise=] with |value| on |equivalentJob|'s [=job/client=]'s responsible event loop using the DOM manipulation task source as the task source.

Reject Job Promise

: Input :: |job|, a job :: |reason|, an exception : Output :: none 1. If |job|'s [=job/client=] is not null, queue a task to reject |job|'s [=job/job promise=] with |reason| on |job|'s [=job/client=]'s responsible event loop using the DOM manipulation task source as the task source. 1. For each |equivalentJob| in |job|'s list of equivalent jobs: 1. If |equivalentJob|'s [=job/client=] is not null, queue a task to reject |equivalentJob|'s [=job/job promise=] with |reason| on |equivalentJob|'s [=job/client=]'s responsible event loop using the DOM manipulation task source as the task source.

Start Register

: Input :: |scopeURL|, a [=/URL=] or failure or null :: |scriptURL|, a [=/URL=] or failure :: |promise|, a promise :: |client|, a [=/service worker client=] :: |referrer|, a [=/URL=] :: |workerType|, a worker type :: |useCache|, a boolean : Output :: none 1. If |scriptURL| is failure, reject |promise| with a TypeError and abort these steps. 1. If |scriptURL|'s [=url/scheme=] is not one of "http" and "https", reject |promise| with a TypeError and abort these steps. 1. If any of the strings in |scriptURL|'s [=url/path=] contains either ASCII case-insensitive "%2f" or ASCII case-insensitive "%5c", reject |promise| with a TypeError and abort these steps. 1. If |scopeURL| is null, set |scopeURL| to the result of parsing the string "./" with |scriptURL|. Note: The scope url for the registration is set to the location of the service worker script by default. 1. If |scopeURL| is failure, reject |promise| with a TypeError and abort these steps. 1. If |scopeURL|'s [=url/scheme=] is not one of "http" and "https", reject |promise| with a TypeError and abort these steps. 1. If any of the strings in |scopeURL|'s [=url/path=] contains either ASCII case-insensitive "%2f" or ASCII case-insensitive "%5c", reject |promise| with a TypeError and abort these steps. 1. Let |job| be the result of running [=Create Job=] with *register*, |scopeURL|, |scriptURL|, |promise|, and |client|. 1. Set |job|'s [=job/worker type=] to |workerType|. 1. Set |job|'s [=job/use cache=] to |useCache|. 1. Set |job|'s [=job/referrer=] to |referrer|. 1. Invoke [=Schedule Job=] with |job|.

Register

: Input :: |job|, a job : Output :: none 1. If the result of running potentially trustworthy origin with the [=environment settings object/origin=] of |job|'s [=job/script url=] as the argument is Not Trusted, then: 1. Invoke Reject Job Promise with |job| and a "{{SecurityError}}" exception. 1. Invoke Finish Job with |job| and abort these steps. 1. If the [=environment settings object/origin=] of |job|'s [=job/script url=] is not |job|'s [=job/referrer=]'s [=environment settings object/origin=], then: 1. Invoke Reject Job Promise with |job| and a "{{SecurityError}}" exception. 1. Invoke Finish Job with |job| and abort these steps. 1. If the [=environment settings object/origin=] of |job|'s [=job/scope url=] is not |job|'s [=job/referrer=]'s [=environment settings object/origin=], then: 1. Invoke Reject Job Promise with |job| and a "{{SecurityError}}" exception. 1. Invoke Finish Job with |job| and abort these steps. 1. Let |registration| be the result of running the Get Registration algorithm passing |job|'s [=job/scope url=] as the argument. 1. If |registration| is not null, then: 1. If |registration|'s uninstalling flag is set, unset it. 1. Let |newestWorker| be the result of running the Get Newest Worker algorithm passing |registration| as the argument. 1. If |newestWorker| is not null, |job|'s [=job/script url=] [=url/equals=] |newestWorker|'s [=service worker/script url=] with the *exclude fragments flag* set, and |job|'s [=job/use cache=]'s value equals |registration|'s [=service worker registration/use cache=]'s value, then: 1. Invoke Resolve Job Promise with |job| and the {{ServiceWorkerRegistration}} object which represents |registration|. 1. Invoke Finish Job with |job| and abort these steps. 1. Else: 1. Invoke Set Registration algorithm with |job|'s [=job/scope url=] and |job|'s [=job/use cache=]. 1. Invoke Update algorithm passing |job| as the argument.

Update

: Input :: |job|, a job : Output :: none 1. Let |registration| be the result of running the Get Registration algorithm passing |job|'s [=job/scope url=] as the argument. 1. If |registration| is null or |registration|'s uninstalling flag is set, then: 1. Invoke Reject Job Promise with |job| and a TypeError. 1. Invoke Finish Job with |job| and abort these steps. 1. Let |newestWorker| be the result of running Get Newest Worker algorithm passing |registration| as the argument. 1. If |job|'s job type is *update*, and |newestWorker|'s [=service worker/script url=] does not [=url/equal=] |job|'s [=job/script url=] with the *exclude fragments flag* set, then: 1. Invoke Reject Job Promise with |job| and a TypeError. 1. Invoke Finish Job with |job| and abort these steps. 1. Let |httpsState| be "none". 1. Let |referrerPolicy| be the empty string. 1. Switching on |job|'s worker type, run these substeps with the following options: : "classic" :: Fetch a classic worker script given |job|’s serialized [=job/script url=], |job|’s [=job/client=], "serviceworker", and the to-be-created environment settings object for this service worker. : "module" :: Fetch a module worker script graph given |job|’s serialized [=job/script url=], |job|’s [=job/client=], "serviceworker", "omit", and the to-be-created environment settings object for this service worker. To [=fetching scripts/perform the fetch=] given |request|, run the following steps: 1. Append \`Service-Worker\`/\`script\` to |request|'s [=request/header list=]. Note: See the definition of the Service-Worker header in Appendix B: Extended HTTP headers. 1. Set |request|'s [=request/cache mode=] to "no-cache" if any of the following are true: * |registration|'s [=service worker registration/use cache=] is false. * |job|'s [=force bypass cache flag=] is set. * |newestWorker| is not null, and |registration|'s [=last update check time=] is not null and the time difference in seconds calculated by the current time minus |registration|’s [=last update check time=] is greater than 86400. Note: Even if the cache mode is not set to "no-cache", the user agent obeys Cache-Control header's max-age value in the network layer to determine if it should bypass the browser cache. 1. Set |request|'s [=service-workers mode=] to "`none`". 1. If the [=fetching scripts/is top-level=] flag is unset, then return the result of [=/fetching=] |request|. 1. Append \`Service-Worker\`/\`script\` to |request|'s [=request/header list=]. Note: See the definition of the Service-Worker header in Appendix B: Extended HTTP headers. 1. Set |request|'s [=request/redirect mode=] to "error". 1. [=/Fetch=] |request|, and asynchronously wait to run the remaining steps as part of fetch's process response for the [=/response=] |response|. 1. [=Extract a MIME type=] from the |response|'s [=response/header list=]. If this MIME type (ignoring parameters) is not a [=JavaScript MIME type=], then: 1. Invoke [=Reject Job Promise=] with |job| and a "{{SecurityError}}" exception. 1. Asynchronously complete these steps with a [=network error=]. 1. Let |serviceWorkerAllowed| be the result of [=extracting header list values=] given \`Service-Worker-Allowed\` and |response|'s [=response/header list=]. Note: See the definition of the Service-Worker-Allowed header in Appendix B: Extended HTTP headers. 1. Set |httpsState| to |response|'s [=response/HTTPS state=]. 1. Set |referrerPolicy| to the result of parse a referrer policy from a Referrer-Policy header of |response|. 1. If |serviceWorkerAllowed| is failure, then: 1. Asynchronously complete these steps with a network error. 1. Let |scopeURL| be |registration|'s [=service worker registration/scope url=]. 1. Let |maxScopeString| be null. 1. If |serviceWorkerAllowed| is null, then: 1. Set |maxScopeString| to "/" concatenated with the strings, except the last string that denotes the script's file name, in |job|'s [=job/script url=]'s [=url/path=] (including empty strings), separated from each other by "/". 1. Else: 1. Let |maxScope| be the result of parsing |serviceWorkerAllowed| with |job|'s [=job/script url=]. 1. Set |maxScopeString| to "/" concatenated with the strings in |maxScope|'s [=url/path=] (including empty strings), separated from each other by "/". 1. Let |scopeString| be "/" concatenated with the strings in |scopeURL|'s [=url/path=] (including empty strings), separated from each other by "/". 1. If |scopeString| starts with |maxScopeString|, do nothing. 1. Else: 1. Invoke Reject Job Promise with |job| and a "{{SecurityError}}" exception. 1. Asynchronously complete these steps with a network error. 1. If |response|'s cache state is not "local", set |registration|'s last update check time to the current time. Issue: The response's cache state concept had been removed from fetch. The fetch issue #376 tracks the request to restore the concept or add some similar way to check this state. 1. Return true. If the algorithm asynchronously completes with null, then: 1. Invoke Reject Job Promise with |job| and a TypeError. Note: This will do nothing if Reject Job Promise was previously invoked with a "{{SecurityError}}" exception. 1. If |newestWorker| is null, invoke Clear Registration algorithm passing |registration| as its argument. 1. Invoke Finish Job with |job| and abort these steps. Else, continue the rest of these steps after the algorithm's asynchronous completion, with |script| being the asynchronous completion value. 1. If |newestWorker| is not null, |newestWorker|'s [=service worker/script url=] [=url/equals=] |job|'s [=job/script url=] with the *exclude fragments flag* set, and |script|'s [=source text=] is a byte-for-byte match with |newestWorker|'s [=script resource=]'s [=source text=], if |script| is a [=classic script=], and |script|'s [=module script/module record=]'s \[[ECMAScriptCode]] is a byte-for-byte match with |newestWorker|'s [=script resource=]'s [=module script/module record=]'s \[[ECMAScriptCode]] otherwise, then: 1. Invoke Resolve Job Promise with |job| and the {{ServiceWorkerRegistration}} object which represents |registration|. 1. Invoke Finish Job with |job| and abort these steps. 1. Else: 1. Let |worker| be a new [=/service worker=]. 1. Generate a unique opaque string and set |worker|'s id to the value. 1. Set |worker|'s [=service worker/script url=] to |job|'s [=job/script url=], |worker|'s script resource to |script|, and |worker|'s type to |job|'s worker type. 1. Set |worker|'s script resource's HTTPS state to |httpsState|. 1. Set |worker|'s script resource's [=script resource/referrer policy=] to |referrerPolicy|. 1. Invoke Run Service Worker algorithm given |worker|, and with the *force bypass cache for importscripts flag* set if |job|'s [=job/force bypass cache flag=] is set. 1. If an uncaught runtime script error occurs during the above step, then: 1. Invoke Reject Job Promise with |job| and a TypeError. 1. If |newestWorker| is null, invoke Clear Registration algorithm passing |registration| as its argument. 1. Invoke Finish Job with |job| and abort these steps. 1. Invoke Install algorithm with |job|, |worker|, and |registration| as its arguments.

Soft Update

The user agent *may* call this as often as it likes to check for updates. : Input :: |registration|, a [=/service worker registration=] :: *force bypass cache flag*, an optional flag unset by default Note: Implementers may use the *force bypass cache flag* to aid debugging (e.g. invocations from developer tools), and other specifications that extend service workers may also use the flag on their own needs. : Output :: None 1. Let |newestWorker| be the result of running Get Newest Worker algorithm passing |registration| as its argument. 1. If |newestWorker| is null, abort these steps. 1. Let |job| be the result of running Create Job with *update*, |registration|'s [=service worker registration/scope url=], |newestWorker|'s [=service worker/script url=], null, and null. 1. Set |job|'s worker type to |newestWorker|'s [=service worker/type=]. 1. Set |job|'s force bypass cache flag if its *force bypass cache flag* is set. 1. Invoke Schedule Job with |job|.

Install

: Input :: |job|, a job :: |worker|, a [=/service worker=] :: |registration|, a [=/service worker registration=] : Output :: none 1. Let |installFailed| be false. 1. Let |newestWorker| be the result of running Get Newest Worker algorithm passing |registration| as its argument. 1. Run the Update Registration State algorithm passing |registration|, "installing" and |worker| as the arguments. 1. Run the Update Worker State algorithm passing |registration|'s installing worker and *installing* as the arguments. 1. Assert: |job|'s [=job/job promise=] is not null. 1. Invoke Resolve Job Promise with |job| and the {{ServiceWorkerRegistration}} object which represents |registration|. 1. Queue a task to fire an event named updatefound at all the {{ServiceWorkerRegistration}} objects for all the [=/service worker clients=] whose creation URL matches |registration|'s [=service worker registration/scope url=] and all the [=/service workers=] whose containing service worker registration is |registration|. 1. Let |installingWorker| be |registration|'s installing worker. 1. Invoke Run Service Worker algorithm given |installingWorker|, and with the *force bypass cache for importscripts flag* set if |job|'s [=job/force bypass cache flag=] is set. 1. Queue a task |task| to run the following substeps: 1. Let |e| be the result of creating an event with {{InstallEvent}}. 1. Initialize |e|’s {{Event/type}} attribute to {{install!!event}}. 1. Dispatch |e| at |installingWorker|'s [=service worker/global object=]. 1. *WaitForAsynchronousExtensions*: Run the following substeps in parallel: 1. Wait until |e|'s [=ExtendableEvent/pending promises count=] is zero. 1. If the result of waiting for all of |e|'s extend lifetime promises rejected, set |installFailed| to true. If |task| is discarded or the script has been aborted by the termination of |installingWorker|, set |installFailed| to true. 1. Wait for |task| to have executed or been discarded. 1. Wait for the step labeled *WaitForAsynchronousExtensions* to complete. 1. If |installFailed| is true, then: 1. Run the Update Worker State algorithm passing |registration|'s [=installing worker=] and *redundant* as the arguments. 1. Run the Update Registration State algorithm passing |registration|, "installing" and null as the arguments. 1. If |newestWorker| is null, invoke Clear Registration algorithm passing |registration| as its argument. 1. Invoke Finish Job with |job| and abort these steps. 1. Set |registration|'s installing worker's imported scripts updated flag. 1. If |registration|'s waiting worker is not null, then: 1. [=Terminate Service Worker|Terminate=] |registration|'s [=waiting worker=]. 1. Run the [=Update Worker State=] algorithm passing |registration|'s [=waiting worker=] and *redundant* as the arguments. 1. Run the Update Registration State algorithm passing |registration|, "waiting" and |registration|'s installing worker as the arguments. 1. Run the Update Registration State algorithm passing |registration|, "installing" and null as the arguments. 1. Run the Update Worker State algorithm passing |registration|'s waiting worker and *installed* as the arguments. 1. Invoke Finish Job with |job|. 1. Wait for all the tasks queued by Update Worker State invoked in this algorithm have executed. 1. Invoke [=Try Activate=] with |registration|. Note: If [=Try Activate=] does not trigger [=Activate=] here, [=Activate=] is tried again when the last client controlled by the existing [=active worker=] is [=Handle Service Worker Client Unload|unloaded=], {{ServiceWorkerGlobalScope/skipWaiting()}} is asynchronously called, or the [=extend lifetime promises=] for the existing [=active worker=] settle.

Activate

: Input :: |registration|, a [=/service worker registration=] : Output :: None 1. If |registration|'s waiting worker is null, abort these steps. 1. If |registration|'s [=active worker=] is not null, then: 1. [=Terminate Service Worker|Terminate=] |registration|'s [=active worker=]. 1. Run the [=Update Worker State=] algorithm passing |registration|'s [=active worker=] and *redundant* as the arguments. 1. Run the Update Registration State algorithm passing |registration|, "active" and |registration|'s waiting worker as the arguments. 1. Run the Update Registration State algorithm passing |registration|, "waiting" and null as the arguments. 1. Run the Update Worker State algorithm passing |registration|'s active worker and *activating* as the arguments. Note: Once an active worker is activating, neither a runtime script error nor a force termination of the active worker prevents the active worker from getting activated. 1. For each [=/service worker client=] |client| whose creation URL matches |registration|'s [=service worker registration/scope url=]: 1. If |client| is a window client, unassociate |client|'s responsible document from its application cache, if it has one. 1. Else if |client| is a shared worker client, unassociate |client|'s [=environment settings object/global object=] from its application cache, if it has one. Note: Resources will now use the service worker registration instead of the existing application cache. 1. For each [=/service worker client=] |client| who is using |registration|: 1. Set |client|'s active worker to |registration|'s active worker. 1. Invoke Notify Controller Change algorithm with |client| as the argument. 1. Let |activeWorker| be |registration|'s active worker. 1. Invoke Run Service Worker algorithm with |activeWorker| as the argument. 1. Queue a task |task| to run the following substeps: 1. Let |e| be the result of creating an event with {{ExtendableEvent}}. 1. Initialize |e|’s {{Event/type}} attribute to {{activate!!event}}. 1. Dispatch |e| at |activeWorker|'s [=service worker/global object=]. 1. *WaitForAsynchronousExtensions*: Wait, in parallel, until |e|'s [=ExtendableEvent/pending promises count=] is zero. 1. Wait for |task| to have executed or been discarded, or the script to have been aborted by the termination of |activeWorker|. 1. Wait for the step labeled *WaitForAsynchronousExtensions* to complete. 1. Run the Update Worker State algorithm passing |registration|'s active worker and *activated* as the arguments.

Try Activate

: Input :: |registration|, a [=/service worker registration=] : Output :: None 1. If |registration|'s [=waiting worker=] is null, return. 1. If |registration|'s [=active worker=] is not null and |registration|'s [=active worker=]'s [=state=] is *activating*, return. Note: If the existing active worker is still in activating state, the activation of the waiting worker is delayed. 1. Invoke [=Activate=] with |registration| if either of the following is true: * |registration|'s [=active worker=] is null. * The result of running [=Service Worker Has No Pending Events=] with |registration|’s [=active worker=] is true, and no [=/service worker client=] is [=using=] |registration| or |registration|’s [=waiting worker=]'s [=skip waiting flag=] is set.

Run Service Worker

: Input :: |serviceWorker|, a [=/service worker=] :: *force bypass cache for importscripts flag*, an optional flag unset by default : Output :: None 1. Let |script| be |serviceWorker|'s [=service worker/script resource=]. 1. Assert: |script| is not null. 1. If |serviceWorker| is already running, abort these steps. 1. Create a separate parallel execution environment (i.e. a separate thread or process or equivalent construct), and run the rest of these steps in that context. 1. Call the JavaScript [=InitializeHostDefinedRealm|InitializeHostDefinedRealm()=] abstract operation with the following customizations: * For the global object, create a new {{ServiceWorkerGlobalScope}} object. Let |workerGlobalScope| be the created object. * Let |realmExecutionContext| be the created [=execution context|JavaScript execution context=]. 1. Set |serviceWorker|'s [=service worker/global object=] to |workerGlobalScope|. 1. Let |workerEventLoop| be a newly created event loop. 1. Let |settingsObject| be a new environment settings object whose algorithms are defined as follows: : The [=environment settings object/realm execution context=] :: Return |realmExecutionContext|. : The [=environment settings object/global object=] :: Return |workerGlobalScope|. : The responsible event loop :: Return |workerEventLoop|. : The [=environment settings object/referrer policy=] :: Return |workerGlobalScope|'s [=WorkerGlobalScope/referrer policy=]. : The API URL character encoding :: Return UTF-8. : The API base URL :: Return |serviceWorker|'s [=service worker/script url=]. : The [=environment settings object/origin=] :: Return its registering [=/service worker client=]'s [=environment settings object/origin=]. : The creation URL :: Return |workerGlobalScope|'s [=WorkerGlobalScope/url=]. : The [=environment settings object/HTTPS state=] :: Return |workerGlobalScope|'s [=WorkerGlobalScope/HTTPS state=]. 1. Set |workerGlobalScope|'s [=WorkerGlobalScope/url=] to |serviceWorker|'s [=service worker/script url=]. 1. Set |workerGlobalScope|'s [=WorkerGlobalScope/HTTPS state=] to |serviceWorker|'s script resource's HTTPS state. 1. Set |workerGlobalScope|'s [=WorkerGlobalScope/referrer policy=] to |serviceWorker|'s script resource's [=script resource/referrer policy=]. 1. Set |workerGlobalScope|'s [=WorkerGlobalScope/type=] to |serviceWorker|'s type. 1. Set |workerGlobalScope|'s [=ServiceWorkerGlobalScope/force bypass cache for importscripts flag=] if its *force bypass cache for importscripts flag* is set. 1. Create a new {{WorkerLocation}} object and associate it with |workerGlobalScope|. 1. If |serviceWorker| is an active worker, and there are any tasks queued in |serviceWorker|'s containing service worker registration's [=service worker registration/task queues=], queue them to |serviceWorker|'s event loop's [=/task queues=] in the same order using their original task sources. 1. If |script| is a classic script, then run the classic script |script|. Otherwise, it is a module script; run the module script |script|. Note: In addition to the usual possibilities of returning a value or failing due to an exception, this could be prematurely aborted by the kill a worker or terminate a worker algorithms. 1. If |script|'s has ever been evaluated flag is unset, then: 1. For each |eventType| of |settingsObject|'s [=environment settings object/global object=]'s associated list of event listeners' event types: 1. [=set/Append=] |eventType| to |workerGlobalScope|'s associated [=ServiceWorkerGlobalScope/service worker=]'s set of event types to handle. Note: If the global object's associated list of event listeners does not have any event listener added at this moment, the service worker's set of event types to handle remains an empty set. The user agents are encouraged to show a warning that the event listeners must be added on the very first evaluation of the worker script. 1. Set |script|'s has ever been evaluated flag. 1. Run the responsible event loop specified by |settingsObject| until it is destroyed. 1. Empty |workerGlobalScope|'s list of active timers.

Terminate Service Worker

: Input :: |serviceWorker|, a [=/service worker=] : Output :: None 1. If |serviceWorker| is not running, abort these steps. 1. Let |serviceWorkerGlobalScope| be |serviceWorker|'s [=service worker/global object=]. 1. Set |serviceWorkerGlobalScope|'s closing flag to true. 1. [=set/Remove=] all the [=items=] from |serviceWorker|'s [=set of extended events=]. 1. If there are any tasks, whose task source is either the handle fetch task source or the handle functional event task source, queued in |serviceWorkerGlobalScope|'s event loop's [=/task queues=], queue them to |serviceWorker|'s containing service worker registration's corresponding [=service worker registration/task queues=] in the same order using their original task sources, and discard all the tasks (including tasks whose task source is neither the handle fetch task source nor the handle functional event task source) from |serviceWorkerGlobalScope|'s event loop's [=/task queues=] without processing them. Note: This effectively means that the fetch events and the other functional events such as push events are backed up by the registration's task queues while the other tasks including message events are discarded. 1. Abort the script currently running in |serviceWorker|.

Handle Fetch

The Handle Fetch algorithm is the entry point for the [=/fetch=] handling handed to the [=/service worker=] context. : Input :: |request|, a [=/request=] : Output :: |response|, a [=/response=] 1. Let |handleFetchFailed| be false. 1. Let |respondWithEntered| be false. 1. Let |eventCanceled| be false. 1. Let |r| be a new {{Request}} object associated with |request|. 1. Let |headersObject| be |r|'s {{Request/headers}} attribute value. 1. Set |headersObject|'s [=Headers/guard=] to *immutable*. 1. Let |response| be null. 1. Let |registration| be null. 1. Let |client| be |request|'s [=request/client=]. 1. Let |reservedClient| be |request|'s [=request/reserved client=]. 1. Let |preloadResponse| be a new [=promise=]. 1. Assert: |request|'s [=request/destination=] is not "serviceworker". 1. If |request| is a potential-navigation-or-subresource request, then: 1. Return null. 1. Else if |request| is a non-subresource request, then: Note: If the non-subresource request is under the scope of a service worker registration, application cache is completely bypassed regardless of whether the non-subresource request uses the service worker registration. 1. If |reservedClient| is not null and is an environment settings object, then: 1. If |reservedClient| is not a secure context, return null. 1. Else: 1. If |request|'s [=request/url=] is not a potentially trustworthy URL, return null. 1. If |request| is a navigation request and the navigation triggering it was initiated with a shift+reload or equivalent, return null. 1. Set |registration| to the result of running Match Service Worker Registration algorithm passing |request|'s [=request/url=] as the argument. 1. If |registration| is null or |registration|'s active worker is null, return null. 1. If |request|'s [=request/destination=] is not {{RequestDestination/"report"}}, set |reservedClient|'s active service worker to |registration|'s active worker. 1. If |request| is a [=navigation request=], |registration|'s [=navigation preload enabled flag=] is set, |request|'s [=request/method=] is \`GET\`, and |registration|'s [=active worker=]'s set of event types to handle [=set/contains=] fetch, then: Note: If the above is true except |registration|'s [=active worker=]'s set of event types to handle **does not** contain fetch, then the user agent may wish to show a console warning, as the developer's intent isn't clear. 1. Let |preloadRequest| be the result of [=request/cloning=] the request |request|. 1. Let |preloadRequestHeaders| be |preloadRequest|'s [=request/header list=]. 1. Let |preloadResponseObject| be a new {{Response}} object associated with a new {{Headers}} object whose [=guard=] is "`immutable`". 1. [=header list/Append=] to |preloadRequestHeaders| a new [=header=] whose [=header/name=] is \`Service-Worker-Navigation-Preload\` and [=header/value=] is |registration|'s [=navigation preload header value=]. 1. Set |preloadRequest|'s [=service-workers mode=] to "`none`". 1. Run the following substeps [=in parallel=]: 1. [=Fetch=] |preloadRequest|. To [=process response=] for |navigationPreloadResponse|, run these substeps: 1. If |navigationPreloadResponse|'s [=response/type=] is "`error`", reject |preloadResponse| with a `TypeError` and terminate these substeps. 1. Associate |preloadResponseObject| with |navigationPreloadResponse|. 1. Resolve |preloadResponse| with |navigationPreloadResponse|. 1. Else, resolve |preloadResponse| with undefined. Note: From this point, the [=/service worker client=] starts to use its active service worker's containing service worker registration. 1. Else if |request| is a subresource request, then: 1. If |client|'s active service worker is non-null, set |registration| to |client|'s active service worker's containing service worker registration. 1. Else, return null. 1. Let |activeWorker| be |registration|'s active worker. 1. If |activeWorker|'s set of event types to handle does not [=set/contain=] fetch, then: 1. Return null and continue running these steps in parallel. 1. If |request| is a non-subresource request, or |request| is a subresource request and the time difference in seconds calculated by the current time minus |registration|'s last update check time is greater than 86400, invoke Soft Update algorithm with |registration|. 1. Abort these steps. Note: To avoid unnecessary delays, the Handle Fetch enforces early return when no event listeners have been deterministically added in the service worker's global during the very first script execution. 1. If |activeWorker|'s state is *activating*, wait for |activeWorker|'s state to become *activated*. 1. Invoke Run Service Worker algorithm with |activeWorker| as the argument. 1. Queue a task |task| to run the following substeps: 1. Let |e| be the result of creating an event with {{FetchEvent}}. 1. Initialize |e|’s {{Event/type}} attribute to {{fetch!!event}}. 1. Initialize |e|’s {{Event/cancelable}} attribute to true. 1. Initialize |e|’s {{FetchEvent/request}} attribute to |r|. 1. Initialize |e|’s {{FetchEvent/preloadResponse}} to |preloadResponse|. 1. Initialize |e|'s {{FetchEvent/clientId}} attribute to |client|'s [=environment/id=]. 1. If |request| is a non-subresource request and |request|'s [=request/destination=] is not {{RequestDestination/"report"}}, initialize |e|'s {{FetchEvent/reservedClientId}} attribute to |reservedClient|'s [=environment/id=], and to the empty string otherwise. 1. If |request| is a navigation request, initialize |e|'s {{FetchEvent/targetClientId}} attribute to |request|'s [=request/target client id=], and to the empty string otherwise. 1. Dispatch |e| at |activeWorker|'s [=service worker/global object=]. 1. Invoke [=Update Service Worker Extended Events Set=] with |activeWorker| and |e|. 1. If |e|'s [=FetchEvent/respond-with entered flag=] is set, set |respondWithEntered| to true. 1. If |e|'s [=FetchEvent/wait to respond flag=] is set, then: 1. Wait until |e|'s [=FetchEvent/wait to respond flag=] is unset. 1. If |e|'s [=FetchEvent/respond-with error flag=] is set, set |handleFetchFailed| to true. 1. Else, set |response| to |e|'s [=FetchEvent/potential response=]. 1. If |e|'s canceled flag is set, set |eventCanceled| to true. If |task| is discarded or the script has been aborted by the termination of |activeWorker|, set |handleFetchFailed| to true. The |task| *must* use |activeWorker|'s event loop and the handle fetch task source. 1. Wait for |task| to have executed or been discarded. 1. If |respondWithEntered| is false, then: 1. If |eventCanceled| is true, return a network error and continue running these steps in parallel. 1. Else, return null and continue running these steps in parallel. 1. If |request| is a non-subresource request, or |request| is a subresource request and the time difference in seconds calculated by the current time minus |registration|'s last update check time is greater than 86400, invoke Soft Update algorithm with |registration|. 1. Abort these steps. 1. If |handleFetchFailed| is true, then: 1. Return a network error and continue running these steps in parallel. 1. If |request| is a non-subresource request, or |request| is a subresource request and the time difference in seconds calculated by the current time minus |registration|'s last update check time is greater than 86400, invoke Soft Update algorithm with |registration|. 1. Else: 1. Return |response| and continue running these steps in parallel. 1. If |request| is a non-subresource request, or |request| is a subresource request and the time difference in seconds calculated by the current time minus |registration|'s last update check time is greater than 86400, invoke Soft Update algorithm with |registration|.

Handle Foreign Fetch

The [=Handle Foreign Fetch=] algorithm is the entry point for the [=/fetch=] handling handed to the [=/service worker=] context to handle foreign fetch requests. : Input :: |request|, a [=/request=] : Output :: |response|, a [=/response=]
1. Let |handleFetchFailed| be false. 1. Let |respondWithEntered| be false. 1. Let |eventCanceled| be false. 1. If |request| is not a subresource request, return null and abort these steps. Note: Foreign fetch only allows intercepting of subresource requests. Navigation requests can be intercepted by the regular fetch event anyway, so there is no benefit to supporting those requests here as well. 1. If |request|'s [=request/client=] is not a secure context, return null and abort these steps. 1. Let |activeWorker| be the result of running the [=Match Service Worker for Foreign Fetch=] algorithm passing |request|'s [=request/url=] as the argument. 1. If |activeWorker| is null, return null. 1. If |activeWorker|'s state is *activating*, then: 1. Wait for |activeWorker|'s state to become *activated*. 1. If |activeWorker|'s [=environment settings object/origin=] is the same as |request|'s [=request/origin=], return null. 1. Let |originMatches| be false. 1. If |activeWorker|'s list of foreign fetch origins is empty, set |originMatches| to true. 1. For each |origin| in |activeWorker|'s list of foreign fetch origins: 1. If |origin| is equal to |request|'s [=request/origin=], set |originMatches| to true. 1. If |originMatches| is false, return null. 1. If |request|'s [=request/method=] is not a [=CORS-safelisted method=], or if there is at least one [=header=] in |request|'s [=request/header list=] for whose [=header/name=] is not a [=CORS-safelisted request-header=], return null. Note: In the future this might be relaxed by adding supported methods and headers to the {{ForeignFetchOptions}}. 1. Let |r| be a new {{Request}} object associated with |request|. 1. Invoke [=Run Service Worker=] algorithm with |activeWorker| as the argument. 1. Queue a task |task| to run the following substeps: 1. Let |e| be the result of creating an event with {{ForeignFetchEvent}}. 1. Initialize |e|’s {{Event/type}} attribute to {{foreignfetch!!event}}. 1. Initialize |e|’s {{Event/cancelable}} attribute to true. 1. Initialize |e|’s {{ForeignFetchEvent/request}} attribute to |r|. 1. Initialize |e|’s {{ForeignFetchEvent/origin}} attribute to the Unicode serialization of |request|'s [=request/origin=]. 1. Dispatch |e| at |activeWorker|'s [=service worker/global object=]. 1. Invoke [=Update Service Worker Extended Events Set=] with |activeWorker| and |e|. 1. If |e|'s [=ForeignFetchEvent/respond-with entered flag=] is set, set |respondWithEntered| to true. 1. If |e|'s wait to respond flag is set, wait until |e|'s wait to respond flag is unset. 1. Let |internalResponse| be |e|'s [=ForeignFetchEvent/potential response=]. 1. If |internalResponse| is a filtered response, set |internalResponse| to |internalResponse|'s internal response. 1. If |e|'s respond-with error flag is set, set |handleFetchFailed| to true. 1. Else if |e|'s [=ForeignFetchEvent/origin=] is null: 1. If |e|'s list of exposed headers is not empty, set |handleFetchFailed| to true. 1. Else if |e|'s [=ForeignFetchEvent/potential response=] is a opaque-redirect filtered response, set |response| to |e|'s [=ForeignFetchEvent/potential response=]. 1. Else set |response| to an opaque filtered response of |internalResponse|. 1. Else if |e|'s [=ForeignFetchEvent/origin=] is not equal to the Unicode serialization of |request|'s [=request/origin=], set |handleFetchFailed| to true. 1. Else if |e|'s [=ForeignFetchEvent/potential response=] is an opaque filtered response or is an opaque-redirect filtered response, set |response| to |e|'s [=ForeignFetchEvent/potential response=]. 1. Else if |request|'s response tainting is "opaque", set |response| to an opaque filtered response of |internalResponse|. 1. Else: 1. Let |headers| be |e|'s list of exposed headers. 1. If |response| is a CORS filtered response, remove from |internalResponse|'s CORS-exposed header-name list all values not in |headers|. 1. Else set |internalResponse|'s CORS-exposed header-name list to |headers|. 1. Set |response| to a CORS filtered response of |internalResponse|. 1. If |e|'s canceled flag is set, set |eventCanceled| to true. If |task| is discarded or the script has been aborted by the termination of |activeWorker|, set |handleFetchFailed| to true. The |task| *must* use |activeWorker|'s event loop and the handle fetch task source. 1. Wait for |task| to have executed or been discarded. 1. If |respondWithEntered| is false, then: 1. If |eventCanceled| is true, then: 1. Return a network error. 1. Else: 1. Return null. 1. If |handleFetchFailed| is true, then: 1. Return a network error. 1. Else: 1. Return |response|.

Handle Functional Event

: Input :: |event|, an {{ExtendableEvent}} object :: |registration|, a [=/service worker registration=] :: |callbackSteps|, an algorithm : Output :: None 1. Assert: scope to registration map contains a value equal to |registration|. 1. Assert: |registration|'s active worker is not null. 1. Let |activeWorker| be |registration|'s active worker. 1. If |activeWorker|'s set of event types to handle does not [=set/contain=] |event|'s {{Event/type}}, then: 1. Return and continue running these steps in parallel. 1. If the time difference in seconds calculated by the current time minus |registration|'s last update check time is greater than 86400, invoke Soft Update algorithm with |registration|. 1. Abort these steps. Note: To avoid unnecessary delays, the Handle Functional Event enforces early return when no event listeners have been deterministically added in the service worker's global during the very first script execution. 1. If |activeWorker|'s state is *activating*, wait for |activeWorker|'s state to become *activated*. 1. Invoke Run Service Worker algorithm with |activeWorker| as the argument. 1. Queue a task |task| to run these substeps: 1. Invoke |callbackSteps| with |activeWorker|'s [=service worker/global object=] as its argument. 1. Invoke [=Update Service Worker Extended Events Set=] with |activeWorker| and |event|. The |task| *must* use |activeWorker|'s event loop and the handle functional event task source. 1. Wait for |task| to have executed or been discarded. 1. If the time difference in seconds calculated by the current time minus |registration|'s last update check time is greater than 86400, invoke Soft Update algorithm with |registration|.

Handle Service Worker Client Unload

The user agent *must* run these steps when a [=/service worker client=] unloads by unloading, being killed, or terminating. : Input :: |client|, a [=/service worker client=] : Output :: None 1. Run the following steps atomically. 1. Let |registration| be the [=/service worker registration=] used by |client|. 1. If |registration| is null, abort these steps. 1. If any other [=/service worker client=] is using |registration|, abort these steps. 1. If |registration|'s [=uninstalling flag=] is set, invoke [=Try Clear Registration=] with |registration|. 1. If |registration| is not null, invoke [=Try Activate=] with |registration|.

Handle User Agent Shutdown

: Input :: None : Output :: None 1. [=map/For each=] scope → |registration| of scope to registration map: 1. If |registration|'s installing worker |installingWorker| is not null, then: 1. If |registration|'s [=waiting worker=] is null and |registration|'s [=active worker=] is null, invoke Clear Registration with |registration| and continue to the next iteration of the loop. 1. Else, set |installingWorker| to null. 1. If |registration|'s waiting worker is not null, run the following substep in parallel: 1. Invoke Activate with |registration|.

Update Service Worker Extended Events Set

: Input :: |worker|, a [=/service worker=] :: |event|, an [=event=] : Output :: None 1. Assert: |event|'s [=dispatch flag=] is unset. 1. For each |item| of |worker|'s [=set of extended events=]: 1. If |item|'s [=pending promises count=] is zero, [=set/remove=] |item| from |worker|'s [=set of extended events=]. 1. If |event|'s [=pending promises count=] is not zero, [=set/append=] |event| to |worker|'s [=set of extended events=].

Unregister

: Input :: |job|, a job : Output :: none 1. If the [=environment settings object/origin=] of |job|'s [=job/scope url=] is not |job|'s [=job/client=]'s [=environment settings object/origin=], then: 1. Invoke Reject Job Promise with |job| and a "{{SecurityError}}" exception. 1. Invoke Finish Job with |job| and abort these steps. 1. Let |registration| be the result of running Get Registration algorithm passing |job|'s [=job/scope url=] as the argument. 1. If |registration| is null, then: 1. Invoke Resolve Job Promise with |job| and false. 1. Invoke Finish Job with |job| and abort these steps. 1. Set |registration|'s uninstalling flag. 1. Invoke Resolve Job Promise with |job| and true. 1. Invoke [=Try Clear Registration=] with |registration|. Note: If [=Try Clear Registration=] does not trigger [=Clear Registration=] here, [=Clear Registration=] is tried again when the last client [=using=] the registration is [=Handle Service Worker Client Unload|unloaded=] or the [=extend lifetime promises=] for the registration's service workers settle. 1. Invoke Finish Job with |job|.

Set Registration

: Input :: |scope|, a [=/URL=] :: |useCache|, a boolean : Output :: |registration|, a [=/service worker registration=] 1. Run the following steps atomically. 1. Let |scopeString| be serialized |scope| with the *exclude fragment flag* set. 1. Let |registration| be a new [=/service worker registration=] whose [=service worker registration/scope url=] is set to |scope| and [=service worker registration/use cache=] is set to |useCache|. 1. [=map/Set=] scope to registration map[|scopeString|] to |registration|. 1. Return |registration|.

Clear Registration

: Input :: |registration|, a [=/service worker registration=] : Output :: None 1. Run the following steps atomically. 1. If |registration|'s installing worker is not null, then: 1. [=Terminate Service Worker|Terminate=] |registration|'s [=installing worker=]. 1. Run the Update Worker State algorithm passing |registration|'s [=installing worker=] and *redundant* as the arguments. 1. Run the Update Registration State algorithm passing |registration|, "installing" and null as the arguments. 1. If |registration|'s waiting worker is not null, then: 1. [=Terminate Service Worker|Terminate=] |registration|'s [=waiting worker=]. 1. Run the Update Worker State algorithm passing |registration|'s [=waiting worker=] and *redundant* as the arguments. 1. Run the Update Registration State algorithm passing |registration|, "waiting" and null as the arguments. 1. If |registration|'s active worker is not null, then: 1. [=Terminate Service Worker|Terminate=] |registration|'s [=active worker=]. 1. Run the Update Worker State algorithm passing |registration|'s [=active worker=] and *redundant* as the arguments. 1. Run the Update Registration State algorithm passing |registration|, "active" and null as the arguments. 1. Let |scopeString| be serialized |registration|'s [=service worker registration/scope url=] with the *exclude fragment flag* set. 1. [=map/Remove=] scope to registration map[|scopeString|].

Try Clear Registration

: Input :: |registration|, a [=/service worker registration=] : Output :: None 1. Invoke [=Clear Registration=] with |registration| if no [=/service worker client=] is [=using=] |registration| and all of the following conditions are true: * |registration|'s [=installing worker=] is null or the result of running [=Service Worker Has No Pending Events=] with |registration|’s [=installing worker=] is true. * |registration|'s [=waiting worker=] is null or the result of running [=Service Worker Has No Pending Events=] with |registration|’s [=waiting worker=] is true. * |registration|'s [=active worker=] is null or the result of running [=Service Worker Has No Pending Events=] with |registration|’s [=active worker=] is true.

Update Registration State

: Input :: |registration|, a [=/service worker registration=] :: |target|, a string (one of "installing", "waiting", and "active") :: |source|, a [=/service worker=] or null : Output :: None 1. Let |registrationObjects| be an array containing all the {{ServiceWorkerRegistration}} objects associated with |registration|. 1. If |target| is "installing", then: 1. Set |registration|'s installing worker to |source|. 1. For each |registrationObject| in |registrationObjects|: 1. Queue a task to set the {{ServiceWorkerRegistration/installing}} attribute of |registrationObject| to the {{ServiceWorker}} object that represents |registration|’s installing worker, or null if |registration|’s installing worker is null. 1. Else if |target| is "waiting", then: 1. Set |registration|'s waiting worker to |source|. 1. For each |registrationObject| in |registrationObjects|: 1. Queue a task to set the {{ServiceWorkerRegistration/waiting}} attribute of |registrationObject| to the {{ServiceWorker}} object that represents |registration|’s waiting worker, or null if |registration|’s waiting worker is null. 1. Else if |target| is "active", then: 1. Set |registration|'s [=service worker registration/active worker=] to |source|. 1. For each |registrationObject| in |registrationObjects|: 1. Queue a task to set the {{ServiceWorkerRegistration/active}} attribute of |registrationObject| to the {{ServiceWorker}} object that represents |registration|’s [=service worker registration/active worker=], or null if |registration|’s [=service worker registration/active worker=] is null. The task *must* use |registrationObject|'s relevant settings object's responsible event loop and the DOM manipulation task source.

Update Worker State

: Input :: |worker|, a [=/service worker=] :: |state|, a [=/service worker=]'s state : Output :: None 1. Set |worker|'s state to |state|. 1. Let |workerObjects| be an array containing all the {{ServiceWorker}} objects associated with |worker|. 1. For each |workerObject| in |workerObjects|: 1. Queue a task to run these substeps: 1. Set the {{ServiceWorker/state}} attribute of |workerObject| to the value (in {{ServiceWorkerState}} enumeration) corresponding to the first matching statement, switching on |worker|'s state: : *installing* :: {{"installing"}} Note: The [=/service worker=] in this state is considered an installing worker. During this state, {{ExtendableEvent/waitUntil()}} can be called inside the {{ServiceWorkerGlobalScope/oninstall}} event handler to extend the life of the installing worker until the passed promise resolves successfully. This is primarily used to ensure that the [=/service worker=] is not active until all of the core caches are populated. : *installed* :: {{"installed"}} Note: The [=/service worker=] in this state is considered a waiting worker. : *activating* :: {{"activating"}} Note: The [=/service worker=] in this state is considered an active worker. During this state, {{ExtendableEvent/waitUntil()}} can be called inside the {{ServiceWorkerGlobalScope/onactivate}} event handler to extend the life of the active worker until the passed promise resolves successfully. No functional events are dispatched until the state becomes *activated*. : *activated* :: {{"activated"}} Note: The [=/service worker=] in this state is considered an active worker ready to handle functional events. : *redundant* :: {{"redundant"}} Note: A new [=/service worker=] is replacing the current [=/service worker=], or the current [=/service worker=] is being discarded due to an install failure. 1. Fire an event named statechange at |workerObject|. The task *must* use |workerObject|'s relevant settings object's responsible event loop and the DOM manipulation task source.

Notify Controller Change

: Input :: |client|, a [=/service worker client=] : Output :: None 1. Assert: |client| is not null. 1. If |client| is an [=environment settings object=], queue a task to [=fire an event=] named controllerchange at the {{ServiceWorkerContainer}} object that |client| is [=ServiceWorkerContainer/service worker client|associated=] with. The task *must* use |client|'s responsible event loop and the DOM manipulation task source.

Match Service Worker Registration

: Input :: |clientURL|, a [=/URL=] : Output :: |registration|, a [=/service worker registration=] 1. Run the following steps atomically. 1. Let |clientURLString| be serialized |clientURL|. 1. Let |matchingScope| be the empty string. 1. Let |allScopes| be the result of [=map/get the keys|getting the keys=] from scope to registration map. 1. Set |matchingScope| to the longest value in |allScopes| which the value of |clientURLString| starts with, if it exists. Note: The URL string matching in this step is prefix-based rather than path-structural (e.g. a client URL string with "/prefix-of/resource.html" will match a registration for a scope with "/prefix"). 1. Let |parsedMatchingScope| be null. 1. If |matchingScope| is not the empty string, set |parsedMatchingScope| to the result of parsing |matchingScope|. 1. Let |registration| be the result of running Get Registration algorithm passing |parsedMatchingScope| as the argument. 1. If |registration| is not null and |registration|'s uninstalling flag is set, return null. 1. Return |registration|.

Match Service Worker for Foreign Fetch

: Input :: |requestURL|, a [=/URL=] : Output :: |worker|, a [=/service worker=] 1. Run the following steps atomically. 1. Let |registration| be the result of running the [=Match Service Worker Registration=] algorithm passing |requestURL| as the argument. 1. If |registration| is null, return null. 1. Let |worker| be |registration|'s [=service worker registration/active worker=]. 1. If |worker| is null, return null. 1. Let |requestURLString| be the serialized |requestURL|. 1. For each [=/URL=] |scope| in |worker|'s list of foreign fetch scopes: 1. Let |scopeString| be the serialized |scope|. 1. If |requestURLString| starts with |scopeString| return |worker|. 1. Return null.

Get Registration

: Input :: |scope|, a [=/URL=] : Output :: |registration|, a [=/service worker registration=] 1. Run the following steps atomically. 1. Let |scopeString| be the empty string. 1. If |scope| is not null, set |scopeString| to serialized |scope| with the *exclude fragment flag* set. 1. Let |registration| be null. 1. [=map/For each=] |key| → |value| of scope to registration map: 1. If |scopeString| matches |key|, set |registration| to |value|. 1. Return |registration|.

Get Newest Worker

: Input :: |registration|, a [=/service worker registration=] : Output :: |newestWorker|, a [=/service worker=] 1. Run the following steps atomically. 1. Let |newestWorker| be null. 1. If |registration|'s installing worker is not null, set |newestWorker| to |registration|'s installing worker. 1. Else if |registration|'s waiting worker is not null, set |newestWorker| to |registration|'s waiting worker. 1. Else if |registration|'s active worker is not null, set |newestWorker| to |registration|'s active worker. 1. Return |newestWorker|.

Service Worker Has No Pending Events

: Input :: |worker|, a [=/service worker=] : Output :: True or false, a boolean 1. Let |sum| be zero. 1. For each |item| of |worker|'s [=set of extended events=]: 1. Add |item|'s [=pending promises count=] to |sum|. 1. If |sum| is zero, return true. 1. Else, return false.

Create Client

: Input :: |client|, a [=/service worker client=] : Output :: |clientObject|, a {{Client}} object 1. Let |clientObject| be a new {{Client}} object. 1. Set |clientObject|'s [=Client/service worker client=] to |client|. 1. Set |clientObject|'s [=Client/reserved state=] to true if |client|'s [=environment/execution ready flag=] is unset, and false otherwise. 1. Return |clientObject|.

Create Window Client

: Input :: |client|, a [=/service worker client=] :: |visibilityState|, a string :: |focusState|, a boolean :: |ancestorOriginsList|, a list : Output :: |windowClient|, a {{WindowClient}} object 1. Let |windowClient| be a new {{WindowClient}} object. 1. Set |windowClient|'s [=Client/service worker client=] to |client|. 1. Set |windowClient|'s visibility state to |visibilityState|. 1. Set |windowClient|'s focus state to |focusState|. 1. Set |windowClient|'s [=WindowClient/ancestor origins array=] to a [=frozen array type|frozen array=] created from |ancestorOriginsList|. 1. Return |windowClient|.

Query Cache

: Input :: |request|, a {{Request}} object :: |options|, a {{CacheQueryOptions}} object, optional :: |targetStorage|, an array that has [{{Request}}, {{Response}}] pairs as its elements, optional : Output :: |resultArray|, an array that has [{{Request}}, {{Response}}] pairs as its elements 1. Let |requestArray| be an empty array. 1. Let |responseArray| be an empty array. 1. Let |resultArray| be an empty array. 1. If |options|.{{CacheQueryOptions/ignoreMethod}} is false and |request|.method is not \`GET\`, return |resultArray|. 1. Let |cachedURL| and |requestURL| be null. 1. If the optional argument |targetStorage| is omitted, then: 1. For each fetching record |entry| of its request to response map, in key insertion order: 1. Set |cachedURL| to |entry|.\[[key]]'s associated [=Request/request=]'s [=request/url=]. 1. Set |requestURL| to |request|'s associated [=Request/request=]'s [=request/url=]. 1. If |options|.ignoreSearch is true, then: 1. Set |cachedURL|'s [=url/query=] to the empty string. 1. Set |requestURL|'s [=url/query=] to the empty string. 1. If |cachedURL| [=url/equals=] |requestURL| with the *exclude fragments flag* set, then: 1. Add a copy of |entry|.\[[key]] to |requestArray|. 1. Add a copy of |entry|.\[[value]] to |responseArray|. 1. Else: 1. For each |record| in |targetStorage|: 1. Set |cachedURL| to |record|[0]'s associated [=Request/request=]'s [=request/url=]. 1. Set |requestURL| to |request|'s associated [=Request/request=]'s [=request/url=]. 1. If |options|.{{CacheQueryOptions/ignoreSearch}} is true, then: 1. Set |cachedURL|'s [=url/query=] to the empty string. 1. Set |requestURL|'s [=url/query=] to the empty string. 1. If |cachedURL| [=url/equals=] |requestURL| with the *exclude fragments flag* set, then: 1. Add |record|[0] to |requestArray|. 1. Add |record|[1] to |responseArray|. 1. For each |cachedResponse| in |responseArray| with the index |index|: 1. Let |cachedRequest| be the |index|th element in |requestArray|. 1. If |cachedResponse|'s [=Response/response=]'s [=response/header list=] contains no header [=header/named=] \`Vary\`, or |options|.{{CacheQueryOptions/ignoreVary}} is true, then: 1. Add an array [|cachedRequest|, |cachedResponse|] to |resultArray|. 1. Continue to the next iteration of the loop. 1. Let |varyHeaders| be the array containing the elements corresponding to the [=http/field-values=] of the Vary header. 1. Let |matchFailed| be false. 1. For each |f| in |varyHeaders|: 1. If |f| matches "*", or the result of running |cachedRequest|.{{Request/headers}} object's {{Headers/get(name)}} method with |f| as the argument does not match the result of running |request|.{{Request/headers}} object's {{Headers/get(name)}} method with |f| as the argument, then: 1. Set |matchFailed| to true. 1. Break the loop. 1. If |matchFailed| is false, add an array [|cachedRequest|, |cachedResponse|] to |resultArray|. 1. Return |resultArray|.

Batch Cache Operations

: Input :: |operations|, an array of {{CacheBatchOperation}} dictionary objects : Output :: |promise|, a promise resolves with an array of {{Response}} objects 1. Let |promise| be a promise resolved with no value. 1. Return the result of transforming |promise| with a fulfillment handler that performs the following substeps in parallel: 1. Let |itemsCopy| be a new request to response map that is a copy of its context object's request to response map. 1. Let |addedRecords| be an empty array. 1. Try running the following substeps atomically: 1. Let |resultArray| be an empty array. 1. For each |operation| in |operations|: 1. If |operation|.{{CacheBatchOperation/type}} matches neither "delete" nor "put", throw a TypeError. 1. If |operation|.{{CacheBatchOperation/type}} matches "delete" and |operation|.{{CacheBatchOperation/response}} is not null, throw a TypeError. 1. If the result of running Query Cache algorithm passing |operation|.{{CacheBatchOperation/request}}, |operation|.{{CacheBatchOperation/options}}, and |addedRecords| as the arguments is not an empty array, throw an "{{InvalidStateError}}" exception. 1. Let |requestResponseArray| be the result of running Query Cache algorithm passing |operation|.{{CacheBatchOperation/request}} and |operation|.{{CacheBatchOperation/options}} as the arguments. 1. For each |requestResponse| in |requestResponseArray|: 1. If |operation|.{{CacheBatchOperation/type}} matches "delete", remove the corresponding fetching record from request to response map. 1. If |operation|.{{CacheBatchOperation/type}} matches "put", then: 1. If |operation|.{{CacheBatchOperation/response}} is null, throw a TypeError. 1. Let |r| be |operation|.{{CacheBatchOperation/request}}'s associated [=Request/request=]. 1. If |r|'s [=request/url=]'s [=url/scheme=] is not one of "http" and "https", throw a TypeError. 1. If |r|'s [=request/method=] is not \`GET\`, throw a TypeError. 1. If |operation|.{{CacheBatchOperation/options}} is not null, throw a TypeError. 1. Set |requestResponseArray| to the result of running Query Cache algorithm passing |operation|.{{CacheBatchOperation/request}}. 1. If |requestResponseArray| is not an empty array, then: 1. Let |requestResponse| be |requestResponseArray|[0]. 1. Let |fetchingRecord| be the corresponding fetching record for |requestResponse|[0] and |requestResponse|[1] in request to response map. 1. Set |fetchingRecord|.\[[key]] to |operation|.{{CacheBatchOperation/request}} and |fetchingRecord|.\[[value]] to |operation|.{{CacheBatchOperation/response}}. 1. Else: 1. Set a newly-created fetching record {\[[key]]: |operation|.{{CacheBatchOperation/request}}, \[[value]]: |operation|.{{CacheBatchOperation/response}}} to request to response map. Note: The cache commit is allowed as long as the response's headers are available. 1. If the cache write operation in the previous two steps failed due to exceeding the granted quota limit, throw a "{{QuotaExceededError}}" exception. 1. Add an array [|operation|.request, |operation|.response] to |addedRecords|. 1. Add |operation|.response to |resultArray|. 1. Return |resultArray|. 1. And then, if an exception was thrown, then: 1. Set the context object's request to response map to |itemsCopy|. 1. Throw the exception

Appendix B: Extended HTTP headers

Service Worker Script Request

An HTTP request to [=/fetch=] a [=/service worker=]'s script resource will include the following header: : \`Service-Worker\` :: Indicates this request is a [=/service worker=]'s script resource request. Note: This header helps administrators log the requests and detect threats.

Service Worker Script Response

An HTTP response to a [=/service worker=]'s script resource request can include the following header: : \`Service-Worker-Allowed\` :: Indicates the user agent will override the path restriction, which limits the maximum allowed [=service worker registration/scope url=] that the script can control, to the given value. Note: The value is a URL. If a relative URL is given, it is parsed against the script's URL.
Default scope:
        // Maximum allowed scope defaults to the path the script sits in
        // "/js" in this example
        navigator.serviceWorker.register("/js/sw.js").then(() => {
          console.log("Install succeeded with the default scope '/js'.");
        });
      
Upper path without Service-Worker-Allowed header:
        // Set the scope to an upper path of the script location
        // Response has no Service-Worker-Allowed header
        navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).catch(() => {
          console.error("Install failed due to the path restriction violation.");
        });
      
Upper path with Service-Worker-Allowed header:
        // Set the scope to an upper path of the script location
        // Response included "Service-Worker-Allowed : /"
        navigator.serviceWorker.register("/js/sw.js", { scope: "/" }).then(() => {
          console.log("Install succeeded as the max allowed scope was overriden to '/'.");
        });
      
A path restriction voliation even with Service-Worker-Allowed header:
        // Set the scope to an upper path of the script location
        // Response included "Service-Worker-Allowed : /foo"
        navigator.serviceWorker.register("/foo/bar/sw.js", { scope: "/" }).catch(() => {
          console.error("Install failed as the scope is still out of the overriden maximum allowed scope.");
        });
      

Syntax

ABNF for the values of the headers used by the [=/service worker=]'s script resource requests and responses:
      Service-Worker = %x73.63.72.69.70.74 ; "script", case-sensitive
    
Note: The validation of the Service-Worker-Allowed header's values is done by URL parsing algorithm (in Update algorithm) instead of using ABNF.

Acknowledgements

Deep thanks go to Andrew Betts for organizing and hosting a small workshop of like-minded individuals including: Jake Archibald, Jackson Gabbard, Tobie Langel, Robin Berjon, Patrick Lauke, Christian Heilmann. From the clarity of the day's discussions and the use-cases outlined there, much has become possible. Further thanks to Andrew for raising consciousness about the offline problem. His organization of EdgeConf and inclusion of Offline as a persistent topic there has created many opportunities and connections that have enabled this work to progress. Anne van Kesteren has generously lent his encyclopedic knowledge of Web Platform arcana and standards development experience throughout the development of the service worker. This specification would be incomplete without his previous work in describing the real-world behavior of URLs, HTTP Fetch, Promises, and DOM. Similarly, this specification would not be possible without Ian Hickson's rigorous Web Worker spec. Much thanks to him. In no particular order, deep gratitude for design guidance and discussion goes to: Jungkee Song, Alec Flett, David Barrett-Kahn, Aaron Boodman, Michael Nordman, Tom Ashworth, Kinuko Yasuda, Darin Fisher, Jonas Sicking, Jesús Leganés Combarro, Mark Christian, Dave Hermann, Yehuda Katz, François Remy, Ilya Grigorik, Will Chan, Domenic Denicola, Nikhil Marathe, Yves Lafon, Adam Barth, Greg Simon, Devdatta Akhawe, Dominic Cooney, Jeffrey Yasskin, Joshua Bell, Boris Zbarsky, Matt Falkenhagen, Tobie Langel, Gavin Peters, Ben Kelly, Hiroki Nakagawa, Jake Archibald, Josh Soref, Jinho Bang, Yutaka Hirano, Michael(tm) Smith, and isonmad. Jason Weber, Chris Wilson, Paul Kinlan, Ehsan Akhgari, and Daniel Austin have provided valuable, well-timed feedback on requirements and the standardization process. The authors would also like to thank Dimitri Glazkov for his scripts and formatting tools which have been essential in the production of this specification. The authors are also grateful for his considerable guidance. Thanks also to Vivian Cromwell, Greg Simon, Alex Komoroske, Wonsuk Lee, and Seojin Kim for their considerable professional support.