diff --git a/source b/source index 9f6bfcc10b4..87002be6f20 100644 --- a/source +++ b/source @@ -2793,6 +2793,21 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute +
Streams
+ +
+

The following terms are defined in Streams: STREAMS

+ + +
+ +
The No-Vary-Search HTTP Response Header Field
@@ -2972,6 +2987,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
  • long
  • object
  • Promise
  • +
  • Uint8Array
  • Uint8ClampedArray
  • unrestricted double
  • unsigned long
  • @@ -7439,6 +7455,11 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute though unresolvable, about: URL, that is used as an identifier for kinds of media tracks. ABOUT

    +

    This specification defines the URL about:event-stream as a reserved, + though unresolvable, about: URL, that is used as the URL of EventSource objects created via fromReadableStream(). ABOUT

    +

    This specification defines the URL about:srcdoc as a reserved, though unresolvable, about: URL, that is used as the URL of constructor(USVString url, optional EventSourceInit eventSourceInitDict = {}); + static EventSource fromReadableStream(ReadableStream stream); + readonly attribute USVString url; readonly attribute boolean withCredentials; + readonly attribute DOMString lastEventId; + readonly attribute unsigned long long reconnectionTime; // ready state const unsigned short CONNECTING = 0; @@ -128394,6 +128419,7 @@ interface EventSource : EventTarget { attribute EventHandler onmessage; attribute EventHandler onerror; undefined close(); + undefined reset(); }; dictionary EventSourceInit { @@ -128417,10 +128443,15 @@ dictionary EventSourceInit {

  • A last event ID string. This must initially be the empty string.

  • + +
  • A stream reader (a + ReadableStreamDefaultReader or null), initially null.

  • -

    Apart from url these are not currently exposed on - the EventSource object.

    +

    Apart from url, last event ID string, and reconnection time, these are not currently + exposed on the EventSource object.

    @@ -128439,26 +128470,56 @@ dictionary EventSourceInit { connection requests to url to "include".

    +
    source = EventSource.fromReadableStream(stream)
    + +
    +

    Creates a new EventSource that reads from the given + ReadableStream. The stream cannot be locked. + The EventSource will parse the stream as a text/event-stream + format event stream.

    + +

    No network connection is managed and no reconnection is attempted when the + stream closes or errors.

    +
    +
    source.close()

    Aborts any instances of the fetch algorithm started for this EventSource object, and sets the readyState attribute to CLOSED.

    + data-x="dom-EventSource-CLOSED">CLOSED. If the source was created from a + ReadableStream, the stream is also canceled.

    +
    + +
    source.reset()
    + +
    +

    Discards any partially received event data in the parser's internal buffers. This is useful + when using fromReadableStream() with a + TransformStream to implement reconnection, as a broken connection may leave an + incomplete event in the buffer. Calling this between reconnections ensures the parser starts + from a clean state.

    + +

    Has no effect on EventSource objects that were not created via fromReadableStream().

    source.url

    Returns the URL providing the event - stream.

    + stream. Returns "about:event-stream" when the source was created from a + ReadableStream.

    source.withCredentials

    Returns true if the credentials mode for connection requests to the URL providing the event - stream is set to "include", and false otherwise.

    + stream is set to "include", and false otherwise. Always returns + false when the source was created from a ReadableStream.

    source.readyState
    @@ -128467,6 +128528,21 @@ dictionary EventSourceInit {

    Returns the state of this EventSource object's connection. It can have the values described below.

    + +
    source.lastEventId
    + +
    +

    Returns the last event ID string that was set by the server via the id field, or the empty string if none have been received.

    +
    + +
    source.reconnectionTime
    + +
    +

    Returns the reconnection time in milliseconds. This is initially an + implementation-defined value, and can be updated by the server via the retry field.

    +
    @@ -128555,6 +128631,37 @@ dictionary EventSourceInit {
    +
    +

    The static fromReadableStream(stream) + method, when invoked, must run these steps:

    + +
      +
    1. Let reader be ? AcquireReadableStreamDefaultReader(stream).

    2. + +
    3. Let ev be a new EventSource object.

    4. + +
    5. Set ev's url to the URL + record about:event-stream.

    6. + +
    7. Set ev's stream reader + to reader.

    8. + +
    9. Announce the connection.

    10. + +
    11. +

      In parallel, interpret + reader line by line.

      + +

      When the stream signals done or an error: fail the connection.

      +
    12. + +
    13. Return ev.

    14. +
    +
    + +
    +

    The url attribute's getter must return the serialization of @@ -128568,6 +128675,20 @@ dictionary EventSourceInit { false.

    +
    +

    The lastEventId attribute's getter must return this + EventSource object's last event ID + string.

    +
    + +
    +

    The reconnectionTime attribute's getter must + return this EventSource object's reconnection time.

    +
    +

    The readyState attribute represents the state of the connection. It can have the following values:

    @@ -128600,11 +128721,40 @@ dictionary EventSourceInit {

    The close() - method must abort any instances of the fetch algorithm started - for this EventSource object, and must set the readyState attribute to CLOSED.

    + method must run the following steps:

    + +
      +
    1. Abort any instances of the fetch algorithm started + for this EventSource object.

    2. + +
    3. Let reader be this EventSource object's stream reader.

    4. + +
    5. If reader is not null, then + ! ReadableStreamCancel(reader.[[stream]], undefined).

    6. + +
    7. Set the readyState attribute to CLOSED.

    8. +
    + +
    + +
    +

    The reset() + method must run the following steps:

    + +
      +
    1. If this EventSource object's stream reader is null, then return.

    2. + +
    3. Act as if the end of the file has been reached for the purposes of interpreting the event stream.

    4. + +
    5. Resume interpreting subsequent input from this + EventSource object's stream + reader.

    6. +
    @@ -129044,6 +129194,52 @@ data: test +
    +

    The fromReadableStream() method + allows applications to handle networking and reconnection logic themselves, while still using + EventSource for event stream parsing. The following example uses a + TransformStream to allow multiple fetch() responses to be piped + through to a single EventSource:

    + +
    const url = "https://example.com/events";
    +const ts = new TransformStream();
    +const source = EventSource.fromReadableStream(ts.readable);
    +source.onmessage = (event) => {
    +  console.log("Received:", event.data);
    +};
    +
    +async function connect() {
    +  const headers = { "Authorization": "Bearer token123" };
    +  if (source.lastEventId) {
    +    headers["Last-Event-ID"] = source.lastEventId;
    +  }
    +  try {
    +    const response = await fetch(url, { headers });
    +    await response.body.pipeTo(ts.writable, { preventClose: true });
    +  } catch (e) {
    +    // Discard any incomplete event left in the parser's buffer.
    +    source.reset();
    +  }
    +
    +  // The fetch stream has ended, but ts.writable is still open, so
    +  // ts.readable does not signal done and the EventSource stays open.
    +  // If close() was called, stop reconnecting:
    +  if (source.readyState === EventSource.CLOSED) return;
    +  // Wait and reconnect:
    +  const delay = source.reconnectionTime;
    +  setTimeout(connect, delay);
    +}
    +
    +connect();
    + +

    Using { preventClose: true } in the pipeTo() call prevents the TransformStream's writable + side from being closed when the fetch stream ends. This keeps the readable side — and therefore + the EventSource — alive between reconnections, preserving all registered event + listeners.

    +
    + +

    Authoring notes

    Legacy proxy servers are known to, in certain cases, drop HTTP connections after a short @@ -129149,17 +129345,40 @@ data: test

    If a user agent is to forcibly close an EventSource object (this happens when a Document object goes away - permanently), the user agent must abort any instances of the fetch algorithm started for this EventSource object, - and must set the readyState attribute to CLOSED.

    + permanently), the user agent must run the following steps:

    + + +
      +
    1. Abort any instances of the fetch algorithm started + for this EventSource object.

    2. + +
    3. Let reader be this EventSource object's stream reader.

    4. + +
    5. If reader is not null, then + ! ReadableStreamCancel(reader.[[stream]], undefined).

    6. + +
    7. Set the readyState attribute to CLOSED.

    8. +

    If an EventSource object is garbage collected while its connection is still open, - the user agent must abort any instance of the fetch algorithm - opened by this EventSource.

    + the user agent must run the following steps:

    + + +
      +
    1. Abort any instance of the fetch algorithm opened by + this EventSource.

    2. + +
    3. Let reader be this EventSource object's stream reader.

    4. + +
    5. If reader is not null, then + ! ReadableStreamCancel(reader.[[stream]], undefined).

    6. +
    @@ -156699,6 +156918,9 @@ INSERT INTERFACES HERE
    [STORAGE]
    Storage, A. van Kesteren. WHATWG.
    +
    [STREAMS]
    +
    Streams, A. van Kesteren, D. Denicola, R. Dahl, T. Cargill. WHATWG.
    +
    [SVG]
    Scalable Vector Graphics (SVG) 2, N Andronikos, R. Atanassov, T. Bah, B. Birtles, B. Brinza, C. Concolato, E. Dahlström, C. Lilley, C. McCormack, D. Schepers, R. Schwerdtfeger, D. Storey, S. Takagi, J. Watt. W3C.