diff --git a/index.html b/index.html index 295228c..cb22b62 100644 --- a/index.html +++ b/index.html @@ -170,9 +170,19 @@

A push subscription is a message delivery context established between the - user agent and the push service on behalf of a web application. Each - push subscription is associated with a service worker registration and a - service worker registration has at most one push subscription. + user agent and the push service on behalf of a web application. +

+

+ A [=push subscription=] has an associated scope, which + is a [=/URL=]. +

+

+ A [=push subscription=] is considered to have a window-accessible scope when its [=push subscription/scope=] is + a [=/list=] of [=list/size=] 1 and [=push subscription/scope=][0] is the empty string. +

+

+ I.e., the [=url/path=] component of the [=/URL=] serializes as "`/`".

A push subscription has an associated push endpoint. It MUST be the @@ -192,12 +202,9 @@

creating the push subscription.

- If the user agent has to change the keys for any reason, it MUST fire the - "`pushsubscriptionchange`" event with the service worker registration - associated with the push subscription as |registration|, a {{PushSubscription}} - instance representing the push subscription having the old keys as - |oldSubscription| and a {{PushSubscription}} instance representing the push - subscription having the new keys as |newSubscription|. + If the user agent has to change the keys of a [=push subscription=] for any reason + and the [=push subscription=]'s [=associated service worker registration=] is non-null, + it MUST [=refresh=] the [=push subscription=].

To create a push subscription, given an {{PushSubscriptionOptionsInit}} @@ -242,17 +249,41 @@

- Subscription Refreshes + Relationship to service worker registrations +

+

+ A [=push subscription=]'s associated service worker registration is the + [=service worker registration=] whose [=service worker registration/scope URL=] + [=URL/equals=] the [=push subscription=]'s [=push subscription/scope=], if any; + otherwise null. +

+

+ A [=push subscription=]'s [=associated service worker registration=] can only be null + when it has a [=push subscription/window-accessible scope=]. +

+

+ And vice versa, a [=service worker registration=]'s associated push + subscription is the [=push subscription=] whose [=push subscription/scope=] + [=URL/equals=] the [=service worker registration=]'s [=service worker + registration/scope URL=], if any; otherwise null. +

+
+
+

+ Subscription refreshes

A user agent or push service MAY choose to refresh a push - subscription at any time, for example because it has reached a certain age. + subscription whose [=associated service worker registration=] is non-null at any + time, for example because it has reached a certain age.

When this happens, the user agent MUST run the steps to create a push subscription given the PushSubscriptionOptions that were provided for - creating the current push subscription. The new push subscription MUST - have a key pair that's different from the original subscription. + creating the current push subscription, and set the new [=push subscription=]'s + [=push subscription/scope=] to the original subscription's [=push subscription/scope=]. + The new push subscription MUST have a key pair that's different from the + original subscription.

When successful, user agent then MUST fire the "`pushsubscriptionchange`" @@ -279,7 +310,7 @@

- Subscription Deactivation + Subscription deactivation

When a push subscription is deactivated, both @@ -288,13 +319,13 @@

delivered.

- A push subscription is deactivated when its associated service worker - registration is unregistered, though a push subscription MAY be - deactivated earlier. + A push subscription without a [=push subscription/window-accessible scope=] is + deactivated when its associated service worker registration is + unregistered, though a push subscription MAY be deactivated earlier.

- A push subscription is removed when service worker registration is - cleared. + A push subscription without a [=push subscription/window-accessible scope=] is + removed when service worker registration is cleared.

@@ -520,23 +551,23 @@

-

- Extensions to the `ServiceWorkerRegistration` Interface +

+ `PushManagerAttribute` mixin

- The Service Worker specification defines a {{ServiceWorkerRegistration}} interface - [[SERVICE-WORKERS]], which this specification extends. + This specifications extends the {{Window}} and {{ServiceWorkerRegistration}} objects + through the {{PushManagerAttribute}} mixin. [[HTML]] [[SERVICE-WORKERS]]

-
+      
         [SecureContext]
-        partial interface ServiceWorkerRegistration {
+        interface mixin PushManagerAttribute {
           readonly attribute PushManager pushManager;
         };
+        Window includes PushManagerAttribute;
+        ServiceWorkerRegistration includes PushManagerAttribute;
       

- The pushManager attribute exposes a {{PushManager}}, which has an associated - service worker registration represented by the {{ServiceWorkerRegistration}} on - which the attribute is exposed. + The pushManager attribute exposes a {{PushManager}}.

@@ -578,7 +609,23 @@

  • Let |global| be [=this=]' [=relevant global object=].
  • -
  • Return |promise| and continue [=in parallel=]. +
  • Let |scope| be null. +
  • +
  • Let |registration| be null. +
  • +
  • If [=this=] is a {{Window}} object, then set |scope| to the result of running the + [=basic URL parser=] given "`/`" and |global|'s associated Document's + [=Document/URL=]. +
  • +
  • Otherwise: +
      +
    1. [=/Assert=]: [=this=] is a {{ServiceWorkerRegistration}} object. +
    2. +
    3. Set |registration| to [=this=]'s associated [=service worker registration=]. +
    4. +
    +
  • +
  • Run these steps [=in parallel=]: -
  • -
  • If the |options| argument has a {{PushSubscriptionOptionsInit/userVisibleOnly}} value - set to `false` and the user agent requires it to be `true`, [=queue a global task=] on the - [=networking task source=] using |global| to [=reject=] |promise| {{"NotAllowedError"}} - {{DOMException}} -
  • -
  • If the |options| argument does not include a non-null value for the - {{PushSubscriptionOptionsInit/applicationServerKey}} member, and the push service - requires one to be given, [=queue a global task=] on the [=networking task source=] using - |global| to [=reject=] |promise| with a {{"NotSupportedError"}} {{DOMException}}. -
  • -
  • If the |options| argument includes a non-null value for the - {{PushSubscriptionOptions/applicationServerKey}} attribute, run the following sub-steps:
      -
    1. If |options|'s {{PushSubscriptionOptionsInit/applicationServerKey}} is a - {{DOMString}}, set its value to an {{ArrayBuffer}} containing the sequence of octets - that result from decoding |options|'s - {{PushSubscriptionOptionsInit/applicationServerKey}} using the base64url encoding - [[RFC7515]]. +
    2. If the |options| argument has a {{PushSubscriptionOptionsInit/userVisibleOnly}} + value set to `false` and the user agent requires it to be `true`, [=queue a global + task=] on the [=networking task source=] using |global| to [=reject=] |promise| + {{"NotAllowedError"}} {{DOMException}}
    3. -
    4. If decoding fails, [=queue a global task=] on the [=networking task source=] using - |global| to [=reject=] |promise| with an {{"InvalidCharacterError"}} {{DOMException}} - and terminate these steps. +
    5. If the |options| argument does not include a non-null value for the + {{PushSubscriptionOptionsInit/applicationServerKey}} member, and the push + service requires one to be given, [=queue a global task=] on the [=networking task + source=] using |global| to [=reject=] |promise| with a {{"NotSupportedError"}} + {{DOMException}}.
    6. -
    7. Ensure that |options|'s {{PushSubscriptionOptionsInit/applicationServerKey}} - describes a valid point on the P-256 curve. If its value is invalid, [=queue a global - task=] on the [=networking task source=] using |global| to [=reject=] |promise| with an - {{"InvalidAccessError"}} {{DOMException}} and terminate these steps. +
    8. If the |options| argument includes a non-null value for the + {{PushSubscriptionOptions/applicationServerKey}} attribute: +
        +
      1. If |options|'s {{PushSubscriptionOptionsInit/applicationServerKey}} is a + {{DOMString}}, set its value to an {{ArrayBuffer}} containing the sequence of + octets that result from decoding |options|'s + {{PushSubscriptionOptionsInit/applicationServerKey}} using the base64url encoding + [[RFC7515]]. +
      2. +
      3. If decoding fails, [=queue a global task=] on the [=networking task source=] + using |global| to [=reject=] |promise| with an {{"InvalidCharacterError"}} + {{DOMException}} and terminate these steps. +
      4. +
      5. Ensure that |options|'s {{PushSubscriptionOptionsInit/applicationServerKey}} + describes a valid point on the P-256 curve. If its value is invalid, [=queue a + global task=] on the [=networking task source=] using |global| to [=reject=] + |promise| with an {{"InvalidAccessError"}} {{DOMException}} and terminate these + steps. +
      6. +
    9. -
    -
  • -
  • Let |registration:ServiceWorkerRegistration| be [=this=]'s associated service worker - registration. -
  • -
  • If |registration|'s [=service worker registration/active worker=] is null, [=queue a - global task=] on the [=networking task source=] using |global| to [=reject=] |promise| with - an {{"InvalidStateError"}} {{DOMException}} and terminate these steps. -
  • -
  • Let |permission| be [=request permission to use=] "push". -
  • -
  • If |permission| is {{PermissionState/"denied"}}, [=queue a global task=] on the [=user - interaction task source=] using |global| to [=reject=] |promise| with a - {{"NotAllowedError"}} {{DOMException}} and terminate these steps. -
  • -
  • If |registration| has a push subscription: -
      -
    1. Let |subscription| be the result of obtaining |registration|'s push - subscription. If there is an error, [=queue a global task=] on the [=networking - task source=] using |global| to [=reject=] |promise| with an {{"AbortError"}} - {{DOMException}} and terminate these steps. +
    2. Let |subscription| be null. +
    3. +
    4. If |scope| is non-null: +
        +
      1. If there is a [=push subscription=] with a [=push + subscription/window-accessible scope=] whose [=push subscription/scope=] + [=URL/equals=] |scope|, then set |subscription| to that [=push subscription=]. +
      2. +
    5. -
    6. Compare the |options| argument with the `options` attribute of |subscription|. The - contents of {{BufferSource}} values are compared for equality rather than - [=ECMAScript/reference record|reference=]. +
    7. Otherwise: +
        +
      1. [=/Assert=]: |registration| is non-null. +
      2. +
      3. If |registration|'s [=service worker registration/active worker=] is null, + [=queue a global task=] on the [=networking task source=] using |global| to + [=reject=] |promise| with an {{"InvalidStateError"}} {{DOMException}} and terminate + these steps. +
      4. +
      5. If |registration|'s [=associated push subscription=] is non-null, then set + |subscription| to |registration|'s [=associated push subscription=]. +
      6. +
      7. Set |scope| to |registration|'s [=service worker registration/scope URL=]. +
      8. +
    8. -
    9. If any attribute on |options| contains a different value to that stored for - |subscription|, then [=queue a global task=] on the [=networking task source=] using - |global| to [=reject=] |promise| with an {{"InvalidStateError"}} {{DOMException}} and - terminate these steps. +
    10. Let |permission| be [=request permission to use=] "push".
    11. -
    12. When the request has been completed, [=queue a global task=] on the [=networking - task source=] using |global| to [=resolve=] |promise| with |subscription| and terminate - these steps. +
    13. If |permission| is {{PermissionState/"denied"}}, [=queue a global task=] on the + [=user interaction task source=] using |global| to [=reject=] |promise| with a + {{"NotAllowedError"}} {{DOMException}} and terminate these steps. +
    14. +
    15. If |subscription| is non-null: +
        +
      1. If there is an error with |subscription|, then [=queue a global task=] on the + [=networking task source=] using |global| to [=reject=] |promise| with an + {{"AbortError"}} {{DOMException}} and terminate these steps. +
      2. +
      3. Compare the |options| argument with the `options` attribute of |subscription|. + The contents of {{BufferSource}} values are compared for equality rather than + [=ECMAScript/reference record|reference=]. +
      4. +
      5. If any attribute on |options| contains a different value to that stored for + |subscription|, then [=queue a global task=] on the [=networking task source=] + using |global| to [=reject=] |promise| with an {{"InvalidStateError"}} + {{DOMException}} and terminate these steps. +
      6. +
      7. [=Queue a global task=] on the [=networking task source=] using |global| to + [=resolve=] |promise| with |subscription| and terminate these steps. +
      8. +
      +
    16. +
    17. [=/Assert=]: |subscription| is null and |scope| is a [=/URL=]. +
    18. +
    19. Set |subscription| to the result of trying to [=create a push subscription=] with + |options|. If creating the subscription [=exception/throws=] an [=exception=], [=queue + a global task=] on the [=networking task source=] using |global| to [=reject=] + |promise| with a that [=exception=] and terminate these steps. +
    20. +
    21. Set |subscription|'s [=push subscription/scope=] to |scope|. +
    22. +
    23. [=Queue a global task=] on the [=networking task source=] using |global| to + [=resolve=] |promise| with a {{PushSubscription}} corresponding to |subscription|.
  • -
  • Let |subscription| be the result of trying to [=create a push subscription=] with - |options|. If creating the subscription [=exception/throws=] an [=exception=], [=queue a - global task=] on the [=networking task source=] using |global| to [=reject=] |promise| with - a that [=exception=] and terminate these these steps. -
  • -
  • Otherwise, [=queue a global task=] on the [=networking task source=] using |global| to - [=resolve=] |promise| with a {{PushSubscription}} providing the details of the new - |subscription|. +
  • Return |promise|.
  • @@ -671,17 +744,54 @@

    1. Let |promise| be a new promise.
    2. -
    3. Return |promise| and continue the following steps asynchronously. +
    4. Let |global| be [=this=]'s [=relevant global object=].
    5. -
    6. If the Service Worker is not subscribed, resolve |promise| with null. +
    7. Let |windowScope| be null.
    8. -
    9. Retrieve the push subscription associated with the Service Worker. +
    10. Let |registration| be null.
    11. -
    12. If there is an error, reject |promise| with a {{DOMException}} whose name is - {{"AbortError"}} and terminate these steps. +
    13. If [=this=] is a {{Window}} object, then set |windowScope| to the result of running the + [=basic URL parser=] given "`/`" and [=this=]'s associated Document's + [=Document/URL=]. +
    14. +
    15. Otherwise: +
        +
      1. [=/Assert=]: [=this=] is a {{ServiceWorkerRegistration}} object. +
      2. +
      3. Set |registration| to [=this=]'s associated [=service worker registration=]. +
      4. +
      +
    16. +
    17. Run these steps [=/in parallel=]: +
        +
      1. Let |subscription| be null. +
      2. +
      3. If |windowScope| is non-null: +
          +
        1. If there is a [=push subscription=] whose [=push subscription/scope=] is + |windowScope|, then set |subscription| to that [=push subscription=]. +
        2. +
        +
      4. +
      5. Otherwise: +
          +
        1. [=/Assert=]: |registration| is non-null. +
        2. +
        3. If |registration|'s [=associated push subscription=] is non-null, then set + |subscription| to |registration|'s [=associated push subscription=]. +
        4. +
        +
      6. +
      7. If [=subscription=] is null, then resolve |promise| with null. +
      8. +
      9. If there is an error with |subscription|, reject |promise| with a {{DOMException}} + whose name is {{"AbortError"}} and terminate these steps. +
      10. +
      11. Resolve |promise| with a {{PushSubscription}} corresponding to |subscription|. +
      12. +
    18. -
    19. When the request has been completed, resolve |promise| with a {{PushSubscription}} - providing the details of the retrieved push subscription. +
    20. Return |promise|.