Repository: tserkov/vue-sse
Branch: v2
Commit: addad93db116
Files: 25
Total size: 184.5 KB
Directory structure:
gitextract_pn7ugql7/
├── .babelrc
├── .editorconfig
├── .eslintrc.json
├── .gitignore
├── .prettierrc
├── LICENSE.md
├── README.md
├── dist/
│ ├── vue-sse.common.js
│ ├── vue-sse.esm.browser.js
│ ├── vue-sse.esm.js
│ ├── vue-sse.js
│ └── vue-sse.mjs
├── jest.config.js
├── package.json
├── rollup.config.js
├── src/
│ ├── index.cjs.js
│ ├── index.js
│ ├── sse-client.js
│ └── sse-manager.js
├── test/
│ ├── .eslintrc.json
│ ├── setup.js
│ ├── sse-client.spec.js
│ └── sse-manager.spec.js
└── types/
├── index.d.ts
└── vue.d.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .babelrc
================================================
{
"presets": ["@babel/preset-env"]
}
================================================
FILE: .editorconfig
================================================
root = true
[*]
end_of_line = lf
insert_final_newline = true
[*.js]
charset = utf-8
indent_style = space
indent_size = 2
================================================
FILE: .eslintrc.json
================================================
{
"root": true,
"extends": [
"plugin:vue/recommended"
]
}
================================================
FILE: .gitignore
================================================
node_modules
/lib
# SublimeText
*.sublime-project
*.sublime-workspace
================================================
FILE: .prettierrc
================================================
{
"printWidth": 120,
"trailingComma": "all",
"singleQuote": true
}
================================================
FILE: LICENSE.md
================================================
MIT License
Copyright (c) 2021 James Churchard
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# VueSSE
[]()
[]()
VueSSE enables effortless use of [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) by providing a high-level interface to an underlying [EventSource](https://developer.mozilla.org/en-US/docs/Web/API/EventSource).
## Install
```bash
# npm
npm install --save vue-sse
# OR yarn
yarn add vue-sse
```
```javascript
// in main.js
import VueSSE from 'vue-sse';
// using defaults
Vue.use(VueSSE);
// OR specify custom defaults (described below)
Vue.use(VueSSE, {
format: 'json',
polyfill: true,
url: '/my-events-server',
withCredentials: true,
});
```
## Quickstart
```js
this.$sse.create('/my-events-server')
.on('message', (msg) => console.info('Message:', msg))
.on('error', (err) => console.error('Failed to parse or lost connection:', err))
.connect()
.catch((err) => console.error('Failed make initial connection:', err));
```
## Usage
Clients can be created from the Vue object via `Vue.$sse.create(...)` or from within components via `this.$sse.create(...)`
All of the following are valid calls to create a client:
- `this.$sse.create('/your-events-endpoint')` to connect to the specified URL without specifying any config
- `this.$sse.create({ url: '/your-events-endpoint', format: 'json' })` will automatically parse incoming messages as JSON
- `this.$sse.create({ url: '/your-events-endpoint', withCredentials: true })` will set CORS on the request
Once you've created a client, you can add handlers before or after calling `connect()`, which must be called.
## Configuration
`$sse.create` accepts the following config options when installing VueSSE via `Vue.use` and when calling `$sse.create`.
| Option | Type | Description | Default |
| --- | --- | --- | -- |
| format | `"plain"` \| `"json"` \| `(event: MessageEvent) => any` | Specify pre-processing, if any, to perform on incoming messages. Messages that fail formatting will emit an error. | `"plain"` |
| url | `string` | The location of the SSE server. | `""` |
| withCredentials | `boolean` | Indicates if CORS should be set to include credentials. | `false` |
| polyfill | `boolean` | Include an [EventSource polyfill](https://github.com/Yaffle/EventSource) for older browsers. | `false` |
| forcePolyfill | `boolean` | Forces the [EventSource polyfill](https://github.com/Yaffle/EventSource) to always be used over native. | `false` |
| polyfillOptions | `object` | Custom options to provide to the [EventSource polyfill](https://github.com/Yaffle/EventSource#custom-headers). Only used if `forcePolyfill` is true. | `null` |
If `$sse.create` is called with a string, it must be the URL to the SSE server.
## Methods
Once you've successfully connected to an events server, a client will be returned with the following methods:
| Name | Description |
| --- | --- |
| __connect__(): _Promise<SSEClient>_ | Connects to the server. __Must be called.__ |
| __on__(event: _string_, (data: _any_) => _void_): _SSEClient_ | Adds an event-specific listener to the event stream. The handler function receives the message as its argument (formatted if a format was specified), and the original underlying Event. For non-event messages, specify `""` or `"message"` as the event. |
| __once__(event: _string_, (data: _any_) => _void_): _SSEClient_ | Same as `on(...)`, but only triggered once. |
| __off__(event: _string_, (data: _any_ => _void_)): _SSEClient_ | Removes the given handler from the event stream. The function must be the same as provided to `on`/`once`. |
| __on__('error', (err) => void): _SSEClient_ | Allows your application to handle any errors thrown, such as loss of server connection and pre-processing errors. |
| __disconnect__(): _void_ | Closes the connection. The client can be re-used by calling `connect()`. __Must be called!__ (Usually, in the `beforeDestroy` of your component.) |
## Properties
| Name | Type | Description |
| --- | --- | --- |
| source | `EventSource` | Returns the underlying EventSource. |
## Cleanup
Every connection must be disconnected when the component is destroyed. There are two ways to achieve this:
1. Call `disconnect()` on the client during `beforeDestroy`, or
2. Add the following option to your component to have them automatically closed for you during `beforeDestroy`:
```js
export default {
name: 'my-component',
data() { /* ... */ },
// ...
sse: {
cleanup: true,
},
// ...
}
```
## Vue 3
This plugin works the same in both Vue 2 and 3. The Composition API is not yet supported.
## Example
An example project is provided at [tserkov/vue-sse-example](https://github.com/tserkov/vue-sse-example).
### Kitchen Sink
```html
<template>
<div>
<p
v-for="(message, idx) in messages"
:key="idx"
>{{ message }}</p>
</div>
</template>
<script>
// We store the reference to the SSE client out here
// so we can access it from other methods
let sseClient;
export default {
name: 'sse-test',
data() {
return {
messages: [],
};
},
mounted() {
sseClient = this.$sse.create({
url: '/your-events-server',
format: 'json',
withCredentials: true,
polyfill: true,
});
// Catch any errors (ie. lost connections, etc.)
sseClient.on('error', (e) => {
console.error('lost connection or failed to parse!', e);
// If this error is due to an unexpected disconnection, EventSource will
// automatically attempt to reconnect indefinitely. You will _not_ need to
// re-add your handlers.
});
// Handle messages without a specific event
sseClient.on('message', this.handleMessage);
// Handle 'chat' messages
sseClient.on('chat', this.handleChat);
// Handle once for a ban message
sseClient.once('ban', this.handleBan);
sseClient.connect()
.then(sse => {
console.log('We\'re connected!');
// Unsubscribes from event-less messages after 7 seconds
setTimeout(() => {
sseClient.off('message', this.handleMessage);
console.log('Stopped listening to event-less messages!');
}, 7000);
// Unsubscribes from chat messages after 14 seconds
setTimeout(() => {
sse.off('chat', this.handleChat);
console.log('Stopped listening to chat messages!');
}, 14000);
})
.catch((err) => {
// When this error is caught, it means the initial connection to the
// events server failed. No automatic attempts to reconnect will be made.
console.error('Failed to connect to server', err);
});
},
methods: {
handleBan(banMessage) {
// Note that we can access properties of message, since our parser is set to JSON
// and the hypothetical object has a `reason` property.
this.messages.push(`You've been banned! Reason: ${banMessage.reason}`);
},
handleChat(message) {
// Note that we can access properties of message, since our parser is set to JSON
// and the hypothetical object has these properties.
this.messages.push(`${message.user} said: ${message.text}`);
},
handleMessage(message, lastEventId) {
console.warn('Received a message w/o an event!', message, lastEventId);
},
},
beforeDestroy() {
// Make sure to close the connection with the events server
// when the component is destroyed, or we'll have ghost connections!
sseClient.disconnect();
// Alternatively, we could have added the `sse: { cleanup: true }` option to our component,
// and the SSEManager would have automatically disconnected during beforeDestroy.
},
};
</script>
```
================================================
FILE: dist/vue-sse.common.js
================================================
/*!
* vue-sse v2.5.0
* (c) 2021 James Churchard
* @license MIT
*/
'use strict';
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn) {
var module = { exports: {} };
return fn(module, module.exports), module.exports;
}
/** @license
* eventsource.js
* Available under MIT License (MIT)
* https://github.com/Yaffle/EventSource/
*/
var eventsource = createCommonjsModule(function (module, exports) {
/*jslint indent: 2, vars: true, plusplus: true */
/*global setTimeout, clearTimeout */
(function (global) {
var setTimeout = global.setTimeout;
var clearTimeout = global.clearTimeout;
var XMLHttpRequest = global.XMLHttpRequest;
var XDomainRequest = global.XDomainRequest;
var ActiveXObject = global.ActiveXObject;
var NativeEventSource = global.EventSource;
var document = global.document;
var Promise = global.Promise;
var fetch = global.fetch;
var Response = global.Response;
var TextDecoder = global.TextDecoder;
var TextEncoder = global.TextEncoder;
var AbortController = global.AbortController;
if (typeof window !== "undefined" && !("readyState" in document) && document.body == null) { // Firefox 2
document.readyState = "loading";
window.addEventListener("load", function (event) {
document.readyState = "complete";
}, false);
}
if (XMLHttpRequest == null && ActiveXObject != null) { // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest_in_IE6
XMLHttpRequest = function () {
return new ActiveXObject("Microsoft.XMLHTTP");
};
}
if (Object.create == undefined) {
Object.create = function (C) {
function F(){}
F.prototype = C;
return new F();
};
}
if (!Date.now) {
Date.now = function now() {
return new Date().getTime();
};
}
// see #118 (Promise#finally with polyfilled Promise)
// see #123 (data URLs crash Edge)
// see #125 (CSP violations)
// see pull/#138
// => No way to polyfill Promise#finally
if (AbortController == undefined) {
var originalFetch2 = fetch;
fetch = function (url, options) {
var signal = options.signal;
return originalFetch2(url, {headers: options.headers, credentials: options.credentials, cache: options.cache}).then(function (response) {
var reader = response.body.getReader();
signal._reader = reader;
if (signal._aborted) {
signal._reader.cancel();
}
return {
status: response.status,
statusText: response.statusText,
headers: response.headers,
body: {
getReader: function () {
return reader;
}
}
};
});
};
AbortController = function () {
this.signal = {
_reader: null,
_aborted: false
};
this.abort = function () {
if (this.signal._reader != null) {
this.signal._reader.cancel();
}
this.signal._aborted = true;
};
};
}
function TextDecoderPolyfill() {
this.bitsNeeded = 0;
this.codePoint = 0;
}
TextDecoderPolyfill.prototype.decode = function (octets) {
function valid(codePoint, shift, octetsCount) {
if (octetsCount === 1) {
return codePoint >= 0x0080 >> shift && codePoint << shift <= 0x07FF;
}
if (octetsCount === 2) {
return codePoint >= 0x0800 >> shift && codePoint << shift <= 0xD7FF || codePoint >= 0xE000 >> shift && codePoint << shift <= 0xFFFF;
}
if (octetsCount === 3) {
return codePoint >= 0x010000 >> shift && codePoint << shift <= 0x10FFFF;
}
throw new Error();
}
function octetsCount(bitsNeeded, codePoint) {
if (bitsNeeded === 6 * 1) {
return codePoint >> 6 > 15 ? 3 : codePoint > 31 ? 2 : 1;
}
if (bitsNeeded === 6 * 2) {
return codePoint > 15 ? 3 : 2;
}
if (bitsNeeded === 6 * 3) {
return 3;
}
throw new Error();
}
var REPLACER = 0xFFFD;
var string = "";
var bitsNeeded = this.bitsNeeded;
var codePoint = this.codePoint;
for (var i = 0; i < octets.length; i += 1) {
var octet = octets[i];
if (bitsNeeded !== 0) {
if (octet < 128 || octet > 191 || !valid(codePoint << 6 | octet & 63, bitsNeeded - 6, octetsCount(bitsNeeded, codePoint))) {
bitsNeeded = 0;
codePoint = REPLACER;
string += String.fromCharCode(codePoint);
}
}
if (bitsNeeded === 0) {
if (octet >= 0 && octet <= 127) {
bitsNeeded = 0;
codePoint = octet;
} else if (octet >= 192 && octet <= 223) {
bitsNeeded = 6 * 1;
codePoint = octet & 31;
} else if (octet >= 224 && octet <= 239) {
bitsNeeded = 6 * 2;
codePoint = octet & 15;
} else if (octet >= 240 && octet <= 247) {
bitsNeeded = 6 * 3;
codePoint = octet & 7;
} else {
bitsNeeded = 0;
codePoint = REPLACER;
}
if (bitsNeeded !== 0 && !valid(codePoint, bitsNeeded, octetsCount(bitsNeeded, codePoint))) {
bitsNeeded = 0;
codePoint = REPLACER;
}
} else {
bitsNeeded -= 6;
codePoint = codePoint << 6 | octet & 63;
}
if (bitsNeeded === 0) {
if (codePoint <= 0xFFFF) {
string += String.fromCharCode(codePoint);
} else {
string += String.fromCharCode(0xD800 + (codePoint - 0xFFFF - 1 >> 10));
string += String.fromCharCode(0xDC00 + (codePoint - 0xFFFF - 1 & 0x3FF));
}
}
}
this.bitsNeeded = bitsNeeded;
this.codePoint = codePoint;
return string;
};
// Firefox < 38 throws an error with stream option
var supportsStreamOption = function () {
try {
return new TextDecoder().decode(new TextEncoder().encode("test"), {stream: true}) === "test";
} catch (error) {
console.debug("TextDecoder does not support streaming option. Using polyfill instead: " + error);
}
return false;
};
// IE, Edge
if (TextDecoder == undefined || TextEncoder == undefined || !supportsStreamOption()) {
TextDecoder = TextDecoderPolyfill;
}
var k = function () {
};
function XHRWrapper(xhr) {
this.withCredentials = false;
this.readyState = 0;
this.status = 0;
this.statusText = "";
this.responseText = "";
this.onprogress = k;
this.onload = k;
this.onerror = k;
this.onreadystatechange = k;
this._contentType = "";
this._xhr = xhr;
this._sendTimeout = 0;
this._abort = k;
}
XHRWrapper.prototype.open = function (method, url) {
this._abort(true);
var that = this;
var xhr = this._xhr;
var state = 1;
var timeout = 0;
this._abort = function (silent) {
if (that._sendTimeout !== 0) {
clearTimeout(that._sendTimeout);
that._sendTimeout = 0;
}
if (state === 1 || state === 2 || state === 3) {
state = 4;
xhr.onload = k;
xhr.onerror = k;
xhr.onabort = k;
xhr.onprogress = k;
xhr.onreadystatechange = k;
// IE 8 - 9: XDomainRequest#abort() does not fire any event
// Opera < 10: XMLHttpRequest#abort() does not fire any event
xhr.abort();
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
if (!silent) {
that.readyState = 4;
that.onabort(null);
that.onreadystatechange();
}
}
state = 0;
};
var onStart = function () {
if (state === 1) {
//state = 2;
var status = 0;
var statusText = "";
var contentType = undefined;
if (!("contentType" in xhr)) {
try {
status = xhr.status;
statusText = xhr.statusText;
contentType = xhr.getResponseHeader("Content-Type");
} catch (error) {
// IE < 10 throws exception for `xhr.status` when xhr.readyState === 2 || xhr.readyState === 3
// Opera < 11 throws exception for `xhr.status` when xhr.readyState === 2
// https://bugs.webkit.org/show_bug.cgi?id=29121
status = 0;
statusText = "";
contentType = undefined;
// Firefox < 14, Chrome ?, Safari ?
// https://bugs.webkit.org/show_bug.cgi?id=29658
// https://bugs.webkit.org/show_bug.cgi?id=77854
}
} else {
status = 200;
statusText = "OK";
contentType = xhr.contentType;
}
if (status !== 0) {
state = 2;
that.readyState = 2;
that.status = status;
that.statusText = statusText;
that._contentType = contentType;
that.onreadystatechange();
}
}
};
var onProgress = function () {
onStart();
if (state === 2 || state === 3) {
state = 3;
var responseText = "";
try {
responseText = xhr.responseText;
} catch (error) {
// IE 8 - 9 with XMLHttpRequest
}
that.readyState = 3;
that.responseText = responseText;
that.onprogress();
}
};
var onFinish = function (type, event) {
if (event == null || event.preventDefault == null) {
event = {
preventDefault: k
};
}
// Firefox 52 fires "readystatechange" (xhr.readyState === 4) without final "readystatechange" (xhr.readyState === 3)
// IE 8 fires "onload" without "onprogress"
onProgress();
if (state === 1 || state === 2 || state === 3) {
state = 4;
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
that.readyState = 4;
if (type === "load") {
that.onload(event);
} else if (type === "error") {
that.onerror(event);
} else if (type === "abort") {
that.onabort(event);
} else {
throw new TypeError();
}
that.onreadystatechange();
}
};
var onReadyStateChange = function (event) {
if (xhr != undefined) { // Opera 12
if (xhr.readyState === 4) {
if (!("onload" in xhr) || !("onerror" in xhr) || !("onabort" in xhr)) {
onFinish(xhr.responseText === "" ? "error" : "load", event);
}
} else if (xhr.readyState === 3) {
if (!("onprogress" in xhr)) { // testing XMLHttpRequest#responseText too many times is too slow in IE 11
// and in Firefox 3.6
onProgress();
}
} else if (xhr.readyState === 2) {
onStart();
}
}
};
var onTimeout = function () {
timeout = setTimeout(function () {
onTimeout();
}, 500);
if (xhr.readyState === 3) {
onProgress();
}
};
// XDomainRequest#abort removes onprogress, onerror, onload
if ("onload" in xhr) {
xhr.onload = function (event) {
onFinish("load", event);
};
}
if ("onerror" in xhr) {
xhr.onerror = function (event) {
onFinish("error", event);
};
}
// improper fix to match Firefox behaviour, but it is better than just ignore abort
// see https://bugzilla.mozilla.org/show_bug.cgi?id=768596
// https://bugzilla.mozilla.org/show_bug.cgi?id=880200
// https://code.google.com/p/chromium/issues/detail?id=153570
// IE 8 fires "onload" without "onprogress
if ("onabort" in xhr) {
xhr.onabort = function (event) {
onFinish("abort", event);
};
}
if ("onprogress" in xhr) {
xhr.onprogress = onProgress;
}
// IE 8 - 9 (XMLHTTPRequest)
// Opera < 12
// Firefox < 3.5
// Firefox 3.5 - 3.6 - ? < 9.0
// onprogress is not fired sometimes or delayed
// see also #64 (significant lag in IE 11)
if ("onreadystatechange" in xhr) {
xhr.onreadystatechange = function (event) {
onReadyStateChange(event);
};
}
if ("contentType" in xhr || !("ontimeout" in XMLHttpRequest.prototype)) {
url += (url.indexOf("?") === -1 ? "?" : "&") + "padding=true";
}
xhr.open(method, url, true);
if ("readyState" in xhr) {
// workaround for Opera 12 issue with "progress" events
// #91 (XMLHttpRequest onprogress not fired for streaming response in Edge 14-15-?)
timeout = setTimeout(function () {
onTimeout();
}, 0);
}
};
XHRWrapper.prototype.abort = function () {
this._abort(false);
};
XHRWrapper.prototype.getResponseHeader = function (name) {
return this._contentType;
};
XHRWrapper.prototype.setRequestHeader = function (name, value) {
var xhr = this._xhr;
if ("setRequestHeader" in xhr) {
xhr.setRequestHeader(name, value);
}
};
XHRWrapper.prototype.getAllResponseHeaders = function () {
// XMLHttpRequest#getAllResponseHeaders returns null for CORS requests in Firefox 3.6.28
return this._xhr.getAllResponseHeaders != undefined ? this._xhr.getAllResponseHeaders() || "" : "";
};
XHRWrapper.prototype.send = function () {
// loading indicator in Safari < ? (6), Chrome < 14, Firefox
// https://bugzilla.mozilla.org/show_bug.cgi?id=736723
if ((!("ontimeout" in XMLHttpRequest.prototype) || (!("sendAsBinary" in XMLHttpRequest.prototype) && !("mozAnon" in XMLHttpRequest.prototype))) &&
document != undefined &&
document.readyState != undefined &&
document.readyState !== "complete") {
var that = this;
that._sendTimeout = setTimeout(function () {
that._sendTimeout = 0;
that.send();
}, 4);
return;
}
var xhr = this._xhr;
// withCredentials should be set after "open" for Safari and Chrome (< 19 ?)
if ("withCredentials" in xhr) {
xhr.withCredentials = this.withCredentials;
}
try {
// xhr.send(); throws "Not enough arguments" in Firefox 3.0
xhr.send(undefined);
} catch (error1) {
// Safari 5.1.7, Opera 12
throw error1;
}
};
function toLowerCase(name) {
return name.replace(/[A-Z]/g, function (c) {
return String.fromCharCode(c.charCodeAt(0) + 0x20);
});
}
function HeadersPolyfill(all) {
// Get headers: implemented according to mozilla's example code: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders#Example
var map = Object.create(null);
var array = all.split("\r\n");
for (var i = 0; i < array.length; i += 1) {
var line = array[i];
var parts = line.split(": ");
var name = parts.shift();
var value = parts.join(": ");
map[toLowerCase(name)] = value;
}
this._map = map;
}
HeadersPolyfill.prototype.get = function (name) {
return this._map[toLowerCase(name)];
};
if (XMLHttpRequest != null && XMLHttpRequest.HEADERS_RECEIVED == null) { // IE < 9, Firefox 3.6
XMLHttpRequest.HEADERS_RECEIVED = 2;
}
function XHRTransport() {
}
XHRTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) {
xhr.open("GET", url);
var offset = 0;
xhr.onprogress = function () {
var responseText = xhr.responseText;
var chunk = responseText.slice(offset);
offset += chunk.length;
onProgressCallback(chunk);
};
xhr.onerror = function (event) {
event.preventDefault();
onFinishCallback(new Error("NetworkError"));
};
xhr.onload = function () {
onFinishCallback(null);
};
xhr.onabort = function () {
onFinishCallback(null);
};
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
var status = xhr.status;
var statusText = xhr.statusText;
var contentType = xhr.getResponseHeader("Content-Type");
var headers = xhr.getAllResponseHeaders();
onStartCallback(status, statusText, contentType, new HeadersPolyfill(headers));
}
};
xhr.withCredentials = withCredentials;
for (var name in headers) {
if (Object.prototype.hasOwnProperty.call(headers, name)) {
xhr.setRequestHeader(name, headers[name]);
}
}
xhr.send();
return xhr;
};
function HeadersWrapper(headers) {
this._headers = headers;
}
HeadersWrapper.prototype.get = function (name) {
return this._headers.get(name);
};
function FetchTransport() {
}
FetchTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) {
var reader = null;
var controller = new AbortController();
var signal = controller.signal;
var textDecoder = new TextDecoder();
fetch(url, {
headers: headers,
credentials: withCredentials ? "include" : "same-origin",
signal: signal,
cache: "no-store"
}).then(function (response) {
reader = response.body.getReader();
onStartCallback(response.status, response.statusText, response.headers.get("Content-Type"), new HeadersWrapper(response.headers));
// see https://github.com/promises-aplus/promises-spec/issues/179
return new Promise(function (resolve, reject) {
var readNextChunk = function () {
reader.read().then(function (result) {
if (result.done) {
//Note: bytes in textDecoder are ignored
resolve(undefined);
} else {
var chunk = textDecoder.decode(result.value, {stream: true});
onProgressCallback(chunk);
readNextChunk();
}
})["catch"](function (error) {
reject(error);
});
};
readNextChunk();
});
})["catch"](function (error) {
if (error.name === "AbortError") {
return undefined;
} else {
return error;
}
}).then(function (error) {
onFinishCallback(error);
});
return {
abort: function () {
if (reader != null) {
reader.cancel(); // https://bugzilla.mozilla.org/show_bug.cgi?id=1583815
}
controller.abort();
}
};
};
function EventTarget() {
this._listeners = Object.create(null);
}
function throwError(e) {
setTimeout(function () {
throw e;
}, 0);
}
EventTarget.prototype.dispatchEvent = function (event) {
event.target = this;
var typeListeners = this._listeners[event.type];
if (typeListeners != undefined) {
var length = typeListeners.length;
for (var i = 0; i < length; i += 1) {
var listener = typeListeners[i];
try {
if (typeof listener.handleEvent === "function") {
listener.handleEvent(event);
} else {
listener.call(this, event);
}
} catch (e) {
throwError(e);
}
}
}
};
EventTarget.prototype.addEventListener = function (type, listener) {
type = String(type);
var listeners = this._listeners;
var typeListeners = listeners[type];
if (typeListeners == undefined) {
typeListeners = [];
listeners[type] = typeListeners;
}
var found = false;
for (var i = 0; i < typeListeners.length; i += 1) {
if (typeListeners[i] === listener) {
found = true;
}
}
if (!found) {
typeListeners.push(listener);
}
};
EventTarget.prototype.removeEventListener = function (type, listener) {
type = String(type);
var listeners = this._listeners;
var typeListeners = listeners[type];
if (typeListeners != undefined) {
var filtered = [];
for (var i = 0; i < typeListeners.length; i += 1) {
if (typeListeners[i] !== listener) {
filtered.push(typeListeners[i]);
}
}
if (filtered.length === 0) {
delete listeners[type];
} else {
listeners[type] = filtered;
}
}
};
function Event(type) {
this.type = type;
this.target = undefined;
}
function MessageEvent(type, options) {
Event.call(this, type);
this.data = options.data;
this.lastEventId = options.lastEventId;
}
MessageEvent.prototype = Object.create(Event.prototype);
function ConnectionEvent(type, options) {
Event.call(this, type);
this.status = options.status;
this.statusText = options.statusText;
this.headers = options.headers;
}
ConnectionEvent.prototype = Object.create(Event.prototype);
function ErrorEvent(type, options) {
Event.call(this, type);
this.error = options.error;
}
ErrorEvent.prototype = Object.create(Event.prototype);
var WAITING = -1;
var CONNECTING = 0;
var OPEN = 1;
var CLOSED = 2;
var AFTER_CR = -1;
var FIELD_START = 0;
var FIELD = 1;
var VALUE_START = 2;
var VALUE = 3;
var contentTypeRegExp = /^text\/event\-stream(;.*)?$/i;
var MINIMUM_DURATION = 1000;
var MAXIMUM_DURATION = 18000000;
var parseDuration = function (value, def) {
var n = value == null ? def : parseInt(value, 10);
if (n !== n) {
n = def;
}
return clampDuration(n);
};
var clampDuration = function (n) {
return Math.min(Math.max(n, MINIMUM_DURATION), MAXIMUM_DURATION);
};
var fire = function (that, f, event) {
try {
if (typeof f === "function") {
f.call(that, event);
}
} catch (e) {
throwError(e);
}
};
function EventSourcePolyfill(url, options) {
EventTarget.call(this);
options = options || {};
this.onopen = undefined;
this.onmessage = undefined;
this.onerror = undefined;
this.url = undefined;
this.readyState = undefined;
this.withCredentials = undefined;
this.headers = undefined;
this._close = undefined;
start(this, url, options);
}
function getBestXHRTransport() {
return (XMLHttpRequest != undefined && ("withCredentials" in XMLHttpRequest.prototype)) || XDomainRequest == undefined
? new XMLHttpRequest()
: new XDomainRequest();
}
var isFetchSupported = fetch != undefined && Response != undefined && "body" in Response.prototype;
function start(es, url, options) {
url = String(url);
var withCredentials = Boolean(options.withCredentials);
var lastEventIdQueryParameterName = options.lastEventIdQueryParameterName || "lastEventId";
var initialRetry = clampDuration(1000);
var heartbeatTimeout = parseDuration(options.heartbeatTimeout, 45000);
var lastEventId = "";
var retry = initialRetry;
var wasActivity = false;
var textLength = 0;
var headers = options.headers || {};
var TransportOption = options.Transport;
var xhr = isFetchSupported && TransportOption == undefined ? undefined : new XHRWrapper(TransportOption != undefined ? new TransportOption() : getBestXHRTransport());
var transport = TransportOption != null && typeof TransportOption !== "string" ? new TransportOption() : (xhr == undefined ? new FetchTransport() : new XHRTransport());
var abortController = undefined;
var timeout = 0;
var currentState = WAITING;
var dataBuffer = "";
var lastEventIdBuffer = "";
var eventTypeBuffer = "";
var textBuffer = "";
var state = FIELD_START;
var fieldStart = 0;
var valueStart = 0;
var onStart = function (status, statusText, contentType, headers) {
if (currentState === CONNECTING) {
if (status === 200 && contentType != undefined && contentTypeRegExp.test(contentType)) {
currentState = OPEN;
wasActivity = Date.now();
retry = initialRetry;
es.readyState = OPEN;
var event = new ConnectionEvent("open", {
status: status,
statusText: statusText,
headers: headers
});
es.dispatchEvent(event);
fire(es, es.onopen, event);
} else {
var message = "";
if (status !== 200) {
if (statusText) {
statusText = statusText.replace(/\s+/g, " ");
}
message = "EventSource's response has a status " + status + " " + statusText + " that is not 200. Aborting the connection.";
} else {
message = "EventSource's response has a Content-Type specifying an unsupported type: " + (contentType == undefined ? "-" : contentType.replace(/\s+/g, " ")) + ". Aborting the connection.";
}
close();
var event = new ConnectionEvent("error", {
status: status,
statusText: statusText,
headers: headers
});
es.dispatchEvent(event);
fire(es, es.onerror, event);
console.error(message);
}
}
};
var onProgress = function (textChunk) {
if (currentState === OPEN) {
var n = -1;
for (var i = 0; i < textChunk.length; i += 1) {
var c = textChunk.charCodeAt(i);
if (c === "\n".charCodeAt(0) || c === "\r".charCodeAt(0)) {
n = i;
}
}
var chunk = (n !== -1 ? textBuffer : "") + textChunk.slice(0, n + 1);
textBuffer = (n === -1 ? textBuffer : "") + textChunk.slice(n + 1);
if (textChunk !== "") {
wasActivity = Date.now();
textLength += textChunk.length;
}
for (var position = 0; position < chunk.length; position += 1) {
var c = chunk.charCodeAt(position);
if (state === AFTER_CR && c === "\n".charCodeAt(0)) {
state = FIELD_START;
} else {
if (state === AFTER_CR) {
state = FIELD_START;
}
if (c === "\r".charCodeAt(0) || c === "\n".charCodeAt(0)) {
if (state !== FIELD_START) {
if (state === FIELD) {
valueStart = position + 1;
}
var field = chunk.slice(fieldStart, valueStart - 1);
var value = chunk.slice(valueStart + (valueStart < position && chunk.charCodeAt(valueStart) === " ".charCodeAt(0) ? 1 : 0), position);
if (field === "data") {
dataBuffer += "\n";
dataBuffer += value;
} else if (field === "id") {
lastEventIdBuffer = value;
} else if (field === "event") {
eventTypeBuffer = value;
} else if (field === "retry") {
initialRetry = parseDuration(value, initialRetry);
retry = initialRetry;
} else if (field === "heartbeatTimeout") {
heartbeatTimeout = parseDuration(value, heartbeatTimeout);
if (timeout !== 0) {
clearTimeout(timeout);
timeout = setTimeout(function () {
onTimeout();
}, heartbeatTimeout);
}
}
}
if (state === FIELD_START) {
if (dataBuffer !== "") {
lastEventId = lastEventIdBuffer;
if (eventTypeBuffer === "") {
eventTypeBuffer = "message";
}
var event = new MessageEvent(eventTypeBuffer, {
data: dataBuffer.slice(1),
lastEventId: lastEventIdBuffer
});
es.dispatchEvent(event);
if (eventTypeBuffer === "open") {
fire(es, es.onopen, event);
} else if (eventTypeBuffer === "message") {
fire(es, es.onmessage, event);
} else if (eventTypeBuffer === "error") {
fire(es, es.onerror, event);
}
if (currentState === CLOSED) {
return;
}
}
dataBuffer = "";
eventTypeBuffer = "";
}
state = c === "\r".charCodeAt(0) ? AFTER_CR : FIELD_START;
} else {
if (state === FIELD_START) {
fieldStart = position;
state = FIELD;
}
if (state === FIELD) {
if (c === ":".charCodeAt(0)) {
valueStart = position + 1;
state = VALUE_START;
}
} else if (state === VALUE_START) {
state = VALUE;
}
}
}
}
}
};
var onFinish = function (error) {
if (currentState === OPEN || currentState === CONNECTING) {
currentState = WAITING;
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
timeout = setTimeout(function () {
onTimeout();
}, retry);
retry = clampDuration(Math.min(initialRetry * 16, retry * 2));
es.readyState = CONNECTING;
var event = new ErrorEvent("error", {error: error});
es.dispatchEvent(event);
fire(es, es.onerror, event);
if (error != undefined) {
console.error(error);
}
}
};
var close = function () {
currentState = CLOSED;
if (abortController != undefined) {
abortController.abort();
abortController = undefined;
}
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
es.readyState = CLOSED;
};
var onTimeout = function () {
timeout = 0;
if (currentState !== WAITING) {
if (!wasActivity && abortController != undefined) {
onFinish(new Error("No activity within " + heartbeatTimeout + " milliseconds." + " " + (currentState === CONNECTING ? "No response received." : textLength + " chars received.") + " " + "Reconnecting."));
if (abortController != undefined) {
abortController.abort();
abortController = undefined;
}
} else {
var nextHeartbeat = Math.max((wasActivity || Date.now()) + heartbeatTimeout - Date.now(), 1);
wasActivity = false;
timeout = setTimeout(function () {
onTimeout();
}, nextHeartbeat);
}
return;
}
wasActivity = false;
textLength = 0;
timeout = setTimeout(function () {
onTimeout();
}, heartbeatTimeout);
currentState = CONNECTING;
dataBuffer = "";
eventTypeBuffer = "";
lastEventIdBuffer = lastEventId;
textBuffer = "";
fieldStart = 0;
valueStart = 0;
state = FIELD_START;
// https://bugzilla.mozilla.org/show_bug.cgi?id=428916
// Request header field Last-Event-ID is not allowed by Access-Control-Allow-Headers.
var requestURL = url;
if (url.slice(0, 5) !== "data:" && url.slice(0, 5) !== "blob:") {
if (lastEventId !== "") {
requestURL += (url.indexOf("?") === -1 ? "?" : "&") + lastEventIdQueryParameterName +"=" + encodeURIComponent(lastEventId);
}
}
var withCredentials = es.withCredentials;
var requestHeaders = {};
requestHeaders["Accept"] = "text/event-stream";
var headers = es.headers;
if (headers != undefined) {
for (var name in headers) {
if (Object.prototype.hasOwnProperty.call(headers, name)) {
requestHeaders[name] = headers[name];
}
}
}
try {
abortController = transport.open(xhr, onStart, onProgress, onFinish, requestURL, withCredentials, requestHeaders);
} catch (error) {
close();
throw error;
}
};
es.url = url;
es.readyState = CONNECTING;
es.withCredentials = withCredentials;
es.headers = headers;
es._close = close;
onTimeout();
}
EventSourcePolyfill.prototype = Object.create(EventTarget.prototype);
EventSourcePolyfill.prototype.CONNECTING = CONNECTING;
EventSourcePolyfill.prototype.OPEN = OPEN;
EventSourcePolyfill.prototype.CLOSED = CLOSED;
EventSourcePolyfill.prototype.close = function () {
this._close();
};
EventSourcePolyfill.CONNECTING = CONNECTING;
EventSourcePolyfill.OPEN = OPEN;
EventSourcePolyfill.CLOSED = CLOSED;
EventSourcePolyfill.prototype.withCredentials = undefined;
var R = NativeEventSource;
if (XMLHttpRequest != undefined && (NativeEventSource == undefined || !("withCredentials" in NativeEventSource.prototype))) {
// Why replace a native EventSource ?
// https://bugzilla.mozilla.org/show_bug.cgi?id=444328
// https://bugzilla.mozilla.org/show_bug.cgi?id=831392
// https://code.google.com/p/chromium/issues/detail?id=260144
// https://code.google.com/p/chromium/issues/detail?id=225654
// ...
R = EventSourcePolyfill;
}
(function (factory) {
{
var v = factory(exports);
if (v !== undefined) { module.exports = v; }
}
})(function (exports) {
exports.EventSourcePolyfill = EventSourcePolyfill;
exports.NativeEventSource = NativeEventSource;
exports.EventSource = R;
});
}(typeof globalThis === 'undefined' ? (typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : commonjsGlobal) : globalThis));
});
var eventsource$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.assign(/*#__PURE__*/Object.create(null), eventsource, {
'default': eventsource
}));
var formatText = function (e) { return e.data; };
var formatJSON = function (e) { return JSON.parse(e.data); };
var SSEClient = function SSEClient(config) {
this._handlers = {};
this._listeners = {};
this._source = null;
if (config.format) {
if (typeof config.format === 'string') {
if (config.format === 'plain') {
this._format = formatText;
} else if (config.format === 'json') {
this._format = formatJSON;
} else {
this._format = formatText;
}
} else if (typeof config.format === 'function') {
this._format = config.format;
} else {
this._format = formatText;
}
} else {
this._format = formatText;
}
if (config.handlers) {
for (var event in config.handlers) {
this.on(event, config.handlers[event]);
}
}
this.url = config.url;
this.withCredentials = !!config.withCredentials;
this.polyfillOptions = config.polyfillOptions || {};
this.forcePolyfill = !!config.forcePolyfill;
};
var prototypeAccessors = { source: { configurable: true } };
prototypeAccessors.source.get = function () {
return this._source;
};
SSEClient.prototype.connect = function connect () {
var this$1 = this;
if (this.forcePolyfill) {
this._source = new eventsource.EventSourcePolyfill(
this.url,
Object.assign({}, this.polyfillOptions, {
withCredentials: this.withCredentials,
})
);
} else {
this._source = new window.EventSource(this.url, {
withCredentials: this.withCredentials,
});
}
return new Promise(function (resolve, reject) {
this$1._source.onopen = function () {
// Add event listeners that were added before we connected
for (var event in this$1._listeners) {
this$1._source.addEventListener(event, this$1._listeners[event]);
}
this$1._source.onerror = null;
resolve(this$1);
};
this$1._source.onerror = reject;
});
};
SSEClient.prototype.disconnect = function disconnect () {
if (this._source !== null) {
this._source.close();
this._source = null;
}
};
SSEClient.prototype.on = function on (event, handler) {
if (!event) {
// Default "event-less" event
event = 'message';
}
if (!this._listeners[event]) {
this._create(event);
}
this._handlers[event].push(handler);
return this;
};
SSEClient.prototype.once = function once (event, handler) {
var this$1 = this;
this.on(event, function (e) {
this$1.off(event, handler);
handler(e);
});
return this;
};
SSEClient.prototype.off = function off (event, handler) {
if (!this._handlers[event]) {
// no handlers registered for event
return this;
}
var idx = this._handlers[event].indexOf(handler);
if (idx === -1) {
// handler not registered for event
return this;
}
// remove handler from event
this._handlers[event].splice(idx, 1);
if (this._handlers[event].length === 0) {
// remove listener since no handlers exist
this._source.removeEventListener(event, this._listeners[event]);
delete this._handlers[event];
delete this._listeners[event];
}
return this;
};
SSEClient.prototype._create = function _create (event) {
var this$1 = this;
this._handlers[event] = [];
this._listeners[event] = function (message) {
var data;
try {
data = this$1._format(message);
} catch (err) {
if (typeof this$1._source.onerror === 'function') {
this$1._source.onerror(err);
}
return;
}
this$1._handlers[event].forEach(function (handler) { return handler(data, message.lastEventId); });
};
if (this._source) {
this._source.addEventListener(event, this._listeners[event]);
}
};
Object.defineProperties( SSEClient.prototype, prototypeAccessors );
function install(Vue, config) {
if (Vue.config && Vue.config.globalProperties) {
// Vue3
Vue.config.globalProperties.$sse = new SSEManager(config);
} else {
// Vue2
// eslint-disable-next-line no-param-reassign, no-multi-assign
Vue.$sse = Vue.prototype.$sse = new SSEManager(config);
}
if (config && config.polyfill) {
Promise.resolve().then(function () { return eventsource$1; });
}
// This mixin allows components to specify that all clients that were
// created within it should be automatically disconnected (cleanup)
// when the component is destroyed.
Vue.mixin({
beforeCreate: function beforeCreate() {
if (this.$options.sse && this.$options.sse.cleanup) {
// We instantiate an SSEManager for this specific instance
// in order to track it (see discussions in #13 for rationale).
this.$sse = new SSEManager();
// We also set $clients to an empty array, as opposed to null,
// so that beforeDestroy and create know to use it.
this.$sse.$clients = [];
}
},
beforeDestroy: function beforeDestroy() {
if (this.$sse.$clients !== null) {
this.$sse.$clients.forEach(function (c) { return c.disconnect(); });
this.$sse.$clients = [];
}
},
});
}
var SSEManager = function SSEManager(config) {
this.$defaultConfig = Object.assign(
{
format: formatText,
sendCredentials: false,
},
config
);
this.$clients = null;
};
SSEManager.prototype.create = function create (configOrURL) {
var config;
if (typeof configOrURL === 'object') {
config = configOrURL;
} else if (typeof configOrURL === 'string') {
config = {
url: configOrURL,
};
} else {
config = {};
}
var client = new SSEClient(Object.assign({}, this.$defaultConfig, config));
// If $clients is not null, then it's array that we should push this
// client into for later cleanup in our mixin's beforeDestroy.
if (this.$clients !== null) {
this.$clients.push(client);
}
return client;
};
var index_cjs = {
SSEManager: SSEManager,
install: install,
};
module.exports = index_cjs;
================================================
FILE: dist/vue-sse.esm.browser.js
================================================
/*!
* vue-sse v2.5.0
* (c) 2021 James Churchard
* @license MIT
*/
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn) {
var module = { exports: {} };
return fn(module, module.exports), module.exports;
}
/** @license
* eventsource.js
* Available under MIT License (MIT)
* https://github.com/Yaffle/EventSource/
*/
var eventsource = createCommonjsModule(function (module, exports) {
/*jslint indent: 2, vars: true, plusplus: true */
/*global setTimeout, clearTimeout */
(function (global) {
var setTimeout = global.setTimeout;
var clearTimeout = global.clearTimeout;
var XMLHttpRequest = global.XMLHttpRequest;
var XDomainRequest = global.XDomainRequest;
var ActiveXObject = global.ActiveXObject;
var NativeEventSource = global.EventSource;
var document = global.document;
var Promise = global.Promise;
var fetch = global.fetch;
var Response = global.Response;
var TextDecoder = global.TextDecoder;
var TextEncoder = global.TextEncoder;
var AbortController = global.AbortController;
if (typeof window !== "undefined" && !("readyState" in document) && document.body == null) { // Firefox 2
document.readyState = "loading";
window.addEventListener("load", function (event) {
document.readyState = "complete";
}, false);
}
if (XMLHttpRequest == null && ActiveXObject != null) { // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest_in_IE6
XMLHttpRequest = function () {
return new ActiveXObject("Microsoft.XMLHTTP");
};
}
if (Object.create == undefined) {
Object.create = function (C) {
function F(){}
F.prototype = C;
return new F();
};
}
if (!Date.now) {
Date.now = function now() {
return new Date().getTime();
};
}
// see #118 (Promise#finally with polyfilled Promise)
// see #123 (data URLs crash Edge)
// see #125 (CSP violations)
// see pull/#138
// => No way to polyfill Promise#finally
if (AbortController == undefined) {
var originalFetch2 = fetch;
fetch = function (url, options) {
var signal = options.signal;
return originalFetch2(url, {headers: options.headers, credentials: options.credentials, cache: options.cache}).then(function (response) {
var reader = response.body.getReader();
signal._reader = reader;
if (signal._aborted) {
signal._reader.cancel();
}
return {
status: response.status,
statusText: response.statusText,
headers: response.headers,
body: {
getReader: function () {
return reader;
}
}
};
});
};
AbortController = function () {
this.signal = {
_reader: null,
_aborted: false
};
this.abort = function () {
if (this.signal._reader != null) {
this.signal._reader.cancel();
}
this.signal._aborted = true;
};
};
}
function TextDecoderPolyfill() {
this.bitsNeeded = 0;
this.codePoint = 0;
}
TextDecoderPolyfill.prototype.decode = function (octets) {
function valid(codePoint, shift, octetsCount) {
if (octetsCount === 1) {
return codePoint >= 0x0080 >> shift && codePoint << shift <= 0x07FF;
}
if (octetsCount === 2) {
return codePoint >= 0x0800 >> shift && codePoint << shift <= 0xD7FF || codePoint >= 0xE000 >> shift && codePoint << shift <= 0xFFFF;
}
if (octetsCount === 3) {
return codePoint >= 0x010000 >> shift && codePoint << shift <= 0x10FFFF;
}
throw new Error();
}
function octetsCount(bitsNeeded, codePoint) {
if (bitsNeeded === 6 * 1) {
return codePoint >> 6 > 15 ? 3 : codePoint > 31 ? 2 : 1;
}
if (bitsNeeded === 6 * 2) {
return codePoint > 15 ? 3 : 2;
}
if (bitsNeeded === 6 * 3) {
return 3;
}
throw new Error();
}
var REPLACER = 0xFFFD;
var string = "";
var bitsNeeded = this.bitsNeeded;
var codePoint = this.codePoint;
for (var i = 0; i < octets.length; i += 1) {
var octet = octets[i];
if (bitsNeeded !== 0) {
if (octet < 128 || octet > 191 || !valid(codePoint << 6 | octet & 63, bitsNeeded - 6, octetsCount(bitsNeeded, codePoint))) {
bitsNeeded = 0;
codePoint = REPLACER;
string += String.fromCharCode(codePoint);
}
}
if (bitsNeeded === 0) {
if (octet >= 0 && octet <= 127) {
bitsNeeded = 0;
codePoint = octet;
} else if (octet >= 192 && octet <= 223) {
bitsNeeded = 6 * 1;
codePoint = octet & 31;
} else if (octet >= 224 && octet <= 239) {
bitsNeeded = 6 * 2;
codePoint = octet & 15;
} else if (octet >= 240 && octet <= 247) {
bitsNeeded = 6 * 3;
codePoint = octet & 7;
} else {
bitsNeeded = 0;
codePoint = REPLACER;
}
if (bitsNeeded !== 0 && !valid(codePoint, bitsNeeded, octetsCount(bitsNeeded, codePoint))) {
bitsNeeded = 0;
codePoint = REPLACER;
}
} else {
bitsNeeded -= 6;
codePoint = codePoint << 6 | octet & 63;
}
if (bitsNeeded === 0) {
if (codePoint <= 0xFFFF) {
string += String.fromCharCode(codePoint);
} else {
string += String.fromCharCode(0xD800 + (codePoint - 0xFFFF - 1 >> 10));
string += String.fromCharCode(0xDC00 + (codePoint - 0xFFFF - 1 & 0x3FF));
}
}
}
this.bitsNeeded = bitsNeeded;
this.codePoint = codePoint;
return string;
};
// Firefox < 38 throws an error with stream option
var supportsStreamOption = function () {
try {
return new TextDecoder().decode(new TextEncoder().encode("test"), {stream: true}) === "test";
} catch (error) {
console.debug("TextDecoder does not support streaming option. Using polyfill instead: " + error);
}
return false;
};
// IE, Edge
if (TextDecoder == undefined || TextEncoder == undefined || !supportsStreamOption()) {
TextDecoder = TextDecoderPolyfill;
}
var k = function () {
};
function XHRWrapper(xhr) {
this.withCredentials = false;
this.readyState = 0;
this.status = 0;
this.statusText = "";
this.responseText = "";
this.onprogress = k;
this.onload = k;
this.onerror = k;
this.onreadystatechange = k;
this._contentType = "";
this._xhr = xhr;
this._sendTimeout = 0;
this._abort = k;
}
XHRWrapper.prototype.open = function (method, url) {
this._abort(true);
var that = this;
var xhr = this._xhr;
var state = 1;
var timeout = 0;
this._abort = function (silent) {
if (that._sendTimeout !== 0) {
clearTimeout(that._sendTimeout);
that._sendTimeout = 0;
}
if (state === 1 || state === 2 || state === 3) {
state = 4;
xhr.onload = k;
xhr.onerror = k;
xhr.onabort = k;
xhr.onprogress = k;
xhr.onreadystatechange = k;
// IE 8 - 9: XDomainRequest#abort() does not fire any event
// Opera < 10: XMLHttpRequest#abort() does not fire any event
xhr.abort();
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
if (!silent) {
that.readyState = 4;
that.onabort(null);
that.onreadystatechange();
}
}
state = 0;
};
var onStart = function () {
if (state === 1) {
//state = 2;
var status = 0;
var statusText = "";
var contentType = undefined;
if (!("contentType" in xhr)) {
try {
status = xhr.status;
statusText = xhr.statusText;
contentType = xhr.getResponseHeader("Content-Type");
} catch (error) {
// IE < 10 throws exception for `xhr.status` when xhr.readyState === 2 || xhr.readyState === 3
// Opera < 11 throws exception for `xhr.status` when xhr.readyState === 2
// https://bugs.webkit.org/show_bug.cgi?id=29121
status = 0;
statusText = "";
contentType = undefined;
// Firefox < 14, Chrome ?, Safari ?
// https://bugs.webkit.org/show_bug.cgi?id=29658
// https://bugs.webkit.org/show_bug.cgi?id=77854
}
} else {
status = 200;
statusText = "OK";
contentType = xhr.contentType;
}
if (status !== 0) {
state = 2;
that.readyState = 2;
that.status = status;
that.statusText = statusText;
that._contentType = contentType;
that.onreadystatechange();
}
}
};
var onProgress = function () {
onStart();
if (state === 2 || state === 3) {
state = 3;
var responseText = "";
try {
responseText = xhr.responseText;
} catch (error) {
// IE 8 - 9 with XMLHttpRequest
}
that.readyState = 3;
that.responseText = responseText;
that.onprogress();
}
};
var onFinish = function (type, event) {
if (event == null || event.preventDefault == null) {
event = {
preventDefault: k
};
}
// Firefox 52 fires "readystatechange" (xhr.readyState === 4) without final "readystatechange" (xhr.readyState === 3)
// IE 8 fires "onload" without "onprogress"
onProgress();
if (state === 1 || state === 2 || state === 3) {
state = 4;
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
that.readyState = 4;
if (type === "load") {
that.onload(event);
} else if (type === "error") {
that.onerror(event);
} else if (type === "abort") {
that.onabort(event);
} else {
throw new TypeError();
}
that.onreadystatechange();
}
};
var onReadyStateChange = function (event) {
if (xhr != undefined) { // Opera 12
if (xhr.readyState === 4) {
if (!("onload" in xhr) || !("onerror" in xhr) || !("onabort" in xhr)) {
onFinish(xhr.responseText === "" ? "error" : "load", event);
}
} else if (xhr.readyState === 3) {
if (!("onprogress" in xhr)) { // testing XMLHttpRequest#responseText too many times is too slow in IE 11
// and in Firefox 3.6
onProgress();
}
} else if (xhr.readyState === 2) {
onStart();
}
}
};
var onTimeout = function () {
timeout = setTimeout(function () {
onTimeout();
}, 500);
if (xhr.readyState === 3) {
onProgress();
}
};
// XDomainRequest#abort removes onprogress, onerror, onload
if ("onload" in xhr) {
xhr.onload = function (event) {
onFinish("load", event);
};
}
if ("onerror" in xhr) {
xhr.onerror = function (event) {
onFinish("error", event);
};
}
// improper fix to match Firefox behaviour, but it is better than just ignore abort
// see https://bugzilla.mozilla.org/show_bug.cgi?id=768596
// https://bugzilla.mozilla.org/show_bug.cgi?id=880200
// https://code.google.com/p/chromium/issues/detail?id=153570
// IE 8 fires "onload" without "onprogress
if ("onabort" in xhr) {
xhr.onabort = function (event) {
onFinish("abort", event);
};
}
if ("onprogress" in xhr) {
xhr.onprogress = onProgress;
}
// IE 8 - 9 (XMLHTTPRequest)
// Opera < 12
// Firefox < 3.5
// Firefox 3.5 - 3.6 - ? < 9.0
// onprogress is not fired sometimes or delayed
// see also #64 (significant lag in IE 11)
if ("onreadystatechange" in xhr) {
xhr.onreadystatechange = function (event) {
onReadyStateChange(event);
};
}
if ("contentType" in xhr || !("ontimeout" in XMLHttpRequest.prototype)) {
url += (url.indexOf("?") === -1 ? "?" : "&") + "padding=true";
}
xhr.open(method, url, true);
if ("readyState" in xhr) {
// workaround for Opera 12 issue with "progress" events
// #91 (XMLHttpRequest onprogress not fired for streaming response in Edge 14-15-?)
timeout = setTimeout(function () {
onTimeout();
}, 0);
}
};
XHRWrapper.prototype.abort = function () {
this._abort(false);
};
XHRWrapper.prototype.getResponseHeader = function (name) {
return this._contentType;
};
XHRWrapper.prototype.setRequestHeader = function (name, value) {
var xhr = this._xhr;
if ("setRequestHeader" in xhr) {
xhr.setRequestHeader(name, value);
}
};
XHRWrapper.prototype.getAllResponseHeaders = function () {
// XMLHttpRequest#getAllResponseHeaders returns null for CORS requests in Firefox 3.6.28
return this._xhr.getAllResponseHeaders != undefined ? this._xhr.getAllResponseHeaders() || "" : "";
};
XHRWrapper.prototype.send = function () {
// loading indicator in Safari < ? (6), Chrome < 14, Firefox
// https://bugzilla.mozilla.org/show_bug.cgi?id=736723
if ((!("ontimeout" in XMLHttpRequest.prototype) || (!("sendAsBinary" in XMLHttpRequest.prototype) && !("mozAnon" in XMLHttpRequest.prototype))) &&
document != undefined &&
document.readyState != undefined &&
document.readyState !== "complete") {
var that = this;
that._sendTimeout = setTimeout(function () {
that._sendTimeout = 0;
that.send();
}, 4);
return;
}
var xhr = this._xhr;
// withCredentials should be set after "open" for Safari and Chrome (< 19 ?)
if ("withCredentials" in xhr) {
xhr.withCredentials = this.withCredentials;
}
try {
// xhr.send(); throws "Not enough arguments" in Firefox 3.0
xhr.send(undefined);
} catch (error1) {
// Safari 5.1.7, Opera 12
throw error1;
}
};
function toLowerCase(name) {
return name.replace(/[A-Z]/g, function (c) {
return String.fromCharCode(c.charCodeAt(0) + 0x20);
});
}
function HeadersPolyfill(all) {
// Get headers: implemented according to mozilla's example code: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders#Example
var map = Object.create(null);
var array = all.split("\r\n");
for (var i = 0; i < array.length; i += 1) {
var line = array[i];
var parts = line.split(": ");
var name = parts.shift();
var value = parts.join(": ");
map[toLowerCase(name)] = value;
}
this._map = map;
}
HeadersPolyfill.prototype.get = function (name) {
return this._map[toLowerCase(name)];
};
if (XMLHttpRequest != null && XMLHttpRequest.HEADERS_RECEIVED == null) { // IE < 9, Firefox 3.6
XMLHttpRequest.HEADERS_RECEIVED = 2;
}
function XHRTransport() {
}
XHRTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) {
xhr.open("GET", url);
var offset = 0;
xhr.onprogress = function () {
var responseText = xhr.responseText;
var chunk = responseText.slice(offset);
offset += chunk.length;
onProgressCallback(chunk);
};
xhr.onerror = function (event) {
event.preventDefault();
onFinishCallback(new Error("NetworkError"));
};
xhr.onload = function () {
onFinishCallback(null);
};
xhr.onabort = function () {
onFinishCallback(null);
};
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
var status = xhr.status;
var statusText = xhr.statusText;
var contentType = xhr.getResponseHeader("Content-Type");
var headers = xhr.getAllResponseHeaders();
onStartCallback(status, statusText, contentType, new HeadersPolyfill(headers));
}
};
xhr.withCredentials = withCredentials;
for (var name in headers) {
if (Object.prototype.hasOwnProperty.call(headers, name)) {
xhr.setRequestHeader(name, headers[name]);
}
}
xhr.send();
return xhr;
};
function HeadersWrapper(headers) {
this._headers = headers;
}
HeadersWrapper.prototype.get = function (name) {
return this._headers.get(name);
};
function FetchTransport() {
}
FetchTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) {
var reader = null;
var controller = new AbortController();
var signal = controller.signal;
var textDecoder = new TextDecoder();
fetch(url, {
headers: headers,
credentials: withCredentials ? "include" : "same-origin",
signal: signal,
cache: "no-store"
}).then(function (response) {
reader = response.body.getReader();
onStartCallback(response.status, response.statusText, response.headers.get("Content-Type"), new HeadersWrapper(response.headers));
// see https://github.com/promises-aplus/promises-spec/issues/179
return new Promise(function (resolve, reject) {
var readNextChunk = function () {
reader.read().then(function (result) {
if (result.done) {
//Note: bytes in textDecoder are ignored
resolve(undefined);
} else {
var chunk = textDecoder.decode(result.value, {stream: true});
onProgressCallback(chunk);
readNextChunk();
}
})["catch"](function (error) {
reject(error);
});
};
readNextChunk();
});
})["catch"](function (error) {
if (error.name === "AbortError") {
return undefined;
} else {
return error;
}
}).then(function (error) {
onFinishCallback(error);
});
return {
abort: function () {
if (reader != null) {
reader.cancel(); // https://bugzilla.mozilla.org/show_bug.cgi?id=1583815
}
controller.abort();
}
};
};
function EventTarget() {
this._listeners = Object.create(null);
}
function throwError(e) {
setTimeout(function () {
throw e;
}, 0);
}
EventTarget.prototype.dispatchEvent = function (event) {
event.target = this;
var typeListeners = this._listeners[event.type];
if (typeListeners != undefined) {
var length = typeListeners.length;
for (var i = 0; i < length; i += 1) {
var listener = typeListeners[i];
try {
if (typeof listener.handleEvent === "function") {
listener.handleEvent(event);
} else {
listener.call(this, event);
}
} catch (e) {
throwError(e);
}
}
}
};
EventTarget.prototype.addEventListener = function (type, listener) {
type = String(type);
var listeners = this._listeners;
var typeListeners = listeners[type];
if (typeListeners == undefined) {
typeListeners = [];
listeners[type] = typeListeners;
}
var found = false;
for (var i = 0; i < typeListeners.length; i += 1) {
if (typeListeners[i] === listener) {
found = true;
}
}
if (!found) {
typeListeners.push(listener);
}
};
EventTarget.prototype.removeEventListener = function (type, listener) {
type = String(type);
var listeners = this._listeners;
var typeListeners = listeners[type];
if (typeListeners != undefined) {
var filtered = [];
for (var i = 0; i < typeListeners.length; i += 1) {
if (typeListeners[i] !== listener) {
filtered.push(typeListeners[i]);
}
}
if (filtered.length === 0) {
delete listeners[type];
} else {
listeners[type] = filtered;
}
}
};
function Event(type) {
this.type = type;
this.target = undefined;
}
function MessageEvent(type, options) {
Event.call(this, type);
this.data = options.data;
this.lastEventId = options.lastEventId;
}
MessageEvent.prototype = Object.create(Event.prototype);
function ConnectionEvent(type, options) {
Event.call(this, type);
this.status = options.status;
this.statusText = options.statusText;
this.headers = options.headers;
}
ConnectionEvent.prototype = Object.create(Event.prototype);
function ErrorEvent(type, options) {
Event.call(this, type);
this.error = options.error;
}
ErrorEvent.prototype = Object.create(Event.prototype);
var WAITING = -1;
var CONNECTING = 0;
var OPEN = 1;
var CLOSED = 2;
var AFTER_CR = -1;
var FIELD_START = 0;
var FIELD = 1;
var VALUE_START = 2;
var VALUE = 3;
var contentTypeRegExp = /^text\/event\-stream(;.*)?$/i;
var MINIMUM_DURATION = 1000;
var MAXIMUM_DURATION = 18000000;
var parseDuration = function (value, def) {
var n = value == null ? def : parseInt(value, 10);
if (n !== n) {
n = def;
}
return clampDuration(n);
};
var clampDuration = function (n) {
return Math.min(Math.max(n, MINIMUM_DURATION), MAXIMUM_DURATION);
};
var fire = function (that, f, event) {
try {
if (typeof f === "function") {
f.call(that, event);
}
} catch (e) {
throwError(e);
}
};
function EventSourcePolyfill(url, options) {
EventTarget.call(this);
options = options || {};
this.onopen = undefined;
this.onmessage = undefined;
this.onerror = undefined;
this.url = undefined;
this.readyState = undefined;
this.withCredentials = undefined;
this.headers = undefined;
this._close = undefined;
start(this, url, options);
}
function getBestXHRTransport() {
return (XMLHttpRequest != undefined && ("withCredentials" in XMLHttpRequest.prototype)) || XDomainRequest == undefined
? new XMLHttpRequest()
: new XDomainRequest();
}
var isFetchSupported = fetch != undefined && Response != undefined && "body" in Response.prototype;
function start(es, url, options) {
url = String(url);
var withCredentials = Boolean(options.withCredentials);
var lastEventIdQueryParameterName = options.lastEventIdQueryParameterName || "lastEventId";
var initialRetry = clampDuration(1000);
var heartbeatTimeout = parseDuration(options.heartbeatTimeout, 45000);
var lastEventId = "";
var retry = initialRetry;
var wasActivity = false;
var textLength = 0;
var headers = options.headers || {};
var TransportOption = options.Transport;
var xhr = isFetchSupported && TransportOption == undefined ? undefined : new XHRWrapper(TransportOption != undefined ? new TransportOption() : getBestXHRTransport());
var transport = TransportOption != null && typeof TransportOption !== "string" ? new TransportOption() : (xhr == undefined ? new FetchTransport() : new XHRTransport());
var abortController = undefined;
var timeout = 0;
var currentState = WAITING;
var dataBuffer = "";
var lastEventIdBuffer = "";
var eventTypeBuffer = "";
var textBuffer = "";
var state = FIELD_START;
var fieldStart = 0;
var valueStart = 0;
var onStart = function (status, statusText, contentType, headers) {
if (currentState === CONNECTING) {
if (status === 200 && contentType != undefined && contentTypeRegExp.test(contentType)) {
currentState = OPEN;
wasActivity = Date.now();
retry = initialRetry;
es.readyState = OPEN;
var event = new ConnectionEvent("open", {
status: status,
statusText: statusText,
headers: headers
});
es.dispatchEvent(event);
fire(es, es.onopen, event);
} else {
var message = "";
if (status !== 200) {
if (statusText) {
statusText = statusText.replace(/\s+/g, " ");
}
message = "EventSource's response has a status " + status + " " + statusText + " that is not 200. Aborting the connection.";
} else {
message = "EventSource's response has a Content-Type specifying an unsupported type: " + (contentType == undefined ? "-" : contentType.replace(/\s+/g, " ")) + ". Aborting the connection.";
}
close();
var event = new ConnectionEvent("error", {
status: status,
statusText: statusText,
headers: headers
});
es.dispatchEvent(event);
fire(es, es.onerror, event);
console.error(message);
}
}
};
var onProgress = function (textChunk) {
if (currentState === OPEN) {
var n = -1;
for (var i = 0; i < textChunk.length; i += 1) {
var c = textChunk.charCodeAt(i);
if (c === "\n".charCodeAt(0) || c === "\r".charCodeAt(0)) {
n = i;
}
}
var chunk = (n !== -1 ? textBuffer : "") + textChunk.slice(0, n + 1);
textBuffer = (n === -1 ? textBuffer : "") + textChunk.slice(n + 1);
if (textChunk !== "") {
wasActivity = Date.now();
textLength += textChunk.length;
}
for (var position = 0; position < chunk.length; position += 1) {
var c = chunk.charCodeAt(position);
if (state === AFTER_CR && c === "\n".charCodeAt(0)) {
state = FIELD_START;
} else {
if (state === AFTER_CR) {
state = FIELD_START;
}
if (c === "\r".charCodeAt(0) || c === "\n".charCodeAt(0)) {
if (state !== FIELD_START) {
if (state === FIELD) {
valueStart = position + 1;
}
var field = chunk.slice(fieldStart, valueStart - 1);
var value = chunk.slice(valueStart + (valueStart < position && chunk.charCodeAt(valueStart) === " ".charCodeAt(0) ? 1 : 0), position);
if (field === "data") {
dataBuffer += "\n";
dataBuffer += value;
} else if (field === "id") {
lastEventIdBuffer = value;
} else if (field === "event") {
eventTypeBuffer = value;
} else if (field === "retry") {
initialRetry = parseDuration(value, initialRetry);
retry = initialRetry;
} else if (field === "heartbeatTimeout") {
heartbeatTimeout = parseDuration(value, heartbeatTimeout);
if (timeout !== 0) {
clearTimeout(timeout);
timeout = setTimeout(function () {
onTimeout();
}, heartbeatTimeout);
}
}
}
if (state === FIELD_START) {
if (dataBuffer !== "") {
lastEventId = lastEventIdBuffer;
if (eventTypeBuffer === "") {
eventTypeBuffer = "message";
}
var event = new MessageEvent(eventTypeBuffer, {
data: dataBuffer.slice(1),
lastEventId: lastEventIdBuffer
});
es.dispatchEvent(event);
if (eventTypeBuffer === "open") {
fire(es, es.onopen, event);
} else if (eventTypeBuffer === "message") {
fire(es, es.onmessage, event);
} else if (eventTypeBuffer === "error") {
fire(es, es.onerror, event);
}
if (currentState === CLOSED) {
return;
}
}
dataBuffer = "";
eventTypeBuffer = "";
}
state = c === "\r".charCodeAt(0) ? AFTER_CR : FIELD_START;
} else {
if (state === FIELD_START) {
fieldStart = position;
state = FIELD;
}
if (state === FIELD) {
if (c === ":".charCodeAt(0)) {
valueStart = position + 1;
state = VALUE_START;
}
} else if (state === VALUE_START) {
state = VALUE;
}
}
}
}
}
};
var onFinish = function (error) {
if (currentState === OPEN || currentState === CONNECTING) {
currentState = WAITING;
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
timeout = setTimeout(function () {
onTimeout();
}, retry);
retry = clampDuration(Math.min(initialRetry * 16, retry * 2));
es.readyState = CONNECTING;
var event = new ErrorEvent("error", {error: error});
es.dispatchEvent(event);
fire(es, es.onerror, event);
if (error != undefined) {
console.error(error);
}
}
};
var close = function () {
currentState = CLOSED;
if (abortController != undefined) {
abortController.abort();
abortController = undefined;
}
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
es.readyState = CLOSED;
};
var onTimeout = function () {
timeout = 0;
if (currentState !== WAITING) {
if (!wasActivity && abortController != undefined) {
onFinish(new Error("No activity within " + heartbeatTimeout + " milliseconds." + " " + (currentState === CONNECTING ? "No response received." : textLength + " chars received.") + " " + "Reconnecting."));
if (abortController != undefined) {
abortController.abort();
abortController = undefined;
}
} else {
var nextHeartbeat = Math.max((wasActivity || Date.now()) + heartbeatTimeout - Date.now(), 1);
wasActivity = false;
timeout = setTimeout(function () {
onTimeout();
}, nextHeartbeat);
}
return;
}
wasActivity = false;
textLength = 0;
timeout = setTimeout(function () {
onTimeout();
}, heartbeatTimeout);
currentState = CONNECTING;
dataBuffer = "";
eventTypeBuffer = "";
lastEventIdBuffer = lastEventId;
textBuffer = "";
fieldStart = 0;
valueStart = 0;
state = FIELD_START;
// https://bugzilla.mozilla.org/show_bug.cgi?id=428916
// Request header field Last-Event-ID is not allowed by Access-Control-Allow-Headers.
var requestURL = url;
if (url.slice(0, 5) !== "data:" && url.slice(0, 5) !== "blob:") {
if (lastEventId !== "") {
requestURL += (url.indexOf("?") === -1 ? "?" : "&") + lastEventIdQueryParameterName +"=" + encodeURIComponent(lastEventId);
}
}
var withCredentials = es.withCredentials;
var requestHeaders = {};
requestHeaders["Accept"] = "text/event-stream";
var headers = es.headers;
if (headers != undefined) {
for (var name in headers) {
if (Object.prototype.hasOwnProperty.call(headers, name)) {
requestHeaders[name] = headers[name];
}
}
}
try {
abortController = transport.open(xhr, onStart, onProgress, onFinish, requestURL, withCredentials, requestHeaders);
} catch (error) {
close();
throw error;
}
};
es.url = url;
es.readyState = CONNECTING;
es.withCredentials = withCredentials;
es.headers = headers;
es._close = close;
onTimeout();
}
EventSourcePolyfill.prototype = Object.create(EventTarget.prototype);
EventSourcePolyfill.prototype.CONNECTING = CONNECTING;
EventSourcePolyfill.prototype.OPEN = OPEN;
EventSourcePolyfill.prototype.CLOSED = CLOSED;
EventSourcePolyfill.prototype.close = function () {
this._close();
};
EventSourcePolyfill.CONNECTING = CONNECTING;
EventSourcePolyfill.OPEN = OPEN;
EventSourcePolyfill.CLOSED = CLOSED;
EventSourcePolyfill.prototype.withCredentials = undefined;
var R = NativeEventSource;
if (XMLHttpRequest != undefined && (NativeEventSource == undefined || !("withCredentials" in NativeEventSource.prototype))) {
// Why replace a native EventSource ?
// https://bugzilla.mozilla.org/show_bug.cgi?id=444328
// https://bugzilla.mozilla.org/show_bug.cgi?id=831392
// https://code.google.com/p/chromium/issues/detail?id=260144
// https://code.google.com/p/chromium/issues/detail?id=225654
// ...
R = EventSourcePolyfill;
}
(function (factory) {
{
var v = factory(exports);
if (v !== undefined) module.exports = v;
}
})(function (exports) {
exports.EventSourcePolyfill = EventSourcePolyfill;
exports.NativeEventSource = NativeEventSource;
exports.EventSource = R;
});
}(typeof globalThis === 'undefined' ? (typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : commonjsGlobal) : globalThis));
});
var eventsource$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.assign(/*#__PURE__*/Object.create(null), eventsource, {
'default': eventsource
}));
const formatText = (e) => e.data;
const formatJSON = (e) => JSON.parse(e.data);
class SSEClient {
constructor(config) {
this._handlers = {};
this._listeners = {};
this._source = null;
if (config.format) {
if (typeof config.format === 'string') {
if (config.format === 'plain') {
this._format = formatText;
} else if (config.format === 'json') {
this._format = formatJSON;
} else {
this._format = formatText;
}
} else if (typeof config.format === 'function') {
this._format = config.format;
} else {
this._format = formatText;
}
} else {
this._format = formatText;
}
if (config.handlers) {
for (const event in config.handlers) {
this.on(event, config.handlers[event]);
}
}
this.url = config.url;
this.withCredentials = !!config.withCredentials;
this.polyfillOptions = config.polyfillOptions || {};
this.forcePolyfill = !!config.forcePolyfill;
}
get source() {
return this._source;
}
connect() {
if (this.forcePolyfill) {
this._source = new eventsource.EventSourcePolyfill(
this.url,
Object.assign({}, this.polyfillOptions, {
withCredentials: this.withCredentials,
}),
);
} else {
this._source = new window.EventSource(this.url, {
withCredentials: this.withCredentials,
});
}
return new Promise((resolve, reject) => {
this._source.onopen = () => {
// Add event listeners that were added before we connected
for (let event in this._listeners) {
this._source.addEventListener(event, this._listeners[event]);
}
this._source.onerror = null;
resolve(this);
};
this._source.onerror = reject;
});
}
disconnect() {
if (this._source !== null) {
this._source.close();
this._source = null;
}
}
on(event, handler) {
if (!event) {
// Default "event-less" event
event = 'message';
}
if (!this._listeners[event]) {
this._create(event);
}
this._handlers[event].push(handler);
return this;
}
once(event, handler) {
this.on(event, (e) => {
this.off(event, handler);
handler(e);
});
return this;
}
off(event, handler) {
if (!this._handlers[event]) {
// no handlers registered for event
return this;
}
const idx = this._handlers[event].indexOf(handler);
if (idx === -1) {
// handler not registered for event
return this;
}
// remove handler from event
this._handlers[event].splice(idx, 1);
if (this._handlers[event].length === 0) {
// remove listener since no handlers exist
this._source.removeEventListener(event, this._listeners[event]);
delete this._handlers[event];
delete this._listeners[event];
}
return this;
}
_create(event) {
this._handlers[event] = [];
this._listeners[event] = (message) => {
let data;
try {
data = this._format(message);
} catch (err) {
if (typeof this._source.onerror === 'function') {
this._source.onerror(err);
}
return;
}
this._handlers[event].forEach((handler) => handler(data, message.lastEventId));
};
if (this._source) {
this._source.addEventListener(event, this._listeners[event]);
}
}
}
function install(Vue, config) {
if (Vue.config && Vue.config.globalProperties) {
// Vue3
Vue.config.globalProperties.$sse = new SSEManager(config);
} else {
// Vue2
// eslint-disable-next-line no-param-reassign, no-multi-assign
Vue.$sse = Vue.prototype.$sse = new SSEManager(config);
}
if (config && config.polyfill) {
Promise.resolve().then(function () { return eventsource$1; });
}
// This mixin allows components to specify that all clients that were
// created within it should be automatically disconnected (cleanup)
// when the component is destroyed.
Vue.mixin({
beforeCreate() {
if (this.$options.sse && this.$options.sse.cleanup) {
// We instantiate an SSEManager for this specific instance
// in order to track it (see discussions in #13 for rationale).
this.$sse = new SSEManager();
// We also set $clients to an empty array, as opposed to null,
// so that beforeDestroy and create know to use it.
this.$sse.$clients = [];
}
},
beforeDestroy() {
if (this.$sse.$clients !== null) {
this.$sse.$clients.forEach((c) => c.disconnect());
this.$sse.$clients = [];
}
},
});
}
class SSEManager {
constructor(config) {
this.$defaultConfig = Object.assign(
{
format: formatText,
sendCredentials: false,
},
config,
);
this.$clients = null;
}
create(configOrURL) {
let config;
if (typeof configOrURL === 'object') {
config = configOrURL;
} else if (typeof configOrURL === 'string') {
config = {
url: configOrURL,
};
} else {
config = {};
}
const client = new SSEClient(Object.assign({}, this.$defaultConfig, config));
// If $clients is not null, then it's array that we should push this
// client into for later cleanup in our mixin's beforeDestroy.
if (this.$clients !== null) {
this.$clients.push(client);
}
return client;
}
}
var index = {
install,
};
export default index;
export { SSEManager, install };
================================================
FILE: dist/vue-sse.esm.js
================================================
/*!
* vue-sse v2.5.0
* (c) 2021 James Churchard
* @license MIT
*/
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn) {
var module = { exports: {} };
return fn(module, module.exports), module.exports;
}
/** @license
* eventsource.js
* Available under MIT License (MIT)
* https://github.com/Yaffle/EventSource/
*/
var eventsource = createCommonjsModule(function (module, exports) {
/*jslint indent: 2, vars: true, plusplus: true */
/*global setTimeout, clearTimeout */
(function (global) {
var setTimeout = global.setTimeout;
var clearTimeout = global.clearTimeout;
var XMLHttpRequest = global.XMLHttpRequest;
var XDomainRequest = global.XDomainRequest;
var ActiveXObject = global.ActiveXObject;
var NativeEventSource = global.EventSource;
var document = global.document;
var Promise = global.Promise;
var fetch = global.fetch;
var Response = global.Response;
var TextDecoder = global.TextDecoder;
var TextEncoder = global.TextEncoder;
var AbortController = global.AbortController;
if (typeof window !== "undefined" && !("readyState" in document) && document.body == null) { // Firefox 2
document.readyState = "loading";
window.addEventListener("load", function (event) {
document.readyState = "complete";
}, false);
}
if (XMLHttpRequest == null && ActiveXObject != null) { // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest_in_IE6
XMLHttpRequest = function () {
return new ActiveXObject("Microsoft.XMLHTTP");
};
}
if (Object.create == undefined) {
Object.create = function (C) {
function F(){}
F.prototype = C;
return new F();
};
}
if (!Date.now) {
Date.now = function now() {
return new Date().getTime();
};
}
// see #118 (Promise#finally with polyfilled Promise)
// see #123 (data URLs crash Edge)
// see #125 (CSP violations)
// see pull/#138
// => No way to polyfill Promise#finally
if (AbortController == undefined) {
var originalFetch2 = fetch;
fetch = function (url, options) {
var signal = options.signal;
return originalFetch2(url, {headers: options.headers, credentials: options.credentials, cache: options.cache}).then(function (response) {
var reader = response.body.getReader();
signal._reader = reader;
if (signal._aborted) {
signal._reader.cancel();
}
return {
status: response.status,
statusText: response.statusText,
headers: response.headers,
body: {
getReader: function () {
return reader;
}
}
};
});
};
AbortController = function () {
this.signal = {
_reader: null,
_aborted: false
};
this.abort = function () {
if (this.signal._reader != null) {
this.signal._reader.cancel();
}
this.signal._aborted = true;
};
};
}
function TextDecoderPolyfill() {
this.bitsNeeded = 0;
this.codePoint = 0;
}
TextDecoderPolyfill.prototype.decode = function (octets) {
function valid(codePoint, shift, octetsCount) {
if (octetsCount === 1) {
return codePoint >= 0x0080 >> shift && codePoint << shift <= 0x07FF;
}
if (octetsCount === 2) {
return codePoint >= 0x0800 >> shift && codePoint << shift <= 0xD7FF || codePoint >= 0xE000 >> shift && codePoint << shift <= 0xFFFF;
}
if (octetsCount === 3) {
return codePoint >= 0x010000 >> shift && codePoint << shift <= 0x10FFFF;
}
throw new Error();
}
function octetsCount(bitsNeeded, codePoint) {
if (bitsNeeded === 6 * 1) {
return codePoint >> 6 > 15 ? 3 : codePoint > 31 ? 2 : 1;
}
if (bitsNeeded === 6 * 2) {
return codePoint > 15 ? 3 : 2;
}
if (bitsNeeded === 6 * 3) {
return 3;
}
throw new Error();
}
var REPLACER = 0xFFFD;
var string = "";
var bitsNeeded = this.bitsNeeded;
var codePoint = this.codePoint;
for (var i = 0; i < octets.length; i += 1) {
var octet = octets[i];
if (bitsNeeded !== 0) {
if (octet < 128 || octet > 191 || !valid(codePoint << 6 | octet & 63, bitsNeeded - 6, octetsCount(bitsNeeded, codePoint))) {
bitsNeeded = 0;
codePoint = REPLACER;
string += String.fromCharCode(codePoint);
}
}
if (bitsNeeded === 0) {
if (octet >= 0 && octet <= 127) {
bitsNeeded = 0;
codePoint = octet;
} else if (octet >= 192 && octet <= 223) {
bitsNeeded = 6 * 1;
codePoint = octet & 31;
} else if (octet >= 224 && octet <= 239) {
bitsNeeded = 6 * 2;
codePoint = octet & 15;
} else if (octet >= 240 && octet <= 247) {
bitsNeeded = 6 * 3;
codePoint = octet & 7;
} else {
bitsNeeded = 0;
codePoint = REPLACER;
}
if (bitsNeeded !== 0 && !valid(codePoint, bitsNeeded, octetsCount(bitsNeeded, codePoint))) {
bitsNeeded = 0;
codePoint = REPLACER;
}
} else {
bitsNeeded -= 6;
codePoint = codePoint << 6 | octet & 63;
}
if (bitsNeeded === 0) {
if (codePoint <= 0xFFFF) {
string += String.fromCharCode(codePoint);
} else {
string += String.fromCharCode(0xD800 + (codePoint - 0xFFFF - 1 >> 10));
string += String.fromCharCode(0xDC00 + (codePoint - 0xFFFF - 1 & 0x3FF));
}
}
}
this.bitsNeeded = bitsNeeded;
this.codePoint = codePoint;
return string;
};
// Firefox < 38 throws an error with stream option
var supportsStreamOption = function () {
try {
return new TextDecoder().decode(new TextEncoder().encode("test"), {stream: true}) === "test";
} catch (error) {
console.debug("TextDecoder does not support streaming option. Using polyfill instead: " + error);
}
return false;
};
// IE, Edge
if (TextDecoder == undefined || TextEncoder == undefined || !supportsStreamOption()) {
TextDecoder = TextDecoderPolyfill;
}
var k = function () {
};
function XHRWrapper(xhr) {
this.withCredentials = false;
this.readyState = 0;
this.status = 0;
this.statusText = "";
this.responseText = "";
this.onprogress = k;
this.onload = k;
this.onerror = k;
this.onreadystatechange = k;
this._contentType = "";
this._xhr = xhr;
this._sendTimeout = 0;
this._abort = k;
}
XHRWrapper.prototype.open = function (method, url) {
this._abort(true);
var that = this;
var xhr = this._xhr;
var state = 1;
var timeout = 0;
this._abort = function (silent) {
if (that._sendTimeout !== 0) {
clearTimeout(that._sendTimeout);
that._sendTimeout = 0;
}
if (state === 1 || state === 2 || state === 3) {
state = 4;
xhr.onload = k;
xhr.onerror = k;
xhr.onabort = k;
xhr.onprogress = k;
xhr.onreadystatechange = k;
// IE 8 - 9: XDomainRequest#abort() does not fire any event
// Opera < 10: XMLHttpRequest#abort() does not fire any event
xhr.abort();
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
if (!silent) {
that.readyState = 4;
that.onabort(null);
that.onreadystatechange();
}
}
state = 0;
};
var onStart = function () {
if (state === 1) {
//state = 2;
var status = 0;
var statusText = "";
var contentType = undefined;
if (!("contentType" in xhr)) {
try {
status = xhr.status;
statusText = xhr.statusText;
contentType = xhr.getResponseHeader("Content-Type");
} catch (error) {
// IE < 10 throws exception for `xhr.status` when xhr.readyState === 2 || xhr.readyState === 3
// Opera < 11 throws exception for `xhr.status` when xhr.readyState === 2
// https://bugs.webkit.org/show_bug.cgi?id=29121
status = 0;
statusText = "";
contentType = undefined;
// Firefox < 14, Chrome ?, Safari ?
// https://bugs.webkit.org/show_bug.cgi?id=29658
// https://bugs.webkit.org/show_bug.cgi?id=77854
}
} else {
status = 200;
statusText = "OK";
contentType = xhr.contentType;
}
if (status !== 0) {
state = 2;
that.readyState = 2;
that.status = status;
that.statusText = statusText;
that._contentType = contentType;
that.onreadystatechange();
}
}
};
var onProgress = function () {
onStart();
if (state === 2 || state === 3) {
state = 3;
var responseText = "";
try {
responseText = xhr.responseText;
} catch (error) {
// IE 8 - 9 with XMLHttpRequest
}
that.readyState = 3;
that.responseText = responseText;
that.onprogress();
}
};
var onFinish = function (type, event) {
if (event == null || event.preventDefault == null) {
event = {
preventDefault: k
};
}
// Firefox 52 fires "readystatechange" (xhr.readyState === 4) without final "readystatechange" (xhr.readyState === 3)
// IE 8 fires "onload" without "onprogress"
onProgress();
if (state === 1 || state === 2 || state === 3) {
state = 4;
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
that.readyState = 4;
if (type === "load") {
that.onload(event);
} else if (type === "error") {
that.onerror(event);
} else if (type === "abort") {
that.onabort(event);
} else {
throw new TypeError();
}
that.onreadystatechange();
}
};
var onReadyStateChange = function (event) {
if (xhr != undefined) { // Opera 12
if (xhr.readyState === 4) {
if (!("onload" in xhr) || !("onerror" in xhr) || !("onabort" in xhr)) {
onFinish(xhr.responseText === "" ? "error" : "load", event);
}
} else if (xhr.readyState === 3) {
if (!("onprogress" in xhr)) { // testing XMLHttpRequest#responseText too many times is too slow in IE 11
// and in Firefox 3.6
onProgress();
}
} else if (xhr.readyState === 2) {
onStart();
}
}
};
var onTimeout = function () {
timeout = setTimeout(function () {
onTimeout();
}, 500);
if (xhr.readyState === 3) {
onProgress();
}
};
// XDomainRequest#abort removes onprogress, onerror, onload
if ("onload" in xhr) {
xhr.onload = function (event) {
onFinish("load", event);
};
}
if ("onerror" in xhr) {
xhr.onerror = function (event) {
onFinish("error", event);
};
}
// improper fix to match Firefox behaviour, but it is better than just ignore abort
// see https://bugzilla.mozilla.org/show_bug.cgi?id=768596
// https://bugzilla.mozilla.org/show_bug.cgi?id=880200
// https://code.google.com/p/chromium/issues/detail?id=153570
// IE 8 fires "onload" without "onprogress
if ("onabort" in xhr) {
xhr.onabort = function (event) {
onFinish("abort", event);
};
}
if ("onprogress" in xhr) {
xhr.onprogress = onProgress;
}
// IE 8 - 9 (XMLHTTPRequest)
// Opera < 12
// Firefox < 3.5
// Firefox 3.5 - 3.6 - ? < 9.0
// onprogress is not fired sometimes or delayed
// see also #64 (significant lag in IE 11)
if ("onreadystatechange" in xhr) {
xhr.onreadystatechange = function (event) {
onReadyStateChange(event);
};
}
if ("contentType" in xhr || !("ontimeout" in XMLHttpRequest.prototype)) {
url += (url.indexOf("?") === -1 ? "?" : "&") + "padding=true";
}
xhr.open(method, url, true);
if ("readyState" in xhr) {
// workaround for Opera 12 issue with "progress" events
// #91 (XMLHttpRequest onprogress not fired for streaming response in Edge 14-15-?)
timeout = setTimeout(function () {
onTimeout();
}, 0);
}
};
XHRWrapper.prototype.abort = function () {
this._abort(false);
};
XHRWrapper.prototype.getResponseHeader = function (name) {
return this._contentType;
};
XHRWrapper.prototype.setRequestHeader = function (name, value) {
var xhr = this._xhr;
if ("setRequestHeader" in xhr) {
xhr.setRequestHeader(name, value);
}
};
XHRWrapper.prototype.getAllResponseHeaders = function () {
// XMLHttpRequest#getAllResponseHeaders returns null for CORS requests in Firefox 3.6.28
return this._xhr.getAllResponseHeaders != undefined ? this._xhr.getAllResponseHeaders() || "" : "";
};
XHRWrapper.prototype.send = function () {
// loading indicator in Safari < ? (6), Chrome < 14, Firefox
// https://bugzilla.mozilla.org/show_bug.cgi?id=736723
if ((!("ontimeout" in XMLHttpRequest.prototype) || (!("sendAsBinary" in XMLHttpRequest.prototype) && !("mozAnon" in XMLHttpRequest.prototype))) &&
document != undefined &&
document.readyState != undefined &&
document.readyState !== "complete") {
var that = this;
that._sendTimeout = setTimeout(function () {
that._sendTimeout = 0;
that.send();
}, 4);
return;
}
var xhr = this._xhr;
// withCredentials should be set after "open" for Safari and Chrome (< 19 ?)
if ("withCredentials" in xhr) {
xhr.withCredentials = this.withCredentials;
}
try {
// xhr.send(); throws "Not enough arguments" in Firefox 3.0
xhr.send(undefined);
} catch (error1) {
// Safari 5.1.7, Opera 12
throw error1;
}
};
function toLowerCase(name) {
return name.replace(/[A-Z]/g, function (c) {
return String.fromCharCode(c.charCodeAt(0) + 0x20);
});
}
function HeadersPolyfill(all) {
// Get headers: implemented according to mozilla's example code: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders#Example
var map = Object.create(null);
var array = all.split("\r\n");
for (var i = 0; i < array.length; i += 1) {
var line = array[i];
var parts = line.split(": ");
var name = parts.shift();
var value = parts.join(": ");
map[toLowerCase(name)] = value;
}
this._map = map;
}
HeadersPolyfill.prototype.get = function (name) {
return this._map[toLowerCase(name)];
};
if (XMLHttpRequest != null && XMLHttpRequest.HEADERS_RECEIVED == null) { // IE < 9, Firefox 3.6
XMLHttpRequest.HEADERS_RECEIVED = 2;
}
function XHRTransport() {
}
XHRTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) {
xhr.open("GET", url);
var offset = 0;
xhr.onprogress = function () {
var responseText = xhr.responseText;
var chunk = responseText.slice(offset);
offset += chunk.length;
onProgressCallback(chunk);
};
xhr.onerror = function (event) {
event.preventDefault();
onFinishCallback(new Error("NetworkError"));
};
xhr.onload = function () {
onFinishCallback(null);
};
xhr.onabort = function () {
onFinishCallback(null);
};
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
var status = xhr.status;
var statusText = xhr.statusText;
var contentType = xhr.getResponseHeader("Content-Type");
var headers = xhr.getAllResponseHeaders();
onStartCallback(status, statusText, contentType, new HeadersPolyfill(headers));
}
};
xhr.withCredentials = withCredentials;
for (var name in headers) {
if (Object.prototype.hasOwnProperty.call(headers, name)) {
xhr.setRequestHeader(name, headers[name]);
}
}
xhr.send();
return xhr;
};
function HeadersWrapper(headers) {
this._headers = headers;
}
HeadersWrapper.prototype.get = function (name) {
return this._headers.get(name);
};
function FetchTransport() {
}
FetchTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) {
var reader = null;
var controller = new AbortController();
var signal = controller.signal;
var textDecoder = new TextDecoder();
fetch(url, {
headers: headers,
credentials: withCredentials ? "include" : "same-origin",
signal: signal,
cache: "no-store"
}).then(function (response) {
reader = response.body.getReader();
onStartCallback(response.status, response.statusText, response.headers.get("Content-Type"), new HeadersWrapper(response.headers));
// see https://github.com/promises-aplus/promises-spec/issues/179
return new Promise(function (resolve, reject) {
var readNextChunk = function () {
reader.read().then(function (result) {
if (result.done) {
//Note: bytes in textDecoder are ignored
resolve(undefined);
} else {
var chunk = textDecoder.decode(result.value, {stream: true});
onProgressCallback(chunk);
readNextChunk();
}
})["catch"](function (error) {
reject(error);
});
};
readNextChunk();
});
})["catch"](function (error) {
if (error.name === "AbortError") {
return undefined;
} else {
return error;
}
}).then(function (error) {
onFinishCallback(error);
});
return {
abort: function () {
if (reader != null) {
reader.cancel(); // https://bugzilla.mozilla.org/show_bug.cgi?id=1583815
}
controller.abort();
}
};
};
function EventTarget() {
this._listeners = Object.create(null);
}
function throwError(e) {
setTimeout(function () {
throw e;
}, 0);
}
EventTarget.prototype.dispatchEvent = function (event) {
event.target = this;
var typeListeners = this._listeners[event.type];
if (typeListeners != undefined) {
var length = typeListeners.length;
for (var i = 0; i < length; i += 1) {
var listener = typeListeners[i];
try {
if (typeof listener.handleEvent === "function") {
listener.handleEvent(event);
} else {
listener.call(this, event);
}
} catch (e) {
throwError(e);
}
}
}
};
EventTarget.prototype.addEventListener = function (type, listener) {
type = String(type);
var listeners = this._listeners;
var typeListeners = listeners[type];
if (typeListeners == undefined) {
typeListeners = [];
listeners[type] = typeListeners;
}
var found = false;
for (var i = 0; i < typeListeners.length; i += 1) {
if (typeListeners[i] === listener) {
found = true;
}
}
if (!found) {
typeListeners.push(listener);
}
};
EventTarget.prototype.removeEventListener = function (type, listener) {
type = String(type);
var listeners = this._listeners;
var typeListeners = listeners[type];
if (typeListeners != undefined) {
var filtered = [];
for (var i = 0; i < typeListeners.length; i += 1) {
if (typeListeners[i] !== listener) {
filtered.push(typeListeners[i]);
}
}
if (filtered.length === 0) {
delete listeners[type];
} else {
listeners[type] = filtered;
}
}
};
function Event(type) {
this.type = type;
this.target = undefined;
}
function MessageEvent(type, options) {
Event.call(this, type);
this.data = options.data;
this.lastEventId = options.lastEventId;
}
MessageEvent.prototype = Object.create(Event.prototype);
function ConnectionEvent(type, options) {
Event.call(this, type);
this.status = options.status;
this.statusText = options.statusText;
this.headers = options.headers;
}
ConnectionEvent.prototype = Object.create(Event.prototype);
function ErrorEvent(type, options) {
Event.call(this, type);
this.error = options.error;
}
ErrorEvent.prototype = Object.create(Event.prototype);
var WAITING = -1;
var CONNECTING = 0;
var OPEN = 1;
var CLOSED = 2;
var AFTER_CR = -1;
var FIELD_START = 0;
var FIELD = 1;
var VALUE_START = 2;
var VALUE = 3;
var contentTypeRegExp = /^text\/event\-stream(;.*)?$/i;
var MINIMUM_DURATION = 1000;
var MAXIMUM_DURATION = 18000000;
var parseDuration = function (value, def) {
var n = value == null ? def : parseInt(value, 10);
if (n !== n) {
n = def;
}
return clampDuration(n);
};
var clampDuration = function (n) {
return Math.min(Math.max(n, MINIMUM_DURATION), MAXIMUM_DURATION);
};
var fire = function (that, f, event) {
try {
if (typeof f === "function") {
f.call(that, event);
}
} catch (e) {
throwError(e);
}
};
function EventSourcePolyfill(url, options) {
EventTarget.call(this);
options = options || {};
this.onopen = undefined;
this.onmessage = undefined;
this.onerror = undefined;
this.url = undefined;
this.readyState = undefined;
this.withCredentials = undefined;
this.headers = undefined;
this._close = undefined;
start(this, url, options);
}
function getBestXHRTransport() {
return (XMLHttpRequest != undefined && ("withCredentials" in XMLHttpRequest.prototype)) || XDomainRequest == undefined
? new XMLHttpRequest()
: new XDomainRequest();
}
var isFetchSupported = fetch != undefined && Response != undefined && "body" in Response.prototype;
function start(es, url, options) {
url = String(url);
var withCredentials = Boolean(options.withCredentials);
var lastEventIdQueryParameterName = options.lastEventIdQueryParameterName || "lastEventId";
var initialRetry = clampDuration(1000);
var heartbeatTimeout = parseDuration(options.heartbeatTimeout, 45000);
var lastEventId = "";
var retry = initialRetry;
var wasActivity = false;
var textLength = 0;
var headers = options.headers || {};
var TransportOption = options.Transport;
var xhr = isFetchSupported && TransportOption == undefined ? undefined : new XHRWrapper(TransportOption != undefined ? new TransportOption() : getBestXHRTransport());
var transport = TransportOption != null && typeof TransportOption !== "string" ? new TransportOption() : (xhr == undefined ? new FetchTransport() : new XHRTransport());
var abortController = undefined;
var timeout = 0;
var currentState = WAITING;
var dataBuffer = "";
var lastEventIdBuffer = "";
var eventTypeBuffer = "";
var textBuffer = "";
var state = FIELD_START;
var fieldStart = 0;
var valueStart = 0;
var onStart = function (status, statusText, contentType, headers) {
if (currentState === CONNECTING) {
if (status === 200 && contentType != undefined && contentTypeRegExp.test(contentType)) {
currentState = OPEN;
wasActivity = Date.now();
retry = initialRetry;
es.readyState = OPEN;
var event = new ConnectionEvent("open", {
status: status,
statusText: statusText,
headers: headers
});
es.dispatchEvent(event);
fire(es, es.onopen, event);
} else {
var message = "";
if (status !== 200) {
if (statusText) {
statusText = statusText.replace(/\s+/g, " ");
}
message = "EventSource's response has a status " + status + " " + statusText + " that is not 200. Aborting the connection.";
} else {
message = "EventSource's response has a Content-Type specifying an unsupported type: " + (contentType == undefined ? "-" : contentType.replace(/\s+/g, " ")) + ". Aborting the connection.";
}
close();
var event = new ConnectionEvent("error", {
status: status,
statusText: statusText,
headers: headers
});
es.dispatchEvent(event);
fire(es, es.onerror, event);
console.error(message);
}
}
};
var onProgress = function (textChunk) {
if (currentState === OPEN) {
var n = -1;
for (var i = 0; i < textChunk.length; i += 1) {
var c = textChunk.charCodeAt(i);
if (c === "\n".charCodeAt(0) || c === "\r".charCodeAt(0)) {
n = i;
}
}
var chunk = (n !== -1 ? textBuffer : "") + textChunk.slice(0, n + 1);
textBuffer = (n === -1 ? textBuffer : "") + textChunk.slice(n + 1);
if (textChunk !== "") {
wasActivity = Date.now();
textLength += textChunk.length;
}
for (var position = 0; position < chunk.length; position += 1) {
var c = chunk.charCodeAt(position);
if (state === AFTER_CR && c === "\n".charCodeAt(0)) {
state = FIELD_START;
} else {
if (state === AFTER_CR) {
state = FIELD_START;
}
if (c === "\r".charCodeAt(0) || c === "\n".charCodeAt(0)) {
if (state !== FIELD_START) {
if (state === FIELD) {
valueStart = position + 1;
}
var field = chunk.slice(fieldStart, valueStart - 1);
var value = chunk.slice(valueStart + (valueStart < position && chunk.charCodeAt(valueStart) === " ".charCodeAt(0) ? 1 : 0), position);
if (field === "data") {
dataBuffer += "\n";
dataBuffer += value;
} else if (field === "id") {
lastEventIdBuffer = value;
} else if (field === "event") {
eventTypeBuffer = value;
} else if (field === "retry") {
initialRetry = parseDuration(value, initialRetry);
retry = initialRetry;
} else if (field === "heartbeatTimeout") {
heartbeatTimeout = parseDuration(value, heartbeatTimeout);
if (timeout !== 0) {
clearTimeout(timeout);
timeout = setTimeout(function () {
onTimeout();
}, heartbeatTimeout);
}
}
}
if (state === FIELD_START) {
if (dataBuffer !== "") {
lastEventId = lastEventIdBuffer;
if (eventTypeBuffer === "") {
eventTypeBuffer = "message";
}
var event = new MessageEvent(eventTypeBuffer, {
data: dataBuffer.slice(1),
lastEventId: lastEventIdBuffer
});
es.dispatchEvent(event);
if (eventTypeBuffer === "open") {
fire(es, es.onopen, event);
} else if (eventTypeBuffer === "message") {
fire(es, es.onmessage, event);
} else if (eventTypeBuffer === "error") {
fire(es, es.onerror, event);
}
if (currentState === CLOSED) {
return;
}
}
dataBuffer = "";
eventTypeBuffer = "";
}
state = c === "\r".charCodeAt(0) ? AFTER_CR : FIELD_START;
} else {
if (state === FIELD_START) {
fieldStart = position;
state = FIELD;
}
if (state === FIELD) {
if (c === ":".charCodeAt(0)) {
valueStart = position + 1;
state = VALUE_START;
}
} else if (state === VALUE_START) {
state = VALUE;
}
}
}
}
}
};
var onFinish = function (error) {
if (currentState === OPEN || currentState === CONNECTING) {
currentState = WAITING;
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
timeout = setTimeout(function () {
onTimeout();
}, retry);
retry = clampDuration(Math.min(initialRetry * 16, retry * 2));
es.readyState = CONNECTING;
var event = new ErrorEvent("error", {error: error});
es.dispatchEvent(event);
fire(es, es.onerror, event);
if (error != undefined) {
console.error(error);
}
}
};
var close = function () {
currentState = CLOSED;
if (abortController != undefined) {
abortController.abort();
abortController = undefined;
}
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
es.readyState = CLOSED;
};
var onTimeout = function () {
timeout = 0;
if (currentState !== WAITING) {
if (!wasActivity && abortController != undefined) {
onFinish(new Error("No activity within " + heartbeatTimeout + " milliseconds." + " " + (currentState === CONNECTING ? "No response received." : textLength + " chars received.") + " " + "Reconnecting."));
if (abortController != undefined) {
abortController.abort();
abortController = undefined;
}
} else {
var nextHeartbeat = Math.max((wasActivity || Date.now()) + heartbeatTimeout - Date.now(), 1);
wasActivity = false;
timeout = setTimeout(function () {
onTimeout();
}, nextHeartbeat);
}
return;
}
wasActivity = false;
textLength = 0;
timeout = setTimeout(function () {
onTimeout();
}, heartbeatTimeout);
currentState = CONNECTING;
dataBuffer = "";
eventTypeBuffer = "";
lastEventIdBuffer = lastEventId;
textBuffer = "";
fieldStart = 0;
valueStart = 0;
state = FIELD_START;
// https://bugzilla.mozilla.org/show_bug.cgi?id=428916
// Request header field Last-Event-ID is not allowed by Access-Control-Allow-Headers.
var requestURL = url;
if (url.slice(0, 5) !== "data:" && url.slice(0, 5) !== "blob:") {
if (lastEventId !== "") {
requestURL += (url.indexOf("?") === -1 ? "?" : "&") + lastEventIdQueryParameterName +"=" + encodeURIComponent(lastEventId);
}
}
var withCredentials = es.withCredentials;
var requestHeaders = {};
requestHeaders["Accept"] = "text/event-stream";
var headers = es.headers;
if (headers != undefined) {
for (var name in headers) {
if (Object.prototype.hasOwnProperty.call(headers, name)) {
requestHeaders[name] = headers[name];
}
}
}
try {
abortController = transport.open(xhr, onStart, onProgress, onFinish, requestURL, withCredentials, requestHeaders);
} catch (error) {
close();
throw error;
}
};
es.url = url;
es.readyState = CONNECTING;
es.withCredentials = withCredentials;
es.headers = headers;
es._close = close;
onTimeout();
}
EventSourcePolyfill.prototype = Object.create(EventTarget.prototype);
EventSourcePolyfill.prototype.CONNECTING = CONNECTING;
EventSourcePolyfill.prototype.OPEN = OPEN;
EventSourcePolyfill.prototype.CLOSED = CLOSED;
EventSourcePolyfill.prototype.close = function () {
this._close();
};
EventSourcePolyfill.CONNECTING = CONNECTING;
EventSourcePolyfill.OPEN = OPEN;
EventSourcePolyfill.CLOSED = CLOSED;
EventSourcePolyfill.prototype.withCredentials = undefined;
var R = NativeEventSource;
if (XMLHttpRequest != undefined && (NativeEventSource == undefined || !("withCredentials" in NativeEventSource.prototype))) {
// Why replace a native EventSource ?
// https://bugzilla.mozilla.org/show_bug.cgi?id=444328
// https://bugzilla.mozilla.org/show_bug.cgi?id=831392
// https://code.google.com/p/chromium/issues/detail?id=260144
// https://code.google.com/p/chromium/issues/detail?id=225654
// ...
R = EventSourcePolyfill;
}
(function (factory) {
{
var v = factory(exports);
if (v !== undefined) { module.exports = v; }
}
})(function (exports) {
exports.EventSourcePolyfill = EventSourcePolyfill;
exports.NativeEventSource = NativeEventSource;
exports.EventSource = R;
});
}(typeof globalThis === 'undefined' ? (typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : commonjsGlobal) : globalThis));
});
var eventsource$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.assign(/*#__PURE__*/Object.create(null), eventsource, {
'default': eventsource
}));
var formatText = function (e) { return e.data; };
var formatJSON = function (e) { return JSON.parse(e.data); };
var SSEClient = function SSEClient(config) {
this._handlers = {};
this._listeners = {};
this._source = null;
if (config.format) {
if (typeof config.format === 'string') {
if (config.format === 'plain') {
this._format = formatText;
} else if (config.format === 'json') {
this._format = formatJSON;
} else {
this._format = formatText;
}
} else if (typeof config.format === 'function') {
this._format = config.format;
} else {
this._format = formatText;
}
} else {
this._format = formatText;
}
if (config.handlers) {
for (var event in config.handlers) {
this.on(event, config.handlers[event]);
}
}
this.url = config.url;
this.withCredentials = !!config.withCredentials;
this.polyfillOptions = config.polyfillOptions || {};
this.forcePolyfill = !!config.forcePolyfill;
};
var prototypeAccessors = { source: { configurable: true } };
prototypeAccessors.source.get = function () {
return this._source;
};
SSEClient.prototype.connect = function connect () {
var this$1 = this;
if (this.forcePolyfill) {
this._source = new eventsource.EventSourcePolyfill(
this.url,
Object.assign({}, this.polyfillOptions, {
withCredentials: this.withCredentials,
})
);
} else {
this._source = new window.EventSource(this.url, {
withCredentials: this.withCredentials,
});
}
return new Promise(function (resolve, reject) {
this$1._source.onopen = function () {
// Add event listeners that were added before we connected
for (var event in this$1._listeners) {
this$1._source.addEventListener(event, this$1._listeners[event]);
}
this$1._source.onerror = null;
resolve(this$1);
};
this$1._source.onerror = reject;
});
};
SSEClient.prototype.disconnect = function disconnect () {
if (this._source !== null) {
this._source.close();
this._source = null;
}
};
SSEClient.prototype.on = function on (event, handler) {
if (!event) {
// Default "event-less" event
event = 'message';
}
if (!this._listeners[event]) {
this._create(event);
}
this._handlers[event].push(handler);
return this;
};
SSEClient.prototype.once = function once (event, handler) {
var this$1 = this;
this.on(event, function (e) {
this$1.off(event, handler);
handler(e);
});
return this;
};
SSEClient.prototype.off = function off (event, handler) {
if (!this._handlers[event]) {
// no handlers registered for event
return this;
}
var idx = this._handlers[event].indexOf(handler);
if (idx === -1) {
// handler not registered for event
return this;
}
// remove handler from event
this._handlers[event].splice(idx, 1);
if (this._handlers[event].length === 0) {
// remove listener since no handlers exist
this._source.removeEventListener(event, this._listeners[event]);
delete this._handlers[event];
delete this._listeners[event];
}
return this;
};
SSEClient.prototype._create = function _create (event) {
var this$1 = this;
this._handlers[event] = [];
this._listeners[event] = function (message) {
var data;
try {
data = this$1._format(message);
} catch (err) {
if (typeof this$1._source.onerror === 'function') {
this$1._source.onerror(err);
}
return;
}
this$1._handlers[event].forEach(function (handler) { return handler(data, message.lastEventId); });
};
if (this._source) {
this._source.addEventListener(event, this._listeners[event]);
}
};
Object.defineProperties( SSEClient.prototype, prototypeAccessors );
function install(Vue, config) {
if (Vue.config && Vue.config.globalProperties) {
// Vue3
Vue.config.globalProperties.$sse = new SSEManager(config);
} else {
// Vue2
// eslint-disable-next-line no-param-reassign, no-multi-assign
Vue.$sse = Vue.prototype.$sse = new SSEManager(config);
}
if (config && config.polyfill) {
Promise.resolve().then(function () { return eventsource$1; });
}
// This mixin allows components to specify that all clients that were
// created within it should be automatically disconnected (cleanup)
// when the component is destroyed.
Vue.mixin({
beforeCreate: function beforeCreate() {
if (this.$options.sse && this.$options.sse.cleanup) {
// We instantiate an SSEManager for this specific instance
// in order to track it (see discussions in #13 for rationale).
this.$sse = new SSEManager();
// We also set $clients to an empty array, as opposed to null,
// so that beforeDestroy and create know to use it.
this.$sse.$clients = [];
}
},
beforeDestroy: function beforeDestroy() {
if (this.$sse.$clients !== null) {
this.$sse.$clients.forEach(function (c) { return c.disconnect(); });
this.$sse.$clients = [];
}
},
});
}
var SSEManager = function SSEManager(config) {
this.$defaultConfig = Object.assign(
{
format: formatText,
sendCredentials: false,
},
config
);
this.$clients = null;
};
SSEManager.prototype.create = function create (configOrURL) {
var config;
if (typeof configOrURL === 'object') {
config = configOrURL;
} else if (typeof configOrURL === 'string') {
config = {
url: configOrURL,
};
} else {
config = {};
}
var client = new SSEClient(Object.assign({}, this.$defaultConfig, config));
// If $clients is not null, then it's array that we should push this
// client into for later cleanup in our mixin's beforeDestroy.
if (this.$clients !== null) {
this.$clients.push(client);
}
return client;
};
var index = {
install: install,
};
export default index;
export { SSEManager, install };
================================================
FILE: dist/vue-sse.js
================================================
/*!
* vue-sse v2.5.0
* (c) 2021 James Churchard
* @license MIT
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.VueSSE = factory());
}(this, (function () { 'use strict';
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn) {
var module = { exports: {} };
return fn(module, module.exports), module.exports;
}
/** @license
* eventsource.js
* Available under MIT License (MIT)
* https://github.com/Yaffle/EventSource/
*/
var eventsource = createCommonjsModule(function (module, exports) {
/*jslint indent: 2, vars: true, plusplus: true */
/*global setTimeout, clearTimeout */
(function (global) {
var setTimeout = global.setTimeout;
var clearTimeout = global.clearTimeout;
var XMLHttpRequest = global.XMLHttpRequest;
var XDomainRequest = global.XDomainRequest;
var ActiveXObject = global.ActiveXObject;
var NativeEventSource = global.EventSource;
var document = global.document;
var Promise = global.Promise;
var fetch = global.fetch;
var Response = global.Response;
var TextDecoder = global.TextDecoder;
var TextEncoder = global.TextEncoder;
var AbortController = global.AbortController;
if (typeof window !== "undefined" && !("readyState" in document) && document.body == null) { // Firefox 2
document.readyState = "loading";
window.addEventListener("load", function (event) {
document.readyState = "complete";
}, false);
}
if (XMLHttpRequest == null && ActiveXObject != null) { // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest_in_IE6
XMLHttpRequest = function () {
return new ActiveXObject("Microsoft.XMLHTTP");
};
}
if (Object.create == undefined) {
Object.create = function (C) {
function F(){}
F.prototype = C;
return new F();
};
}
if (!Date.now) {
Date.now = function now() {
return new Date().getTime();
};
}
// see #118 (Promise#finally with polyfilled Promise)
// see #123 (data URLs crash Edge)
// see #125 (CSP violations)
// see pull/#138
// => No way to polyfill Promise#finally
if (AbortController == undefined) {
var originalFetch2 = fetch;
fetch = function (url, options) {
var signal = options.signal;
return originalFetch2(url, {headers: options.headers, credentials: options.credentials, cache: options.cache}).then(function (response) {
var reader = response.body.getReader();
signal._reader = reader;
if (signal._aborted) {
signal._reader.cancel();
}
return {
status: response.status,
statusText: response.statusText,
headers: response.headers,
body: {
getReader: function () {
return reader;
}
}
};
});
};
AbortController = function () {
this.signal = {
_reader: null,
_aborted: false
};
this.abort = function () {
if (this.signal._reader != null) {
this.signal._reader.cancel();
}
this.signal._aborted = true;
};
};
}
function TextDecoderPolyfill() {
this.bitsNeeded = 0;
this.codePoint = 0;
}
TextDecoderPolyfill.prototype.decode = function (octets) {
function valid(codePoint, shift, octetsCount) {
if (octetsCount === 1) {
return codePoint >= 0x0080 >> shift && codePoint << shift <= 0x07FF;
}
if (octetsCount === 2) {
return codePoint >= 0x0800 >> shift && codePoint << shift <= 0xD7FF || codePoint >= 0xE000 >> shift && codePoint << shift <= 0xFFFF;
}
if (octetsCount === 3) {
return codePoint >= 0x010000 >> shift && codePoint << shift <= 0x10FFFF;
}
throw new Error();
}
function octetsCount(bitsNeeded, codePoint) {
if (bitsNeeded === 6 * 1) {
return codePoint >> 6 > 15 ? 3 : codePoint > 31 ? 2 : 1;
}
if (bitsNeeded === 6 * 2) {
return codePoint > 15 ? 3 : 2;
}
if (bitsNeeded === 6 * 3) {
return 3;
}
throw new Error();
}
var REPLACER = 0xFFFD;
var string = "";
var bitsNeeded = this.bitsNeeded;
var codePoint = this.codePoint;
for (var i = 0; i < octets.length; i += 1) {
var octet = octets[i];
if (bitsNeeded !== 0) {
if (octet < 128 || octet > 191 || !valid(codePoint << 6 | octet & 63, bitsNeeded - 6, octetsCount(bitsNeeded, codePoint))) {
bitsNeeded = 0;
codePoint = REPLACER;
string += String.fromCharCode(codePoint);
}
}
if (bitsNeeded === 0) {
if (octet >= 0 && octet <= 127) {
bitsNeeded = 0;
codePoint = octet;
} else if (octet >= 192 && octet <= 223) {
bitsNeeded = 6 * 1;
codePoint = octet & 31;
} else if (octet >= 224 && octet <= 239) {
bitsNeeded = 6 * 2;
codePoint = octet & 15;
} else if (octet >= 240 && octet <= 247) {
bitsNeeded = 6 * 3;
codePoint = octet & 7;
} else {
bitsNeeded = 0;
codePoint = REPLACER;
}
if (bitsNeeded !== 0 && !valid(codePoint, bitsNeeded, octetsCount(bitsNeeded, codePoint))) {
bitsNeeded = 0;
codePoint = REPLACER;
}
} else {
bitsNeeded -= 6;
codePoint = codePoint << 6 | octet & 63;
}
if (bitsNeeded === 0) {
if (codePoint <= 0xFFFF) {
string += String.fromCharCode(codePoint);
} else {
string += String.fromCharCode(0xD800 + (codePoint - 0xFFFF - 1 >> 10));
string += String.fromCharCode(0xDC00 + (codePoint - 0xFFFF - 1 & 0x3FF));
}
}
}
this.bitsNeeded = bitsNeeded;
this.codePoint = codePoint;
return string;
};
// Firefox < 38 throws an error with stream option
var supportsStreamOption = function () {
try {
return new TextDecoder().decode(new TextEncoder().encode("test"), {stream: true}) === "test";
} catch (error) {
console.debug("TextDecoder does not support streaming option. Using polyfill instead: " + error);
}
return false;
};
// IE, Edge
if (TextDecoder == undefined || TextEncoder == undefined || !supportsStreamOption()) {
TextDecoder = TextDecoderPolyfill;
}
var k = function () {
};
function XHRWrapper(xhr) {
this.withCredentials = false;
this.readyState = 0;
this.status = 0;
this.statusText = "";
this.responseText = "";
this.onprogress = k;
this.onload = k;
this.onerror = k;
this.onreadystatechange = k;
this._contentType = "";
this._xhr = xhr;
this._sendTimeout = 0;
this._abort = k;
}
XHRWrapper.prototype.open = function (method, url) {
this._abort(true);
var that = this;
var xhr = this._xhr;
var state = 1;
var timeout = 0;
this._abort = function (silent) {
if (that._sendTimeout !== 0) {
clearTimeout(that._sendTimeout);
that._sendTimeout = 0;
}
if (state === 1 || state === 2 || state === 3) {
state = 4;
xhr.onload = k;
xhr.onerror = k;
xhr.onabort = k;
xhr.onprogress = k;
xhr.onreadystatechange = k;
// IE 8 - 9: XDomainRequest#abort() does not fire any event
// Opera < 10: XMLHttpRequest#abort() does not fire any event
xhr.abort();
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
if (!silent) {
that.readyState = 4;
that.onabort(null);
that.onreadystatechange();
}
}
state = 0;
};
var onStart = function () {
if (state === 1) {
//state = 2;
var status = 0;
var statusText = "";
var contentType = undefined;
if (!("contentType" in xhr)) {
try {
status = xhr.status;
statusText = xhr.statusText;
contentType = xhr.getResponseHeader("Content-Type");
} catch (error) {
// IE < 10 throws exception for `xhr.status` when xhr.readyState === 2 || xhr.readyState === 3
// Opera < 11 throws exception for `xhr.status` when xhr.readyState === 2
// https://bugs.webkit.org/show_bug.cgi?id=29121
status = 0;
statusText = "";
contentType = undefined;
// Firefox < 14, Chrome ?, Safari ?
// https://bugs.webkit.org/show_bug.cgi?id=29658
// https://bugs.webkit.org/show_bug.cgi?id=77854
}
} else {
status = 200;
statusText = "OK";
contentType = xhr.contentType;
}
if (status !== 0) {
state = 2;
that.readyState = 2;
that.status = status;
that.statusText = statusText;
that._contentType = contentType;
that.onreadystatechange();
}
}
};
var onProgress = function () {
onStart();
if (state === 2 || state === 3) {
state = 3;
var responseText = "";
try {
responseText = xhr.responseText;
} catch (error) {
// IE 8 - 9 with XMLHttpRequest
}
that.readyState = 3;
that.responseText = responseText;
that.onprogress();
}
};
var onFinish = function (type, event) {
if (event == null || event.preventDefault == null) {
event = {
preventDefault: k
};
}
// Firefox 52 fires "readystatechange" (xhr.readyState === 4) without final "readystatechange" (xhr.readyState === 3)
// IE 8 fires "onload" without "onprogress"
onProgress();
if (state === 1 || state === 2 || state === 3) {
state = 4;
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
that.readyState = 4;
if (type === "load") {
that.onload(event);
} else if (type === "error") {
that.onerror(event);
} else if (type === "abort") {
that.onabort(event);
} else {
throw new TypeError();
}
that.onreadystatechange();
}
};
var onReadyStateChange = function (event) {
if (xhr != undefined) { // Opera 12
if (xhr.readyState === 4) {
if (!("onload" in xhr) || !("onerror" in xhr) || !("onabort" in xhr)) {
onFinish(xhr.responseText === "" ? "error" : "load", event);
}
} else if (xhr.readyState === 3) {
if (!("onprogress" in xhr)) { // testing XMLHttpRequest#responseText too many times is too slow in IE 11
// and in Firefox 3.6
onProgress();
}
} else if (xhr.readyState === 2) {
onStart();
}
}
};
var onTimeout = function () {
timeout = setTimeout(function () {
onTimeout();
}, 500);
if (xhr.readyState === 3) {
onProgress();
}
};
// XDomainRequest#abort removes onprogress, onerror, onload
if ("onload" in xhr) {
xhr.onload = function (event) {
onFinish("load", event);
};
}
if ("onerror" in xhr) {
xhr.onerror = function (event) {
onFinish("error", event);
};
}
// improper fix to match Firefox behaviour, but it is better than just ignore abort
// see https://bugzilla.mozilla.org/show_bug.cgi?id=768596
// https://bugzilla.mozilla.org/show_bug.cgi?id=880200
// https://code.google.com/p/chromium/issues/detail?id=153570
// IE 8 fires "onload" without "onprogress
if ("onabort" in xhr) {
xhr.onabort = function (event) {
onFinish("abort", event);
};
}
if ("onprogress" in xhr) {
xhr.onprogress = onProgress;
}
// IE 8 - 9 (XMLHTTPRequest)
// Opera < 12
// Firefox < 3.5
// Firefox 3.5 - 3.6 - ? < 9.0
// onprogress is not fired sometimes or delayed
// see also #64 (significant lag in IE 11)
if ("onreadystatechange" in xhr) {
xhr.onreadystatechange = function (event) {
onReadyStateChange(event);
};
}
if ("contentType" in xhr || !("ontimeout" in XMLHttpRequest.prototype)) {
url += (url.indexOf("?") === -1 ? "?" : "&") + "padding=true";
}
xhr.open(method, url, true);
if ("readyState" in xhr) {
// workaround for Opera 12 issue with "progress" events
// #91 (XMLHttpRequest onprogress not fired for streaming response in Edge 14-15-?)
timeout = setTimeout(function () {
onTimeout();
}, 0);
}
};
XHRWrapper.prototype.abort = function () {
this._abort(false);
};
XHRWrapper.prototype.getResponseHeader = function (name) {
return this._contentType;
};
XHRWrapper.prototype.setRequestHeader = function (name, value) {
var xhr = this._xhr;
if ("setRequestHeader" in xhr) {
xhr.setRequestHeader(name, value);
}
};
XHRWrapper.prototype.getAllResponseHeaders = function () {
// XMLHttpRequest#getAllResponseHeaders returns null for CORS requests in Firefox 3.6.28
return this._xhr.getAllResponseHeaders != undefined ? this._xhr.getAllResponseHeaders() || "" : "";
};
XHRWrapper.prototype.send = function () {
// loading indicator in Safari < ? (6), Chrome < 14, Firefox
// https://bugzilla.mozilla.org/show_bug.cgi?id=736723
if ((!("ontimeout" in XMLHttpRequest.prototype) || (!("sendAsBinary" in XMLHttpRequest.prototype) && !("mozAnon" in XMLHttpRequest.prototype))) &&
document != undefined &&
document.readyState != undefined &&
document.readyState !== "complete") {
var that = this;
that._sendTimeout = setTimeout(function () {
that._sendTimeout = 0;
that.send();
}, 4);
return;
}
var xhr = this._xhr;
// withCredentials should be set after "open" for Safari and Chrome (< 19 ?)
if ("withCredentials" in xhr) {
xhr.withCredentials = this.withCredentials;
}
try {
// xhr.send(); throws "Not enough arguments" in Firefox 3.0
xhr.send(undefined);
} catch (error1) {
// Safari 5.1.7, Opera 12
throw error1;
}
};
function toLowerCase(name) {
return name.replace(/[A-Z]/g, function (c) {
return String.fromCharCode(c.charCodeAt(0) + 0x20);
});
}
function HeadersPolyfill(all) {
// Get headers: implemented according to mozilla's example code: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders#Example
var map = Object.create(null);
var array = all.split("\r\n");
for (var i = 0; i < array.length; i += 1) {
var line = array[i];
var parts = line.split(": ");
var name = parts.shift();
var value = parts.join(": ");
map[toLowerCase(name)] = value;
}
this._map = map;
}
HeadersPolyfill.prototype.get = function (name) {
return this._map[toLowerCase(name)];
};
if (XMLHttpRequest != null && XMLHttpRequest.HEADERS_RECEIVED == null) { // IE < 9, Firefox 3.6
XMLHttpRequest.HEADERS_RECEIVED = 2;
}
function XHRTransport() {
}
XHRTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) {
xhr.open("GET", url);
var offset = 0;
xhr.onprogress = function () {
var responseText = xhr.responseText;
var chunk = responseText.slice(offset);
offset += chunk.length;
onProgressCallback(chunk);
};
xhr.onerror = function (event) {
event.preventDefault();
onFinishCallback(new Error("NetworkError"));
};
xhr.onload = function () {
onFinishCallback(null);
};
xhr.onabort = function () {
onFinishCallback(null);
};
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
var status = xhr.status;
var statusText = xhr.statusText;
var contentType = xhr.getResponseHeader("Content-Type");
var headers = xhr.getAllResponseHeaders();
onStartCallback(status, statusText, contentType, new HeadersPolyfill(headers));
}
};
xhr.withCredentials = withCredentials;
for (var name in headers) {
if (Object.prototype.hasOwnProperty.call(headers, name)) {
xhr.setRequestHeader(name, headers[name]);
}
}
xhr.send();
return xhr;
};
function HeadersWrapper(headers) {
this._headers = headers;
}
HeadersWrapper.prototype.get = function (name) {
return this._headers.get(name);
};
function FetchTransport() {
}
FetchTransport.prototype.open = function (xhr, onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) {
var reader = null;
var controller = new AbortController();
var signal = controller.signal;
var textDecoder = new TextDecoder();
fetch(url, {
headers: headers,
credentials: withCredentials ? "include" : "same-origin",
signal: signal,
cache: "no-store"
}).then(function (response) {
reader = response.body.getReader();
onStartCallback(response.status, response.statusText, response.headers.get("Content-Type"), new HeadersWrapper(response.headers));
// see https://github.com/promises-aplus/promises-spec/issues/179
return new Promise(function (resolve, reject) {
var readNextChunk = function () {
reader.read().then(function (result) {
if (result.done) {
//Note: bytes in textDecoder are ignored
resolve(undefined);
} else {
var chunk = textDecoder.decode(result.value, {stream: true});
onProgressCallback(chunk);
readNextChunk();
}
})["catch"](function (error) {
reject(error);
});
};
readNextChunk();
});
})["catch"](function (error) {
if (error.name === "AbortError") {
return undefined;
} else {
return error;
}
}).then(function (error) {
onFinishCallback(error);
});
return {
abort: function () {
if (reader != null) {
reader.cancel(); // https://bugzilla.mozilla.org/show_bug.cgi?id=1583815
}
controller.abort();
}
};
};
function EventTarget() {
this._listeners = Object.create(null);
}
function throwError(e) {
setTimeout(function () {
throw e;
}, 0);
}
EventTarget.prototype.dispatchEvent = function (event) {
event.target = this;
var typeListeners = this._listeners[event.type];
if (typeListeners != undefined) {
var length = typeListeners.length;
for (var i = 0; i < length; i += 1) {
var listener = typeListeners[i];
try {
if (typeof listener.handleEvent === "function") {
listener.handleEvent(event);
} else {
listener.call(this, event);
}
} catch (e) {
throwError(e);
}
}
}
};
EventTarget.prototype.addEventListener = function (type, listener) {
type = String(type);
var listeners = this._listeners;
var typeListeners = listeners[type];
if (typeListeners == undefined) {
typeListeners = [];
listeners[type] = typeListeners;
}
var found = false;
for (var i = 0; i < typeListeners.length; i += 1) {
if (typeListeners[i] === listener) {
found = true;
}
}
if (!found) {
typeListeners.push(listener);
}
};
EventTarget.prototype.removeEventListener = function (type, listener) {
type = String(type);
var listeners = this._listeners;
var typeListeners = listeners[type];
if (typeListeners != undefined) {
var filtered = [];
for (var i = 0; i < typeListeners.length; i += 1) {
if (typeListeners[i] !== listener) {
filtered.push(typeListeners[i]);
}
}
if (filtered.length === 0) {
delete listeners[type];
} else {
listeners[type] = filtered;
}
}
};
function Event(type) {
this.type = type;
this.target = undefined;
}
function MessageEvent(type, options) {
Event.call(this, type);
this.data = options.data;
this.lastEventId = options.lastEventId;
}
MessageEvent.prototype = Object.create(Event.prototype);
function ConnectionEvent(type, options) {
Event.call(this, type);
this.status = options.status;
this.statusText = options.statusText;
this.headers = options.headers;
}
ConnectionEvent.prototype = Object.create(Event.prototype);
function ErrorEvent(type, options) {
Event.call(this, type);
this.error = options.error;
}
ErrorEvent.prototype = Object.create(Event.prototype);
var WAITING = -1;
var CONNECTING = 0;
var OPEN = 1;
var CLOSED = 2;
var AFTER_CR = -1;
var FIELD_START = 0;
var FIELD = 1;
var VALUE_START = 2;
var VALUE = 3;
var contentTypeRegExp = /^text\/event\-stream(;.*)?$/i;
var MINIMUM_DURATION = 1000;
var MAXIMUM_DURATION = 18000000;
var parseDuration = function (value, def) {
var n = value == null ? def : parseInt(value, 10);
if (n !== n) {
n = def;
}
return clampDuration(n);
};
var clampDuration = function (n) {
return Math.min(Math.max(n, MINIMUM_DURATION), MAXIMUM_DURATION);
};
var fire = function (that, f, event) {
try {
if (typeof f === "function") {
f.call(that, event);
}
} catch (e) {
throwError(e);
}
};
function EventSourcePolyfill(url, options) {
EventTarget.call(this);
options = options || {};
this.onopen = undefined;
this.onmessage = undefined;
this.onerror = undefined;
this.url = undefined;
this.readyState = undefined;
this.withCredentials = undefined;
this.headers = undefined;
this._close = undefined;
start(this, url, options);
}
function getBestXHRTransport() {
return (XMLHttpRequest != undefined && ("withCredentials" in XMLHttpRequest.prototype)) || XDomainRequest == undefined
? new XMLHttpRequest()
: new XDomainRequest();
}
var isFetchSupported = fetch != undefined && Response != undefined && "body" in Response.prototype;
function start(es, url, options) {
url = String(url);
var withCredentials = Boolean(options.withCredentials);
var lastEventIdQueryParameterName = options.lastEventIdQueryParameterName || "lastEventId";
var initialRetry = clampDuration(1000);
var heartbeatTimeout = parseDuration(options.heartbeatTimeout, 45000);
var lastEventId = "";
var retry = initialRetry;
var wasActivity = false;
var textLength = 0;
var headers = options.headers || {};
var TransportOption = options.Transport;
var xhr = isFetchSupported && TransportOption == undefined ? undefined : new XHRWrapper(TransportOption != undefined ? new TransportOption() : getBestXHRTransport());
var transport = TransportOption != null && typeof TransportOption !== "string" ? new TransportOption() : (xhr == undefined ? new FetchTransport() : new XHRTransport());
var abortController = undefined;
var timeout = 0;
var currentState = WAITING;
var dataBuffer = "";
var lastEventIdBuffer = "";
var eventTypeBuffer = "";
var textBuffer = "";
var state = FIELD_START;
var fieldStart = 0;
var valueStart = 0;
var onStart = function (status, statusText, contentType, headers) {
if (currentState === CONNECTING) {
if (status === 200 && contentType != undefined && contentTypeRegExp.test(contentType)) {
currentState = OPEN;
wasActivity = Date.now();
retry = initialRetry;
es.readyState = OPEN;
var event = new ConnectionEvent("open", {
status: status,
statusText: statusText,
headers: headers
});
es.dispatchEvent(event);
fire(es, es.onopen, event);
} else {
var message = "";
if (status !== 200) {
if (statusText) {
statusText = statusText.replace(/\s+/g, " ");
}
message = "EventSource's response has a status " + status + " " + statusText + " that is not 200. Aborting the connection.";
} else {
message = "EventSource's response has a Content-Type specifying an unsupported type: " + (contentType == undefined ? "-" : contentType.replace(/\s+/g, " ")) + ". Aborting the connection.";
}
close();
var event = new ConnectionEvent("error", {
status: status,
statusText: statusText,
headers: headers
});
es.dispatchEvent(event);
fire(es, es.onerror, event);
console.error(message);
}
}
};
var onProgress = function (textChunk) {
if (currentState === OPEN) {
var n = -1;
for (var i = 0; i < textChunk.length; i += 1) {
var c = textChunk.charCodeAt(i);
if (c === "\n".charCodeAt(0) || c === "\r".charCodeAt(0)) {
n = i;
}
}
var chunk = (n !== -1 ? textBuffer : "") + textChunk.slice(0, n + 1);
textBuffer = (n === -1 ? textBuffer : "") + textChunk.slice(n + 1);
if (textChunk !== "") {
wasActivity = Date.now();
textLength += textChunk.length;
}
for (var position = 0; position < chunk.length; position += 1) {
var c = chunk.charCodeAt(position);
if (state === AFTER_CR && c === "\n".charCodeAt(0)) {
state = FIELD_START;
} else {
if (state === AFTER_CR) {
state = FIELD_START;
}
if (c === "\r".charCodeAt(0) || c === "\n".charCodeAt(0)) {
if (state !== FIELD_START) {
if (state === FIELD) {
valueStart = position + 1;
}
var field = chunk.slice(fieldStart, valueStart - 1);
var value = chunk.slice(valueStart + (valueStart < position && chunk.charCodeAt(valueStart) === " ".charCodeAt(0) ? 1 : 0), position);
if (field === "data") {
dataBuffer += "\n";
dataBuffer += value;
} else if (field === "id") {
lastEventIdBuffer = value;
} else if (field === "event") {
eventTypeBuffer = value;
} else if (field === "retry") {
initialRetry = parseDuration(value, initialRetry);
retry = initialRetry;
} else if (field === "heartbeatTimeout") {
heartbeatTimeout = parseDuration(value, heartbeatTimeout);
if (timeout !== 0) {
clearTimeout(timeout);
timeout = setTimeout(function () {
onTimeout();
}, heartbeatTimeout);
}
}
}
if (state === FIELD_START) {
if (dataBuffer !== "") {
lastEventId = lastEventIdBuffer;
if (eventTypeBuffer === "") {
eventTypeBuffer = "message";
}
var event = new MessageEvent(eventTypeBuffer, {
data: dataBuffer.slice(1),
lastEventId: lastEventIdBuffer
});
es.dispatchEvent(event);
if (eventTypeBuffer === "open") {
fire(es, es.onopen, event);
} else if (eventTypeBuffer === "message") {
fire(es, es.onmessage, event);
} else if (eventTypeBuffer === "error") {
fire(es, es.onerror, event);
}
if (currentState === CLOSED) {
return;
}
}
dataBuffer = "";
eventTypeBuffer = "";
}
state = c === "\r".charCodeAt(0) ? AFTER_CR : FIELD_START;
} else {
if (state === FIELD_START) {
fieldStart = position;
state = FIELD;
}
if (state === FIELD) {
if (c === ":".charCodeAt(0)) {
valueStart = position + 1;
state = VALUE_START;
}
} else if (state === VALUE_START) {
state = VALUE;
}
}
}
}
}
};
var onFinish = function (error) {
if (currentState === OPEN || currentState === CONNECTING) {
currentState = WAITING;
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
timeout = setTimeout(function () {
onTimeout();
}, retry);
retry = clampDuration(Math.min(initialRetry * 16, retry * 2));
es.readyState = CONNECTING;
var event = new ErrorEvent("error", {error: error});
es.dispatchEvent(event);
fire(es, es.onerror, event);
if (error != undefined) {
console.error(error);
}
}
};
var close = function () {
currentState = CLOSED;
if (abortController != undefined) {
abortController.abort();
abortController = undefined;
}
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
es.readyState = CLOSED;
};
var onTimeout = function () {
timeout = 0;
if (currentState !== WAITING) {
if (!wasActivity && abortController != undefined) {
onFinish(new Error("No activity within " + heartbeatTimeout + " milliseconds." + " " + (currentState === CONNECTING ? "No response received." : textLength + " chars received.") + " " + "Reconnecting."));
if (abortController != undefined) {
abortController.abort();
abortController = undefined;
}
} else {
var nextHeartbeat = Math.max((wasActivity || Date.now()) + heartbeatTimeout - Date.now(), 1);
wasActivity = false;
timeout = setTimeout(function () {
onTimeout();
}, nextHeartbeat);
}
return;
}
wasActivity = false;
textLength = 0;
timeout = setTimeout(function () {
onTimeout();
}, heartbeatTimeout);
currentState = CONNECTING;
dataBuffer = "";
eventTypeBuffer = "";
lastEventIdBuffer = lastEventId;
textBuffer = "";
fieldStart = 0;
valueStart = 0;
state = FIELD_START;
// https://bugzilla.mozilla.org/show_bug.cgi?id=428916
// Request header field Last-Event-ID is not allowed by Access-Control-Allow-Headers.
var requestURL = url;
if (url.slice(0, 5) !== "data:" && url.slice(0, 5) !== "blob:") {
if (lastEventId !== "") {
requestURL += (url.indexOf("?") === -1 ? "?" : "&") + lastEventIdQueryParameterName +"=" + encodeURIComponent(lastEventId);
}
}
var withCredentials = es.withCredentials;
var requestHeaders = {};
requestHeaders["Accept"] = "text/event-stream";
var headers = es.headers;
if (headers != undefined) {
for (var name in headers) {
if (Object.prototype.hasOwnProperty.call(headers, name)) {
requestHeaders[name] = headers[name];
}
}
}
try {
abortController = transport.open(xhr, onStart, onProgress, onFinish, requestURL, withCredentials, requestHeaders);
} catch (error) {
close();
throw error;
}
};
es.url = url;
es.readyState = CONNECTING;
es.withCredentials = withCredentials;
es.headers = headers;
es._close = close;
onTimeout();
}
EventSourcePolyfill.prototype = Object.create(EventTarget.prototype);
EventSourcePolyfill.prototype.CONNECTING = CONNECTING;
EventSourcePolyfill.prototype.OPEN = OPEN;
EventSourcePolyfill.prototype.CLOSED = CLOSED;
EventSourcePolyfill.prototype.close = function () {
this._close();
};
EventSourcePolyfill.CONNECTING = CONNECTING;
EventSourcePolyfill.OPEN = OPEN;
EventSourcePolyfill.CLOSED = CLOSED;
EventSourcePolyfill.prototype.withCredentials = undefined;
var R = NativeEventSource;
if (XMLHttpRequest != undefined && (NativeEventSource == undefined || !("withCredentials" in NativeEventSource.prototype))) {
// Why replace a native EventSource ?
// https://bugzilla.mozilla.org/show_bug.cgi?id=444328
// https://bugzilla.mozilla.org/show_bug.cgi?id=831392
// https://code.google.com/p/chromium/issues/detail?id=260144
// https://code.google.com/p/chromium/issues/detail?id=225654
// ...
R = EventSourcePolyfill;
}
(function (factory) {
{
var v = factory(exports);
if (v !== undefined) { module.exports = v; }
}
})(function (exports) {
exports.EventSourcePolyfill = EventSourcePolyfill;
exports.NativeEventSource = NativeEventSource;
exports.EventSource = R;
});
}(typeof globalThis === 'undefined' ? (typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : commonjsGlobal) : globalThis));
});
var eventsource$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.assign(/*#__PURE__*/Object.create(null), eventsource, {
'default': eventsource
}));
var formatText = function (e) { return e.data; };
var formatJSON = function (e) { return JSON.parse(e.data); };
var SSEClient = function SSEClient(config) {
this._handlers = {};
this._listeners = {};
this._source = null;
if (config.format) {
if (typeof config.format === 'string') {
if (config.format === 'plain') {
this._format = formatText;
} else if (config.format === 'json') {
this._format = formatJSON;
} else {
this._format = formatText;
}
} else if (typeof config.format === 'function') {
this._format = config.format;
} else {
this._format = formatText;
}
} else {
this._format = formatText;
}
if (config.handlers) {
for (var event in config.handlers) {
this.on(event, config.handlers[event]);
}
}
this.url = config.url;
this.withCredentials = !!config.withCredentials;
this.polyfillOptions = config.polyfillOptions || {};
this.forcePolyfill = !!config.forcePolyfill;
};
var prototypeAccessors = { source: { configurable: true } };
prototypeAccessors.source.get = function () {
return this._source;
};
SSEClient.prototype.connect = function connect () {
var this$1 = this;
if (this.forcePolyfill) {
this._source = new eventsource.EventSourcePolyfill(
this.url,
Object.assign({}, this.polyfillOptions, {
withCredentials: this.withCredentials,
})
);
} else {
this._source = new window.EventSource(this.url, {
withCredentials: this.withCredentials,
});
}
return new Promise(function (resolve, reject) {
this$1._source.onopen = function () {
// Add event listeners that were added before we connected
for (var event in this$1._listeners) {
this$1._source.addEventListener(event, this$1._listeners[event]);
}
this$1._source.onerror = null;
resolve(this$1);
};
this$1._source.onerror = reject;
});
};
SSEClient.prototype.disconnect = function disconnect () {
if (this._source !== null) {
this._source.close();
this._source = null;
}
};
SSEClient.prototype.on = function on (event, handler) {
if (!event) {
// Default "event-less" event
event = 'message';
}
if (!this._listeners[event]) {
this._create(event);
}
this._handlers[event].push(handler);
return this;
};
SSEClient.prototype.once = function once (event, handler) {
var this$1 = this;
this.on(event, function (e) {
this$1.off(event, handler);
handler(e);
});
return this;
};
SSEClient.prototype.off = function off (event, handler) {
if (!this._handlers[event]) {
// no handlers registered for event
return this;
}
var idx = this._handlers[event].indexOf(handler);
if (idx === -1) {
// handler not registered for event
return this;
}
// remove handler from event
this._handlers[event].splice(idx, 1);
if (this._handlers[event].length === 0) {
// remove listener since no handlers exist
this._source.removeEventListener(event, this._listeners[event]);
delete this._handlers[event];
delete this._listeners[event];
}
return this;
};
SSEClient.prototype._create = function _create (event) {
var this$1 = this;
this._handlers[event] = [];
this._listeners[event] = function (message) {
var data;
try {
data = this$1._format(message);
} catch (err) {
if (typeof this$1._source.onerror === 'function') {
this$1._source.onerror(err);
}
return;
}
this$1._handlers[event].forEach(function (handler) { return handler(data, message.lastEventId); });
};
if (this._source) {
this._source.addEventListener(event, this._listeners[event]);
}
};
Object.defineProperties( SSEClient.prototype, prototypeAccessors );
function install(Vue, config) {
if (Vue.config && Vue.config.globalProperties) {
// Vue3
Vue.config.globalProperties.$sse = new SSEManager(config);
} else {
// Vue2
// eslint-disable-next-line no-param-reassign, no-multi-assign
Vue.$sse = Vue.prototype.$sse = new SSEManager(config);
}
if (config && config.polyfill) {
Promise.resolve().then(function () { return eventsource$1; });
}
// This mixin allows components to specify that all clients that were
// created within it should be automatically disconnected (cleanup)
// when the component is destroyed.
Vue.mixin({
beforeCreate: function beforeCreate() {
if (this.$options.sse && this.$options.sse.cleanup) {
// We instantiate an SSEManager for this specific instance
// in order to track it (see discussions in #13 for rationale).
this.$sse = new SSEManager();
// We also set $clients to an empty array, as opposed to null,
// so that beforeDestroy and create know to use it.
this.$sse.$clients = [];
}
},
beforeDestroy: function beforeDestroy() {
if (this.$sse.$clients !== null) {
this.$sse.$clients.forEach(function (c) { return c.disconnect(); });
this.$sse.$clients = [];
}
},
});
}
var SSEManager = function SSEManager(config) {
this.$defaultConfig = Object.assign(
{
format: formatText,
sendCredentials: false,
},
config
);
this.$clients = null;
};
SSEManager.prototype.create = function create (configOrURL) {
var config;
if (typeof configOrURL === 'object') {
config = configOrURL;
} else if (typeof configOrURL === 'string') {
config = {
url: configOrURL,
};
} else {
config = {};
}
var client = new SSEClient(Object.assign({}, this.$defaultConfig, config));
// If $clients is not null, then it's array that we should push this
// client into for later cleanup in our mixin's beforeDestroy.
if (this.$clients !== null) {
this.$clients.push(client);
}
return client;
};
var index_cjs = {
SSEManager: SSEManager,
install: install,
};
return index_cjs;
})));
================================================
FILE: dist/vue-sse.mjs
================================================
import VueSSE from './vue-sse.common.js';
const {
SSEManager,
install,
} = VueSSE;
export {
VueSSE as default,
SSEManager,
install,
};
================================================
FILE: jest.config.js
================================================
module.exports = {
collectCoverageFrom: [
'src/**.*.js',
'!src/index.cjs.js',
],
coverageDirectory: 'coverage',
coverageProvider: 'v8',
rootDir: __dirname,
setupFilesAfterEnv: ['./test/setup.js'],
testMatch: ['<rootDir>/test/**/*.spec.js'],
testPathIgnorePatterns: ['/node_modules/'],
transform: {
'^.+\\.js$': '<rootDir>/node_modules/babel-jest',
},
};
================================================
FILE: package.json
================================================
{
"name": "vue-sse",
"version": "2.5.2",
"description": "A Vue plugin for using Server-Sent Events (EventSource)",
"main": "dist/vue-sse.common.js",
"exports": {
".": {
"module": "./dist/vue-sse.esm.js",
"require": "./dist/vue-sse.common.js",
"import": "./dist/vue-sse.mjs"
},
"./": "./"
},
"module": "dist/vue-sse.esm.js",
"typings": "types/index.d.ts",
"unpkg": "dist/vue-sse.js",
"jsdelivr": "dist/vue-sse.js",
"sideEffects": [
"./src/sse-client.js"
],
"files": [
"dist",
"types/*.d.ts"
],
"scripts": {
"build": "rollup -c rollup.config.js",
"format": "prettier --write \"src/**/*.js\"",
"lint": "eslint src test",
"postversion": "git push && git push --tags",
"prepare": "npm run build",
"prepublishOnly": "npm test && npm run lint",
"preversion": "npm run lint",
"test": "npm run lint && npm run test:unit",
"test:unit": "jest",
"test:types": "tsc -p types/test",
"version": "npm run format && git add -A src"
},
"repository": {
"type": "git",
"url": "git+https://github.com/tserkov/vue-sse.git"
},
"keywords": [
"vue",
"sse",
"eventsource",
"server sent events"
],
"author": "tserkov",
"license": "MIT",
"bugs": {
"url": "https://github.com/tserkov/vue-sse/issues"
},
"homepage": "https://github.com/tserkov/vue-sse",
"dependencies": {
"event-source-polyfill": "^1.0.22"
},
"peerDependencies": {
"vue": "^2.0.0 || ^3.0.0"
},
"devDependencies": {
"@babel/core": "^7.12.17",
"@babel/preset-env": "^7.12.17",
"@rollup/plugin-buble": "^0.21.3",
"@rollup/plugin-commonjs": "^17.1.0",
"@rollup/plugin-node-resolve": "^11.2.0",
"@vue/test-utils": "^1.1.4",
"babel-jest": "^26.6.3",
"babel-loader": "^8.2.2",
"eslint": "^7.20.0",
"eslint-plugin-vue": "^7.6.0",
"jest": "^26.6.3",
"mocksse": "^1.0.2",
"rollup": "^2.37.1",
"rollup-plugin-terser": "^7.0.2",
"typescript": "^4.1.5",
"vue": "^2.6.12",
"vue-loader": "^15.9.6"
}
}
================================================
FILE: rollup.config.js
================================================
import buble from '@rollup/plugin-buble';
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import { terser } from 'rollup-plugin-terser'
import pkg from './package.json';
const banner = `/*!
* vue-sse v${pkg.version}
* (c) ${new Date().getFullYear()} James Churchard
* @license MIT
*/`
export default [
{
input: 'src/index.js',
output: {
banner,
file: 'dist/vue-sse.esm.browser.js',
format: 'es',
},
plugins: [
resolve(),
commonjs(),
],
inlineDynamicImports: true,
},
{
input: 'src/index.js',
output: {
banner,
file: 'dist/vue-sse.esm.browser.min.js',
format: 'es',
},
plugins: [
resolve(),
commonjs(),
terser({ module: true })
],
inlineDynamicImports: true,
},
{
input: 'src/index.js',
output: {
banner,
file: 'dist/vue-sse.esm.js',
format: 'es',
},
plugins: [
buble(),
resolve(),
commonjs(),
],
inlineDynamicImports: true,
},
{
input: 'src/index.cjs.js',
output: {
banner,
file: 'dist/vue-sse.js',
format: 'umd',
name: 'VueSSE',
},
plugins: [
buble(),
resolve(),
commonjs(),
],
inlineDynamicImports: true,
},
{
input: 'src/index.cjs.js',
output: {
banner,
file: 'dist/vue-sse.min.js',
format: 'umd',
name: 'VueSSE',
},
plugins: [
buble(),
resolve(),
commonjs(),
terser({ module: false })
],
inlineDynamicImports: true,
},
{
input: 'src/index.cjs.js',
output: {
banner,
file: 'dist/vue-sse.common.js',
format: 'cjs',
exports: 'default',
},
plugins: [
buble(),
resolve(),
commonjs(),
],
inlineDynamicImports: true,
},
];
================================================
FILE: src/index.cjs.js
================================================
import SSEManager, { install } from './sse-manager';
export default {
SSEManager,
install,
};
================================================
FILE: src/index.js
================================================
import SSEManager, { install } from './sse-manager';
export default {
install,
};
export { SSEManager, install };
================================================
FILE: src/sse-client.js
================================================
import { EventSourcePolyfill } from 'event-source-polyfill';
export const formatText = (e) => e.data;
export const formatJSON = (e) => JSON.parse(e.data);
export default class SSEClient {
constructor(config) {
this._handlers = {};
this._listeners = {};
this._source = null;
if (config.format) {
if (typeof config.format === 'string') {
if (config.format === 'plain') {
this._format = formatText;
} else if (config.format === 'json') {
this._format = formatJSON;
} else {
this._format = formatText;
}
} else if (typeof config.format === 'function') {
this._format = config.format;
} else {
this._format = formatText;
}
} else {
this._format = formatText;
}
if (config.handlers) {
for (const event in config.handlers) {
this.on(event, config.handlers[event]);
}
}
this.url = config.url;
this.withCredentials = !!config.withCredentials;
this.polyfillOptions = config.polyfillOptions || {};
this.forcePolyfill = !!config.forcePolyfill;
}
get source() {
return this._source;
}
connect() {
if (this.forcePolyfill) {
this._source = new EventSourcePolyfill(
this.url,
Object.assign({}, this.polyfillOptions, {
withCredentials: this.withCredentials,
}),
);
} else {
this._source = new window.EventSource(this.url, {
withCredentials: this.withCredentials,
});
}
return new Promise((resolve, reject) => {
this._source.onopen = () => {
// Add event listeners that were added before we connected
for (let event in this._listeners) {
this._source.addEventListener(event, this._listeners[event]);
}
this._source.onerror = null;
resolve(this);
};
this._source.onerror = reject;
});
}
disconnect() {
if (this._source !== null) {
this._source.close();
this._source = null;
}
}
on(event, handler) {
if (!event) {
// Default "event-less" event
event = 'message';
}
if (!this._listeners[event]) {
this._create(event);
}
this._handlers[event].push(handler);
return this;
}
once(event, handler) {
this.on(event, (e) => {
this.off(event, handler);
handler(e);
});
return this;
}
off(event, handler) {
if (!this._handlers[event]) {
// no handlers registered for event
return this;
}
const idx = this._handlers[event].indexOf(handler);
if (idx === -1) {
// handler not registered for event
return this;
}
// remove handler from event
this._handlers[event].splice(idx, 1);
if (this._handlers[event].length === 0) {
// remove listener since no handlers exist
this._source.removeEventListener(event, this._listeners[event]);
delete this._handlers[event];
delete this._listeners[event];
}
return this;
}
_create(event) {
this._handlers[event] = [];
this._listeners[event] = (message) => {
let data;
try {
data = this._format(message);
} catch (err) {
if (typeof this._source.onerror === 'function') {
this._source.onerror(err);
}
return;
}
this._handlers[event].forEach((handler) => handler(data, message.lastEventId));
};
if (this._source) {
this._source.addEventListener(event, this._listeners[event]);
}
}
}
================================================
FILE: src/sse-manager.js
================================================
import SSEClient, { formatText } from './sse-client';
export function install(Vue, config) {
if (Vue.config && Vue.config.globalProperties) {
// Vue3
Vue.config.globalProperties.$sse = new SSEManager(config);
} else {
// Vue2
// eslint-disable-next-line no-param-reassign, no-multi-assign
Vue.$sse = Vue.prototype.$sse = new SSEManager(config);
}
if (config && config.polyfill) {
import('event-source-polyfill');
}
// This mixin allows components to specify that all clients that were
// created within it should be automatically disconnected (cleanup)
// when the component is destroyed.
Vue.mixin({
beforeCreate() {
if (this.$options.sse && this.$options.sse.cleanup) {
// We instantiate an SSEManager for this specific instance
// in order to track it (see discussions in #13 for rationale).
this.$sse = new SSEManager();
// We also set $clients to an empty array, as opposed to null,
// so that beforeDestroy and create know to use it.
this.$sse.$clients = [];
}
},
beforeDestroy() {
if (this.$sse.$clients !== null) {
this.$sse.$clients.forEach((c) => c.disconnect());
this.$sse.$clients = [];
}
},
});
}
export class SSEManager {
constructor(config) {
this.$defaultConfig = Object.assign(
{
format: formatText,
sendCredentials: false,
},
config,
);
this.$clients = null;
}
create(configOrURL) {
let config;
if (typeof configOrURL === 'object') {
config = configOrURL;
} else if (typeof configOrURL === 'string') {
config = {
url: configOrURL,
};
} else {
config = {};
}
const client = new SSEClient(Object.assign({}, this.$defaultConfig, config));
// If $clients is not null, then it's array that we should push this
// client into for later cleanup in our mixin's beforeDestroy.
if (this.$clients !== null) {
this.$clients.push(client);
}
return client;
}
}
export default SSEManager;
================================================
FILE: test/.eslintrc.json
================================================
{
"env": {
"jest": true
}
}
================================================
FILE: test/setup.js
================================================
import { EventSource } from 'mocksse';
Object.defineProperty(global, 'window', {
value: {
EventSource,
navigator: {
userAgent: 'jest',
},
},
});
================================================
FILE: test/sse-client.spec.js
================================================
import { MockEvent } from 'mocksse';
import SSEClient from '../src/sse-client';
describe('SSEClient', () => {
it('can receive eventless text messages', (done) => {
new MockEvent({
url: '/eventless-text',
responses: [{
type: 'message',
data: 'a short message',
}],
});
const client = new SSEClient({
url: '/eventless-text',
format: 'plain',
handlers: {
message: (msg) => {
try {
expect(msg).toEqual('a short message');
done();
} catch (err) {
done(err);
} finally {
client.disconnect();
}
},
},
});
client.connect();
});
it('can receive eventless json messages', (done) => {
new MockEvent({
url: '/eventless-json',
responses: [{
type: 'message',
data: '{"pi":3.14}',
}],
});
const client = new SSEClient({
url: '/eventless-json',
format: 'json',
handlers: {
message: (msg) => {
try {
expect(msg).toStrictEqual({ pi: 3.14 });
done();
} catch (err) {
done(err);
} finally {
client.disconnect();
}
},
},
});
client.connect();
});
it('can receive custom event messages', (done) => {
new MockEvent({
url: '/custom-event',
responses: [{
type: 'ping',
data: 'ok!',
}],
});
const client = new SSEClient({
url: '/custom-event',
handlers: {
ping: (msg) => {
try {
expect(msg).toStrictEqual('ok!');
done();
} catch (err) {
done(err);
} finally {
client.disconnect();
}
},
},
});
client.connect();
});
});
================================================
FILE: test/sse-manager.spec.js
================================================
import { createLocalVue, mount } from '@vue/test-utils';
import SSEManager from '../src/sse-manager';
import VueSSE from '../src/index';
describe('SSEManager', () => {
it('creates a client that inherits from manager config', () => {
const $sse = new SSEManager({
url: 'foo.local',
withCredentials: true,
});
const client = $sse.create({});
expect(client.url).toEqual('foo.local');
expect(client.withCredentials).toEqual(true);
});
it('creates a client that overrides manager config', () => {
const $sse = new SSEManager({
url: 'foo.local',
withCredentials: true,
});
const client = $sse.create({
url: 'bar.local',
withCredentials: false,
});
expect(client.url).toEqual('bar.local');
expect(client.withCredentials).toEqual(false);
});
it('creates a client from url string not config object', () => {
const $sse = new SSEManager();
const client = $sse.create('foo.local');
expect(client.url).toEqual('foo.local');
});
it('creates a client and cleans up', () => {
const localVue = createLocalVue()
localVue.use(VueSSE);
const wrapper = mount({
template: '<div></div>',
sse: {
cleanup: true,
},
mounted() {
this.$sse.create('bar.local');
},
}, { localVue });
wrapper.destroy();
expect(wrapper.vm.$sse.$clients).not.toBe(null);
expect(wrapper.vm.$sse.$clients).toHaveLength(0);
});
it('creates a client and does not clean up', () => {
const localVue = createLocalVue()
localVue.use(VueSSE);
const wrapper = mount({
template: '<div></div>',
sse: {
cleanup: false,
},
mounted() {
this.$sse.create('bar.local');
},
}, { localVue });
wrapper.destroy();
expect(wrapper.vm.$sse.$clients).toBe(null);
});
});
================================================
FILE: types/index.d.ts
================================================
import './vue';
import Vue from 'vue';
export type MessageFormatter<T> = (event: MessageEvent) => T;
export type MessageHandler = (data: any, lastEventId: string) => void;
export interface SSEConfig {
format?: 'plain' | 'json' | MessageFormatter<any>;
handlers?: Partial<Record<string, MessageHandler>>;
polyfill?: boolean;
forcePolyfill?: boolean;
polyfillOptions?: object;
url?: string;
withCredentials?: boolean;
}
export interface SSEComponentOptions {
cleanup?: boolean;
}
export declare class SSEManager {
$defaultConfig: SSEConfig;
$clients: SSEClient[] | null;
constructor(config?: SSEConfig);
create(configOrURL?: SSEConfig | string): SSEClient;
}
export declare class SSEClient {
url: string;
withCredentials: boolean;
_format: MessageFormatter<any>;
_handlers: Partial<Record<string, MessageHandler[]>>;
_listeners: Partial<Record<string, EventListener>>;
_source: EventSource;
constructor(config?: SSEConfig);
connect(): Promise<SSEClient>;
disconnect(): void;
on(event: string, handler: MessageHandler): SSEClient;
once(event: string, handler: MessageHandler): SSEClient;
off(event: string, handler: MessageHandler): SSEClient;
get source(): EventSource;
}
export declare function install(vue: typeof Vue, config?: SSEConfig): void;
declare const _default: {
SSEClient: typeof SSEClient;
SSEManager: typeof SSEManager;
install: typeof install;
}
export default _default;
================================================
FILE: types/vue.d.ts
================================================
import Vue from 'vue';
import { SSEComponentOptions, SSEManager } from './index';
declare module 'vue/types/vue' {
interface VueConstructor {
readonly $sse: SSEManager;
}
interface Vue {
$sse: SSEManager;
}
}
declare module 'vue/types/options' {
interface ComponentOptions<V extends Vue> {
sse?: SSEComponentOptions;
}
}
gitextract_pn7ugql7/
├── .babelrc
├── .editorconfig
├── .eslintrc.json
├── .gitignore
├── .prettierrc
├── LICENSE.md
├── README.md
├── dist/
│ ├── vue-sse.common.js
│ ├── vue-sse.esm.browser.js
│ ├── vue-sse.esm.js
│ ├── vue-sse.js
│ └── vue-sse.mjs
├── jest.config.js
├── package.json
├── rollup.config.js
├── src/
│ ├── index.cjs.js
│ ├── index.js
│ ├── sse-client.js
│ └── sse-manager.js
├── test/
│ ├── .eslintrc.json
│ ├── setup.js
│ ├── sse-client.spec.js
│ └── sse-manager.spec.js
└── types/
├── index.d.ts
└── vue.d.ts
SYMBOL INDEX (120 symbols across 9 files)
FILE: dist/vue-sse.common.js
function createCommonjsModule (line 10) | function createCommonjsModule(fn) {
function F (line 57) | function F(){}
function TextDecoderPolyfill (line 111) | function TextDecoderPolyfill() {
function valid (line 117) | function valid(codePoint, shift, octetsCount) {
function octetsCount (line 129) | function octetsCount(bitsNeeded, codePoint) {
function XHRWrapper (line 211) | function XHRWrapper(xhr) {
function toLowerCase (line 464) | function toLowerCase(name) {
function HeadersPolyfill (line 470) | function HeadersPolyfill(all) {
function XHRTransport (line 491) | function XHRTransport() {
function HeadersWrapper (line 532) | function HeadersWrapper(headers) {
function FetchTransport (line 539) | function FetchTransport() {
function EventTarget (line 592) | function EventTarget() {
function throwError (line 596) | function throwError(e) {
function Event (line 658) | function Event(type) {
function MessageEvent (line 663) | function MessageEvent(type, options) {
function ConnectionEvent (line 671) | function ConnectionEvent(type, options) {
function ErrorEvent (line 680) | function ErrorEvent(type, options) {
function EventSourcePolyfill (line 724) | function EventSourcePolyfill(url, options) {
function getBestXHRTransport (line 742) | function getBestXHRTransport() {
function start (line 750) | function start(es, url, options) {
function install (line 1220) | function install(Vue, config) {
FILE: dist/vue-sse.esm.browser.js
function createCommonjsModule (line 8) | function createCommonjsModule(fn) {
function F (line 55) | function F(){}
function TextDecoderPolyfill (line 109) | function TextDecoderPolyfill() {
function valid (line 115) | function valid(codePoint, shift, octetsCount) {
function octetsCount (line 127) | function octetsCount(bitsNeeded, codePoint) {
function XHRWrapper (line 209) | function XHRWrapper(xhr) {
function toLowerCase (line 462) | function toLowerCase(name) {
function HeadersPolyfill (line 468) | function HeadersPolyfill(all) {
function XHRTransport (line 489) | function XHRTransport() {
function HeadersWrapper (line 530) | function HeadersWrapper(headers) {
function FetchTransport (line 537) | function FetchTransport() {
function EventTarget (line 590) | function EventTarget() {
function throwError (line 594) | function throwError(e) {
function Event (line 656) | function Event(type) {
function MessageEvent (line 661) | function MessageEvent(type, options) {
function ConnectionEvent (line 669) | function ConnectionEvent(type, options) {
function ErrorEvent (line 678) | function ErrorEvent(type, options) {
function EventSourcePolyfill (line 722) | function EventSourcePolyfill(url, options) {
function getBestXHRTransport (line 740) | function getBestXHRTransport() {
function start (line 748) | function start(es, url, options) {
class SSEClient (line 1059) | class SSEClient {
method constructor (line 1060) | constructor(config) {
method source (line 1095) | get source() {
method connect (line 1099) | connect() {
method disconnect (line 1129) | disconnect() {
method on (line 1136) | on(event, handler) {
method once (line 1151) | once(event, handler) {
method off (line 1161) | off(event, handler) {
method _create (line 1186) | _create(event) {
function install (line 1210) | function install(Vue, config) {
class SSEManager (line 1248) | class SSEManager {
method constructor (line 1249) | constructor(config) {
method create (line 1261) | create(configOrURL) {
FILE: dist/vue-sse.esm.js
function createCommonjsModule (line 8) | function createCommonjsModule(fn) {
function F (line 55) | function F(){}
function TextDecoderPolyfill (line 109) | function TextDecoderPolyfill() {
function valid (line 115) | function valid(codePoint, shift, octetsCount) {
function octetsCount (line 127) | function octetsCount(bitsNeeded, codePoint) {
function XHRWrapper (line 209) | function XHRWrapper(xhr) {
function toLowerCase (line 462) | function toLowerCase(name) {
function HeadersPolyfill (line 468) | function HeadersPolyfill(all) {
function XHRTransport (line 489) | function XHRTransport() {
function HeadersWrapper (line 530) | function HeadersWrapper(headers) {
function FetchTransport (line 537) | function FetchTransport() {
function EventTarget (line 590) | function EventTarget() {
function throwError (line 594) | function throwError(e) {
function Event (line 656) | function Event(type) {
function MessageEvent (line 661) | function MessageEvent(type, options) {
function ConnectionEvent (line 669) | function ConnectionEvent(type, options) {
function ErrorEvent (line 678) | function ErrorEvent(type, options) {
function EventSourcePolyfill (line 722) | function EventSourcePolyfill(url, options) {
function getBestXHRTransport (line 740) | function getBestXHRTransport() {
function start (line 748) | function start(es, url, options) {
function install (line 1218) | function install(Vue, config) {
FILE: dist/vue-sse.js
function createCommonjsModule (line 14) | function createCommonjsModule(fn) {
function F (line 61) | function F(){}
function TextDecoderPolyfill (line 115) | function TextDecoderPolyfill() {
function valid (line 121) | function valid(codePoint, shift, octetsCount) {
function octetsCount (line 133) | function octetsCount(bitsNeeded, codePoint) {
function XHRWrapper (line 215) | function XHRWrapper(xhr) {
function toLowerCase (line 468) | function toLowerCase(name) {
function HeadersPolyfill (line 474) | function HeadersPolyfill(all) {
function XHRTransport (line 495) | function XHRTransport() {
function HeadersWrapper (line 536) | function HeadersWrapper(headers) {
function FetchTransport (line 543) | function FetchTransport() {
function EventTarget (line 596) | function EventTarget() {
function throwError (line 600) | function throwError(e) {
function Event (line 662) | function Event(type) {
function MessageEvent (line 667) | function MessageEvent(type, options) {
function ConnectionEvent (line 675) | function ConnectionEvent(type, options) {
function ErrorEvent (line 684) | function ErrorEvent(type, options) {
function EventSourcePolyfill (line 728) | function EventSourcePolyfill(url, options) {
function getBestXHRTransport (line 746) | function getBestXHRTransport() {
function start (line 754) | function start(es, url, options) {
function install (line 1224) | function install(Vue, config) {
FILE: src/sse-client.js
class SSEClient (line 7) | class SSEClient {
method constructor (line 8) | constructor(config) {
method source (line 43) | get source() {
method connect (line 47) | connect() {
method disconnect (line 77) | disconnect() {
method on (line 84) | on(event, handler) {
method once (line 99) | once(event, handler) {
method off (line 109) | off(event, handler) {
method _create (line 134) | _create(event) {
FILE: src/sse-manager.js
function install (line 3) | function install(Vue, config) {
class SSEManager (line 41) | class SSEManager {
method constructor (line 42) | constructor(config) {
method create (line 54) | create(configOrURL) {
FILE: test/sse-manager.spec.js
method mounted (line 50) | mounted() {
method mounted (line 70) | mounted() {
FILE: types/index.d.ts
type MessageFormatter (line 4) | type MessageFormatter<T> = (event: MessageEvent) => T;
type MessageHandler (line 6) | type MessageHandler = (data: any, lastEventId: string) => void;
type SSEConfig (line 8) | interface SSEConfig {
type SSEComponentOptions (line 18) | interface SSEComponentOptions {
class SSEManager (line 22) | class SSEManager {
class SSEClient (line 30) | class SSEClient {
FILE: types/vue.d.ts
type VueConstructor (line 5) | interface VueConstructor {
type Vue (line 9) | interface Vue {
type ComponentOptions (line 15) | interface ComponentOptions<V extends Vue> {
Condensed preview — 25 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (203K chars).
[
{
"path": ".babelrc",
"chars": 38,
"preview": "{\n \"presets\": [\"@babel/preset-env\"]\n}"
},
{
"path": ".editorconfig",
"chars": 123,
"preview": "root = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\n\n[*.js]\ncharset = utf-8\nindent_style = space\nindent_size ="
},
{
"path": ".eslintrc.json",
"chars": 67,
"preview": "{\n \"root\": true,\n \"extends\": [\n \"plugin:vue/recommended\"\n ]\n}"
},
{
"path": ".gitignore",
"chars": 71,
"preview": "node_modules\n/lib\n\n# SublimeText\n*.sublime-project\n*.sublime-workspace\n"
},
{
"path": ".prettierrc",
"chars": 72,
"preview": "{\n \"printWidth\": 120,\n \"trailingComma\": \"all\",\n \"singleQuote\": true\n}"
},
{
"path": "LICENSE.md",
"chars": 1072,
"preview": "MIT License\n\nCopyright (c) 2021 James Churchard\n\nPermission is hereby granted, free of charge, to any person obtaining a"
},
{
"path": "README.md",
"chars": 7770,
"preview": "# VueSSE\n[]()\n[ 2021 James Churchard\n * @license MIT\n */\n'use strict';\n\nvar commonjsGlobal = typeof globalT"
},
{
"path": "dist/vue-sse.esm.browser.js",
"chars": 40238,
"preview": "/*!\n * vue-sse v2.5.0\n * (c) 2021 James Churchard\n * @license MIT\n */\nvar commonjsGlobal = typeof globalThis !== 'undefi"
},
{
"path": "dist/vue-sse.esm.js",
"chars": 40628,
"preview": "/*!\n * vue-sse v2.5.0\n * (c) 2021 James Churchard\n * @license MIT\n */\nvar commonjsGlobal = typeof globalThis !== 'undefi"
},
{
"path": "dist/vue-sse.js",
"chars": 42122,
"preview": "/*!\n * vue-sse v2.5.0\n * (c) 2021 James Churchard\n * @license MIT\n */\n(function (global, factory) {\n\ttypeof exports === "
},
{
"path": "dist/vue-sse.mjs",
"chars": 147,
"preview": "import VueSSE from './vue-sse.common.js';\n\nconst {\n SSEManager,\n install,\n} = VueSSE;\n\nexport {\n VueSSE as default,\n "
},
{
"path": "jest.config.js",
"chars": 386,
"preview": "module.exports = {\n collectCoverageFrom: [\n 'src/**.*.js',\n '!src/index.cjs.js',\n ],\n coverageDirectory: 'cover"
},
{
"path": "package.json",
"chars": 2076,
"preview": "{\n \"name\": \"vue-sse\",\n \"version\": \"2.5.2\",\n \"description\": \"A Vue plugin for using Server-Sent Events (EventSource)\","
},
{
"path": "rollup.config.js",
"chars": 1877,
"preview": "import buble from '@rollup/plugin-buble';\nimport resolve from '@rollup/plugin-node-resolve'\nimport commonjs from '@rollu"
},
{
"path": "src/index.cjs.js",
"chars": 99,
"preview": "import SSEManager, { install } from './sse-manager';\n\nexport default {\n SSEManager,\n install,\n};\n"
},
{
"path": "src/index.js",
"chars": 118,
"preview": "import SSEManager, { install } from './sse-manager';\n\nexport default {\n install,\n};\n\nexport { SSEManager, install };\n"
},
{
"path": "src/sse-client.js",
"chars": 3549,
"preview": "import { EventSourcePolyfill } from 'event-source-polyfill';\n\nexport const formatText = (e) => e.data;\n\nexport const for"
},
{
"path": "src/sse-manager.js",
"chars": 2087,
"preview": "import SSEClient, { formatText } from './sse-client';\n\nexport function install(Vue, config) {\n if (Vue.config && Vue.co"
},
{
"path": "test/.eslintrc.json",
"chars": 35,
"preview": "{\n \"env\": {\n \"jest\": true\n }\n}"
},
{
"path": "test/setup.js",
"chars": 168,
"preview": "import { EventSource } from 'mocksse';\n\nObject.defineProperty(global, 'window', {\n value: {\n EventSource,\n naviga"
},
{
"path": "test/sse-client.spec.js",
"chars": 1854,
"preview": "import { MockEvent } from 'mocksse';\nimport SSEClient from '../src/sse-client';\n\ndescribe('SSEClient', () => {\n it('can"
},
{
"path": "test/sse-manager.spec.js",
"chars": 1870,
"preview": "import { createLocalVue, mount } from '@vue/test-utils';\nimport SSEManager from '../src/sse-manager';\nimport VueSSE from"
},
{
"path": "types/index.d.ts",
"chars": 1424,
"preview": "import './vue';\nimport Vue from 'vue';\n\nexport type MessageFormatter<T> = (event: MessageEvent) => T;\n\nexport type Messa"
},
{
"path": "types/vue.d.ts",
"chars": 348,
"preview": "import Vue from 'vue';\nimport { SSEComponentOptions, SSEManager } from './index';\n\ndeclare module 'vue/types/vue' {\n in"
}
]
About this extraction
This page contains the full source code of the tserkov/vue-sse GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 25 files (184.5 KB), approximately 45.3k tokens, and a symbol index with 120 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.