diff --git a/index.html b/index.html index e4b4acb..0937b5f 100644 --- a/index.html +++ b/index.html @@ -56,7 +56,8 @@ }; -
+The Push API enables sending of a push message to a web application via @@ -164,6 +165,534 @@
+ A declarative push message is a [=push message=] whose data is a JSON document + that is understood by the user agent. A user agent opportunistically parses each incoming + [=push message=] to determine if it is a [=declarative push message=] using the + [=declarative push message parser=]. +
++ A [=declarative push message=] allows for the creation and display of a notification + without the involvement of a service worker. Nevertheless, a service worker can still be + involved if desired by the [=application server=]. In such a scenario the declarative + nature of the [=push message=] serves as a backup in case the service worker was evicted + due to storage pressure, for instance. And also provides a more object-oriented approach + to transmitting notification data. +
++ { + "web_push": 8030, + "notification": { + "title": "Ada emailed ‘London’", + "lang": "en-US", + "dir": "ltr", + "body": "Did you hear about the tube strikes?", + "navigate": "https://email.example/message/12" + } + } ++
+ A [=declarative push message=] has the following members: +
+web_push
(required)
+ + An integer that must be 8030. Used to disambiguate a [=declarative push message=] + from other JSON documents. +
+notification
(required)
+
+ A JSON object consisting of the following members, all analogous to Notifications
+ API features, though sometimes with a slightly stricter type. Apart from
+ title
all members are derived from the {{NotificationOptions}}
+ dictionary and to be maintained in tandem. [[NOTIFICATIONS]]
+
title
(required)
+ + A string. +
+dir
+
+ "auto
", "ltr
", or "rtl
".
+
lang
+ + A string that holds a language tag. +
+body
+ + A string. +
+navigate
(required)
+ + A string that holds a URL. +
+tag
+ + A string. +
+image
+ + A string that holds a URL. +
+icon
+ + A string that holds a URL. +
+badge
+ + A string that holds a URL. +
+vibrate
+ + An array of [=/32-bit unsigned integers=]. +
+timestamp
+ + A [=/64-bit unsigned integer=]. +
+renotify
+ + A boolean. +
+silent
+ + A boolean. +
+requireInteraction
+ + A boolean. +
+
+ This is not named require_interaction
for consistency with the
+ {{NotificationOptions}} dictionary.
+
data
+ + Any JSON value. +
+actions
+ + An array of JSON objects consisting of the following members, all derived from + the {{NotificationAction}} dictionary and to be maintained in tandem. +
+action
(required)
+ + A string. +
+title
(required)
+ + A string. +
+navigate
(required)
+ + A string that holds a URL. +
+icon
+ + A string that holds a URL. +
+mutable
+
+ A boolean. When true causes a push
event to be dispatched to a service
+ worker (if any) containing the {{Notification}} object described by the
+ declarative push message.
+
+ A declarative push message parser result is a [=/tuple=] consisting of a + notification (a + [=/notification=]) and a mutable (a boolean). +
++ The declarative push message parser given a [=/byte sequence=] + bytes, [=/origin=] origin, [=/URL=] baseURL, and + {{EpochTimeStamp}} fallbackTimestamp runs these steps. They return failure + or a [=/declarative push message parser result=]. +
++ Let message be the result of [=parse JSON bytes to an Infra + value|parsing JSON bytes to an Infra value=] given bytes. If that throws + an exception, then return failure. +
++ If message is not a [=/map=], then return failure. +
++ If message["`web_push`"] does not [=map/exist=] or is not 8030, then + return failure. +
++ If message["`notification`"] does not [=map/exist=], then return + failure. +
++ Let notificationInput be message["`notification`"]. +
++ If notificationInput is not a [=/map=], then return failure. +
++ If notificationInput["`title`"] does not [=map/exist=] or is not a + string, then return failure. +
++ If notificationInput["`navigate`"] does not [=map/exist=] or is not a + string, then return failure. +
++ Let notificationTitle be notificationInput["`title`"]. +
++ Let notificationOptions be a {{NotificationOptions}} dictionary. +
++ If notificationInput["`dir`"] [=map/exists=] and is "`auto`", "`ltr`", + or "`rtl`", then set notificationOptions["{{NotificationOptions/dir}}"] + to notificationInput["`dir`"]. +
++ If notificationInput["`lang`"] [=map/exists=] and is a string, then set + notificationOptions["{{NotificationOptions/lang}}"] to + notificationInput["`lang`"]. +
++ If notificationInput["`body`"] [=map/exists=] and is a string, then set + notificationOptions["{{NotificationOptions/body}}"] to + notificationInput["`body`"]. +
++ Set notificationOptions["{{NotificationOptions/navigate}}"] to + notificationInput["`navigate`"], [=string/converted=]. +
++ If notificationInput["`tag`"] [=map/exists=] and is a string, then set + notificationOptions["{{NotificationOptions/tag}}"] to + notificationInput["`tag`"]. +
++ If notificationInput["`image`"] [=map/exists=] and is a string, then set + notificationOptions["{{NotificationOptions/image}}"] to + notificationInput["`image`"], [=string/converted=]. +
++ If notificationInput["`icon`"] [=map/exists=] and is a string, then set + notificationOptions["{{NotificationOptions/icon}}"] to + notificationInput["`icon`"], [=string/converted=]. +
++ If notificationInput["`badge`"] [=map/exists=] and is a string, then set + notificationOptions["{{NotificationOptions/badge}}"] to + notificationInput["`badge`"], [=string/converted=]. +
++ If notificationInput["`vibrate`"] [=map/exists=] and is a [=/list=] of + which each [=list/item=] is a [=/32-bit unsigned integer=], then set + notificationOptions["{{NotificationOptions/vibrate}}"] to + notificationInput["`vibrate`"]. +
++ If notificationInput["`timestamp`"] [=map/exists=] and is a [=/64-bit + unsigned integer=], then set + notificationOptions["{{NotificationOptions/timestamp}}"] to + notificationInput["`timestamp`"]. +
++ If notificationInput["`renotify`"] [=map/exists=] and is a boolean, then + set notificationOptions["{{NotificationOptions/renotify}}"] to + notificationInput["`renotify`"]. +
++ If notificationInput["`silent`"] [=map/exists=] and is a boolean, then + set notificationOptions["{{NotificationOptions/silent}}"] to + notificationInput["`silent`"]. +
++ If notificationInput["`requireInteraction`"] [=map/exists=] and is a + boolean, then set + notificationOptions["{{NotificationOptions/requireInteraction}}"] to + notificationInput["`requireInteraction`"]. +
++ If notificationInput["`data`"] [=map/exists=], then set + notificationOptions["{{NotificationOptions/data}}"] to the result of + running convert an Infra value to a JSON-compatible JavaScript value given + notificationInput["`data`"]. +
++ If notificationInput["`actions`"] [=map/exists=] and is a [=/list=]: +
++ Let notificationActions be « ». +
++ [=list/For each=] actionInput of + notificationInput["`actions`"]: +
++ If actionInput["`action`"] does not [=map/exist=] or is not a + string, then [=iteration/continue=]. +
++ If actionInput["`title`"] does not [=map/exist=] or is not a + string, then [=iteration/continue=]. +
++ If actionInput["`navigate`"] does not [=map/exist=] or is not a + string, then [=iteration/continue=]. +
++ Let actionNavigate be actionInput["`navigate`"], + [=string/converted=]. +
++ Let notificationAction be the {{NotificationAction}} dictionary + «[ "{{NotificationAction/action}}" → actionInput["`action`"], + "{{NotificationAction/title}}" → actionInput["`title`"], + "{{NotificationAction/navigate}}" → actionNavigate ]». +
++ If actionInput["`icon`"] [=map/exists=] and is a string, then + set notificationAction["{{NotificationAction/icon}}"] to + actionInput["`icon`"], [=string/converted=]. +
++ [=list/Append=] notificationAction to + notificationActions. +
++ Set notificationOptions["{{NotificationOptions/actions}}"] to + notificationActions. +
++ Let notification be the result of creating a notification given + notificationTitle, notificationOptions, origin, + baseURL, and fallbackTimestamp. If this throws an exception, + then return failure. +
++ If notification's [=notification/navigation URL=] is null, then return + failure. +
++ If the [=notification action/navigation URL=] of any [=/notification action=] of + notification's [=notification/actions=] is null, then return failure. +
++ Let mutable be false. +
++ If message["`mutable`"] [=map/exists=] and + message["`mutable`"] is a boolean, then set mutable to + message["`mutable`"]. +
++ Return (notification, mutable). +
++[SecureContext] partial interface ServiceWorkerRegistration { readonly attribute PushManager pushManager; @@ -978,8 +1507,8 @@};
- {{PushMessageData}} objects have an associated bytes (a [=byte sequence=]), - which is set on creation. + {{PushMessageData}} objects have an associated bytes (a [=byte sequence=]), which is set on creation.
The arrayBuffer() method steps are to return an {{ArrayBuffer}} whose contents @@ -995,11 +1524,11 @@
{{ArrayBuffer}} whose contents are [=this=]'s [=bytes=]. Exceptions thrown during the creation of the {{ArrayBuffer}} object are re-thrown. -
+
The json() method steps are to return the result of [=parse JSON bytes to a JavaScript value|parsing JSON bytes to a JavaScript value=] given [=this=]'s [=bytes=].
-+
The text() method steps are to return the result of running UTF-8 decode on [=this=]'s [=bytes=].
@@ -1010,7 +1539,7 @@
+[Exposed=ServiceWorker, SecureContext] interface PushEvent : ExtendableEvent { constructor(DOMString type, optional PushEventInit eventInitDict = {}); readonly attribute PushMessageData? data; + readonly attribute Notification? notification; + }; + + dictionary PushEventInit : ExtendableEventInit { + PushMessageDataInit? data = null; + Notification? notification = null; }; + + typedef (BufferSource or USVString) PushMessageDataInit;When a constructor of the PushEvent interface, or of an interface that @@ -1082,29 +1619,15 @@
- The data, when getting, returns the value it was initialized with. + The data attribute must return the value it was initialized with.
-- typedef (BufferSource or USVString) PushMessageDataInit; - - dictionary PushEventInit : ExtendableEventInit { - PushMessageDataInit data; - }; -
- The data member contains the data included in the push message when - included and the user agent verified its authenticity. The value will be set to - `null` in all other cases. + The notification attribute must return the value it was initialized with.
+ If the push message payload could not be decrypted for any reason, then + [=acknowledge a push message|acknowledge=] the push message and abort + these steps. +
++ A `push` event is not fired for a push message that was not successfully + decrypted using the key pair associated with the push subscription. +
++ If |bytes| is non-null: +
++ Let |baseURL| be |registration|'s [=service worker registration/scope URL=]. +
++ Let |origin| be |baseURL|'s [=url/origin=]. +
++ Let |fallbackTimestamp| be [=current coarsened wall time=]. +
++ Let |declarativeResult| be the result of running the [=/declarative push message + parser=] given |bytes|, |origin|, |baseURL|, and |fallbackTimestamp|. +
++ If |declarativeResult| is not failure: +
+ Let |notification| be |declarativeResult|'s [=declarative push message parser + result/notification=]. +
++ Set |notification|'s [=notification/service worker registration=] to + |registration|. +
+ Let |notificationShown| be false. +
++ If |declarativeResult|'s [=declarative push message parser result/mutable=] + is true: +
++ Let |result| be the result of [=fire a push event|firing a push event=] + given |registration|, null, and a new {{Notification}} object representing + |notification|. +
++ If |result| is not failure, then set |notificationShown| to |result|'s + [=push event result/notification shown=]. +
++ If |notificationShown| is false, then run the [=notification show steps=] + given |notification|. +
++ [=acknowledge a push message|Acknowledge=] the push message and abort + these steps. +
- A `push` event will not be fired for a push message that was not - successfully decrypted using the key pair associated with the push - subscription. -
+ Let |data| be a new {{PushMessageData}} object whose [=PushMessageData/bytes=] is + |bytes| if |bytes| is non-null; otherwise null. +
++ Let |result| be the result of [=fire a push event|firing a push event=] given + |registration|, |data|, and null. +
++ If result is failure and the same push message has been delivered + to a service worker registration multiple times unsuccessfully, then + [=acknowledge a push message|acknowledge=] the push message. +
++ If result is not failure, then [=acknowledge a push message|acknowledge=] + the push message. +
++ A push event result is a [=/tuple=] consisting of a notification shown (a [=/boolean=]). +
++ To fire a push event given a [=/service worker registration=] |registration|, + {{PushMessageData}} object or null |data|, and a [=/notification=] or null |notification|, + run these steps. They return failure or a [=/push event result=]. +
++ Let |notificationResult| be null. +
+Fire a functional event named "`push`" using PushEvent on @@ -1156,44 +1800,80 @@
Then run the following steps in parallel, with |dispatchedEvent|:
- If the same push message has been delivered to a service worker - registration multiple times unsuccessfully, acknowledge the receipt of the - push message according to [[RFC8030]]. + Wait for all of the promises in the [=ExtendableEvent/extend lifetime promises=] + of |dispatchedEvent| to resolve.
+- Acknowledging the push message causes the push service to stop - delivering the message and to report success to the application server. - This prevents the same push message from being retried by the push - service indefinitely. + If they do not resolve successfully, then set |notificationResult| to failure and + abort these steps.
+- Acknowledging also means that an application server could incorrectly - receive a delivery receipt indicating successful delivery of the push - message. Therefore, multiple rejections SHOULD be permitted before - acknowledging; allowing at least three attempts is recommended. + Set |notificationResult| to true if + {{ServiceWorkerRegistration/showNotification()}} has been invoked; otherwise + false.
+ Wait for |notificationResult| to be non-null. +
++ If |notificationResult| is failure, then return failure. +
++ [=/Assert=]: |notificationResult| is a [=/boolean=]. +
++ Return (|notificationResult|). +
++ To acknowledge a push message given a push message + pushMessage means to acknowledge the receipt of pushMessage + according to [[RFC8030]]. +
++ Acknowledging the push message causes the push service to stop delivering + the message and to report success to the application server. This prevents the + same push message from being retried by the push service indefinitely. +
++ Acknowledging also means that an application server could incorrectly receive a + delivery receipt indicating successful delivery of the push message. Therefore, + multiple rejections SHOULD be permitted before acknowledging; allowing at least three + attempts is recommended. +
+[Exposed=ServiceWorker, SecureContext] interface PushSubscriptionChangeEvent : ExtendableEvent { constructor(DOMString type, optional PushSubscriptionChangeEventInit eventInitDict = {}); @@ -1255,7 +1935,7 @@
PushSubscriptionChangeEventInit Interface
-+dictionary PushSubscriptionChangeEventInit : ExtendableEventInit { PushSubscription newSubscription = null; PushSubscription oldSubscription = null;